From 7c7612a971b4418ffe97850fd5612dfc574ad891 Mon Sep 17 00:00:00 2001 From: Jeremie Roy Date: Mon, 22 Apr 2013 22:42:11 +0200 Subject: [PATCH 01/38] integration of font and text system --- 3rdparty/freetype/FTL.TXT | 169 + 3rdparty/freetype/README.md | 5 + 3rdparty/freetype/freetype.h | 117420 +++++++++++++++ examples/10-font_alpha/basics.cpp | 207 + .../distance_field_text.cpp | 160 + examples/common/cube_atlas.cpp | 483 + examples/common/cube_atlas.h | 136 + examples/common/font/font_manager.cpp | 792 + examples/common/font/font_manager.h | 208 + examples/common/font/fs_font_basic.sc | 16 + .../common/font/fs_font_distance_field.sc | 27 + .../font/fs_font_distance_field_subpixel.sc | 40 + examples/common/font/makefile | 17 + examples/common/font/text_buffer_manager.cpp | 812 + examples/common/font/text_buffer_manager.h | 90 + examples/common/font/varying.def.sc | 9 + examples/common/font/vs_font_basic.sc | 11 + .../common/font/vs_font_distance_field.sc | 11 + .../font/vs_font_distance_field_subpixel.sc | 15 + examples/makefile | 1 + .../runtime/shaders/dx11/fs_font_basic.bin | Bin 0 -> 898 bytes .../shaders/dx11/fs_font_distance_field.bin | Bin 0 -> 1366 bytes .../dx11/fs_font_distance_field_subpixel.bin | Bin 0 -> 1622 bytes .../runtime/shaders/dx11/vs_font_basic.bin | Bin 0 -> 1300 bytes .../shaders/dx11/vs_font_distance_field.bin | Bin 0 -> 1300 bytes .../dx11/vs_font_distance_field_subpixel.bin | Bin 0 -> 1300 bytes .../runtime/shaders/dx9/fs_font_basic.bin | Bin 0 -> 445 bytes .../shaders/dx9/fs_font_distance_field.bin | Bin 0 -> 737 bytes .../dx9/fs_font_distance_field_subpixel.bin | Bin 0 -> 885 bytes .../runtime/shaders/dx9/vs_font_basic.bin | Bin 0 -> 335 bytes .../shaders/dx9/vs_font_distance_field.bin | Bin 0 -> 335 bytes .../dx9/vs_font_distance_field_subpixel.bin | Bin 0 -> 335 bytes .../runtime/shaders/gles/fs_font_basic.bin | Bin 0 -> 389 bytes .../shaders/gles/fs_font_distance_field.bin | Bin 0 -> 773 bytes .../gles/fs_font_distance_field_subpixel.bin | Bin 0 -> 1119 bytes .../runtime/shaders/gles/vs_font_basic.bin | Bin 0 -> 414 bytes .../shaders/gles/vs_font_distance_field.bin | Bin 0 -> 414 bytes .../gles/vs_font_distance_field_subpixel.bin | Bin 0 -> 414 bytes .../runtime/shaders/glsl/fs_font_basic.bin | Bin 0 -> 350 bytes .../shaders/glsl/fs_font_distance_field.bin | Bin 0 -> 734 bytes .../glsl/fs_font_distance_field_subpixel.bin | Bin 0 -> 1080 bytes .../runtime/shaders/glsl/vs_font_basic.bin | Bin 0 -> 375 bytes .../shaders/glsl/vs_font_distance_field.bin | Bin 0 -> 375 bytes .../glsl/vs_font_distance_field_subpixel.bin | Bin 0 -> 375 bytes premake/premake4.lua | 2 + 45 files changed, 120631 insertions(+) create mode 100644 3rdparty/freetype/FTL.TXT create mode 100644 3rdparty/freetype/README.md create mode 100644 3rdparty/freetype/freetype.h create mode 100644 examples/10-font_alpha/basics.cpp create mode 100644 examples/11-font_distance_field/distance_field_text.cpp create mode 100644 examples/common/cube_atlas.cpp create mode 100644 examples/common/cube_atlas.h create mode 100644 examples/common/font/font_manager.cpp create mode 100644 examples/common/font/font_manager.h create mode 100644 examples/common/font/fs_font_basic.sc create mode 100644 examples/common/font/fs_font_distance_field.sc create mode 100644 examples/common/font/fs_font_distance_field_subpixel.sc create mode 100644 examples/common/font/makefile create mode 100644 examples/common/font/text_buffer_manager.cpp create mode 100644 examples/common/font/text_buffer_manager.h create mode 100644 examples/common/font/varying.def.sc create mode 100644 examples/common/font/vs_font_basic.sc create mode 100644 examples/common/font/vs_font_distance_field.sc create mode 100644 examples/common/font/vs_font_distance_field_subpixel.sc create mode 100644 examples/runtime/shaders/dx11/fs_font_basic.bin create mode 100644 examples/runtime/shaders/dx11/fs_font_distance_field.bin create mode 100644 examples/runtime/shaders/dx11/fs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/dx11/vs_font_basic.bin create mode 100644 examples/runtime/shaders/dx11/vs_font_distance_field.bin create mode 100644 examples/runtime/shaders/dx11/vs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/dx9/fs_font_basic.bin create mode 100644 examples/runtime/shaders/dx9/fs_font_distance_field.bin create mode 100644 examples/runtime/shaders/dx9/fs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/dx9/vs_font_basic.bin create mode 100644 examples/runtime/shaders/dx9/vs_font_distance_field.bin create mode 100644 examples/runtime/shaders/dx9/vs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/gles/fs_font_basic.bin create mode 100644 examples/runtime/shaders/gles/fs_font_distance_field.bin create mode 100644 examples/runtime/shaders/gles/fs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/gles/vs_font_basic.bin create mode 100644 examples/runtime/shaders/gles/vs_font_distance_field.bin create mode 100644 examples/runtime/shaders/gles/vs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/glsl/fs_font_basic.bin create mode 100644 examples/runtime/shaders/glsl/fs_font_distance_field.bin create mode 100644 examples/runtime/shaders/glsl/fs_font_distance_field_subpixel.bin create mode 100644 examples/runtime/shaders/glsl/vs_font_basic.bin create mode 100644 examples/runtime/shaders/glsl/vs_font_distance_field.bin create mode 100644 examples/runtime/shaders/glsl/vs_font_distance_field_subpixel.bin diff --git a/3rdparty/freetype/FTL.TXT b/3rdparty/freetype/FTL.TXT new file mode 100644 index 00000000..bbaba33f --- /dev/null +++ b/3rdparty/freetype/FTL.TXT @@ -0,0 +1,169 @@ + The FreeType Project LICENSE + ---------------------------- + + 2006-Jan-27 + + Copyright 1996-2002, 2006 by + David Turner, Robert Wilhelm, and Werner Lemberg + + + +Introduction +============ + + The FreeType Project is distributed in several archive packages; + some of them may contain, in addition to the FreeType font engine, + various tools and contributions which rely on, or relate to, the + FreeType Project. + + This license applies to all files found in such packages, and + which do not fall under their own explicit license. The license + affects thus the FreeType font engine, the test programs, + documentation and makefiles, at the very least. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we will be + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + FreeType code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering The FreeType Project and + assume no liability related to The FreeType Project. + + + Finally, many people asked us for a preferred form for a + credit/disclaimer to use in compliance with this license. We thus + encourage you to use the following text: + + """ + Portions of this software are copyright © The FreeType + Project (www.freetype.org). All rights reserved. + """ + + Please replace with the value from the FreeType version you + actually use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `package', `FreeType Project', + and `FreeType archive' refer to the set of files originally + distributed by the authors (David Turner, Robert Wilhelm, and + Werner Lemberg) as the `FreeType Project', be they named as alpha, + beta or final release. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using the FreeType + engine'. + + This license applies to all files distributed in the original + FreeType Project, including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The FreeType Project is copyright (C) 1996-2000 by David Turner, + Robert Wilhelm, and Werner Lemberg. All rights reserved except as + specified below. + +1. No Warranty +-------------- + + THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO + USE, OF THE FREETYPE PROJECT. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the FreeType Project (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`FTL.TXT') unaltered; any additions, deletions or changes to + the original files must be clearly indicated in accompanying + documentation. The copyright notices of the unaltered, + original files must be preserved in all copies of source + files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part of the work of the + FreeType Team, in the distribution documentation. We also + encourage you to put an URL to the FreeType web page in your + documentation, though this isn't mandatory. + + These conditions apply to any software derived from or based on + the FreeType Project, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither the FreeType authors and contributors nor you shall use + the name of the other for commercial, advertising, or promotional + purposes without specific prior written permission. + + We suggest, but do not require, that you use one or more of the + following phrases to refer to this software in your documentation + or advertising materials: `FreeType Project', `FreeType Engine', + `FreeType library', or `FreeType Distribution'. + + As you have not signed this license, you are not required to + accept it. However, as the FreeType Project is copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the FreeType + Project, you indicate that you understand and accept all the terms + of this license. + +4. Contacts +----------- + + There are two mailing lists related to FreeType: + + o freetype@nongnu.org + + Discusses general use and applications of FreeType, as well as + future and wanted additions to the library and distribution. + If you are looking for support, start in this list if you + haven't found anything to help you in the documentation. + + o freetype-devel@nongnu.org + + Discusses bugs, as well as engine internals, design issues, + specific licenses, porting, etc. + + Our home page can be found at + + http://www.freetype.org + + +--- end of FTL.TXT --- diff --git a/3rdparty/freetype/README.md b/3rdparty/freetype/README.md new file mode 100644 index 00000000..c149d1d1 --- /dev/null +++ b/3rdparty/freetype/README.md @@ -0,0 +1,5 @@ +The Freetype code is copyright 2013 The FreeType Project. +All rights reserved. (www.freetype.org). +Distributed under the FreeType License: see FTL.TXT. + +freetype.h is an amalagmation of Freetype 2.4.11 made by Jeremie Roy in march 2013. \ No newline at end of file diff --git a/3rdparty/freetype/freetype.h b/3rdparty/freetype/freetype.h new file mode 100644 index 00000000..74173222 --- /dev/null +++ b/3rdparty/freetype/freetype.h @@ -0,0 +1,117420 @@ +#pragma once +/***************************************************************************/ +/* */ +/* ftsystem.c */ +/* */ +/* ANSI-specific FreeType low-level system interface (body). */ +/* */ +/* Copyright 1996-2002, 2006, 2008-2011 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 contains the default interface used by FreeType to access */ +/* low-level, i.e. memory management, i/o access as well as thread */ +/* synchronisation. It can be replaced by user-specific routines if */ +/* necessary. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* ft2build.h */ +/* */ +/* FreeType 2 build and setup macros. */ +/* (Generic version) */ +/* */ +/* Copyright 1996-2001, 2006 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 corresponds to the default `ft2build.h' file for */ +/* FreeType 2. It uses the `freetype' include root. */ +/* */ +/* Note that specific platforms might use a different configuration. */ +/* See builds/unix/ft2unix.h for an example. */ +/* */ +/*************************************************************************/ +#ifndef __FT2_BUILD_GENERIC_H__ +#define __FT2_BUILD_GENERIC_H__ +/***************************************************************************/ +/* */ +/* ftheader.h */ +/* */ +/* Build macros of the FreeType 2 library. */ +/* */ +/* Copyright 1996-2008, 2010, 2012 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 __FT_HEADER_H__ +#define __FT_HEADER_H__ +/*@***********************************************************************/ +/* */ +/* */ +/* FT_BEGIN_HEADER */ +/* */ +/* */ +/* This macro is used in association with @FT_END_HEADER in header */ +/* files to ensure that the declarations within are properly */ +/* encapsulated in an `extern "C" { .. }' block when included from a */ +/* C++ compiler. */ +/* */ +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +/* nothing */ +#define FT_BEGIN_HEADER +#endif +/*@***********************************************************************/ +/* */ +/* */ +/* FT_END_HEADER */ +/* */ +/* */ +/* This macro is used in association with @FT_BEGIN_HEADER in header */ +/* files to ensure that the declarations within are properly */ +/* encapsulated in an `extern "C" { .. }' block when included from a */ +/* C++ compiler. */ +/* */ +#ifdef __cplusplus +#define FT_END_HEADER } +#else +/* nothing */ +#define FT_END_HEADER +#endif +/*************************************************************************/ +/* */ +/* Aliases for the FreeType 2 public and configuration files. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/*
*/ +/* header_file_macros */ +/* */ +/* */ +/* Header File Macros */ +/* */ +/* <Abstract> */ +/* Macro definitions used to #include specific header files. */ +/* */ +/* <Description> */ +/* The following macros are defined to the name of specific */ +/* FreeType~2 header files. They can be used directly in #include */ +/* statements as in: */ +/* */ +/* { */ +/* #include FT_FREETYPE_H */ +/* #include FT_MULTIPLE_MASTERS_H */ +/* #include FT_GLYPH_H */ +/* } */ +/* */ +/* There are several reasons why we are now using macros to name */ +/* public header files. The first one is that such macros are not */ +/* limited to the infamous 8.3~naming rule required by DOS (and */ +/* `FT_MULTIPLE_MASTERS_H' is a lot more meaningful than `ftmm.h'). */ +/* */ +/* The second reason is that it allows for more flexibility in the */ +/* way FreeType~2 is installed on a given system. */ +/* */ +/*************************************************************************/ +/* configuration files */ +/************************************************************************* + * + * @macro: + * FT_CONFIG_CONFIG_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType~2 configuration data. + * + */ +#ifndef FT_CONFIG_CONFIG_H +#define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h> +#endif +/************************************************************************* + * + * @macro: + * FT_CONFIG_STANDARD_LIBRARY_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType~2 interface to the standard C library functions. + * + */ +#ifndef FT_CONFIG_STANDARD_LIBRARY_H +#define FT_CONFIG_STANDARD_LIBRARY_H <freetype/config/ftstdlib.h> +#endif +/************************************************************************* + * + * @macro: + * FT_CONFIG_OPTIONS_H + * + * @description: + * A macro used in #include statements to name the file containing + * FreeType~2 project-specific configuration options. + * + */ +#ifndef FT_CONFIG_OPTIONS_H +#define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h> +#endif +/************************************************************************* + * + * @macro: + * FT_CONFIG_MODULES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType~2 modules that are statically linked to new library + * instances in @FT_Init_FreeType. + * + */ +#ifndef FT_CONFIG_MODULES_H +#define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h> +#endif +/* */ +/* public headers */ +/************************************************************************* + * + * @macro: + * FT_FREETYPE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * base FreeType~2 API. + * + */ +#define FT_FREETYPE_H <freetype/freetype.h> +/************************************************************************* + * + * @macro: + * FT_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType~2 error codes (and messages). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_ERRORS_H <freetype/fterrors.h> +/************************************************************************* + * + * @macro: + * FT_MODULE_ERRORS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list of FreeType~2 module error offsets (and messages). + * + */ +#define FT_MODULE_ERRORS_H <freetype/ftmoderr.h> +/************************************************************************* + * + * @macro: + * FT_SYSTEM_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 interface to low-level operations (i.e., memory management + * and stream i/o). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_SYSTEM_H <freetype/ftsystem.h> +/************************************************************************* + * + * @macro: + * FT_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing type + * definitions related to glyph images (i.e., bitmaps, outlines, + * scan-converter parameters). + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_IMAGE_H <freetype/ftimage.h> +/************************************************************************* + * + * @macro: + * FT_TYPES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * basic data types defined by FreeType~2. + * + * It is included by @FT_FREETYPE_H. + * + */ +#define FT_TYPES_H <freetype/fttypes.h> +/************************************************************************* + * + * @macro: + * FT_LIST_H + * + * @description: + * A macro used in #include statements to name the file containing the + * list management API of FreeType~2. + * + * (Most applications will never need to include this file.) + * + */ +#define FT_LIST_H <freetype/ftlist.h> +/************************************************************************* + * + * @macro: + * FT_OUTLINE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * scalable outline management API of FreeType~2. + * + */ +#define FT_OUTLINE_H <freetype/ftoutln.h> +/************************************************************************* + * + * @macro: + * FT_SIZES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API which manages multiple @FT_Size objects per face. + * + */ +#define FT_SIZES_H <freetype/ftsizes.h> +/************************************************************************* + * + * @macro: + * FT_MODULE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * module management API of FreeType~2. + * + */ +#define FT_MODULE_H <freetype/ftmodapi.h> +/************************************************************************* + * + * @macro: + * FT_RENDER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * renderer module management API of FreeType~2. + * + */ +#define FT_RENDER_H <freetype/ftrender.h> +/************************************************************************* + * + * @macro: + * FT_AUTOHINTER_H + * + * @description: + * A macro used in #include statements to name the file containing + * structures and macros related to the auto-hinting module. + * + */ +#define FT_AUTOHINTER_H <freetype/ftautoh.h> +/************************************************************************* + * + * @macro: + * FT_TYPE1_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the Type~1 format. + * + */ +#define FT_TYPE1_TABLES_H <freetype/t1tables.h> +/************************************************************************* + * + * @macro: + * FT_TRUETYPE_IDS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * enumeration values which identify name strings, languages, encodings, + * etc. This file really contains a _large_ set of constant macro + * definitions, taken from the TrueType and OpenType specifications. + * + */ +#define FT_TRUETYPE_IDS_H <freetype/ttnameid.h> +/************************************************************************* + * + * @macro: + * FT_TRUETYPE_TABLES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * types and API specific to the TrueType (as well as OpenType) format. + * + */ +#define FT_TRUETYPE_TABLES_H <freetype/tttables.h> +/************************************************************************* + * + * @macro: + * FT_TRUETYPE_TAGS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of TrueType four-byte `tags' which identify blocks in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_TRUETYPE_TAGS_H <freetype/tttags.h> +/************************************************************************* + * + * @macro: + * FT_BDF_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which accesses BDF-specific strings from a + * face. + * + */ +#define FT_BDF_H <freetype/ftbdf.h> +/************************************************************************* + * + * @macro: + * FT_CID_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which access CID font information from a + * face. + * + */ +#define FT_CID_H <freetype/ftcid.h> +/************************************************************************* + * + * @macro: + * FT_GZIP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports gzip-compressed files. + * + */ +#define FT_GZIP_H <freetype/ftgzip.h> +/************************************************************************* + * + * @macro: + * FT_LZW_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports LZW-compressed files. + * + */ +#define FT_LZW_H <freetype/ftlzw.h> +/************************************************************************* + * + * @macro: + * FT_BZIP2_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports bzip2-compressed files. + * + */ +#define FT_BZIP2_H <freetype/ftbzip2.h> +/************************************************************************* + * + * @macro: + * FT_WINFONTS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * definitions of an API which supports Windows FNT files. + * + */ +#define FT_WINFONTS_H <freetype/ftwinfnt.h> +/************************************************************************* + * + * @macro: + * FT_GLYPH_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional glyph management component. + * + */ +#define FT_GLYPH_H <freetype/ftglyph.h> +/************************************************************************* + * + * @macro: + * FT_BITMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional bitmap conversion component. + * + */ +#define FT_BITMAP_H <freetype/ftbitmap.h> +/************************************************************************* + * + * @macro: + * FT_BBOX_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional exact bounding box computation routines. + * + */ +#define FT_BBOX_H <freetype/ftbbox.h> +/************************************************************************* + * + * @macro: + * FT_CACHE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * API of the optional FreeType~2 cache sub-system. + * + */ +#define FT_CACHE_H <freetype/ftcache.h> +/************************************************************************* + * + * @macro: + * FT_CACHE_IMAGE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `glyph image' API of the FreeType~2 cache sub-system. + * + * It is used to define a cache for @FT_Glyph elements. You can also + * use the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need to + * store small glyph bitmaps, as it will use less memory. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * glyph image-related cache declarations. + * + */ +#define FT_CACHE_IMAGE_H FT_CACHE_H +/************************************************************************* + * + * @macro: + * FT_CACHE_SMALL_BITMAPS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `small bitmaps' API of the FreeType~2 cache sub-system. + * + * It is used to define a cache for small glyph bitmaps in a relatively + * memory-efficient way. You can also use the API defined in + * @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images, + * including scalable outlines. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * small bitmaps-related cache declarations. + * + */ +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H +/************************************************************************* + * + * @macro: + * FT_CACHE_CHARMAP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * `charmap' API of the FreeType~2 cache sub-system. + * + * This macro is deprecated. Simply include @FT_CACHE_H to have all + * charmap-based cache declarations. + * + */ +#define FT_CACHE_CHARMAP_H FT_CACHE_H +/************************************************************************* + * + * @macro: + * FT_MAC_H + * + * @description: + * A macro used in #include statements to name the file containing the + * Macintosh-specific FreeType~2 API. The latter is used to access + * fonts embedded in resource forks. + * + * This header file must be explicitly included by client applications + * compiled on the Mac (note that the base API still works though). + * + */ +#define FT_MAC_H <freetype/ftmac.h> +/************************************************************************* + * + * @macro: + * FT_MULTIPLE_MASTERS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional multiple-masters management API of FreeType~2. + * + */ +#define FT_MULTIPLE_MASTERS_H <freetype/ftmm.h> +/************************************************************************* + * + * @macro: + * FT_SFNT_NAMES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType~2 API which accesses embedded `name' strings in + * SFNT-based font formats (i.e., TrueType and OpenType). + * + */ +#define FT_SFNT_NAMES_H <freetype/ftsnames.h> +/************************************************************************* + * + * @macro: + * FT_OPENTYPE_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType~2 API which validates OpenType tables (BASE, GDEF, + * GPOS, GSUB, JSTF). + * + */ +#define FT_OPENTYPE_VALIDATE_H <freetype/ftotval.h> +/************************************************************************* + * + * @macro: + * FT_GX_VALIDATE_H + * + * @description: + * A macro used in #include statements to name the file containing the + * optional FreeType~2 API which validates TrueTypeGX/AAT tables (feat, + * mort, morx, bsln, just, kern, opbd, trak, prop). + * + */ +#define FT_GX_VALIDATE_H <freetype/ftgxval.h> +/************************************************************************* + * + * @macro: + * FT_PFR_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which accesses PFR-specific data. + * + */ +#define FT_PFR_H <freetype/ftpfr.h> +/************************************************************************* + * + * @macro: + * FT_STROKER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which provides functions to stroke outline paths. + */ +#define FT_STROKER_H <freetype/ftstroke.h> +/************************************************************************* + * + * @macro: + * FT_SYNTHESIS_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs artificial obliquing and emboldening. + */ +#define FT_SYNTHESIS_H <freetype/ftsynth.h> +/************************************************************************* + * + * @macro: + * FT_XFREE86_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which provides functions specific to the XFree86 and + * X.Org X11 servers. + */ +#define FT_XFREE86_H <freetype/ftxf86.h> +/************************************************************************* + * + * @macro: + * FT_TRIGONOMETRY_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs trigonometric computations (e.g., + * cosines and arc tangents). + */ +#define FT_TRIGONOMETRY_H <freetype/fttrigon.h> +/************************************************************************* + * + * @macro: + * FT_LCD_FILTER_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_LCD_FILTER_H <freetype/ftlcdfil.h> +/************************************************************************* + * + * @macro: + * FT_UNPATENTED_HINTING_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_UNPATENTED_HINTING_H <freetype/ttunpat.h> +/************************************************************************* + * + * @macro: + * FT_INCREMENTAL_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which performs color filtering for subpixel rendering. + */ +#define FT_INCREMENTAL_H <freetype/ftincrem.h> +/************************************************************************* + * + * @macro: + * FT_GASP_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which returns entries from the TrueType GASP table. + */ +#define FT_GASP_H <freetype/ftgasp.h> +/************************************************************************* + * + * @macro: + * FT_ADVANCES_H + * + * @description: + * A macro used in #include statements to name the file containing the + * FreeType~2 API which returns individual and ranged glyph advances. + */ +#define FT_ADVANCES_H <freetype/ftadvanc.h> +/* */ +#define FT_ERROR_DEFINITIONS_H <freetype/fterrdef.h> +/* The internals of the cache sub-system are no longer exposed. We */ +/* default to FT_CACHE_H at the moment just in case, but we know of */ +/* no rogue client that uses them. */ +/* */ +#define FT_CACHE_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MRU_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_MANAGER_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_CACHE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_GLYPH_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_IMAGE_H <freetype/ftcache.h> +#define FT_CACHE_INTERNAL_SBITS_H <freetype/ftcache.h> +#define FT_INCREMENTAL_H <freetype/ftincrem.h> +#define FT_TRUETYPE_UNPATENTED_H <freetype/ttunpat.h> +/* + * Include internal headers definitions from <freetype/internal/...> + * only when building the library. + */ +#ifdef FT2_BUILD_LIBRARY +#define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h> +/***************************************************************************/ +/* */ +/* internal.h */ +/* */ +/* Internal header files (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004 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 automatically included by `ft2build.h'. */ +/* Do not include it manually! */ +/* */ +/*************************************************************************/ +#define FT_INTERNAL_OBJECTS_H <freetype/internal/ftobjs.h> +#define FT_INTERNAL_PIC_H <freetype/internal/ftpic.h> +#define FT_INTERNAL_STREAM_H <freetype/internal/ftstream.h> +#define FT_INTERNAL_MEMORY_H <freetype/internal/ftmemory.h> +#define FT_INTERNAL_DEBUG_H <freetype/internal/ftdebug.h> +#define FT_INTERNAL_CALC_H <freetype/internal/ftcalc.h> +#define FT_INTERNAL_DRIVER_H <freetype/internal/ftdriver.h> +#define FT_INTERNAL_TRACE_H <freetype/internal/fttrace.h> +#define FT_INTERNAL_GLYPH_LOADER_H <freetype/internal/ftgloadr.h> +#define FT_INTERNAL_SFNT_H <freetype/internal/sfnt.h> +#define FT_INTERNAL_SERVICE_H <freetype/internal/ftserv.h> +#define FT_INTERNAL_RFORK_H <freetype/internal/ftrfork.h> +#define FT_INTERNAL_VALIDATE_H <freetype/internal/ftvalid.h> +#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h> +#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h> +#define FT_INTERNAL_POSTSCRIPT_AUX_H <freetype/internal/psaux.h> +#define FT_INTERNAL_POSTSCRIPT_HINTS_H <freetype/internal/pshints.h> +#define FT_INTERNAL_POSTSCRIPT_GLOBALS_H <freetype/internal/psglobal.h> +#define FT_INTERNAL_AUTOHINT_H <freetype/internal/autohint.h> +/* END */ +/* FT2_BUILD_LIBRARY */ +#endif +/* __FT2_BUILD_H__ */ +#endif +/* END */ +/* __FT2_BUILD_GENERIC_H__ */ +#endif +/* END */ +/***************************************************************************/ +/* */ +/* ftconfig.h */ +/* */ +/* ANSI-specific configuration file (specification only). */ +/* */ +/* Copyright 1996-2004, 2006-2008, 2010-2011 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 contains a number of macro definitions that are used */ +/* by the rest of the engine. Most of the macros here are automatically */ +/* determined at compile time, and you should not need to change it to */ +/* port FreeType, except to compile the library with a non-ANSI */ +/* compiler. */ +/* */ +/* Note however that if some specific modifications are needed, we */ +/* advise you to place a modified copy in your build directory. */ +/* */ +/* The build directory is usually `freetype/builds/<system>', and */ +/* contains system-specific files that are always included first when */ +/* building the library. */ +/* */ +/* This ANSI version should stay in `include/freetype/config'. */ +/* */ +/*************************************************************************/ +#define __FTCONFIG_H__ +/***************************************************************************/ +/* */ +/* ftoption.h */ +/* */ +/* User-selectable configuration macros (specification only). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +#define __FTOPTION_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* USER-SELECTABLE CONFIGURATION MACROS */ +/* */ +/* This file contains the default configuration macro definitions for */ +/* a standard build of the FreeType library. There are three ways to */ +/* use this file to build project-specific versions of the library: */ +/* */ +/* - You can modify this file by hand, but this is not recommended in */ +/* cases where you would like to build several versions of the */ +/* library from a single source directory. */ +/* */ +/* - You can put a copy of this file in your build directory, more */ +/* precisely in `$BUILD/freetype/config/ftoption.h', where `$BUILD' */ +/* is the name of a directory that is included _before_ the FreeType */ +/* include path during compilation. */ +/* */ +/* The default FreeType Makefiles and Jamfiles use the build */ +/* directory `builds/<system>' by default, but you can easily change */ +/* that for your own projects. */ +/* */ +/* - Copy the file <ft2build.h> to `$BUILD/ft2build.h' and modify it */ +/* slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to */ +/* locate this file during the build. For example, */ +/* */ +/* #define FT_CONFIG_OPTIONS_H <myftoptions.h> */ +/* #include <freetype/config/ftheader.h> */ +/* */ +/* will use `$BUILD/myftoptions.h' instead of this file for macro */ +/* definitions. */ +/* */ +/* Note also that you can similarly pre-define the macro */ +/* FT_CONFIG_MODULES_H used to locate the file listing of the modules */ +/* that are statically linked to the library at compile time. By */ +/* default, this file is <freetype/config/ftmodule.h>. */ +/* */ +/* We highly recommend using the third method whenever possible. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Uncomment the line below if you want to activate sub-pixel rendering */ +/* (a.k.a. LCD rendering, or ClearType) in this build of the library. */ +/* */ +/* Note that this feature is covered by several Microsoft patents */ +/* and should not be activated in any default build of the library. */ +/* */ +/* This macro has no impact on the FreeType API, only on its */ +/* _implementation_. For example, using FT_RENDER_MODE_LCD when calling */ +/* FT_Render_Glyph still generates a bitmap that is 3 times wider than */ +/* the original size in case this macro isn't defined; however, each */ +/* triplet of subpixels has R=G=B. */ +/* */ +/* This is done to allow FreeType clients to run unmodified, forcing */ +/* them to display normal gray-level anti-aliased glyphs. */ +/* */ +#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING +/*************************************************************************/ +/* */ +/* Many compilers provide a non-ANSI 64-bit data type that can be used */ +/* by FreeType to speed up some computations. However, this will create */ +/* some problems when compiling the library in strict ANSI mode. */ +/* */ +/* For this reason, the use of 64-bit integers is normally disabled when */ +/* the __STDC__ macro is defined. You can however disable this by */ +/* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here. */ +/* */ +/* For most compilers, this will only create compilation warnings when */ +/* building the library. */ +/* */ +/* ObNote: The compiler-specific 64-bit integers are detected in the */ +/* file `ftconfig.h' either statically or through the */ +/* `configure' script on supported platforms. */ +/* */ +#undef FT_CONFIG_OPTION_FORCE_INT64 +/*************************************************************************/ +/* */ +/* If this macro is defined, do not try to use an assembler version of */ +/* performance-critical functions (e.g. FT_MulFix). You should only do */ +/* that to verify that the assembler function works properly, or to */ +/* execute benchmark tests of the various implementations. */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ +#undef FT_CONFIG_OPTION_NO_ASSEMBLER +/*************************************************************************/ +/* */ +/* If this macro is defined, try to use an inlined assembler version of */ +/* the `FT_MulFix' function, which is a `hotspot' when loading and */ +/* hinting glyphs, and which should be executed as fast as possible. */ +/* */ +/* Note that if your compiler or CPU is not supported, this will default */ +/* to the standard and portable implementation found in `ftcalc.c'. */ +/* */ +#define FT_CONFIG_OPTION_INLINE_MULFIX +/*************************************************************************/ +/* */ +/* LZW-compressed file support. */ +/* */ +/* FreeType now handles font files that have been compressed with the */ +/* `compress' program. This is mostly used to parse many of the PCF */ +/* files that come with various X11 distributions. The implementation */ +/* uses NetBSD's `zopen' to partially uncompress the file on the fly */ +/* (see src/lzw/ftgzip.c). */ +/* */ +/* Define this macro if you want to enable this `feature'. */ +/* */ +/* #define FT_CONFIG_OPTION_USE_LZW */ +#undef FT_CONFIG_OPTION_USE_LZW +/*************************************************************************/ +/* */ +/* Gzip-compressed file support. */ +/* */ +/* FreeType now handles font files that have been compressed with the */ +/* `gzip' program. This is mostly used to parse many of the PCF files */ +/* that come with XFree86. The implementation uses `zlib' to */ +/* partially uncompress the file on the fly (see src/gzip/ftgzip.c). */ +/* */ +/* Define this macro if you want to enable this `feature'. See also */ +/* the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below. */ +/* */ +/* #define FT_CONFIG_OPTION_USE_ZLIB */ +#undef FT_CONFIG_OPTION_USE_ZLIB +/*************************************************************************/ +/* */ +/* ZLib library selection */ +/* */ +/* This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined. */ +/* It allows FreeType's `ftgzip' component to link to the system's */ +/* installation of the ZLib library. This is useful on systems like */ +/* Unix or VMS where it generally is already available. */ +/* */ +/* If you let it undefined, the component will use its own copy */ +/* of the zlib sources instead. These have been modified to be */ +/* included directly within the component and *not* export external */ +/* function names. This allows you to link any program with FreeType */ +/* _and_ ZLib without linking conflicts. */ +/* */ +/* Do not #undef this macro here since the build system might define */ +/* it for certain configurations only. */ +/* */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + #undef FT_CONFIG_OPTION_SYSTEM_ZLIB +/*************************************************************************/ +/* */ +/* Bzip2-compressed file support. */ +/* */ +/* FreeType now handles font files that have been compressed with the */ +/* `bzip2' program. This is mostly used to parse many of the PCF */ +/* files that come with XFree86. The implementation uses `libbz2' to */ +/* partially uncompress the file on the fly (see src/bzip2/ftbzip2.c). */ +/* Contrary to gzip, bzip2 currently is not included and need to use */ +/* the system available bzip2 implementation. */ +/* */ +/* Define this macro if you want to enable this `feature'. */ +/* */ +/* #define FT_CONFIG_OPTION_USE_BZIP2 */ +#undef FT_CONFIG_OPTION_USE_BZIP2 +/*************************************************************************/ +/* */ +/* Define to disable the use of file stream functions and types, FILE, */ +/* fopen() etc. Enables the use of smaller system libraries on embedded */ +/* systems that have multiple system libraries, some with or without */ +/* file stream support, in the cases where file stream support is not */ +/* necessary such as memory loading of font files. */ +/* */ +/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ +#undef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT +/*************************************************************************/ +/* */ +/* DLL export compilation */ +/* */ +/* When compiling FreeType as a DLL, some systems/compilers need a */ +/* special keyword in front OR after the return type of function */ +/* declarations. */ +/* */ +/* Two macros are used within the FreeType source code to define */ +/* exported library functions: FT_EXPORT and FT_EXPORT_DEF. */ +/* */ +/* FT_EXPORT( return_type ) */ +/* */ +/* is used in a function declaration, as in */ +/* */ +/* FT_EXPORT( FT_Error ) */ +/* FT_Init_FreeType( FT_Library* alibrary ); */ +/* */ +/* */ +/* FT_EXPORT_DEF( return_type ) */ +/* */ +/* is used in a function definition, as in */ +/* */ +/* FT_EXPORT_DEF( FT_Error ) */ +/* FT_Init_FreeType( FT_Library* alibrary ) */ +/* { */ +/* ... some code ... */ +/* return FT_Err_Ok; */ +/* } */ +/* */ +/* You can provide your own implementation of FT_EXPORT and */ +/* FT_EXPORT_DEF here if you want. If you leave them undefined, they */ +/* will be later automatically defined as `extern return_type' to */ +/* allow normal compilation. */ +/* */ +/* Do not #undef these macros here since the build system might define */ +/* them for certain configurations only. */ +/* */ +/* #define FT_EXPORT(x) extern x */ +/* #define FT_EXPORT_DEF(x) x */ +/*************************************************************************/ +/* */ +/* Glyph Postscript Names handling */ +/* */ +/* By default, FreeType 2 is compiled with the `psnames' module. This */ +/* module is in charge of converting a glyph name string into a */ +/* Unicode value, or return a Macintosh standard glyph name for the */ +/* use with the TrueType `post' table. */ +/* */ +/* Undefine this macro if you do not want `psnames' compiled in your */ +/* build of FreeType. This has the following effects: */ +/* */ +/* - The TrueType driver will provide its own set of glyph names, */ +/* if you build it to support postscript names in the TrueType */ +/* `post' table. */ +/* */ +/* - The Type 1 driver will not be able to synthesize a Unicode */ +/* charmap out of the glyphs found in the fonts. */ +/* */ +/* You would normally undefine this configuration macro when building */ +/* a version of FreeType that doesn't contain a Type 1 or CFF driver. */ +/* */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES +/*************************************************************************/ +/* */ +/* Postscript Names to Unicode Values support */ +/* */ +/* By default, FreeType 2 is built with the `PSNames' module compiled */ +/* in. Among other things, the module is used to convert a glyph name */ +/* into a Unicode value. This is especially useful in order to */ +/* synthesize on the fly a Unicode charmap from the CFF/Type 1 driver */ +/* through a big table named the `Adobe Glyph List' (AGL). */ +/* */ +/* Undefine this macro if you do not want the Adobe Glyph List */ +/* compiled in your `PSNames' module. The Type 1 driver will not be */ +/* able to synthesize a Unicode charmap out of the glyphs found in the */ +/* fonts. */ +/* */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST +/*************************************************************************/ +/* */ +/* Support for Mac fonts */ +/* */ +/* Define this macro if you want support for outline fonts in Mac */ +/* format (mac dfont, mac resource, macbinary containing a mac */ +/* resource) on non-Mac platforms. */ +/* */ +/* Note that the `FOND' resource isn't checked. */ +/* */ +#define FT_CONFIG_OPTION_MAC_FONTS +/*************************************************************************/ +/* */ +/* Guessing methods to access embedded resource forks */ +/* */ +/* Enable extra Mac fonts support on non-Mac platforms (e.g. */ +/* GNU/Linux). */ +/* */ +/* Resource forks which include fonts data are stored sometimes in */ +/* locations which users or developers don't expected. In some cases, */ +/* resource forks start with some offset from the head of a file. In */ +/* other cases, the actual resource fork is stored in file different */ +/* from what the user specifies. If this option is activated, */ +/* FreeType tries to guess whether such offsets or different file */ +/* names must be used. */ +/* */ +/* Note that normal, direct access of resource forks is controlled via */ +/* the FT_CONFIG_OPTION_MAC_FONTS option. */ +/* */ +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +/*************************************************************************/ +/* */ +/* Allow the use of FT_Incremental_Interface to load typefaces that */ +/* contain no glyph data, but supply it via a callback function. */ +/* This is required by clients supporting document formats which */ +/* supply font data incrementally as the document is parsed, such */ +/* as the Ghostscript interpreter for the PostScript language. */ +/* */ +#define FT_CONFIG_OPTION_INCREMENTAL +/*************************************************************************/ +/* */ +/* The size in bytes of the render pool used by the scan-line converter */ +/* to do all of its work. */ +/* */ +/* This must be greater than 4KByte if you use FreeType to rasterize */ +/* glyphs; otherwise, you may set it to zero to avoid unnecessary */ +/* allocation of the render pool. */ +/* */ +#define FT_RENDER_POOL_SIZE 16384L +/*************************************************************************/ +/* */ +/* FT_MAX_MODULES */ +/* */ +/* The maximum number of modules that can be registered in a single */ +/* FreeType library object. 32 is the default. */ +/* */ +#define FT_MAX_MODULES 32 +/*************************************************************************/ +/* */ +/* Debug level */ +/* */ +/* FreeType can be compiled in debug or trace mode. In debug mode, */ +/* errors are reported through the `ftdebug' component. In trace */ +/* mode, additional messages are sent to the standard output during */ +/* execution. */ +/* */ +/* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */ +/* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */ +/* */ +/* Don't define any of these macros to compile in `release' mode! */ +/* */ +/* Do not #undef these macros here since the build system might define */ +/* them for certain configurations only. */ +/* */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ +#undef FT_DEBUG_LEVEL_ERROR +#undef FT_DEBUG_LEVEL_TRACE +/*************************************************************************/ +/* */ +/* Autofitter debugging */ +/* */ +/* If FT_DEBUG_AUTOFIT is defined, FreeType provides some means to */ +/* control the autofitter behaviour for debugging purposes with global */ +/* boolean variables (consequently, you should *never* enable this */ +/* while compiling in `release' mode): */ +/* */ +/* _af_debug_disable_horz_hints */ +/* _af_debug_disable_vert_hints */ +/* _af_debug_disable_blue_hints */ +/* */ +/* Additionally, the following functions provide dumps of various */ +/* internal autofit structures to stdout (using `printf'): */ +/* */ +/* af_glyph_hints_dump_points */ +/* af_glyph_hints_dump_segments */ +/* af_glyph_hints_dump_edges */ +/* */ +/* As an argument, they use another global variable: */ +/* */ +/* _af_debug_hints */ +/* */ +/* Please have a look at the `ftgrid' demo program to see how those */ +/* variables and macros should be used. */ +/* */ +/* Do not #undef these macros here since the build system might define */ +/* them for certain configurations only. */ +/* */ +/* #define FT_DEBUG_AUTOFIT */ +#undef FT_DEBUG_AUTOFIT +/*************************************************************************/ +/* */ +/* Memory Debugging */ +/* */ +/* FreeType now comes with an integrated memory debugger that is */ +/* capable of detecting simple errors like memory leaks or double */ +/* deletes. To compile it within your build of the library, you */ +/* should define FT_DEBUG_MEMORY here. */ +/* */ +/* Note that the memory debugger is only activated at runtime when */ +/* when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */ +/* */ +/* Do not #undef this macro here since the build system might define */ +/* it for certain configurations only. */ +/* */ +/* #define FT_DEBUG_MEMORY */ +#undef FT_DEBUG_MEMORY +/*************************************************************************/ +/* */ +/* Module errors */ +/* */ +/* If this macro is set (which is _not_ the default), the higher byte */ +/* of an error code gives the module in which the error has occurred, */ +/* while the lower byte is the real error code. */ +/* */ +/* Setting this macro makes sense for debugging purposes only, since */ +/* it would break source compatibility of certain programs that use */ +/* FreeType 2. */ +/* */ +/* More details can be found in the files ftmoderr.h and fterrors.h. */ +/* */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS +/*************************************************************************/ +/* */ +/* Position Independent Code */ +/* */ +/* If this macro is set (which is _not_ the default), FreeType2 will */ +/* avoid creating constants that require address fixups. Instead the */ +/* constants will be moved into a struct and additional intialization */ +/* code will be used. */ +/* */ +/* Setting this macro is needed for systems that prohibit address */ +/* fixups, such as BREW. */ +/* */ +/* #define FT_CONFIG_OPTION_PIC */ +#undef FT_CONFIG_OPTION_PIC +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** S F N T D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ +/* embedded bitmaps in all formats using the SFNT module (namely */ +/* TrueType & OpenType). */ +/* */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */ +/* load and enumerate the glyph Postscript names in a TrueType or */ +/* OpenType file. */ +/* */ +/* Note that when you do not compile the `PSNames' module by undefining */ +/* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */ +/* contain additional code used to read the PS Names table from a font. */ +/* */ +/* (By default, the module uses `PSNames' to extract glyph names.) */ +/* */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */ +/* access the internal name table in a SFNT-based format like TrueType */ +/* or OpenType. The name table contains various strings used to */ +/* describe the font, like family name, copyright, version, etc. It */ +/* does not contain any glyph name though. */ +/* */ +/* Accessing SFNT names is done through the functions declared in */ +/* `freetype/ftsnames.h'. */ +/* */ +#define TT_CONFIG_OPTION_SFNT_NAMES +/*************************************************************************/ +/* */ +/* TrueType CMap support */ +/* */ +/* Here you can fine-tune which TrueType CMap table format shall be */ +/* supported. */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ +/* a bytecode interpreter in the TrueType driver. */ +/* */ +/* By undefining this, you will only compile the code necessary to load */ +/* TrueType glyphs without hinting. */ +/* */ +/* Do not #undef this macro here, since the build system might */ +/* define it for certain configurations only. */ +/* */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ +/* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */ +/* replaces the native TrueType hinting mechanism when anything but */ +/* FT_RENDER_MODE_MONO is requested. */ +/* */ +/* Enabling this causes the TrueType driver to ignore instructions under */ +/* certain conditions. This is done in accordance with the guide here, */ +/* with some minor differences: */ +/* */ +/* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ +/* */ +/* By undefining this, you only compile the code necessary to hint */ +/* TrueType glyphs with native TT hinting. */ +/* */ +/* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ +/* defined. */ +/* */ +/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +#undef TT_CONFIG_OPTION_SUBPIXEL_HINTING +/*************************************************************************/ +/* */ +/* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */ +/* of the TrueType bytecode interpreter is used that doesn't implement */ +/* any of the patented opcodes and algorithms. The patents related to */ +/* TrueType hinting have expired worldwide since May 2010; this option */ +/* is now deprecated. */ +/* */ +/* Note that the TT_CONFIG_OPTION_UNPATENTED_HINTING macro is *ignored* */ +/* if you define TT_CONFIG_OPTION_BYTECODE_INTERPRETER; in other words, */ +/* either define TT_CONFIG_OPTION_BYTECODE_INTERPRETER or */ +/* TT_CONFIG_OPTION_UNPATENTED_HINTING but not both at the same time. */ +/* */ +/* This macro is only useful for a small number of font files (mostly */ +/* for Asian scripts) that require bytecode interpretation to properly */ +/* load glyphs. For all other fonts, this produces unpleasant results, */ +/* thus the unpatented interpreter is never used to load glyphs from */ +/* TrueType fonts unless one of the following two options is used. */ +/* */ +/* - The unpatented interpreter is explicitly activated by the user */ +/* through the FT_PARAM_TAG_UNPATENTED_HINTING parameter tag */ +/* when opening the FT_Face. */ +/* */ +/* - FreeType detects that the FT_Face corresponds to one of the */ +/* `trick' fonts (e.g., `Mingliu') it knows about. The font engine */ +/* contains a hard-coded list of font names and other matching */ +/* parameters (see function `tt_face_init' in file */ +/* `src/truetype/ttobjs.c'). */ +/* */ +/* Here a sample code snippet for using FT_PARAM_TAG_UNPATENTED_HINTING. */ +/* */ +/* { */ +/* FT_Parameter parameter; */ +/* FT_Open_Args open_args; */ +/* */ +/* */ +/* parameter.tag = FT_PARAM_TAG_UNPATENTED_HINTING; */ +/* */ +/* open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; */ +/* open_args.pathname = my_font_pathname; */ +/* open_args.num_params = 1; */ +/* open_args.params = ¶meter; */ +/* */ +/* error = FT_Open_Face( library, &open_args, index, &face ); */ +/* ... */ +/* } */ +/* */ +/* #define TT_CONFIG_OPTION_UNPATENTED_HINTING */ +#undef TT_CONFIG_OPTION_UNPATENTED_HINTING +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */ +/* bytecode interpreter with a huge switch statement, rather than a call */ +/* table. This results in smaller and faster code for a number of */ +/* architectures. */ +/* */ +/* Note however that on some compiler/processor combinations, undefining */ +/* this macro will generate faster, though larger, code. */ +/* */ +#define TT_CONFIG_OPTION_INTERPRETER_SWITCH +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the */ +/* TrueType glyph loader to use Apple's definition of how to handle */ +/* component offsets in composite glyphs. */ +/* */ +/* Apple and MS disagree on the default behavior of component offsets */ +/* in composites. Apple says that they should be scaled by the scaling */ +/* factors in the transformation matrix (roughly, it's more complex) */ +/* while MS says they should not. OpenType defines two bits in the */ +/* composite flags array which can be used to disambiguate, but old */ +/* fonts will not have them. */ +/* */ +/* http://www.microsoft.com/typography/otspec/glyf.htm */ +/* http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */ +/* */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include */ +/* support for Apple's distortable font technology (fvar, gvar, cvar, */ +/* and avar tables). This has many similarities to Type 1 Multiple */ +/* Masters support. */ +/* */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT +/*************************************************************************/ +/* */ +/* Define TT_CONFIG_OPTION_BDF if you want to include support for */ +/* an embedded `BDF ' table within SFNT-based bitmap formats. */ +/* */ +#define TT_CONFIG_OPTION_BDF +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* T1_MAX_DICT_DEPTH is the maximum depth of nest dictionaries and */ +/* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */ +/* required. */ +/* */ +#define T1_MAX_DICT_DEPTH 5 +/*************************************************************************/ +/* */ +/* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ +/* calls during glyph loading. */ +/* */ +#define T1_MAX_SUBRS_CALLS 16 +/*************************************************************************/ +/* */ +/* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ +/* minimum of 16 is required. */ +/* */ +/* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */ +/* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 +/*************************************************************************/ +/* */ +/* Define this configuration macro if you want to prevent the */ +/* compilation of `t1afm', which is in charge of reading Type 1 AFM */ +/* files into an existing face. Note that if set, the T1 driver will be */ +/* unable to produce kerning distances. */ +/* */ +#undef T1_CONFIG_OPTION_NO_AFM +/*************************************************************************/ +/* */ +/* Define this configuration macro if you want to prevent the */ +/* compilation of the Multiple Masters font support in the Type 1 */ +/* driver. */ +/* */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Compile autofit module with CJK (Chinese, Japanese, Korean) script */ +/* support. */ +/* */ +#define AF_CONFIG_OPTION_CJK +/*************************************************************************/ +/* */ +/* Compile autofit module with Indic script support. */ +/* */ +#define AF_CONFIG_OPTION_INDIC +/*************************************************************************/ +/* */ +/* Compile autofit module with warp hinting. The idea of the warping */ +/* code is to slightly scale and shift a glyph within a single dimension */ +/* so that as much of its segments are aligned (more or less) on the */ +/* grid. To find out the optimal scaling and shifting value, various */ +/* parameter combinations are tried and scored. */ +/* */ +/* This experimental option is only active if the render mode is */ +/* FT_RENDER_MODE_LIGHT. */ +/* */ +/* #define AF_CONFIG_OPTION_USE_WARPER */ +#undef AF_CONFIG_OPTION_USE_WARPER +/* */ +/* + * Define this variable if you want to keep the layout of internal + * structures that was used prior to FreeType 2.2. This also compiles in + * a few obsolete functions to avoid linking problems on typical Unix + * distributions. + * + * For embedded systems or building a new distribution from scratch, it + * is recommended to disable the macro since it reduces the library's code + * size and activates a few memory-saving optimizations as well. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS*/ +#undef FT_CONFIG_OPTION_OLD_INTERNALS +/* + * To detect legacy cache-lookup call from a rogue client (<= 2.1.7), + * we restrict the number of charmaps in a font. The current API of + * FTC_CMapCache_Lookup() takes cmap_index & charcode, but old API + * takes charcode only. To determine the passed value is for cmap_index + * or charcode, the possible cmap_index is restricted not to exceed + * the minimum possible charcode by a rogue client. It is also very + * unlikely that a rogue client is interested in Unicode values 0 to 15. + * + * NOTE: The original threshold was 4 deduced from popular number of + * cmap subtables in UCS-4 TrueType fonts, but now it is not + * irregular for OpenType fonts to have more than 4 subtables, + * because variation selector subtables are available for Apple + * and Microsoft platforms. + */ +/* + * This macro is defined if either unpatented or native TrueType + * hinting is requested by the definitions above. + */ +#define TT_USE_BYTECODE_INTERPRETER +#undef TT_CONFIG_OPTION_UNPATENTED_HINTING +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftstdlib.h */ +/* */ +/* ANSI-specific library and header configuration file (specification */ +/* only). */ +/* */ +/* Copyright 2002-2007, 2009, 2011-2012 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 group all #includes to the ANSI C library that */ +/* FreeType normally requires. It also defines macros to rename the */ +/* standard functions within the FreeType source code. */ +/* */ +/* Load a file which defines __FTSTDLIB_H__ before this one to override */ +/* it. */ +/* */ +/*************************************************************************/ +#define __FTSTDLIB_H__ +#include <stddef.h> +#define ft_ptrdiff_t ptrdiff_t +/**********************************************************************/ +/* */ +/* integer limits */ +/* */ +/* UINT_MAX and ULONG_MAX are used to automatically compute the size */ +/* of `int' and `long' in bytes at compile-time. So far, this works */ +/* for all platforms the library has been tested on. */ +/* */ +/* Note that on the extremely rare platforms that do not provide */ +/* integer types that are _exactly_ 16 and 32 bits wide (e.g. some */ +/* old Crays where `int' is 36 bits), we do not make any guarantee */ +/* about the correct behaviour of FT2 with all fonts. */ +/* */ +/* In these case, `ftconfig.h' will refuse to compile anyway with a */ +/* message like `couldn't find 32-bit type' or something similar. */ +/* */ +/**********************************************************************/ +#include <limits.h> +#define FT_CHAR_BIT CHAR_BIT +#define FT_USHORT_MAX USHRT_MAX +#define FT_INT_MAX INT_MAX +#define FT_INT_MIN INT_MIN +#define FT_UINT_MAX UINT_MAX +#define FT_ULONG_MAX ULONG_MAX +/**********************************************************************/ +/* */ +/* character and string processing */ +/* */ +/**********************************************************************/ +#include <string.h> +#define ft_memchr memchr +#define ft_memcmp memcmp +#define ft_memcpy memcpy +#define ft_memmove memmove +#define ft_memset memset +#define ft_strcat strcat +#define ft_strcmp strcmp +#define ft_strcpy strcpy +#define ft_strlen strlen +#define ft_strncmp strncmp +#define ft_strncpy strncpy +#define ft_strrchr strrchr +#define ft_strstr strstr +/**********************************************************************/ +/* */ +/* file handling */ +/* */ +/**********************************************************************/ +#include <stdio.h> +#define FT_FILE FILE +#define ft_fclose fclose +#define ft_fopen fopen +#define ft_fread fread +#define ft_fseek fseek +#define ft_ftell ftell +#define ft_sprintf sprintf +/**********************************************************************/ +/* */ +/* sorting */ +/* */ +/**********************************************************************/ +#include <stdlib.h> +#define ft_qsort qsort +/**********************************************************************/ +/* */ +/* memory allocation */ +/* */ +/**********************************************************************/ +#define ft_scalloc calloc +#define ft_sfree free +#define ft_smalloc malloc +#define ft_srealloc realloc +/**********************************************************************/ +/* */ +/* miscellaneous */ +/* */ +/**********************************************************************/ +#define ft_atol atol +#define ft_labs labs +/**********************************************************************/ +/* */ +/* execution control */ +/* */ +/**********************************************************************/ +#include <setjmp.h> +/* note: this cannot be a typedef since */ +#define ft_jmp_buf jmp_buf +/* jmp_buf is defined as a macro */ +/* on certain platforms */ +#define ft_longjmp longjmp +/* same thing here */ +#define ft_setjmp( b ) setjmp( *(ft_jmp_buf*) &(b) ) +/* the following is only used for debugging purposes, i.e., if */ +/* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE are defined */ +#include <stdarg.h> +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* PLATFORM-SPECIFIC CONFIGURATION MACROS */ +/* */ +/* These macros can be toggled to suit a specific system. The current */ +/* ones are defaults used to compile FreeType in an ANSI C environment */ +/* (16bit compilers are also supported). Copy this file to your own */ +/* `freetype/builds/<system>' directory, and edit it to port the engine. */ +/* */ +/*************************************************************************/ +/* There are systems (like the Texas Instruments 'C54x) where a `char' */ +/* has 16 bits. ANSI C says that sizeof(char) is always 1. Since an */ +/* `int' has 16 bits also for this system, sizeof(int) gives 1 which */ +/* is probably unexpected. */ +/* */ +/* `CHAR_BIT' (defined in limits.h) gives the number of bits in a */ +/* `char' type. */ +#ifndef FT_CHAR_BIT +#define FT_CHAR_BIT CHAR_BIT +#endif +/* The size of an `int' type. */ +#if FT_UINT_MAX == 0xFFFFUL +#define FT_SIZEOF_INT (16 / FT_CHAR_BIT) +#elif FT_UINT_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_INT (32 / FT_CHAR_BIT) +#elif FT_UINT_MAX > 0xFFFFFFFFUL && FT_UINT_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_INT (64 / FT_CHAR_BIT) +#else +#error "Unsupported size of `int' type!" +#endif +/* The size of a `long' type. A five-byte `long' (as used e.g. on the */ +/* DM642) is recognized but avoided. */ +#if FT_ULONG_MAX == 0xFFFFFFFFUL +#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFUL +#define FT_SIZEOF_LONG (32 / FT_CHAR_BIT) +#elif FT_ULONG_MAX > 0xFFFFFFFFUL && FT_ULONG_MAX == 0xFFFFFFFFFFFFFFFFUL +#define FT_SIZEOF_LONG (64 / FT_CHAR_BIT) +#else +#error "Unsupported size of `long' type!" +#endif +/* FT_UNUSED is a macro used to indicate that a given parameter is not */ +/* used -- this is only used to get rid of unpleasant compiler warnings */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif +/*************************************************************************/ +/* */ +/* AUTOMATIC CONFIGURATION MACROS */ +/* */ +/* These macros are computed from the ones defined above. Don't touch */ +/* their definition, unless you know precisely what you are doing. No */ +/* porter should need to mess with them. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Mac support */ +/* */ +/* This is the only necessary change, so it is defined here instead */ +/* providing a new configuration file. */ +/* */ +#if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) ) +/* no Carbon frameworks for 64bit 10.4.x */ +/* AvailabilityMacros.h is available since Mac OS X 10.2, */ +/* so guess the system version by maximum errno before inclusion */ +#include <errno.h> +/* defined since 10.2 */ +#ifdef ECANCELED +#include "AvailabilityMacros.h" +#endif +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#undef FT_MACINTOSH +#endif +#elif defined( __SC__ ) || defined( __MRC__ ) +/* Classic MacOS compilers */ +#include "ConditionalMacros.h" +#if TARGET_OS_MAC +#define FT_MACINTOSH 1 +#endif +#endif +/*************************************************************************/ +/* */ +/* <Section> */ +/* basic_types */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Int16 */ +/* */ +/* <Description> */ +/* A typedef for a 16bit signed integer type. */ +/* */ + typedef signed short FT_Int16; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_UInt16 */ +/* */ +/* <Description> */ +/* A typedef for a 16bit unsigned integer type. */ +/* */ + typedef unsigned short FT_UInt16; +/* */ +/* this #if 0 ... #endif clause is for documentation purposes */ +#if 0 +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Int32 */ +/* */ +/* <Description> */ +/* A typedef for a 32bit signed integer type. The size depends on */ +/* the configuration. */ +/* */ + typedef signed XXX FT_Int32; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_UInt32 */ +/* */ +/* A typedef for a 32bit unsigned integer type. The size depends on */ +/* the configuration. */ +/* */ + typedef unsigned XXX FT_UInt32; +/* */ +#endif +#if FT_SIZEOF_INT == (32 / FT_CHAR_BIT) + typedef signed int FT_Int32; + typedef unsigned int FT_UInt32; +#elif FT_SIZEOF_LONG == (32 / FT_CHAR_BIT) + typedef signed long FT_Int32; + typedef unsigned long FT_UInt32; +#else +#error "no 32bit type found -- please check your configuration files" +#endif +/* look up an integer type that is at least 32 bits */ +#if FT_SIZEOF_INT >= (32 / FT_CHAR_BIT) + typedef int FT_Fast; + typedef unsigned int FT_UFast; +#elif FT_SIZEOF_LONG >= (32 / FT_CHAR_BIT) + typedef long FT_Fast; + typedef unsigned long FT_UFast; +#endif +/* determine whether we have a 64-bit int type for platforms without */ +/* Autoconf */ +#if FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) +/* FT_LONG64 must be defined if a 64-bit type is available */ +#define FT_LONG64 +#define FT_INT64 long +/* Visual C++ (and Intel C++) */ +#elif defined( _MSC_VER ) && _MSC_VER >= 900 +/* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 +/* Borland C++ */ +#elif defined( __BORLANDC__ ) +/* XXXX: We should probably check the value of __BORLANDC__ in order */ +/* to test the compiler version. */ +/* this compiler provides the __int64 type */ +#define FT_LONG64 +#define FT_INT64 __int64 +/* Watcom C++ */ +#elif defined( __WATCOMC__ ) +/* Watcom doesn't provide 64-bit data types */ +/* Metrowerks CodeWarrior */ +#elif defined( __MWERKS__ ) +#define FT_LONG64 +#define FT_INT64 long long int +#elif defined( __GNUC__ ) +/* GCC provides the `long long' type */ +#define FT_LONG64 +#define FT_INT64 long long int +/* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ +#endif +/*************************************************************************/ +/* */ +/* A 64-bit data type will create compilation problems if you compile */ +/* in strict ANSI mode. To avoid them, we disable its use if __STDC__ */ +/* is defined. You can however ignore this rule by defining the */ +/* FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */ +/* */ +#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 ) +#ifdef __STDC__ +/* undefine the 64-bit macros in strict ANSI compilation mode */ +#undef FT_LONG64 +#undef FT_INT64 +/* __STDC__ */ +#endif +/* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */ +#endif +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT +/* Provide assembler fragments for performance-critical functions. */ +/* These must be defined `static __inline__' with GCC. */ +/* RVCT */ +#if defined( __CC_ARM ) || defined( __ARMCC__ ) +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm +/* documentation is in freetype.h */ + static __inline FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 t, t2; + __asm + { +/* (lo=t2,hi=t) = a*b */ + smull t2, t, b, a +/* a = (hi >> 31) */ + mov a, t, asr #31 +/* a += 0x8000 */ + add a, a, #0x8000 +/* t2 += a */ + adds t2, t2, a +/* t += carry */ + adc t, t, #0 +/* a = t2 >> 16 */ + mov a, t2, lsr #16 +/* a |= t << 16 */ + orr a, a, t, lsl #16 + } + return a; + } +/* __CC_ARM || __ARMCC__ */ +#endif +#ifdef __GNUC__ +#if defined( __arm__ ) && !defined( __thumb__ ) && \ + !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) +#define FT_MULFIX_ASSEMBLER FT_MulFix_arm +/* documentation is in freetype.h */ + static __inline__ FT_Int32 + FT_MulFix_arm( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 t, t2; + __asm__ __volatile__ ( +/* (lo=%1,hi=%2) = a*b */ + "smull %1, %2, %4, %3\n\t" +/* %0 = (hi >> 31) */ + "mov %0, %2, asr #31\n\t" +/* %0 += 0x8000 */ + "add %0, %0, #0x8000\n\t" +/* %1 += %0 */ + "adds %1, %1, %0\n\t" +/* %2 += carry */ + "adc %2, %2, #0\n\t" +/* %0 = %1 >> 16 */ + "mov %0, %1, lsr #16\n\t" +/* %0 |= %2 << 16 */ + "orr %0, %0, %2, lsl #16\n\t" + : "=r"(a), "=&r"(t2), "=&r"(t) + : "r"(a), "r"(b) + : "cc" ); + return a; + } +/* __arm__ && !__thumb__ && !( __CC_ARM || __ARMCC__ ) */ +#endif +#if defined( __i386__ ) +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 +/* documentation is in freetype.h */ + static __inline__ FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 result; + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x8000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $16, %%eax\n" + "shll $16, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); + return result; + } +/* i386 */ +#endif +/* __GNUC__ */ +#endif +/* Visual C++ */ +#ifdef _MSC_VER +#ifdef _M_IX86 +#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 +/* documentation is in freetype.h */ + static __inline FT_Int32 + FT_MulFix_i386( FT_Int32 a, + FT_Int32 b ) + { + register FT_Int32 result; + __asm + { + mov eax, a + mov edx, b + imul edx + mov ecx, edx + sar ecx, 31 + add ecx, 8000h + add eax, ecx + adc edx, 0 + shr eax, 16 + shl edx, 16 + add eax, edx + mov result, eax + } + return result; + } +/* _M_IX86 */ +#endif +/* _MSC_VER */ +#endif +#ifdef FT_MULFIX_ASSEMBLER +#define FT_MULFIX_INLINED FT_MULFIX_ASSEMBLER +#endif +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x +#else +#ifdef __cplusplus +#define FT_LOCAL( x ) extern "C" x +#define FT_LOCAL_DEF( x ) extern "C" x +#else +#define FT_LOCAL( x ) extern x +#define FT_LOCAL_DEF( x ) x +#endif +/* FT_MAKE_OPTION_SINGLE_OBJECT */ +#endif +#ifndef FT_BASE +#ifdef __cplusplus +#define FT_BASE( x ) extern "C" x +#else +#define FT_BASE( x ) extern x +#endif +/* !FT_BASE */ +#endif +#ifndef FT_BASE_DEF +#ifdef __cplusplus +#define FT_BASE_DEF( x ) x +#else +#define FT_BASE_DEF( x ) x +#endif +/* !FT_BASE_DEF */ +#endif +#ifndef FT_EXPORT +#ifdef __cplusplus +#define FT_EXPORT( x ) extern "C" x +#else +#define FT_EXPORT( x ) extern x +#endif +/* !FT_EXPORT */ +#endif +#ifndef FT_EXPORT_DEF +#ifdef __cplusplus +#define FT_EXPORT_DEF( x ) extern "C" x +#else +#define FT_EXPORT_DEF( x ) extern x +#endif +/* !FT_EXPORT_DEF */ +#endif +#ifndef FT_EXPORT_VAR +#ifdef __cplusplus +#define FT_EXPORT_VAR( x ) extern "C" x +#else +#define FT_EXPORT_VAR( x ) extern x +#endif +/* !FT_EXPORT_VAR */ +#endif +/* The following macros are needed to compile the library with a */ +/* C++ compiler and with 16bit compilers. */ +/* */ +/* This is special. Within C++, you must specify `extern "C"' for */ +/* functions which are used via function pointers, and you also */ +/* must do that for structures which contain function pointers to */ +/* assure C linkage -- it's not possible to have (local) anonymous */ +/* functions which are accessed by (global) function pointers. */ +/* */ +/* */ +/* FT_CALLBACK_DEF is used to _define_ a callback function. */ +/* */ +/* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */ +/* contains pointers to callback functions. */ +/* */ +/* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */ +/* that contains pointers to callback functions. */ +/* */ +/* */ +/* Some 16bit compilers have to redefine these macros to insert */ +/* the infamous `_cdecl' or `__fastcall' declarations. */ +/* */ +#ifndef FT_CALLBACK_DEF +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif +/* FT_CALLBACK_DEF */ +#endif +#ifndef FT_CALLBACK_TABLE +#ifdef __cplusplus +#define FT_CALLBACK_TABLE extern "C" +#define FT_CALLBACK_TABLE_DEF extern "C" +#else +#define FT_CALLBACK_TABLE extern +/* nothing */ +#define FT_CALLBACK_TABLE_DEF +#endif +/* FT_CALLBACK_TABLE */ +#endif +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftdebug.h */ +/* */ +/* Debugging and logging component (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006, 2007, 2008, 2009 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. */ +/* */ +/* */ +/* IMPORTANT: A description of FreeType's debugging support can be */ +/* found in `docs/DEBUG.TXT'. Read it if you need to use or */ +/* understand this code. */ +/* */ +/***************************************************************************/ +#define __FTDEBUG_H__ +/***************************************************************************/ +/* */ +/* freetype.h */ +/* */ +/* FreeType high-level API and common types (specification only). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +#define __FREETYPE_H__ +#ifndef FT_FREETYPE_H +#error "`ft2build.h' hasn't been included yet!" +#error "Please always use macros to include FreeType header files." +#error "Example:" +#error " #include <ft2build.h>" +#error " #include FT_FREETYPE_H" +#endif +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/***************************************************************************/ +/* */ +/* ftmoderr.h */ +/* */ +/* FreeType module error offsets (specification). */ +/* */ +/* Copyright 2001, 2002, 2003, 2004, 2005, 2010 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 FreeType module error offsets. */ +/* */ +/* The lower byte gives the error code, the higher byte gives the */ +/* module. The base module has error offset 0. For example, the error */ +/* `FT_Err_Invalid_File_Format' has value 0x003, the error */ +/* `TT_Err_Invalid_File_Format' has value 0x1103, the error */ +/* `T1_Err_Invalid_File_Format' has value 0x1203, etc. */ +/* */ +/* Undefine the macro FT_CONFIG_OPTION_USE_MODULE_ERRORS in ftoption.h */ +/* to make the higher byte always zero (disabling the module error */ +/* mechanism). */ +/* */ +/* It can also be used to create a module error message table easily */ +/* with something like */ +/* */ +/* { */ +/* #undef __FTMODERR_H__ */ +/* #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, */ +/* #define FT_MODERR_START_LIST { */ +/* #define FT_MODERR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int mod_err_offset; */ +/* const char* mod_err_msg */ +/* } ft_mod_errors[] = */ +/* */ +/* #include FT_MODULE_ERRORS_H */ +/* } */ +/* */ +/* To use such a table, all errors must be ANDed with 0xFF00 to remove */ +/* the error code. */ +/* */ +/*************************************************************************/ +#define __FTMODERR_H__ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#ifndef FT_MODERRDEF +#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0, +#define FT_MODERR_START_LIST enum { +#define FT_MODERR_END_LIST FT_Mod_Err_Max }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_MODERRDEF */ +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST MODULE ERROR BASES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_MODERR_START_LIST + FT_MODERR_START_LIST +#endif + FT_MODERRDEF( Base, 0x000, "base module" ) + FT_MODERRDEF( Autofit, 0x100, "autofitter module" ) + FT_MODERRDEF( BDF, 0x200, "BDF module" ) + FT_MODERRDEF( Bzip2, 0x300, "Bzip2 module" ) + FT_MODERRDEF( Cache, 0x400, "cache module" ) + FT_MODERRDEF( CFF, 0x500, "CFF module" ) + FT_MODERRDEF( CID, 0x600, "CID module" ) + FT_MODERRDEF( Gzip, 0x700, "Gzip module" ) + FT_MODERRDEF( LZW, 0x800, "LZW module" ) + FT_MODERRDEF( OTvalid, 0x900, "OpenType validation module" ) + FT_MODERRDEF( PCF, 0xA00, "PCF module" ) + FT_MODERRDEF( PFR, 0xB00, "PFR module" ) + FT_MODERRDEF( PSaux, 0xC00, "PS auxiliary module" ) + FT_MODERRDEF( PShinter, 0xD00, "PS hinter module" ) + FT_MODERRDEF( PSnames, 0xE00, "PS names module" ) + FT_MODERRDEF( Raster, 0xF00, "raster module" ) + FT_MODERRDEF( SFNT, 0x1000, "SFNT module" ) + FT_MODERRDEF( Smooth, 0x1100, "smooth raster module" ) + FT_MODERRDEF( TrueType, 0x1200, "TrueType module" ) + FT_MODERRDEF( Type1, 0x1300, "Type 1 module" ) + FT_MODERRDEF( Type42, 0x1400, "Type 42 module" ) + FT_MODERRDEF( Winfonts, 0x1500, "Windows FON/FNT module" ) +#ifdef FT_MODERR_END_LIST + FT_MODERR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_MODERR_START_LIST +#undef FT_MODERR_END_LIST +#undef FT_MODERRDEF +#undef FT_NEED_EXTERN_C +/* END */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/***************************************************************************/ +/* */ +/* fttypes.h */ +/* */ +/* FreeType simple types definitions (specification only). */ +/* */ +/* Copyright 1996-2002, 2004, 2006-2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __FTTYPES_H__ +/***************************************************************************/ +/* */ +/* ftsystem.h */ +/* */ +/* FreeType low-level system interface definition (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2005, 2010 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. */ +/* */ +/***************************************************************************/ +#define __FTSYSTEM_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* system_interface */ +/* */ +/* <Title> */ +/* System Interface */ +/* */ +/* <Abstract> */ +/* How FreeType manages memory and i/o. */ +/* */ +/* <Description> */ +/* This section contains various definitions related to memory */ +/* management and i/o access. You need to understand this */ +/* information if you want to use a custom memory manager or you own */ +/* i/o streams. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* M E M O R Y M A N A G E M E N T */ +/* */ +/*************************************************************************/ +/************************************************************************* + * + * @type: + * FT_Memory + * + * @description: + * A handle to a given memory manager object, defined with an + * @FT_MemoryRec structure. + * + */ + typedef struct FT_MemoryRec_* FT_Memory; +/************************************************************************* + * + * @functype: + * FT_Alloc_Func + * + * @description: + * A function used to allocate `size' bytes from `memory'. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * size :: + * The size in bytes to allocate. + * + * @return: + * Address of new memory block. 0~in case of failure. + * + */ + typedef void* + (*FT_Alloc_Func)( FT_Memory memory, + long size ); +/************************************************************************* + * + * @functype: + * FT_Free_Func + * + * @description: + * A function used to release a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * block :: + * The address of the target memory block. + * + */ + typedef void + (*FT_Free_Func)( FT_Memory memory, + void* block ); +/************************************************************************* + * + * @functype: + * FT_Realloc_Func + * + * @description: + * A function used to re-allocate a given block of memory. + * + * @input: + * memory :: + * A handle to the source memory manager. + * + * cur_size :: + * The block's current size in bytes. + * + * new_size :: + * The block's requested new size. + * + * block :: + * The block's current address. + * + * @return: + * New block address. 0~in case of memory shortage. + * + * @note: + * In case of error, the old block must still be available. + * + */ + typedef void* + (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); +/************************************************************************* + * + * @struct: + * FT_MemoryRec + * + * @description: + * A structure used to describe a given memory manager to FreeType~2. + * + * @fields: + * user :: + * A generic typeless pointer for user data. + * + * alloc :: + * A pointer type to an allocation function. + * + * free :: + * A pointer type to an memory freeing function. + * + * realloc :: + * A pointer type to a reallocation function. + * + */ + struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + }; +/*************************************************************************/ +/* */ +/* I / O M A N A G E M E N T */ +/* */ +/*************************************************************************/ +/************************************************************************* + * + * @type: + * FT_Stream + * + * @description: + * A handle to an input stream. + * + */ + typedef struct FT_StreamRec_* FT_Stream; +/************************************************************************* + * + * @struct: + * FT_StreamDesc + * + * @description: + * A union type used to store either a long or a pointer. This is used + * to store a file descriptor or a `FILE*' in an input stream. + * + */ + typedef union FT_StreamDesc_ + { + long value; + void* pointer; + } FT_StreamDesc; +/************************************************************************* + * + * @functype: + * FT_Stream_IoFunc + * + * @description: + * A function used to seek and read data from a given input stream. + * + * @input: + * stream :: + * A handle to the source stream. + * + * offset :: + * The offset of read in stream (always from start). + * + * buffer :: + * The address of the read buffer. + * + * count :: + * The number of bytes to read from the stream. + * + * @return: + * The number of bytes effectively read by the stream. + * + * @note: + * This function might be called to perform a seek or skip operation + * with a `count' of~0. A non-zero return value then indicates an + * error. + * + */ + typedef unsigned long + (*FT_Stream_IoFunc)( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ); +/************************************************************************* + * + * @functype: + * FT_Stream_CloseFunc + * + * @description: + * A function used to close a given input stream. + * + * @input: + * stream :: + * A handle to the target stream. + * + */ + typedef void + (*FT_Stream_CloseFunc)( FT_Stream stream ); +/************************************************************************* + * + * @struct: + * FT_StreamRec + * + * @description: + * A structure used to describe an input stream. + * + * @input: + * base :: + * For memory-based streams, this is the address of the first stream + * byte in memory. This field should always be set to NULL for + * disk-based streams. + * + * size :: + * The stream size in bytes. + * + * pos :: + * The current position within the stream. + * + * descriptor :: + * This field is a union that can hold an integer or a pointer. It is + * used by stream implementations to store file descriptors or `FILE*' + * pointers. + * + * pathname :: + * This field is completely ignored by FreeType. However, it is often + * useful during debugging to use it to store the stream's filename + * (where available). + * + * read :: + * The stream's input function. + * + * close :: + * The stream's close function. + * + * memory :: + * The memory manager to use to preload frames. This is set + * internally by FreeType and shouldn't be touched by stream + * implementations. + * + * cursor :: + * This field is set and used internally by FreeType when parsing + * frames. + * + * limit :: + * This field is set and used internally by FreeType when parsing + * frames. + * + */ + typedef struct FT_StreamRec_ + { + unsigned char* base; + unsigned long size; + unsigned long pos; + FT_StreamDesc descriptor; + FT_StreamDesc pathname; + FT_Stream_IoFunc read; + FT_Stream_CloseFunc close; + FT_Memory memory; + unsigned char* cursor; + unsigned char* limit; + } FT_StreamRec; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ +/* 2010 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* Note: A `raster' is simply a scan-line converter, used to render */ +/* FT_Outlines into FT_Bitmaps. */ +/* */ +/*************************************************************************/ +#define __FTIMAGE_H__ +/* _STANDALONE_ is from ftgrays.c */ +#ifndef _STANDALONE_ +#endif +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* basic_types */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Pos */ +/* */ +/* <Description> */ +/* The type FT_Pos is used to store vectorial coordinates. Depending */ +/* on the context, these can represent distances in integer font */ +/* units, or 16.16, or 26.6 fixed float pixel coordinates. */ +/* */ + typedef signed long FT_Pos; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Vector */ +/* */ +/* <Description> */ +/* A simple structure used to store a 2D vector; coordinates are of */ +/* the FT_Pos type. */ +/* */ +/* <Fields> */ +/* x :: The horizontal coordinate. */ +/* y :: The vertical coordinate. */ +/* */ + typedef struct FT_Vector_ + { + FT_Pos x; + FT_Pos y; + } FT_Vector; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_BBox */ +/* */ +/* <Description> */ +/* A structure used to hold an outline's bounding box, i.e., the */ +/* coordinates of its extrema in the horizontal and vertical */ +/* directions. */ +/* */ +/* <Fields> */ +/* xMin :: The horizontal minimum (left-most). */ +/* */ +/* yMin :: The vertical minimum (bottom-most). */ +/* */ +/* xMax :: The horizontal maximum (right-most). */ +/* */ +/* yMax :: The vertical maximum (top-most). */ +/* */ +/* <Note> */ +/* The bounding box is specified with the coordinates of the lower */ +/* left and the upper right corner. In PostScript, those values are */ +/* often called (llx,lly) and (urx,ury), respectively. */ +/* */ +/* If `yMin' is negative, this value gives the glyph's descender. */ +/* Otherwise, the glyph doesn't descend below the baseline. */ +/* Similarly, if `ymax' is positive, this value gives the glyph's */ +/* ascender. */ +/* */ +/* `xMin' gives the horizontal distance from the glyph's origin to */ +/* the left edge of the glyph's bounding box. If `xMin' is negative, */ +/* the glyph extends to the left of the origin. */ +/* */ + typedef struct FT_BBox_ + { + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; + } FT_BBox; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Pixel_Mode */ +/* */ +/* <Description> */ +/* An enumeration type used to describe the format of pixels in a */ +/* given bitmap. Note that additional formats may be added in the */ +/* future. */ +/* */ +/* <Values> */ +/* FT_PIXEL_MODE_NONE :: */ +/* Value~0 is reserved. */ +/* */ +/* FT_PIXEL_MODE_MONO :: */ +/* A monochrome bitmap, using 1~bit per pixel. Note that pixels */ +/* are stored in most-significant order (MSB), which means that */ +/* the left-most pixel in a byte has value 128. */ +/* */ +/* FT_PIXEL_MODE_GRAY :: */ +/* An 8-bit bitmap, generally used to represent anti-aliased glyph */ +/* images. Each pixel is stored in one byte. Note that the number */ +/* of `gray' levels is stored in the `num_grays' field of the */ +/* @FT_Bitmap structure (it generally is 256). */ +/* */ +/* FT_PIXEL_MODE_GRAY2 :: */ +/* A 2-bit per pixel bitmap, used to represent embedded */ +/* anti-aliased bitmaps in font files according to the OpenType */ +/* specification. We haven't found a single font using this */ +/* format, however. */ +/* */ +/* FT_PIXEL_MODE_GRAY4 :: */ +/* A 4-bit per pixel bitmap, representing embedded anti-aliased */ +/* bitmaps in font files according to the OpenType specification. */ +/* We haven't found a single font using this format, however. */ +/* */ +/* FT_PIXEL_MODE_LCD :: */ +/* An 8-bit bitmap, representing RGB or BGR decimated glyph images */ +/* used for display on LCD displays; the bitmap is three times */ +/* wider than the original glyph image. See also */ +/* @FT_RENDER_MODE_LCD. */ +/* */ +/* FT_PIXEL_MODE_LCD_V :: */ +/* An 8-bit bitmap, representing RGB or BGR decimated glyph images */ +/* used for display on rotated LCD displays; the bitmap is three */ +/* times taller than the original glyph image. See also */ +/* @FT_RENDER_MODE_LCD_V. */ +/* */ + typedef enum FT_Pixel_Mode_ + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, +/* do not remove */ + FT_PIXEL_MODE_MAX + } FT_Pixel_Mode; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* ft_pixel_mode_xxx */ +/* */ +/* <Description> */ +/* A list of deprecated constants. Use the corresponding */ +/* @FT_Pixel_Mode values instead. */ +/* */ +/* <Values> */ +/* ft_pixel_mode_none :: See @FT_PIXEL_MODE_NONE. */ +/* ft_pixel_mode_mono :: See @FT_PIXEL_MODE_MONO. */ +/* ft_pixel_mode_grays :: See @FT_PIXEL_MODE_GRAY. */ +/* ft_pixel_mode_pal2 :: See @FT_PIXEL_MODE_GRAY2. */ +/* ft_pixel_mode_pal4 :: See @FT_PIXEL_MODE_GRAY4. */ +/* */ +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 +/* */ +#if 0 +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Palette_Mode */ +/* */ +/* <Description> */ +/* THIS TYPE IS DEPRECATED. DO NOT USE IT! */ +/* */ +/* An enumeration type to describe the format of a bitmap palette, */ +/* used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */ +/* */ +/* <Values> */ +/* ft_palette_mode_rgb :: The palette is an array of 3-byte RGB */ +/* records. */ +/* */ +/* ft_palette_mode_rgba :: The palette is an array of 4-byte RGBA */ +/* records. */ +/* */ +/* <Note> */ +/* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */ +/* FreeType, these types are not handled by the library itself. */ +/* */ + typedef enum FT_Palette_Mode_ + { + ft_palette_mode_rgb = 0, + ft_palette_mode_rgba, +/* do not remove */ + ft_palette_mode_max + } FT_Palette_Mode; +/* */ +#endif +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Bitmap */ +/* */ +/* <Description> */ +/* A structure used to describe a bitmap or pixmap to the raster. */ +/* Note that we now manage pixmaps of various depths through the */ +/* `pixel_mode' field. */ +/* */ +/* <Fields> */ +/* rows :: The number of bitmap rows. */ +/* */ +/* width :: The number of pixels in bitmap row. */ +/* */ +/* pitch :: The pitch's absolute value is the number of bytes */ +/* taken by one bitmap row, including padding. */ +/* However, the pitch is positive when the bitmap has */ +/* a `down' flow, and negative when it has an `up' */ +/* flow. In all cases, the pitch is an offset to add */ +/* to a bitmap pointer in order to go down one row. */ +/* */ +/* Note that `padding' means the alignment of a */ +/* bitmap to a byte border, and FreeType functions */ +/* normally align to the smallest possible integer */ +/* value. */ +/* */ +/* For the B/W rasterizer, `pitch' is always an even */ +/* number. */ +/* */ +/* To change the pitch of a bitmap (say, to make it a */ +/* multiple of 4), use @FT_Bitmap_Convert. */ +/* Alternatively, you might use callback functions to */ +/* directly render to the application's surface; see */ +/* the file `example2.cpp' in the tutorial for a */ +/* demonstration. */ +/* */ +/* buffer :: A typeless pointer to the bitmap buffer. This */ +/* value should be aligned on 32-bit boundaries in */ +/* most cases. */ +/* */ +/* num_grays :: This field is only used with */ +/* @FT_PIXEL_MODE_GRAY; it gives the number of gray */ +/* levels used in the bitmap. */ +/* */ +/* pixel_mode :: The pixel mode, i.e., how pixel bits are stored. */ +/* See @FT_Pixel_Mode for possible values. */ +/* */ +/* palette_mode :: This field is intended for paletted pixel modes; */ +/* it indicates how the palette is stored. Not */ +/* used currently. */ +/* */ +/* palette :: A typeless pointer to the bitmap palette; this */ +/* field is intended for paletted pixel modes. Not */ +/* used currently. */ +/* */ +/* <Note> */ +/* For now, the only pixel modes supported by FreeType are mono and */ +/* grays. However, drivers might be added in the future to support */ +/* more `colorful' options. */ +/* */ + typedef struct FT_Bitmap_ + { + int rows; + int width; + int pitch; + unsigned char* buffer; + short num_grays; + char pixel_mode; + char palette_mode; + void* palette; + } FT_Bitmap; +/*************************************************************************/ +/* */ +/* <Section> */ +/* outline_processing */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Outline */ +/* */ +/* <Description> */ +/* This structure is used to describe an outline to the scan-line */ +/* converter. */ +/* */ +/* <Fields> */ +/* n_contours :: The number of contours in the outline. */ +/* */ +/* n_points :: The number of points in the outline. */ +/* */ +/* points :: A pointer to an array of `n_points' @FT_Vector */ +/* elements, giving the outline's point coordinates. */ +/* */ +/* tags :: A pointer to an array of `n_points' chars, giving */ +/* each outline point's type. */ +/* */ +/* If bit~0 is unset, the point is `off' the curve, */ +/* i.e., a Bézier control point, while it is `on' if */ +/* set. */ +/* */ +/* Bit~1 is meaningful for `off' points only. If set, */ +/* it indicates a third-order Bézier arc control point; */ +/* and a second-order control point if unset. */ +/* */ +/* If bit~2 is set, bits 5-7 contain the drop-out mode */ +/* (as defined in the OpenType specification; the value */ +/* is the same as the argument to the SCANMODE */ +/* instruction). */ +/* */ +/* Bits 3 and~4 are reserved for internal purposes. */ +/* */ +/* contours :: An array of `n_contours' shorts, giving the end */ +/* point of each contour within the outline. For */ +/* example, the first contour is defined by the points */ +/* `0' to `contours[0]', the second one is defined by */ +/* the points `contours[0]+1' to `contours[1]', etc. */ +/* */ +/* flags :: A set of bit flags used to characterize the outline */ +/* and give hints to the scan-converter and hinter on */ +/* how to convert/grid-fit it. See @FT_OUTLINE_FLAGS. */ +/* */ +/* <Note> */ +/* The B/W rasterizer only checks bit~2 in the `tags' array for the */ +/* first point of each contour. The drop-out mode as given with */ +/* @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and */ +/* @FT_OUTLINE_INCLUDE_STUBS in `flags' is then overridden. */ +/* */ + typedef struct FT_Outline_ + { +/* number of contours in glyph */ + short n_contours; +/* number of points in the glyph */ + short n_points; +/* the outline's points */ + FT_Vector* points; +/* the points flags */ + char* tags; +/* the contour end points */ + short* contours; +/* outline masks */ + int flags; + } FT_Outline; +/* Following limits must be consistent with */ +/* FT_Outline.{n_contours,n_points} */ +#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX +#define FT_OUTLINE_POINTS_MAX SHRT_MAX +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_OUTLINE_FLAGS */ +/* */ +/* <Description> */ +/* A list of bit-field constants use for the flags in an outline's */ +/* `flags' field. */ +/* */ +/* <Values> */ +/* FT_OUTLINE_NONE :: */ +/* Value~0 is reserved. */ +/* */ +/* FT_OUTLINE_OWNER :: */ +/* If set, this flag indicates that the outline's field arrays */ +/* (i.e., `points', `flags', and `contours') are `owned' by the */ +/* outline object, and should thus be freed when it is destroyed. */ +/* */ +/* FT_OUTLINE_EVEN_ODD_FILL :: */ +/* By default, outlines are filled using the non-zero winding rule. */ +/* If set to 1, the outline will be filled using the even-odd fill */ +/* rule (only works with the smooth rasterizer). */ +/* */ +/* FT_OUTLINE_REVERSE_FILL :: */ +/* By default, outside contours of an outline are oriented in */ +/* clock-wise direction, as defined in the TrueType specification. */ +/* This flag is set if the outline uses the opposite direction */ +/* (typically for Type~1 fonts). This flag is ignored by the scan */ +/* converter. */ +/* */ +/* FT_OUTLINE_IGNORE_DROPOUTS :: */ +/* By default, the scan converter will try to detect drop-outs in */ +/* an outline and correct the glyph bitmap to ensure consistent */ +/* shape continuity. If set, this flag hints the scan-line */ +/* converter to ignore such cases. See below for more information. */ +/* */ +/* FT_OUTLINE_SMART_DROPOUTS :: */ +/* Select smart dropout control. If unset, use simple dropout */ +/* control. Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. See */ +/* below for more information. */ +/* */ +/* FT_OUTLINE_INCLUDE_STUBS :: */ +/* If set, turn pixels on for `stubs', otherwise exclude them. */ +/* Ignored if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for */ +/* more information. */ +/* */ +/* FT_OUTLINE_HIGH_PRECISION :: */ +/* This flag indicates that the scan-line converter should try to */ +/* convert this outline to bitmaps with the highest possible */ +/* quality. It is typically set for small character sizes. Note */ +/* that this is only a hint that might be completely ignored by a */ +/* given scan-converter. */ +/* */ +/* FT_OUTLINE_SINGLE_PASS :: */ +/* This flag is set to force a given scan-converter to only use a */ +/* single pass over the outline to render a bitmap glyph image. */ +/* Normally, it is set for very large character sizes. It is only */ +/* a hint that might be completely ignored by a given */ +/* scan-converter. */ +/* */ +/* <Note> */ +/* The flags @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, */ +/* and @FT_OUTLINE_INCLUDE_STUBS are ignored by the smooth */ +/* rasterizer. */ +/* */ +/* There exists a second mechanism to pass the drop-out mode to the */ +/* B/W rasterizer; see the `tags' field in @FT_Outline. */ +/* */ +/* Please refer to the description of the `SCANTYPE' instruction in */ +/* the OpenType specification (in file `ttinst1.doc') how simple */ +/* drop-outs, smart drop-outs, and stubs are defined. */ +/* */ +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 +#define FT_OUTLINE_SMART_DROPOUTS 0x10 +#define FT_OUTLINE_INCLUDE_STUBS 0x20 +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 +/************************************************************************* + * + * @enum: + * ft_outline_flags + * + * @description: + * These constants are deprecated. Please use the corresponding + * @FT_OUTLINE_FLAGS values. + * + * @values: + * ft_outline_none :: See @FT_OUTLINE_NONE. + * ft_outline_owner :: See @FT_OUTLINE_OWNER. + * ft_outline_even_odd_fill :: See @FT_OUTLINE_EVEN_ODD_FILL. + * ft_outline_reverse_fill :: See @FT_OUTLINE_REVERSE_FILL. + * ft_outline_ignore_dropouts :: See @FT_OUTLINE_IGNORE_DROPOUTS. + * ft_outline_high_precision :: See @FT_OUTLINE_HIGH_PRECISION. + * ft_outline_single_pass :: See @FT_OUTLINE_SINGLE_PASS. + */ +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS +/* */ +#define FT_CURVE_TAG( flag ) ( flag & 3 ) +#define FT_CURVE_TAG_ON 1 +#define FT_CURVE_TAG_CONIC 0 +#define FT_CURVE_TAG_CUBIC 2 +#define FT_CURVE_TAG_HAS_SCANMODE 4 +/* reserved for the TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_X 8 +/* reserved for the TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 16 +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Outline_MoveToFunc */ +/* */ +/* <Description> */ +/* A function pointer type used to describe the signature of a `move */ +/* to' function during outline walking/decomposition. */ +/* */ +/* A `move to' is emitted to start a new contour in an outline. */ +/* */ +/* <Input> */ +/* to :: A pointer to the target point of the `move to'. */ +/* */ +/* user :: A typeless pointer which is passed from the caller of the */ +/* decomposition function. */ +/* */ +/* <Return> */ +/* Error code. 0~means success. */ +/* */ + typedef int + (*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Outline_LineToFunc */ +/* */ +/* <Description> */ +/* A function pointer type used to describe the signature of a `line */ +/* to' function during outline walking/decomposition. */ +/* */ +/* A `line to' is emitted to indicate a segment in the outline. */ +/* */ +/* <Input> */ +/* to :: A pointer to the target point of the `line to'. */ +/* */ +/* user :: A typeless pointer which is passed from the caller of the */ +/* decomposition function. */ +/* */ +/* <Return> */ +/* Error code. 0~means success. */ +/* */ + typedef int + (*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Outline_ConicToFunc */ +/* */ +/* <Description> */ +/* A function pointer type used to describe the signature of a `conic */ +/* to' function during outline walking or decomposition. */ +/* */ +/* A `conic to' is emitted to indicate a second-order Bézier arc in */ +/* the outline. */ +/* */ +/* <Input> */ +/* control :: An intermediate control point between the last position */ +/* and the new target in `to'. */ +/* */ +/* to :: A pointer to the target end point of the conic arc. */ +/* */ +/* user :: A typeless pointer which is passed from the caller of */ +/* the decomposition function. */ +/* */ +/* <Return> */ +/* Error code. 0~means success. */ +/* */ + typedef int + (*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Outline_CubicToFunc */ +/* */ +/* <Description> */ +/* A function pointer type used to describe the signature of a `cubic */ +/* to' function during outline walking or decomposition. */ +/* */ +/* A `cubic to' is emitted to indicate a third-order Bézier arc. */ +/* */ +/* <Input> */ +/* control1 :: A pointer to the first Bézier control point. */ +/* */ +/* control2 :: A pointer to the second Bézier control point. */ +/* */ +/* to :: A pointer to the target end point. */ +/* */ +/* user :: A typeless pointer which is passed from the caller of */ +/* the decomposition function. */ +/* */ +/* <Return> */ +/* Error code. 0~means success. */ +/* */ + typedef int + (*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Outline_Funcs */ +/* */ +/* <Description> */ +/* A structure to hold various function pointers used during outline */ +/* decomposition in order to emit segments, conic, and cubic Béziers. */ +/* */ +/* <Fields> */ +/* move_to :: The `move to' emitter. */ +/* */ +/* line_to :: The segment emitter. */ +/* */ +/* conic_to :: The second-order Bézier arc emitter. */ +/* */ +/* cubic_to :: The third-order Bézier arc emitter. */ +/* */ +/* shift :: The shift that is applied to coordinates before they */ +/* are sent to the emitter. */ +/* */ +/* delta :: The delta that is applied to coordinates before they */ +/* are sent to the emitter, but after the shift. */ +/* */ +/* <Note> */ +/* The point coordinates sent to the emitters are the transformed */ +/* version of the original coordinates (this is important for high */ +/* accuracy during scan-conversion). The transformation is simple: */ +/* */ +/* { */ +/* x' = (x << shift) - delta */ +/* y' = (x << shift) - delta */ +/* } */ +/* */ +/* Set the values of `shift' and `delta' to~0 to get the original */ +/* point coordinates. */ +/* */ + typedef struct FT_Outline_Funcs_ + { + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + int shift; + FT_Pos delta; + } FT_Outline_Funcs; +/*************************************************************************/ +/* */ +/* <Section> */ +/* basic_types */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_IMAGE_TAG */ +/* */ +/* <Description> */ +/* This macro converts four-letter tags to an unsigned long type. */ +/* */ +/* <Note> */ +/* Since many 16-bit compilers don't like 32-bit enumerations, you */ +/* should redefine this macro in case of problems to something like */ +/* this: */ +/* */ +/* { */ +/* #define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) value */ +/* } */ +/* */ +/* to get a simple enumeration without assigning special numbers. */ +/* */ +#ifndef FT_IMAGE_TAG +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( (unsigned long)_x1 << 24 ) | \ + ( (unsigned long)_x2 << 16 ) | \ + ( (unsigned long)_x3 << 8 ) | \ + (unsigned long)_x4 ) +/* FT_IMAGE_TAG */ +#endif +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Glyph_Format */ +/* */ +/* <Description> */ +/* An enumeration type used to describe the format of a given glyph */ +/* image. Note that this version of FreeType only supports two image */ +/* formats, even though future font drivers will be able to register */ +/* their own format. */ +/* */ +/* <Values> */ +/* FT_GLYPH_FORMAT_NONE :: */ +/* The value~0 is reserved. */ +/* */ +/* FT_GLYPH_FORMAT_COMPOSITE :: */ +/* The glyph image is a composite of several other images. This */ +/* format is _only_ used with @FT_LOAD_NO_RECURSE, and is used to */ +/* report compound glyphs (like accented characters). */ +/* */ +/* FT_GLYPH_FORMAT_BITMAP :: */ +/* The glyph image is a bitmap, and can be described as an */ +/* @FT_Bitmap. You generally need to access the `bitmap' field of */ +/* the @FT_GlyphSlotRec structure to read it. */ +/* */ +/* FT_GLYPH_FORMAT_OUTLINE :: */ +/* The glyph image is a vectorial outline made of line segments */ +/* and Bézier arcs; it can be described as an @FT_Outline; you */ +/* generally want to access the `outline' field of the */ +/* @FT_GlyphSlotRec structure to read it. */ +/* */ +/* FT_GLYPH_FORMAT_PLOTTER :: */ +/* The glyph image is a vectorial path with no inside and outside */ +/* contours. Some Type~1 fonts, like those in the Hershey family, */ +/* contain glyphs in this format. These are described as */ +/* @FT_Outline, but FreeType isn't currently capable of rendering */ +/* them correctly. */ +/* */ + typedef enum FT_Glyph_Format_ + { + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ) + } FT_Glyph_Format; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* ft_glyph_format_xxx */ +/* */ +/* <Description> */ +/* A list of deprecated constants. Use the corresponding */ +/* @FT_Glyph_Format values instead. */ +/* */ +/* <Values> */ +/* ft_glyph_format_none :: See @FT_GLYPH_FORMAT_NONE. */ +/* ft_glyph_format_composite :: See @FT_GLYPH_FORMAT_COMPOSITE. */ +/* ft_glyph_format_bitmap :: See @FT_GLYPH_FORMAT_BITMAP. */ +/* ft_glyph_format_outline :: See @FT_GLYPH_FORMAT_OUTLINE. */ +/* ft_glyph_format_plotter :: See @FT_GLYPH_FORMAT_PLOTTER. */ +/* */ +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** R A S T E R D E F I N I T I O N S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* A raster is a scan converter, in charge of rendering an outline into */ +/* a a bitmap. This section contains the public API for rasters. */ +/* */ +/* Note that in FreeType 2, all rasters are now encapsulated within */ +/* specific modules called `renderers'. See `freetype/ftrender.h' for */ +/* more details on renderers. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Section> */ +/* raster */ +/* */ +/* <Title> */ +/* Scanline Converter */ +/* */ +/* <Abstract> */ +/* How vectorial outlines are converted into bitmaps and pixmaps. */ +/* */ +/* <Description> */ +/* This section contains technical definitions. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Raster */ +/* */ +/* <Description> */ +/* A handle (pointer) to a raster object. Each object can be used */ +/* independently to convert an outline into a bitmap or pixmap. */ +/* */ + typedef struct FT_RasterRec_* FT_Raster; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Span */ +/* */ +/* <Description> */ +/* A structure used to model a single span of gray (or black) pixels */ +/* when rendering a monochrome or anti-aliased bitmap. */ +/* */ +/* <Fields> */ +/* x :: The span's horizontal start position. */ +/* */ +/* len :: The span's length in pixels. */ +/* */ +/* coverage :: The span color/coverage, ranging from 0 (background) */ +/* to 255 (foreground). Only used for anti-aliased */ +/* rendering. */ +/* */ +/* <Note> */ +/* This structure is used by the span drawing callback type named */ +/* @FT_SpanFunc which takes the y~coordinate of the span as a */ +/* a parameter. */ +/* */ +/* The coverage value is always between 0 and 255. If you want less */ +/* gray values, the callback function has to reduce them. */ +/* */ + typedef struct FT_Span_ + { + short x; + unsigned short len; + unsigned char coverage; + } FT_Span; +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_SpanFunc */ +/* */ +/* <Description> */ +/* A function used as a call-back by the anti-aliased renderer in */ +/* order to let client applications draw themselves the gray pixel */ +/* spans on each scan line. */ +/* */ +/* <Input> */ +/* y :: The scanline's y~coordinate. */ +/* */ +/* count :: The number of spans to draw on this scanline. */ +/* */ +/* spans :: A table of `count' spans to draw on the scanline. */ +/* */ +/* user :: User-supplied data that is passed to the callback. */ +/* */ +/* <Note> */ +/* This callback allows client applications to directly render the */ +/* gray spans of the anti-aliased bitmap to any kind of surfaces. */ +/* */ +/* This can be used to write anti-aliased outlines directly to a */ +/* given background bitmap, and even perform translucency. */ +/* */ +/* Note that the `count' field cannot be greater than a fixed value */ +/* defined by the `FT_MAX_GRAY_SPANS' configuration macro in */ +/* `ftoption.h'. By default, this value is set to~32, which means */ +/* that if there are more than 32~spans on a given scanline, the */ +/* callback is called several times with the same `y' parameter in */ +/* order to draw all callbacks. */ +/* */ +/* Otherwise, the callback is only called once per scan-line, and */ +/* only for those scanlines that do have `gray' pixels on them. */ +/* */ + typedef void + (*FT_SpanFunc)( int y, + int count, + const FT_Span* spans, + void* user ); +#define FT_Raster_Span_Func FT_SpanFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_BitTest_Func */ +/* */ +/* <Description> */ +/* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ +/* */ +/* A function used as a call-back by the monochrome scan-converter */ +/* to test whether a given target pixel is already set to the drawing */ +/* `color'. These tests are crucial to implement drop-out control */ +/* per-se the TrueType spec. */ +/* */ +/* <Input> */ +/* y :: The pixel's y~coordinate. */ +/* */ +/* x :: The pixel's x~coordinate. */ +/* */ +/* user :: User-supplied data that is passed to the callback. */ +/* */ +/* <Return> */ +/* 1~if the pixel is `set', 0~otherwise. */ +/* */ + typedef int + (*FT_Raster_BitTest_Func)( int y, + int x, + void* user ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_BitSet_Func */ +/* */ +/* <Description> */ +/* THIS TYPE IS DEPRECATED. DO NOT USE IT. */ +/* */ +/* A function used as a call-back by the monochrome scan-converter */ +/* to set an individual target pixel. This is crucial to implement */ +/* drop-out control according to the TrueType specification. */ +/* */ +/* <Input> */ +/* y :: The pixel's y~coordinate. */ +/* */ +/* x :: The pixel's x~coordinate. */ +/* */ +/* user :: User-supplied data that is passed to the callback. */ +/* */ +/* <Return> */ +/* 1~if the pixel is `set', 0~otherwise. */ +/* */ + typedef void + (*FT_Raster_BitSet_Func)( int y, + int x, + void* user ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_RASTER_FLAG_XXX */ +/* */ +/* <Description> */ +/* A list of bit flag constants as used in the `flags' field of a */ +/* @FT_Raster_Params structure. */ +/* */ +/* <Values> */ +/* FT_RASTER_FLAG_DEFAULT :: This value is 0. */ +/* */ +/* FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ +/* anti-aliased glyph image should be */ +/* generated. Otherwise, it will be */ +/* monochrome (1-bit). */ +/* */ +/* FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ +/* rendering. In this mode, client */ +/* applications must provide their own span */ +/* callback. This lets them directly */ +/* draw or compose over an existing bitmap. */ +/* If this bit is not set, the target */ +/* pixmap's buffer _must_ be zeroed before */ +/* rendering. */ +/* */ +/* Note that for now, direct rendering is */ +/* only possible with anti-aliased glyphs. */ +/* */ +/* FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ +/* rendering mode. If set, the output will */ +/* be clipped to a box specified in the */ +/* `clip_box' field of the */ +/* @FT_Raster_Params structure. */ +/* */ +/* Note that by default, the glyph bitmap */ +/* is clipped to the target pixmap, except */ +/* in direct rendering mode where all spans */ +/* are generated if no clipping box is set. */ +/* */ +#define FT_RASTER_FLAG_DEFAULT 0x0 +#define FT_RASTER_FLAG_AA 0x1 +#define FT_RASTER_FLAG_DIRECT 0x2 +#define FT_RASTER_FLAG_CLIP 0x4 +/* deprecated */ +#define ft_raster_flag_default FT_RASTER_FLAG_DEFAULT +#define ft_raster_flag_aa FT_RASTER_FLAG_AA +#define ft_raster_flag_direct FT_RASTER_FLAG_DIRECT +#define ft_raster_flag_clip FT_RASTER_FLAG_CLIP +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Raster_Params */ +/* */ +/* <Description> */ +/* A structure to hold the arguments used by a raster's render */ +/* function. */ +/* */ +/* <Fields> */ +/* target :: The target bitmap. */ +/* */ +/* source :: A pointer to the source glyph image (e.g., an */ +/* @FT_Outline). */ +/* */ +/* flags :: The rendering flags. */ +/* */ +/* gray_spans :: The gray span drawing callback. */ +/* */ +/* black_spans :: The black span drawing callback. UNIMPLEMENTED! */ +/* */ +/* bit_test :: The bit test callback. UNIMPLEMENTED! */ +/* */ +/* bit_set :: The bit set callback. UNIMPLEMENTED! */ +/* */ +/* user :: User-supplied data that is passed to each drawing */ +/* callback. */ +/* */ +/* clip_box :: An optional clipping box. It is only used in */ +/* direct rendering mode. Note that coordinates here */ +/* should be expressed in _integer_ pixels (and not in */ +/* 26.6 fixed-point units). */ +/* */ +/* <Note> */ +/* An anti-aliased glyph bitmap is drawn if the @FT_RASTER_FLAG_AA */ +/* bit flag is set in the `flags' field, otherwise a monochrome */ +/* bitmap is generated. */ +/* */ +/* If the @FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ +/* raster will call the `gray_spans' callback to draw gray pixel */ +/* spans, in the case of an aa glyph bitmap, it will call */ +/* `black_spans', and `bit_test' and `bit_set' in the case of a */ +/* monochrome bitmap. This allows direct composition over a */ +/* pre-existing bitmap through user-provided callbacks to perform the */ +/* span drawing/composition. */ +/* */ +/* Note that the `bit_test' and `bit_set' callbacks are required when */ +/* rendering a monochrome bitmap, as they are crucial to implement */ +/* correct drop-out control as defined in the TrueType specification. */ +/* */ + typedef struct FT_Raster_Params_ + { + const FT_Bitmap* target; + const void* source; + int flags; + FT_SpanFunc gray_spans; +/* doesn't work! */ + FT_SpanFunc black_spans; +/* doesn't work! */ + FT_Raster_BitTest_Func bit_test; +/* doesn't work! */ + FT_Raster_BitSet_Func bit_set; + void* user; + FT_BBox clip_box; + } FT_Raster_Params; +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_NewFunc */ +/* */ +/* <Description> */ +/* A function used to create a new raster object. */ +/* */ +/* <Input> */ +/* memory :: A handle to the memory allocator. */ +/* */ +/* <Output> */ +/* raster :: A handle to the new raster object. */ +/* */ +/* <Return> */ +/* Error code. 0~means success. */ +/* */ +/* <Note> */ +/* The `memory' parameter is a typeless pointer in order to avoid */ +/* un-wanted dependencies on the rest of the FreeType code. In */ +/* practice, it is an @FT_Memory object, i.e., a handle to the */ +/* standard FreeType memory allocator. However, this field can be */ +/* completely ignored by a given raster implementation. */ +/* */ + typedef int + (*FT_Raster_NewFunc)( void* memory, + FT_Raster* raster ); +#define FT_Raster_New_Func FT_Raster_NewFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_DoneFunc */ +/* */ +/* <Description> */ +/* A function used to destroy a given raster object. */ +/* */ +/* <Input> */ +/* raster :: A handle to the raster object. */ +/* */ + typedef void + (*FT_Raster_DoneFunc)( FT_Raster raster ); +#define FT_Raster_Done_Func FT_Raster_DoneFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_ResetFunc */ +/* */ +/* <Description> */ +/* FreeType provides an area of memory called the `render pool', */ +/* available to all registered rasters. This pool can be freely used */ +/* during a given scan-conversion but is shared by all rasters. Its */ +/* content is thus transient. */ +/* */ +/* This function is called each time the render pool changes, or just */ +/* after a new raster object is created. */ +/* */ +/* <Input> */ +/* raster :: A handle to the new raster object. */ +/* */ +/* pool_base :: The address in memory of the render pool. */ +/* */ +/* pool_size :: The size in bytes of the render pool. */ +/* */ +/* <Note> */ +/* Rasters can ignore the render pool and rely on dynamic memory */ +/* allocation if they want to (a handle to the memory allocator is */ +/* passed to the raster constructor). However, this is not */ +/* recommended for efficiency purposes. */ +/* */ + typedef void + (*FT_Raster_ResetFunc)( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ); +#define FT_Raster_Reset_Func FT_Raster_ResetFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_SetModeFunc */ +/* */ +/* <Description> */ +/* This function is a generic facility to change modes or attributes */ +/* in a given raster. This can be used for debugging purposes, or */ +/* simply to allow implementation-specific `features' in a given */ +/* raster module. */ +/* */ +/* <Input> */ +/* raster :: A handle to the new raster object. */ +/* */ +/* mode :: A 4-byte tag used to name the mode or property. */ +/* */ +/* args :: A pointer to the new mode/property to use. */ +/* */ + typedef int + (*FT_Raster_SetModeFunc)( FT_Raster raster, + unsigned long mode, + void* args ); +#define FT_Raster_Set_Mode_Func FT_Raster_SetModeFunc +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Raster_RenderFunc */ +/* */ +/* <Description> */ +/* Invoke a given raster to scan-convert a given glyph image into a */ +/* target bitmap. */ +/* */ +/* <Input> */ +/* raster :: A handle to the raster object. */ +/* */ +/* params :: A pointer to an @FT_Raster_Params structure used to */ +/* store the rendering parameters. */ +/* */ +/* <Return> */ +/* Error code. 0~means success. */ +/* */ +/* <Note> */ +/* The exact format of the source image depends on the raster's glyph */ +/* format defined in its @FT_Raster_Funcs structure. It can be an */ +/* @FT_Outline or anything else in order to support a large array of */ +/* glyph formats. */ +/* */ +/* Note also that the render function can fail and return a */ +/* `FT_Err_Unimplemented_Feature' error code if the raster used does */ +/* not support direct composition. */ +/* */ +/* XXX: For now, the standard raster doesn't support direct */ +/* composition but this should change for the final release (see */ +/* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */ +/* for examples of distinct implementations which support direct */ +/* composition). */ +/* */ + typedef int + (*FT_Raster_RenderFunc)( FT_Raster raster, + const FT_Raster_Params* params ); +#define FT_Raster_Render_Func FT_Raster_RenderFunc +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Raster_Funcs */ +/* */ +/* <Description> */ +/* A structure used to describe a given raster class to the library. */ +/* */ +/* <Fields> */ +/* glyph_format :: The supported glyph format for this raster. */ +/* */ +/* raster_new :: The raster constructor. */ +/* */ +/* raster_reset :: Used to reset the render pool within the raster. */ +/* */ +/* raster_render :: A function to render a glyph into a given bitmap. */ +/* */ +/* raster_done :: The raster destructor. */ +/* */ + typedef struct FT_Raster_Funcs_ + { + FT_Glyph_Format glyph_format; + FT_Raster_NewFunc raster_new; + FT_Raster_ResetFunc raster_reset; + FT_Raster_SetModeFunc raster_set_mode; + FT_Raster_RenderFunc raster_render; + FT_Raster_DoneFunc raster_done; + } FT_Raster_Funcs; +/* */ +FT_END_HEADER +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ +#include <stddef.h> +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* basic_types */ +/* */ +/* <Title> */ +/* Basic Data Types */ +/* */ +/* <Abstract> */ +/* The basic data types defined by the library. */ +/* */ +/* <Description> */ +/* This section contains the basic data types defined by FreeType~2, */ +/* ranging from simple scalar types to bitmap descriptors. More */ +/* font-specific structures are defined in a different section. */ +/* */ +/* <Order> */ +/* FT_Byte */ +/* FT_Bytes */ +/* FT_Char */ +/* FT_Int */ +/* FT_UInt */ +/* FT_Int16 */ +/* FT_UInt16 */ +/* FT_Int32 */ +/* FT_UInt32 */ +/* FT_Short */ +/* FT_UShort */ +/* FT_Long */ +/* FT_ULong */ +/* FT_Bool */ +/* FT_Offset */ +/* FT_PtrDist */ +/* FT_String */ +/* FT_Tag */ +/* FT_Error */ +/* FT_Fixed */ +/* FT_Pointer */ +/* FT_Pos */ +/* FT_Vector */ +/* FT_BBox */ +/* FT_Matrix */ +/* FT_FWord */ +/* FT_UFWord */ +/* FT_F2Dot14 */ +/* FT_UnitVector */ +/* FT_F26Dot6 */ +/* */ +/* */ +/* FT_Generic */ +/* FT_Generic_Finalizer */ +/* */ +/* FT_Bitmap */ +/* FT_Pixel_Mode */ +/* FT_Palette_Mode */ +/* FT_Glyph_Format */ +/* FT_IMAGE_TAG */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Bool */ +/* */ +/* <Description> */ +/* A typedef of unsigned char, used for simple booleans. As usual, */ +/* values 1 and~0 represent true and false, respectively. */ +/* */ + typedef unsigned char FT_Bool; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_FWord */ +/* */ +/* <Description> */ +/* A signed 16-bit integer used to store a distance in original font */ +/* units. */ +/* */ +/* distance in FUnits */ + typedef signed short FT_FWord; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_UFWord */ +/* */ +/* <Description> */ +/* An unsigned 16-bit integer used to store a distance in original */ +/* font units. */ +/* */ +/* unsigned distance */ + typedef unsigned short FT_UFWord; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Char */ +/* */ +/* <Description> */ +/* A simple typedef for the _signed_ char type. */ +/* */ + typedef signed char FT_Char; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Byte */ +/* */ +/* <Description> */ +/* A simple typedef for the _unsigned_ char type. */ +/* */ + typedef unsigned char FT_Byte; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Bytes */ +/* */ +/* <Description> */ +/* A typedef for constant memory areas. */ +/* */ + typedef const FT_Byte* FT_Bytes; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Tag */ +/* */ +/* <Description> */ +/* A typedef for 32-bit tags (as used in the SFNT format). */ +/* */ + typedef FT_UInt32 FT_Tag; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_String */ +/* */ +/* <Description> */ +/* A simple typedef for the char type, usually used for strings. */ +/* */ + typedef char FT_String; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Short */ +/* */ +/* <Description> */ +/* A typedef for signed short. */ +/* */ + typedef signed short FT_Short; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_UShort */ +/* */ +/* <Description> */ +/* A typedef for unsigned short. */ +/* */ + typedef unsigned short FT_UShort; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Int */ +/* */ +/* <Description> */ +/* A typedef for the int type. */ +/* */ + typedef signed int FT_Int; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_UInt */ +/* */ +/* <Description> */ +/* A typedef for the unsigned int type. */ +/* */ + typedef unsigned int FT_UInt; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Long */ +/* */ +/* <Description> */ +/* A typedef for signed long. */ +/* */ + typedef signed long FT_Long; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_ULong */ +/* */ +/* <Description> */ +/* A typedef for unsigned long. */ +/* */ + typedef unsigned long FT_ULong; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_F2Dot14 */ +/* */ +/* <Description> */ +/* A signed 2.14 fixed float type used for unit vectors. */ +/* */ + typedef signed short FT_F2Dot14; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_F26Dot6 */ +/* */ +/* <Description> */ +/* A signed 26.6 fixed float type used for vectorial pixel */ +/* coordinates. */ +/* */ + typedef signed long FT_F26Dot6; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Fixed */ +/* */ +/* <Description> */ +/* This type is used to store 16.16 fixed float values, like scaling */ +/* values or matrix coefficients. */ +/* */ + typedef signed long FT_Fixed; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Error */ +/* */ +/* <Description> */ +/* The FreeType error code type. A value of~0 is always interpreted */ +/* as a successful operation. */ +/* */ + typedef int FT_Error; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Pointer */ +/* */ +/* <Description> */ +/* A simple typedef for a typeless pointer. */ +/* */ + typedef void* FT_Pointer; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Offset */ +/* */ +/* <Description> */ +/* This is equivalent to the ANSI~C `size_t' type, i.e., the largest */ +/* _unsigned_ integer type used to express a file size or position, */ +/* or a memory block size. */ +/* */ + typedef size_t FT_Offset; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_PtrDist */ +/* */ +/* <Description> */ +/* This is equivalent to the ANSI~C `ptrdiff_t' type, i.e., the */ +/* largest _signed_ integer type used to express the distance */ +/* between two pointers. */ +/* */ + typedef ft_ptrdiff_t FT_PtrDist; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_UnitVector */ +/* */ +/* <Description> */ +/* A simple structure used to store a 2D vector unit vector. Uses */ +/* FT_F2Dot14 types. */ +/* */ +/* <Fields> */ +/* x :: Horizontal coordinate. */ +/* */ +/* y :: Vertical coordinate. */ +/* */ + typedef struct FT_UnitVector_ + { + FT_F2Dot14 x; + FT_F2Dot14 y; + } FT_UnitVector; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Matrix */ +/* */ +/* <Description> */ +/* A simple structure used to store a 2x2 matrix. Coefficients are */ +/* in 16.16 fixed float format. The computation performed is: */ +/* */ +/* { */ +/* x' = x*xx + y*xy */ +/* y' = x*yx + y*yy */ +/* } */ +/* */ +/* <Fields> */ +/* xx :: Matrix coefficient. */ +/* */ +/* xy :: Matrix coefficient. */ +/* */ +/* yx :: Matrix coefficient. */ +/* */ +/* yy :: Matrix coefficient. */ +/* */ + typedef struct FT_Matrix_ + { + FT_Fixed xx, xy; + FT_Fixed yx, yy; + } FT_Matrix; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Data */ +/* */ +/* <Description> */ +/* Read-only binary data represented as a pointer and a length. */ +/* */ +/* <Fields> */ +/* pointer :: The data. */ +/* */ +/* length :: The length of the data in bytes. */ +/* */ + typedef struct FT_Data_ + { + const FT_Byte* pointer; + FT_Int length; + } FT_Data; +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Generic_Finalizer */ +/* */ +/* <Description> */ +/* Describe a function used to destroy the `client' data of any */ +/* FreeType object. See the description of the @FT_Generic type for */ +/* details of usage. */ +/* */ +/* <Input> */ +/* The address of the FreeType object which is under finalization. */ +/* Its client data is accessed through its `generic' field. */ +/* */ + typedef void (*FT_Generic_Finalizer)(void* object); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Generic */ +/* */ +/* <Description> */ +/* Client applications often need to associate their own data to a */ +/* variety of FreeType core objects. For example, a text layout API */ +/* might want to associate a glyph cache to a given size object. */ +/* */ +/* Some FreeType object contains a `generic' field, of type */ +/* FT_Generic, which usage is left to client applications and font */ +/* servers. */ +/* */ +/* It can be used to store a pointer to client-specific data, as well */ +/* as the address of a `finalizer' function, which will be called by */ +/* FreeType when the object is destroyed (for example, the previous */ +/* client example would put the address of the glyph cache destructor */ +/* in the `finalizer' field). */ +/* */ +/* <Fields> */ +/* data :: A typeless pointer to any client-specified data. This */ +/* field is completely ignored by the FreeType library. */ +/* */ +/* finalizer :: A pointer to a `generic finalizer' function, which */ +/* will be called when the object is destroyed. If this */ +/* field is set to NULL, no code will be called. */ +/* */ + typedef struct FT_Generic_ + { + void* data; + FT_Generic_Finalizer finalizer; + } FT_Generic; +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_MAKE_TAG */ +/* */ +/* <Description> */ +/* This macro converts four-letter tags which are used to label */ +/* TrueType tables into an unsigned long to be used within FreeType. */ +/* */ +/* <Note> */ +/* The produced values *must* be 32-bit integers. Don't redefine */ +/* this macro. */ +/* */ +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + (FT_Tag) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* L I S T M A N A G E M E N T */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Section> */ +/* list_processing */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_ListNode */ +/* */ +/* <Description> */ +/* Many elements and objects in FreeType are listed through an */ +/* @FT_List record (see @FT_ListRec). As its name suggests, an */ +/* FT_ListNode is a handle to a single list element. */ +/* */ + typedef struct FT_ListNodeRec_* FT_ListNode; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_List */ +/* */ +/* <Description> */ +/* A handle to a list record (see @FT_ListRec). */ +/* */ + typedef struct FT_ListRec_* FT_List; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_ListNodeRec */ +/* */ +/* <Description> */ +/* A structure used to hold a single list element. */ +/* */ +/* <Fields> */ +/* prev :: The previous element in the list. NULL if first. */ +/* */ +/* next :: The next element in the list. NULL if last. */ +/* */ +/* data :: A typeless pointer to the listed object. */ +/* */ + typedef struct FT_ListNodeRec_ + { + FT_ListNode prev; + FT_ListNode next; + void* data; + } FT_ListNodeRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_ListRec */ +/* */ +/* <Description> */ +/* A structure used to hold a simple doubly-linked list. These are */ +/* used in many parts of FreeType. */ +/* */ +/* <Fields> */ +/* head :: The head (first element) of doubly-linked list. */ +/* */ +/* tail :: The tail (last element) of doubly-linked list. */ +/* */ + typedef struct FT_ListRec_ + { + FT_ListNode head; + FT_ListNode tail; + } FT_ListRec; +/* */ +#define FT_IS_EMPTY( list ) ( (list).head == 0 ) +/* return base error code (without module-specific prefix) */ +#define FT_ERROR_BASE( x ) ( (x) & 0xFF ) +/* return module error code */ +#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U ) +#define FT_BOOL( x ) ( (FT_Bool)( x ) ) +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* user_allocation */ +/* */ +/* <Title> */ +/* User allocation */ +/* */ +/* <Abstract> */ +/* How client applications should allocate FreeType data structures. */ +/* */ +/* <Description> */ +/* FreeType assumes that structures allocated by the user and passed */ +/* as arguments are zeroed out except for the actual data. In other */ +/* words, it is recommended to use `calloc' (or variants of it) */ +/* instead of `malloc' for allocation. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* B A S I C T Y P E S */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Section> */ +/* base_interface */ +/* */ +/* <Title> */ +/* Base Interface */ +/* */ +/* <Abstract> */ +/* The FreeType~2 base font interface. */ +/* */ +/* <Description> */ +/* This section describes the public high-level API of FreeType~2. */ +/* */ +/* <Order> */ +/* FT_Library */ +/* FT_Face */ +/* FT_Size */ +/* FT_GlyphSlot */ +/* FT_CharMap */ +/* FT_Encoding */ +/* */ +/* FT_FaceRec */ +/* */ +/* FT_FACE_FLAG_SCALABLE */ +/* FT_FACE_FLAG_FIXED_SIZES */ +/* FT_FACE_FLAG_FIXED_WIDTH */ +/* FT_FACE_FLAG_HORIZONTAL */ +/* FT_FACE_FLAG_VERTICAL */ +/* FT_FACE_FLAG_SFNT */ +/* FT_FACE_FLAG_KERNING */ +/* FT_FACE_FLAG_MULTIPLE_MASTERS */ +/* FT_FACE_FLAG_GLYPH_NAMES */ +/* FT_FACE_FLAG_EXTERNAL_STREAM */ +/* FT_FACE_FLAG_FAST_GLYPHS */ +/* FT_FACE_FLAG_HINTER */ +/* */ +/* FT_STYLE_FLAG_BOLD */ +/* FT_STYLE_FLAG_ITALIC */ +/* */ +/* FT_SizeRec */ +/* FT_Size_Metrics */ +/* */ +/* FT_GlyphSlotRec */ +/* FT_Glyph_Metrics */ +/* FT_SubGlyph */ +/* */ +/* FT_Bitmap_Size */ +/* */ +/* FT_Init_FreeType */ +/* FT_Done_FreeType */ +/* */ +/* FT_New_Face */ +/* FT_Done_Face */ +/* FT_New_Memory_Face */ +/* FT_Open_Face */ +/* FT_Open_Args */ +/* FT_Parameter */ +/* FT_Attach_File */ +/* FT_Attach_Stream */ +/* */ +/* FT_Set_Char_Size */ +/* FT_Set_Pixel_Sizes */ +/* FT_Request_Size */ +/* FT_Select_Size */ +/* FT_Size_Request_Type */ +/* FT_Size_Request */ +/* FT_Set_Transform */ +/* FT_Load_Glyph */ +/* FT_Get_Char_Index */ +/* FT_Get_Name_Index */ +/* FT_Load_Char */ +/* */ +/* FT_OPEN_MEMORY */ +/* FT_OPEN_STREAM */ +/* FT_OPEN_PATHNAME */ +/* FT_OPEN_DRIVER */ +/* FT_OPEN_PARAMS */ +/* */ +/* FT_LOAD_DEFAULT */ +/* FT_LOAD_RENDER */ +/* FT_LOAD_MONOCHROME */ +/* FT_LOAD_LINEAR_DESIGN */ +/* FT_LOAD_NO_SCALE */ +/* FT_LOAD_NO_HINTING */ +/* FT_LOAD_NO_BITMAP */ +/* FT_LOAD_CROP_BITMAP */ +/* */ +/* FT_LOAD_VERTICAL_LAYOUT */ +/* FT_LOAD_IGNORE_TRANSFORM */ +/* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */ +/* FT_LOAD_FORCE_AUTOHINT */ +/* FT_LOAD_NO_RECURSE */ +/* FT_LOAD_PEDANTIC */ +/* */ +/* FT_LOAD_TARGET_NORMAL */ +/* FT_LOAD_TARGET_LIGHT */ +/* FT_LOAD_TARGET_MONO */ +/* FT_LOAD_TARGET_LCD */ +/* FT_LOAD_TARGET_LCD_V */ +/* */ +/* FT_Render_Glyph */ +/* FT_Render_Mode */ +/* FT_Get_Kerning */ +/* FT_Kerning_Mode */ +/* FT_Get_Track_Kerning */ +/* FT_Get_Glyph_Name */ +/* FT_Get_Postscript_Name */ +/* */ +/* FT_CharMapRec */ +/* FT_Select_Charmap */ +/* FT_Set_Charmap */ +/* FT_Get_Charmap_Index */ +/* */ +/* FT_FSTYPE_INSTALLABLE_EMBEDDING */ +/* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING */ +/* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING */ +/* FT_FSTYPE_EDITABLE_EMBEDDING */ +/* FT_FSTYPE_NO_SUBSETTING */ +/* FT_FSTYPE_BITMAP_EMBEDDING_ONLY */ +/* */ +/* FT_Get_FSType_Flags */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Glyph_Metrics */ +/* */ +/* <Description> */ +/* A structure used to model the metrics of a single glyph. The */ +/* values are expressed in 26.6 fractional pixel format; if the flag */ +/* @FT_LOAD_NO_SCALE has been used while loading the glyph, values */ +/* are expressed in font units instead. */ +/* */ +/* <Fields> */ +/* width :: */ +/* The glyph's width. */ +/* */ +/* height :: */ +/* The glyph's height. */ +/* */ +/* horiBearingX :: */ +/* Left side bearing for horizontal layout. */ +/* */ +/* horiBearingY :: */ +/* Top side bearing for horizontal layout. */ +/* */ +/* horiAdvance :: */ +/* Advance width for horizontal layout. */ +/* */ +/* vertBearingX :: */ +/* Left side bearing for vertical layout. */ +/* */ +/* vertBearingY :: */ +/* Top side bearing for vertical layout. Larger positive values */ +/* mean further below the vertical glyph origin. */ +/* */ +/* vertAdvance :: */ +/* Advance height for vertical layout. Positive values mean the */ +/* glyph has a positive advance downward. */ +/* */ +/* <Note> */ +/* If not disabled with @FT_LOAD_NO_HINTING, the values represent */ +/* dimensions of the hinted glyph (in case hinting is applicable). */ +/* */ +/* Stroking a glyph with an outside border does not increase */ +/* `horiAdvance' or `vertAdvance'; you have to manually adjust these */ +/* values to account for the added width and height. */ +/* */ + typedef struct FT_Glyph_Metrics_ + { + FT_Pos width; + FT_Pos height; + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; + } FT_Glyph_Metrics; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Bitmap_Size */ +/* */ +/* <Description> */ +/* This structure models the metrics of a bitmap strike (i.e., a set */ +/* of glyphs for a given point size and resolution) in a bitmap font. */ +/* It is used for the `available_sizes' field of @FT_Face. */ +/* */ +/* <Fields> */ +/* height :: The vertical distance, in pixels, between two */ +/* consecutive baselines. It is always positive. */ +/* */ +/* width :: The average width, in pixels, of all glyphs in the */ +/* strike. */ +/* */ +/* size :: The nominal size of the strike in 26.6 fractional */ +/* points. This field is not very useful. */ +/* */ +/* x_ppem :: The horizontal ppem (nominal width) in 26.6 fractional */ +/* pixels. */ +/* */ +/* y_ppem :: The vertical ppem (nominal height) in 26.6 fractional */ +/* pixels. */ +/* */ +/* <Note> */ +/* Windows FNT: */ +/* The nominal size given in a FNT font is not reliable. Thus when */ +/* the driver finds it incorrect, it sets `size' to some calculated */ +/* values and sets `x_ppem' and `y_ppem' to the pixel width and */ +/* height given in the font, respectively. */ +/* */ +/* TrueType embedded bitmaps: */ +/* `size', `width', and `height' values are not contained in the */ +/* bitmap strike itself. They are computed from the global font */ +/* parameters. */ +/* */ + typedef struct FT_Bitmap_Size_ + { + FT_Short height; + FT_Short width; + FT_Pos size; + FT_Pos x_ppem; + FT_Pos y_ppem; + } FT_Bitmap_Size; +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* O B J E C T C L A S S E S */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Library */ +/* */ +/* <Description> */ +/* A handle to a FreeType library instance. Each `library' is */ +/* completely independent from the others; it is the `root' of a set */ +/* of objects like fonts, faces, sizes, etc. */ +/* */ +/* It also embeds a memory manager (see @FT_Memory), as well as a */ +/* scan-line converter object (see @FT_Raster). */ +/* */ +/* For multi-threading applications each thread should have its own */ +/* FT_Library object. */ +/* */ +/* <Note> */ +/* Library objects are normally created by @FT_Init_FreeType, and */ +/* destroyed with @FT_Done_FreeType. */ +/* */ + typedef struct FT_LibraryRec_ *FT_Library; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Module */ +/* */ +/* <Description> */ +/* A handle to a given FreeType module object. Each module can be a */ +/* font driver, a renderer, or anything else that provides services */ +/* to the formers. */ +/* */ + typedef struct FT_ModuleRec_* FT_Module; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Driver */ +/* */ +/* <Description> */ +/* A handle to a given FreeType font driver object. Each font driver */ +/* is a special module capable of creating faces from font files. */ +/* */ + typedef struct FT_DriverRec_* FT_Driver; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Renderer */ +/* */ +/* <Description> */ +/* A handle to a given FreeType renderer. A renderer is a special */ +/* module in charge of converting a glyph image to a bitmap, when */ +/* necessary. Each renderer supports a given glyph image format, and */ +/* one or more target surface depths. */ +/* */ + typedef struct FT_RendererRec_* FT_Renderer; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Face */ +/* */ +/* <Description> */ +/* A handle to a given typographic face object. A face object models */ +/* a given typeface, in a given style. */ +/* */ +/* <Note> */ +/* Each face object also owns a single @FT_GlyphSlot object, as well */ +/* as one or more @FT_Size objects. */ +/* */ +/* Use @FT_New_Face or @FT_Open_Face to create a new face object from */ +/* a given filepathname or a custom input stream. */ +/* */ +/* Use @FT_Done_Face to destroy it (along with its slot and sizes). */ +/* */ +/* <Also> */ +/* See @FT_FaceRec for the publicly accessible fields of a given face */ +/* object. */ +/* */ + typedef struct FT_FaceRec_* FT_Face; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Size */ +/* */ +/* <Description> */ +/* A handle to an object used to model a face scaled to a given */ +/* character size. */ +/* */ +/* <Note> */ +/* Each @FT_Face has an _active_ @FT_Size object that is used by */ +/* functions like @FT_Load_Glyph to determine the scaling */ +/* transformation which is used to load and hint glyphs and metrics. */ +/* */ +/* You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, */ +/* @FT_Request_Size or even @FT_Select_Size to change the content */ +/* (i.e., the scaling values) of the active @FT_Size. */ +/* */ +/* You can use @FT_New_Size to create additional size objects for a */ +/* given @FT_Face, but they won't be used by other functions until */ +/* you activate it through @FT_Activate_Size. Only one size can be */ +/* activated at any given time per face. */ +/* */ +/* <Also> */ +/* See @FT_SizeRec for the publicly accessible fields of a given size */ +/* object. */ +/* */ + typedef struct FT_SizeRec_* FT_Size; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_GlyphSlot */ +/* */ +/* <Description> */ +/* A handle to a given `glyph slot'. A slot is a container where it */ +/* is possible to load any of the glyphs contained in its parent */ +/* face. */ +/* */ +/* In other words, each time you call @FT_Load_Glyph or */ +/* @FT_Load_Char, the slot's content is erased by the new glyph data, */ +/* i.e., the glyph's metrics, its image (bitmap or outline), and */ +/* other control information. */ +/* */ +/* <Also> */ +/* See @FT_GlyphSlotRec for the publicly accessible glyph fields. */ +/* */ + typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_CharMap */ +/* */ +/* <Description> */ +/* A handle to a given character map. A charmap is used to translate */ +/* character codes in a given encoding into glyph indexes for its */ +/* parent's face. Some font formats may provide several charmaps per */ +/* font. */ +/* */ +/* Each face object owns zero or more charmaps, but only one of them */ +/* can be `active' and used by @FT_Get_Char_Index or @FT_Load_Char. */ +/* */ +/* The list of available charmaps in a face is available through the */ +/* `face->num_charmaps' and `face->charmaps' fields of @FT_FaceRec. */ +/* */ +/* The currently active charmap is available as `face->charmap'. */ +/* You should call @FT_Set_Charmap to change it. */ +/* */ +/* <Note> */ +/* When a new face is created (either through @FT_New_Face or */ +/* @FT_Open_Face), the library looks for a Unicode charmap within */ +/* the list and automatically activates it. */ +/* */ +/* <Also> */ +/* See @FT_CharMapRec for the publicly accessible fields of a given */ +/* character map. */ +/* */ + typedef struct FT_CharMapRec_* FT_CharMap; +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_ENC_TAG */ +/* */ +/* <Description> */ +/* This macro converts four-letter tags into an unsigned long. It is */ +/* used to define `encoding' identifiers (see @FT_Encoding). */ +/* */ +/* <Note> */ +/* Since many 16-bit compilers don't like 32-bit enumerations, you */ +/* should redefine this macro in case of problems to something like */ +/* this: */ +/* */ +/* { */ +/* #define FT_ENC_TAG( value, a, b, c, d ) value */ +/* } */ +/* */ +/* to get a simple enumeration without assigning special numbers. */ +/* */ +#ifndef FT_ENC_TAG +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( (FT_UInt32)(a) << 24 ) | \ + ( (FT_UInt32)(b) << 16 ) | \ + ( (FT_UInt32)(c) << 8 ) | \ + (FT_UInt32)(d) ) +/* FT_ENC_TAG */ +#endif +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Encoding */ +/* */ +/* <Description> */ +/* An enumeration used to specify character sets supported by */ +/* charmaps. Used in the @FT_Select_Charmap API function. */ +/* */ +/* <Note> */ +/* Despite the name, this enumeration lists specific character */ +/* repertories (i.e., charsets), and not text encoding methods (e.g., */ +/* UTF-8, UTF-16, etc.). */ +/* */ +/* Other encodings might be defined in the future. */ +/* */ +/* <Values> */ +/* FT_ENCODING_NONE :: */ +/* The encoding value~0 is reserved. */ +/* */ +/* FT_ENCODING_UNICODE :: */ +/* Corresponds to the Unicode character set. This value covers */ +/* all versions of the Unicode repertoire, including ASCII and */ +/* Latin-1. Most fonts include a Unicode charmap, but not all */ +/* of them. */ +/* */ +/* For example, if you want to access Unicode value U+1F028 (and */ +/* the font contains it), use value 0x1F028 as the input value for */ +/* @FT_Get_Char_Index. */ +/* */ +/* FT_ENCODING_MS_SYMBOL :: */ +/* Corresponds to the Microsoft Symbol encoding, used to encode */ +/* mathematical symbols in the 32..255 character code range. For */ +/* more information, see `http://www.ceviz.net/symbol.htm'. */ +/* */ +/* FT_ENCODING_SJIS :: */ +/* Corresponds to Japanese SJIS encoding. More info at */ +/* at `http://langsupport.japanreference.com/encoding.shtml'. */ +/* See note on multi-byte encodings below. */ +/* */ +/* FT_ENCODING_GB2312 :: */ +/* Corresponds to an encoding system for Simplified Chinese as used */ +/* used in mainland China. */ +/* */ +/* FT_ENCODING_BIG5 :: */ +/* Corresponds to an encoding system for Traditional Chinese as */ +/* used in Taiwan and Hong Kong. */ +/* */ +/* FT_ENCODING_WANSUNG :: */ +/* Corresponds to the Korean encoding system known as Wansung. */ +/* For more information see */ +/* `http://www.microsoft.com/typography/unicode/949.txt'. */ +/* */ +/* FT_ENCODING_JOHAB :: */ +/* The Korean standard character set (KS~C 5601-1992), which */ +/* corresponds to MS Windows code page 1361. This character set */ +/* includes all possible Hangeul character combinations. */ +/* */ +/* FT_ENCODING_ADOBE_LATIN_1 :: */ +/* Corresponds to a Latin-1 encoding as defined in a Type~1 */ +/* PostScript font. It is limited to 256 character codes. */ +/* */ +/* FT_ENCODING_ADOBE_STANDARD :: */ +/* Corresponds to the Adobe Standard encoding, as found in Type~1, */ +/* CFF, and OpenType/CFF fonts. It is limited to 256 character */ +/* codes. */ +/* */ +/* FT_ENCODING_ADOBE_EXPERT :: */ +/* Corresponds to the Adobe Expert encoding, as found in Type~1, */ +/* CFF, and OpenType/CFF fonts. It is limited to 256 character */ +/* codes. */ +/* */ +/* FT_ENCODING_ADOBE_CUSTOM :: */ +/* Corresponds to a custom encoding, as found in Type~1, CFF, and */ +/* OpenType/CFF fonts. It is limited to 256 character codes. */ +/* */ +/* FT_ENCODING_APPLE_ROMAN :: */ +/* Corresponds to the 8-bit Apple roman encoding. Many TrueType */ +/* and OpenType fonts contain a charmap for this encoding, since */ +/* older versions of Mac OS are able to use it. */ +/* */ +/* FT_ENCODING_OLD_LATIN_2 :: */ +/* This value is deprecated and was never used nor reported by */ +/* FreeType. Don't use or test for it. */ +/* */ +/* FT_ENCODING_MS_SJIS :: */ +/* Same as FT_ENCODING_SJIS. Deprecated. */ +/* */ +/* FT_ENCODING_MS_GB2312 :: */ +/* Same as FT_ENCODING_GB2312. Deprecated. */ +/* */ +/* FT_ENCODING_MS_BIG5 :: */ +/* Same as FT_ENCODING_BIG5. Deprecated. */ +/* */ +/* FT_ENCODING_MS_WANSUNG :: */ +/* Same as FT_ENCODING_WANSUNG. Deprecated. */ +/* */ +/* FT_ENCODING_MS_JOHAB :: */ +/* Same as FT_ENCODING_JOHAB. Deprecated. */ +/* */ +/* <Note> */ +/* By default, FreeType automatically synthesizes a Unicode charmap */ +/* for PostScript fonts, using their glyph names dictionaries. */ +/* However, it also reports the encodings defined explicitly in the */ +/* font file, for the cases when they are needed, with the Adobe */ +/* values as well. */ +/* */ +/* FT_ENCODING_NONE is set by the BDF and PCF drivers if the charmap */ +/* is neither Unicode nor ISO-8859-1 (otherwise it is set to */ +/* FT_ENCODING_UNICODE). Use @FT_Get_BDF_Charset_ID to find out */ +/* which encoding is really present. If, for example, the */ +/* `cs_registry' field is `KOI8' and the `cs_encoding' field is `R', */ +/* the font is encoded in KOI8-R. */ +/* */ +/* FT_ENCODING_NONE is always set (with a single exception) by the */ +/* winfonts driver. Use @FT_Get_WinFNT_Header and examine the */ +/* `charset' field of the @FT_WinFNT_HeaderRec structure to find out */ +/* which encoding is really present. For example, */ +/* @FT_WinFNT_ID_CP1251 (204) means Windows code page 1251 (for */ +/* Russian). */ +/* */ +/* FT_ENCODING_NONE is set if `platform_id' is @TT_PLATFORM_MACINTOSH */ +/* and `encoding_id' is not @TT_MAC_ID_ROMAN (otherwise it is set to */ +/* FT_ENCODING_APPLE_ROMAN). */ +/* */ +/* If `platform_id' is @TT_PLATFORM_MACINTOSH, use the function */ +/* @FT_Get_CMap_Language_ID to query the Mac language ID which may */ +/* be needed to be able to distinguish Apple encoding variants. See */ +/* */ +/* http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/README.TXT */ +/* */ +/* to get an idea how to do that. Basically, if the language ID */ +/* is~0, don't use it, otherwise subtract 1 from the language ID. */ +/* Then examine `encoding_id'. If, for example, `encoding_id' is */ +/* @TT_MAC_ID_ROMAN and the language ID (minus~1) is */ +/* `TT_MAC_LANGID_GREEK', it is the Greek encoding, not Roman. */ +/* @TT_MAC_ID_ARABIC with `TT_MAC_LANGID_FARSI' means the Farsi */ +/* variant the Arabic encoding. */ +/* */ + typedef enum FT_Encoding_ + { + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_GB2312, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), +/* for backwards compatibility */ + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) + } FT_Encoding; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* ft_encoding_xxx */ +/* */ +/* <Description> */ +/* These constants are deprecated; use the corresponding @FT_Encoding */ +/* values instead. */ +/* */ +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_GB2312 +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_CharMapRec */ +/* */ +/* <Description> */ +/* The base charmap structure. */ +/* */ +/* <Fields> */ +/* face :: A handle to the parent face object. */ +/* */ +/* encoding :: An @FT_Encoding tag identifying the charmap. Use */ +/* this with @FT_Select_Charmap. */ +/* */ +/* platform_id :: An ID number describing the platform for the */ +/* following encoding ID. This comes directly from */ +/* the TrueType specification and should be emulated */ +/* for other formats. */ +/* */ +/* encoding_id :: A platform specific encoding number. This also */ +/* comes from the TrueType specification and should be */ +/* emulated similarly. */ +/* */ + typedef struct FT_CharMapRec_ + { + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; + } FT_CharMapRec; +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* B A S E O B J E C T C L A S S E S */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Face_Internal */ +/* */ +/* <Description> */ +/* An opaque handle to an `FT_Face_InternalRec' structure, used to */ +/* model private data of a given @FT_Face object. */ +/* */ +/* This structure might change between releases of FreeType~2 and is */ +/* not generally available to client applications. */ +/* */ + typedef struct FT_Face_InternalRec_* FT_Face_Internal; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_FaceRec */ +/* */ +/* <Description> */ +/* FreeType root face class structure. A face object models a */ +/* typeface in a font file. */ +/* */ +/* <Fields> */ +/* num_faces :: The number of faces in the font file. Some */ +/* font formats can have multiple faces in */ +/* a font file. */ +/* */ +/* face_index :: The index of the face in the font file. It */ +/* is set to~0 if there is only one face in */ +/* the font file. */ +/* */ +/* face_flags :: A set of bit flags that give important */ +/* information about the face; see */ +/* @FT_FACE_FLAG_XXX for the details. */ +/* */ +/* style_flags :: A set of bit flags indicating the style of */ +/* the face; see @FT_STYLE_FLAG_XXX for the */ +/* details. */ +/* */ +/* num_glyphs :: The number of glyphs in the face. If the */ +/* face is scalable and has sbits (see */ +/* `num_fixed_sizes'), it is set to the number */ +/* of outline glyphs. */ +/* */ +/* For CID-keyed fonts, this value gives the */ +/* highest CID used in the font. */ +/* */ +/* family_name :: The face's family name. This is an ASCII */ +/* string, usually in English, which describes */ +/* the typeface's family (like `Times New */ +/* Roman', `Bodoni', `Garamond', etc). This */ +/* is a least common denominator used to list */ +/* fonts. Some formats (TrueType & OpenType) */ +/* provide localized and Unicode versions of */ +/* this string. Applications should use the */ +/* format specific interface to access them. */ +/* Can be NULL (e.g., in fonts embedded in a */ +/* PDF file). */ +/* */ +/* style_name :: The face's style name. This is an ASCII */ +/* string, usually in English, which describes */ +/* the typeface's style (like `Italic', */ +/* `Bold', `Condensed', etc). Not all font */ +/* formats provide a style name, so this field */ +/* is optional, and can be set to NULL. As */ +/* for `family_name', some formats provide */ +/* localized and Unicode versions of this */ +/* string. Applications should use the format */ +/* specific interface to access them. */ +/* */ +/* num_fixed_sizes :: The number of bitmap strikes in the face. */ +/* Even if the face is scalable, there might */ +/* still be bitmap strikes, which are called */ +/* `sbits' in that case. */ +/* */ +/* available_sizes :: An array of @FT_Bitmap_Size for all bitmap */ +/* strikes in the face. It is set to NULL if */ +/* there is no bitmap strike. */ +/* */ +/* num_charmaps :: The number of charmaps in the face. */ +/* */ +/* charmaps :: An array of the charmaps of the face. */ +/* */ +/* generic :: A field reserved for client uses. See the */ +/* @FT_Generic type description. */ +/* */ +/* bbox :: The font bounding box. Coordinates are */ +/* expressed in font units (see */ +/* `units_per_EM'). The box is large enough */ +/* to contain any glyph from the font. Thus, */ +/* `bbox.yMax' can be seen as the `maximum */ +/* ascender', and `bbox.yMin' as the `minimum */ +/* descender'. Only relevant for scalable */ +/* formats. */ +/* */ +/* Note that the bounding box might be off by */ +/* (at least) one pixel for hinted fonts. See */ +/* @FT_Size_Metrics for further discussion. */ +/* */ +/* units_per_EM :: The number of font units per EM square for */ +/* this face. This is typically 2048 for */ +/* TrueType fonts, and 1000 for Type~1 fonts. */ +/* Only relevant for scalable formats. */ +/* */ +/* ascender :: The typographic ascender of the face, */ +/* expressed in font units. For font formats */ +/* not having this information, it is set to */ +/* `bbox.yMax'. Only relevant for scalable */ +/* formats. */ +/* */ +/* descender :: The typographic descender of the face, */ +/* expressed in font units. For font formats */ +/* not having this information, it is set to */ +/* `bbox.yMin'. Note that this field is */ +/* usually negative. Only relevant for */ +/* scalable formats. */ +/* */ +/* height :: The height is the vertical distance */ +/* between two consecutive baselines, */ +/* expressed in font units. It is always */ +/* positive. Only relevant for scalable */ +/* formats. */ +/* */ +/* max_advance_width :: The maximum advance width, in font units, */ +/* for all glyphs in this face. This can be */ +/* used to make word wrapping computations */ +/* faster. Only relevant for scalable */ +/* formats. */ +/* */ +/* max_advance_height :: The maximum advance height, in font units, */ +/* for all glyphs in this face. This is only */ +/* relevant for vertical layouts, and is set */ +/* to `height' for fonts that do not provide */ +/* vertical metrics. Only relevant for */ +/* scalable formats. */ +/* */ +/* underline_position :: The position, in font units, of the */ +/* underline line for this face. It is the */ +/* center of the underlining stem. Only */ +/* relevant for scalable formats. */ +/* */ +/* underline_thickness :: The thickness, in font units, of the */ +/* underline for this face. Only relevant for */ +/* scalable formats. */ +/* */ +/* glyph :: The face's associated glyph slot(s). */ +/* */ +/* size :: The current active size for this face. */ +/* */ +/* charmap :: The current active charmap for this face. */ +/* */ +/* <Note> */ +/* Fields may be changed after a call to @FT_Attach_File or */ +/* @FT_Attach_Stream. */ +/* */ + typedef struct FT_FaceRec_ + { + FT_Long num_faces; + FT_Long face_index; + FT_Long face_flags; + FT_Long style_flags; + FT_Long num_glyphs; + FT_String* family_name; + FT_String* style_name; + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + FT_Int num_charmaps; + FT_CharMap* charmaps; + FT_Generic generic; +/*# The following member variables (down to `underline_thickness') */ +/*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ +/*# for bitmap fonts. */ + FT_BBox bbox; + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + FT_Short max_advance_width; + FT_Short max_advance_height; + FT_Short underline_position; + FT_Short underline_thickness; + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; +/*@private begin */ + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + FT_ListRec sizes_list; +/* face-specific auto-hinter data */ + FT_Generic autohint; +/* unused */ + void* extensions; + FT_Face_Internal internal; +/*@private end */ + } FT_FaceRec; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_FACE_FLAG_XXX */ +/* */ +/* <Description> */ +/* A list of bit flags used in the `face_flags' field of the */ +/* @FT_FaceRec structure. They inform client applications of */ +/* properties of the corresponding face. */ +/* */ +/* <Values> */ +/* FT_FACE_FLAG_SCALABLE :: */ +/* Indicates that the face contains outline glyphs. This doesn't */ +/* prevent bitmap strikes, i.e., a face can have both this and */ +/* and @FT_FACE_FLAG_FIXED_SIZES set. */ +/* */ +/* FT_FACE_FLAG_FIXED_SIZES :: */ +/* Indicates that the face contains bitmap strikes. See also the */ +/* `num_fixed_sizes' and `available_sizes' fields of @FT_FaceRec. */ +/* */ +/* FT_FACE_FLAG_FIXED_WIDTH :: */ +/* Indicates that the face contains fixed-width characters (like */ +/* Courier, Lucido, MonoType, etc.). */ +/* */ +/* FT_FACE_FLAG_SFNT :: */ +/* Indicates that the face uses the `sfnt' storage scheme. For */ +/* now, this means TrueType and OpenType. */ +/* */ +/* FT_FACE_FLAG_HORIZONTAL :: */ +/* Indicates that the face contains horizontal glyph metrics. This */ +/* should be set for all common formats. */ +/* */ +/* FT_FACE_FLAG_VERTICAL :: */ +/* Indicates that the face contains vertical glyph metrics. This */ +/* is only available in some formats, not all of them. */ +/* */ +/* FT_FACE_FLAG_KERNING :: */ +/* Indicates that the face contains kerning information. If set, */ +/* the kerning distance can be retrieved through the function */ +/* @FT_Get_Kerning. Otherwise the function always return the */ +/* vector (0,0). Note that FreeType doesn't handle kerning data */ +/* from the `GPOS' table (as present in some OpenType fonts). */ +/* */ +/* FT_FACE_FLAG_FAST_GLYPHS :: */ +/* THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. */ +/* */ +/* FT_FACE_FLAG_MULTIPLE_MASTERS :: */ +/* Indicates that the font contains multiple masters and is capable */ +/* of interpolating between them. See the multiple-masters */ +/* specific API for details. */ +/* */ +/* FT_FACE_FLAG_GLYPH_NAMES :: */ +/* Indicates that the font contains glyph names that can be */ +/* retrieved through @FT_Get_Glyph_Name. Note that some TrueType */ +/* fonts contain broken glyph name tables. Use the function */ +/* @FT_Has_PS_Glyph_Names when needed. */ +/* */ +/* FT_FACE_FLAG_EXTERNAL_STREAM :: */ +/* Used internally by FreeType to indicate that a face's stream was */ +/* provided by the client application and should not be destroyed */ +/* when @FT_Done_Face is called. Don't read or test this flag. */ +/* */ +/* FT_FACE_FLAG_HINTER :: */ +/* Set if the font driver has a hinting machine of its own. For */ +/* example, with TrueType fonts, it makes sense to use data from */ +/* the SFNT `gasp' table only if the native TrueType hinting engine */ +/* (with the bytecode interpreter) is available and active. */ +/* */ +/* FT_FACE_FLAG_CID_KEYED :: */ +/* Set if the font is CID-keyed. In that case, the font is not */ +/* accessed by glyph indices but by CID values. For subsetted */ +/* CID-keyed fonts this has the consequence that not all index */ +/* values are a valid argument to FT_Load_Glyph. Only the CID */ +/* values for which corresponding glyphs in the subsetted font */ +/* exist make FT_Load_Glyph return successfully; in all other cases */ +/* you get an `FT_Err_Invalid_Argument' error. */ +/* */ +/* Note that CID-keyed fonts which are in an SFNT wrapper don't */ +/* have this flag set since the glyphs are accessed in the normal */ +/* way (using contiguous indices); the `CID-ness' isn't visible to */ +/* the application. */ +/* */ +/* FT_FACE_FLAG_TRICKY :: */ +/* Set if the font is `tricky', this is, it always needs the */ +/* font format's native hinting engine to get a reasonable result. */ +/* A typical example is the Chinese font `mingli.ttf' which uses */ +/* TrueType bytecode instructions to move and scale all of its */ +/* subglyphs. */ +/* */ +/* It is not possible to autohint such fonts using */ +/* @FT_LOAD_FORCE_AUTOHINT; it will also ignore */ +/* @FT_LOAD_NO_HINTING. You have to set both @FT_LOAD_NO_HINTING */ +/* and @FT_LOAD_NO_AUTOHINT to really disable hinting; however, you */ +/* probably never want this except for demonstration purposes. */ +/* */ +/* Currently, there are about a dozen TrueType fonts in the list of */ +/* tricky fonts; they are hard-coded in file `ttobjs.c'. */ +/* */ +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) +#define FT_FACE_FLAG_CID_KEYED ( 1L << 12 ) +#define FT_FACE_FLAG_TRICKY ( 1L << 13 ) +/************************************************************************* + * + * @macro: + * FT_HAS_HORIZONTAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains + * horizontal metrics (this is true for all font formats though). + * + * @also: + * @FT_HAS_VERTICAL can be used to check for vertical metrics. + * + */ +#define FT_HAS_HORIZONTAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_HORIZONTAL ) +/************************************************************************* + * + * @macro: + * FT_HAS_VERTICAL( face ) + * + * @description: + * A macro that returns true whenever a face object contains real + * vertical metrics (and not only synthesized ones). + * + */ +#define FT_HAS_VERTICAL( face ) \ + ( face->face_flags & FT_FACE_FLAG_VERTICAL ) +/************************************************************************* + * + * @macro: + * FT_HAS_KERNING( face ) + * + * @description: + * A macro that returns true whenever a face object contains kerning + * data that can be accessed with @FT_Get_Kerning. + * + */ +#define FT_HAS_KERNING( face ) \ + ( face->face_flags & FT_FACE_FLAG_KERNING ) +/************************************************************************* + * + * @macro: + * FT_IS_SCALABLE( face ) + * + * @description: + * A macro that returns true whenever a face object contains a scalable + * font face (true for TrueType, Type~1, Type~42, CID, OpenType/CFF, + * and PFR font formats. + * + */ +#define FT_IS_SCALABLE( face ) \ + ( face->face_flags & FT_FACE_FLAG_SCALABLE ) +/************************************************************************* + * + * @macro: + * FT_IS_SFNT( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font + * whose format is based on the SFNT storage scheme. This usually + * means: TrueType fonts, OpenType fonts, as well as SFNT-based embedded + * bitmap fonts. + * + * If this macro is true, all functions defined in @FT_SFNT_NAMES_H and + * @FT_TRUETYPE_TABLES_H are available. + * + */ +#define FT_IS_SFNT( face ) \ + ( face->face_flags & FT_FACE_FLAG_SFNT ) +/************************************************************************* + * + * @macro: + * FT_IS_FIXED_WIDTH( face ) + * + * @description: + * A macro that returns true whenever a face object contains a font face + * that contains fixed-width (or `monospace', `fixed-pitch', etc.) + * glyphs. + * + */ +#define FT_IS_FIXED_WIDTH( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) +/************************************************************************* + * + * @macro: + * FT_HAS_FIXED_SIZES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * embedded bitmaps. See the `available_sizes' field of the + * @FT_FaceRec structure. + * + */ +#define FT_HAS_FIXED_SIZES( face ) \ + ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES ) +/************************************************************************* + * + * @macro: + * FT_HAS_FAST_GLYPHS( face ) + * + * @description: + * Deprecated. + * + */ +#define FT_HAS_FAST_GLYPHS( face ) 0 +/************************************************************************* + * + * @macro: + * FT_HAS_GLYPH_NAMES( face ) + * + * @description: + * A macro that returns true whenever a face object contains some glyph + * names that can be accessed through @FT_Get_Glyph_Name. + * + */ +#define FT_HAS_GLYPH_NAMES( face ) \ + ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) +/************************************************************************* + * + * @macro: + * FT_HAS_MULTIPLE_MASTERS( face ) + * + * @description: + * A macro that returns true whenever a face object contains some + * multiple masters. The functions provided by @FT_MULTIPLE_MASTERS_H + * are then available to choose the exact design you want. + * + */ +#define FT_HAS_MULTIPLE_MASTERS( face ) \ + ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) +/************************************************************************* + * + * @macro: + * FT_IS_CID_KEYED( face ) + * + * @description: + * A macro that returns true whenever a face object contains a CID-keyed + * font. See the discussion of @FT_FACE_FLAG_CID_KEYED for more + * details. + * + * If this macro is true, all functions defined in @FT_CID_H are + * available. + * + */ +#define FT_IS_CID_KEYED( face ) \ + ( face->face_flags & FT_FACE_FLAG_CID_KEYED ) +/************************************************************************* + * + * @macro: + * FT_IS_TRICKY( face ) + * + * @description: + * A macro that returns true whenever a face represents a `tricky' font. + * See the discussion of @FT_FACE_FLAG_TRICKY for more details. + * + */ +#define FT_IS_TRICKY( face ) \ + ( face->face_flags & FT_FACE_FLAG_TRICKY ) +/*************************************************************************/ +/* */ +/* <Const> */ +/* FT_STYLE_FLAG_XXX */ +/* */ +/* <Description> */ +/* A list of bit-flags used to indicate the style of a given face. */ +/* These are used in the `style_flags' field of @FT_FaceRec. */ +/* */ +/* <Values> */ +/* FT_STYLE_FLAG_ITALIC :: */ +/* Indicates that a given face style is italic or oblique. */ +/* */ +/* FT_STYLE_FLAG_BOLD :: */ +/* Indicates that a given face is bold. */ +/* */ +/* <Note> */ +/* The style information as provided by FreeType is very basic. More */ +/* details are beyond the scope and should be done on a higher level */ +/* (for example, by analyzing various fields of the `OS/2' table in */ +/* SFNT based fonts). */ +/* */ +#define FT_STYLE_FLAG_ITALIC ( 1 << 0 ) +#define FT_STYLE_FLAG_BOLD ( 1 << 1 ) +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Size_Internal */ +/* */ +/* <Description> */ +/* An opaque handle to an `FT_Size_InternalRec' structure, used to */ +/* model private data of a given @FT_Size object. */ +/* */ + typedef struct FT_Size_InternalRec_* FT_Size_Internal; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Size_Metrics */ +/* */ +/* <Description> */ +/* The size metrics structure gives the metrics of a size object. */ +/* */ +/* <Fields> */ +/* x_ppem :: The width of the scaled EM square in pixels, hence */ +/* the term `ppem' (pixels per EM). It is also */ +/* referred to as `nominal width'. */ +/* */ +/* y_ppem :: The height of the scaled EM square in pixels, */ +/* hence the term `ppem' (pixels per EM). It is also */ +/* referred to as `nominal height'. */ +/* */ +/* x_scale :: A 16.16 fractional scaling value used to convert */ +/* horizontal metrics from font units to 26.6 */ +/* fractional pixels. Only relevant for scalable */ +/* font formats. */ +/* */ +/* y_scale :: A 16.16 fractional scaling value used to convert */ +/* vertical metrics from font units to 26.6 */ +/* fractional pixels. Only relevant for scalable */ +/* font formats. */ +/* */ +/* ascender :: The ascender in 26.6 fractional pixels. See */ +/* @FT_FaceRec for the details. */ +/* */ +/* descender :: The descender in 26.6 fractional pixels. See */ +/* @FT_FaceRec for the details. */ +/* */ +/* height :: The height in 26.6 fractional pixels. See */ +/* @FT_FaceRec for the details. */ +/* */ +/* max_advance :: The maximum advance width in 26.6 fractional */ +/* pixels. See @FT_FaceRec for the details. */ +/* */ +/* <Note> */ +/* The scaling values, if relevant, are determined first during a */ +/* size changing operation. The remaining fields are then set by the */ +/* driver. For scalable formats, they are usually set to scaled */ +/* values of the corresponding fields in @FT_FaceRec. */ +/* */ +/* Note that due to glyph hinting, these values might not be exact */ +/* for certain fonts. Thus they must be treated as unreliable */ +/* with an error margin of at least one pixel! */ +/* */ +/* Indeed, the only way to get the exact metrics is to render _all_ */ +/* glyphs. As this would be a definite performance hit, it is up to */ +/* client applications to perform such computations. */ +/* */ +/* The FT_Size_Metrics structure is valid for bitmap fonts also. */ +/* */ + typedef struct FT_Size_Metrics_ + { +/* horizontal pixels per EM */ + FT_UShort x_ppem; +/* vertical pixels per EM */ + FT_UShort y_ppem; +/* scaling values used to convert font */ + FT_Fixed x_scale; +/* units to 26.6 fractional pixels */ + FT_Fixed y_scale; +/* ascender in 26.6 frac. pixels */ + FT_Pos ascender; +/* descender in 26.6 frac. pixels */ + FT_Pos descender; +/* text height in 26.6 frac. pixels */ + FT_Pos height; +/* max horizontal advance, in 26.6 pixels */ + FT_Pos max_advance; + } FT_Size_Metrics; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_SizeRec */ +/* */ +/* <Description> */ +/* FreeType root size class structure. A size object models a face */ +/* object at a given size. */ +/* */ +/* <Fields> */ +/* face :: Handle to the parent face object. */ +/* */ +/* generic :: A typeless pointer, which is unused by the FreeType */ +/* library or any of its drivers. It can be used by */ +/* client applications to link their own data to each size */ +/* object. */ +/* */ +/* metrics :: Metrics for this size object. This field is read-only. */ +/* */ + typedef struct FT_SizeRec_ + { +/* parent face object */ + FT_Face face; +/* generic pointer for client uses */ + FT_Generic generic; +/* size metrics */ + FT_Size_Metrics metrics; + FT_Size_Internal internal; + } FT_SizeRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_SubGlyph */ +/* */ +/* <Description> */ +/* The subglyph structure is an internal object used to describe */ +/* subglyphs (for example, in the case of composites). */ +/* */ +/* <Note> */ +/* The subglyph implementation is not part of the high-level API, */ +/* hence the forward structure declaration. */ +/* */ +/* You can however retrieve subglyph information with */ +/* @FT_Get_SubGlyph_Info. */ +/* */ + typedef struct FT_SubGlyphRec_* FT_SubGlyph; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Slot_Internal */ +/* */ +/* <Description> */ +/* An opaque handle to an `FT_Slot_InternalRec' structure, used to */ +/* model private data of a given @FT_GlyphSlot object. */ +/* */ + typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_GlyphSlotRec */ +/* */ +/* <Description> */ +/* FreeType root glyph slot class structure. A glyph slot is a */ +/* container where individual glyphs can be loaded, be they in */ +/* outline or bitmap format. */ +/* */ +/* <Fields> */ +/* library :: A handle to the FreeType library instance */ +/* this slot belongs to. */ +/* */ +/* face :: A handle to the parent face object. */ +/* */ +/* next :: In some cases (like some font tools), several */ +/* glyph slots per face object can be a good */ +/* thing. As this is rare, the glyph slots are */ +/* listed through a direct, single-linked list */ +/* using its `next' field. */ +/* */ +/* generic :: A typeless pointer which is unused by the */ +/* FreeType library or any of its drivers. It */ +/* can be used by client applications to link */ +/* their own data to each glyph slot object. */ +/* */ +/* metrics :: The metrics of the last loaded glyph in the */ +/* slot. The returned values depend on the last */ +/* load flags (see the @FT_Load_Glyph API */ +/* function) and can be expressed either in 26.6 */ +/* fractional pixels or font units. */ +/* */ +/* Note that even when the glyph image is */ +/* transformed, the metrics are not. */ +/* */ +/* linearHoriAdvance :: The advance width of the unhinted glyph. */ +/* Its value is expressed in 16.16 fractional */ +/* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ +/* when loading the glyph. This field can be */ +/* important to perform correct WYSIWYG layout. */ +/* Only relevant for outline glyphs. */ +/* */ +/* linearVertAdvance :: The advance height of the unhinted glyph. */ +/* Its value is expressed in 16.16 fractional */ +/* pixels, unless @FT_LOAD_LINEAR_DESIGN is set */ +/* when loading the glyph. This field can be */ +/* important to perform correct WYSIWYG layout. */ +/* Only relevant for outline glyphs. */ +/* */ +/* advance :: This shorthand is, depending on */ +/* @FT_LOAD_IGNORE_TRANSFORM, the transformed */ +/* advance width for the glyph (in 26.6 */ +/* fractional pixel format). As specified with */ +/* @FT_LOAD_VERTICAL_LAYOUT, it uses either the */ +/* `horiAdvance' or the `vertAdvance' value of */ +/* `metrics' field. */ +/* */ +/* format :: This field indicates the format of the image */ +/* contained in the glyph slot. Typically */ +/* @FT_GLYPH_FORMAT_BITMAP, */ +/* @FT_GLYPH_FORMAT_OUTLINE, or */ +/* @FT_GLYPH_FORMAT_COMPOSITE, but others are */ +/* possible. */ +/* */ +/* bitmap :: This field is used as a bitmap descriptor */ +/* when the slot format is */ +/* @FT_GLYPH_FORMAT_BITMAP. Note that the */ +/* address and content of the bitmap buffer can */ +/* change between calls of @FT_Load_Glyph and a */ +/* few other functions. */ +/* */ +/* bitmap_left :: This is the bitmap's left bearing expressed */ +/* in integer pixels. Of course, this is only */ +/* valid if the format is */ +/* @FT_GLYPH_FORMAT_BITMAP. */ +/* */ +/* bitmap_top :: This is the bitmap's top bearing expressed in */ +/* integer pixels. Remember that this is the */ +/* distance from the baseline to the top-most */ +/* glyph scanline, upwards y~coordinates being */ +/* *positive*. */ +/* */ +/* outline :: The outline descriptor for the current glyph */ +/* image if its format is */ +/* @FT_GLYPH_FORMAT_OUTLINE. Once a glyph is */ +/* loaded, `outline' can be transformed, */ +/* distorted, embolded, etc. However, it must */ +/* not be freed. */ +/* */ +/* num_subglyphs :: The number of subglyphs in a composite glyph. */ +/* This field is only valid for the composite */ +/* glyph format that should normally only be */ +/* loaded with the @FT_LOAD_NO_RECURSE flag. */ +/* For now this is internal to FreeType. */ +/* */ +/* subglyphs :: An array of subglyph descriptors for */ +/* composite glyphs. There are `num_subglyphs' */ +/* elements in there. Currently internal to */ +/* FreeType. */ +/* */ +/* control_data :: Certain font drivers can also return the */ +/* control data for a given glyph image (e.g. */ +/* TrueType bytecode, Type~1 charstrings, etc.). */ +/* This field is a pointer to such data. */ +/* */ +/* control_len :: This is the length in bytes of the control */ +/* data. */ +/* */ +/* other :: Really wicked formats can use this pointer to */ +/* present their own glyph image to client */ +/* applications. Note that the application */ +/* needs to know about the image format. */ +/* */ +/* lsb_delta :: The difference between hinted and unhinted */ +/* left side bearing while autohinting is */ +/* active. Zero otherwise. */ +/* */ +/* rsb_delta :: The difference between hinted and unhinted */ +/* right side bearing while autohinting is */ +/* active. Zero otherwise. */ +/* */ +/* <Note> */ +/* If @FT_Load_Glyph is called with default flags (see */ +/* @FT_LOAD_DEFAULT) the glyph image is loaded in the glyph slot in */ +/* its native format (e.g., an outline glyph for TrueType and Type~1 */ +/* formats). */ +/* */ +/* This image can later be converted into a bitmap by calling */ +/* @FT_Render_Glyph. This function finds the current renderer for */ +/* the native image's format, then invokes it. */ +/* */ +/* The renderer is in charge of transforming the native image through */ +/* the slot's face transformation fields, then converting it into a */ +/* bitmap that is returned in `slot->bitmap'. */ +/* */ +/* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */ +/* to specify the position of the bitmap relative to the current pen */ +/* position (e.g., coordinates (0,0) on the baseline). Of course, */ +/* `slot->format' is also changed to @FT_GLYPH_FORMAT_BITMAP. */ +/* */ +/* <Note> */ +/* Here a small pseudo code fragment which shows how to use */ +/* `lsb_delta' and `rsb_delta': */ +/* */ +/* { */ +/* FT_Pos origin_x = 0; */ +/* FT_Pos prev_rsb_delta = 0; */ +/* */ +/* */ +/* for all glyphs do */ +/* <compute kern between current and previous glyph and add it to */ +/* `origin_x'> */ +/* */ +/* <load glyph with `FT_Load_Glyph'> */ +/* */ +/* if ( prev_rsb_delta - face->glyph->lsb_delta >= 32 ) */ +/* origin_x -= 64; */ +/* else if ( prev_rsb_delta - face->glyph->lsb_delta < -32 ) */ +/* origin_x += 64; */ +/* */ +/* prev_rsb_delta = face->glyph->rsb_delta; */ +/* */ +/* <save glyph image, or render glyph, or ...> */ +/* */ +/* origin_x += face->glyph->advance.x; */ +/* endfor */ +/* } */ +/* */ + typedef struct FT_GlyphSlotRec_ + { + FT_Library library; + FT_Face face; + FT_GlyphSlot next; +/* retained for binary compatibility */ + FT_UInt reserved; + FT_Generic generic; + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + FT_Glyph_Format format; + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + FT_Outline outline; + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + void* control_data; + long control_len; + FT_Pos lsb_delta; + FT_Pos rsb_delta; + void* other; + FT_Slot_Internal internal; + } FT_GlyphSlotRec; +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* F U N C T I O N S */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Init_FreeType */ +/* */ +/* <Description> */ +/* Initialize a new FreeType library object. The set of modules */ +/* that are registered by this function is determined at build time. */ +/* */ +/* <Output> */ +/* alibrary :: A handle to a new library object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* In case you want to provide your own memory allocating routines, */ +/* use @FT_New_Library instead, followed by a call to */ +/* @FT_Add_Default_Modules (or a series of calls to @FT_Add_Module). */ +/* */ +/* For multi-threading applications each thread should have its own */ +/* FT_Library object. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_FreeType */ +/* */ +/* <Description> */ +/* Destroy a given FreeType library object and all of its children, */ +/* including resources, drivers, faces, sizes, etc. */ +/* */ +/* <Input> */ +/* library :: A handle to the target library object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Done_FreeType( FT_Library library ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_OPEN_XXX */ +/* */ +/* <Description> */ +/* A list of bit-field constants used within the `flags' field of the */ +/* @FT_Open_Args structure. */ +/* */ +/* <Values> */ +/* FT_OPEN_MEMORY :: This is a memory-based stream. */ +/* */ +/* FT_OPEN_STREAM :: Copy the stream from the `stream' field. */ +/* */ +/* FT_OPEN_PATHNAME :: Create a new input stream from a C~path */ +/* name. */ +/* */ +/* FT_OPEN_DRIVER :: Use the `driver' field. */ +/* */ +/* FT_OPEN_PARAMS :: Use the `num_params' and `params' fields. */ +/* */ +/* ft_open_memory :: Deprecated; use @FT_OPEN_MEMORY instead. */ +/* */ +/* ft_open_stream :: Deprecated; use @FT_OPEN_STREAM instead. */ +/* */ +/* ft_open_pathname :: Deprecated; use @FT_OPEN_PATHNAME instead. */ +/* */ +/* ft_open_driver :: Deprecated; use @FT_OPEN_DRIVER instead. */ +/* */ +/* ft_open_params :: Deprecated; use @FT_OPEN_PARAMS instead. */ +/* */ +/* <Note> */ +/* The `FT_OPEN_MEMORY', `FT_OPEN_STREAM', and `FT_OPEN_PATHNAME' */ +/* flags are mutually exclusive. */ +/* */ +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 +/* deprecated */ +#define ft_open_memory FT_OPEN_MEMORY +/* deprecated */ +#define ft_open_stream FT_OPEN_STREAM +/* deprecated */ +#define ft_open_pathname FT_OPEN_PATHNAME +/* deprecated */ +#define ft_open_driver FT_OPEN_DRIVER +/* deprecated */ +#define ft_open_params FT_OPEN_PARAMS +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Parameter */ +/* */ +/* <Description> */ +/* A simple structure used to pass more or less generic parameters to */ +/* @FT_Open_Face. */ +/* */ +/* <Fields> */ +/* tag :: A four-byte identification tag. */ +/* */ +/* data :: A pointer to the parameter data. */ +/* */ +/* <Note> */ +/* The ID and function of parameters are driver-specific. See the */ +/* various FT_PARAM_TAG_XXX flags for more information. */ +/* */ + typedef struct FT_Parameter_ + { + FT_ULong tag; + FT_Pointer data; + } FT_Parameter; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Open_Args */ +/* */ +/* <Description> */ +/* A structure used to indicate how to open a new font file or */ +/* stream. A pointer to such a structure can be used as a parameter */ +/* for the functions @FT_Open_Face and @FT_Attach_Stream. */ +/* */ +/* <Fields> */ +/* flags :: A set of bit flags indicating how to use the */ +/* structure. */ +/* */ +/* memory_base :: The first byte of the file in memory. */ +/* */ +/* memory_size :: The size in bytes of the file in memory. */ +/* */ +/* pathname :: A pointer to an 8-bit file pathname. */ +/* */ +/* stream :: A handle to a source stream object. */ +/* */ +/* driver :: This field is exclusively used by @FT_Open_Face; */ +/* it simply specifies the font driver to use to open */ +/* the face. If set to~0, FreeType tries to load the */ +/* face with each one of the drivers in its list. */ +/* */ +/* num_params :: The number of extra parameters. */ +/* */ +/* params :: Extra parameters passed to the font driver when */ +/* opening a new face. */ +/* */ +/* <Note> */ +/* The stream type is determined by the contents of `flags' which */ +/* are tested in the following order by @FT_Open_Face: */ +/* */ +/* If the `FT_OPEN_MEMORY' bit is set, assume that this is a */ +/* memory file of `memory_size' bytes, located at `memory_address'. */ +/* The data are are not copied, and the client is responsible for */ +/* releasing and destroying them _after_ the corresponding call to */ +/* @FT_Done_Face. */ +/* */ +/* Otherwise, if the `FT_OPEN_STREAM' bit is set, assume that a */ +/* custom input stream `stream' is used. */ +/* */ +/* Otherwise, if the `FT_OPEN_PATHNAME' bit is set, assume that this */ +/* is a normal file and use `pathname' to open it. */ +/* */ +/* If the `FT_OPEN_DRIVER' bit is set, @FT_Open_Face only tries to */ +/* open the file with the driver whose handler is in `driver'. */ +/* */ +/* If the `FT_OPEN_PARAMS' bit is set, the parameters given by */ +/* `num_params' and `params' is used. They are ignored otherwise. */ +/* */ +/* Ideally, both the `pathname' and `params' fields should be tagged */ +/* as `const'; this is missing for API backwards compatibility. In */ +/* other words, applications should treat them as read-only. */ +/* */ + typedef struct FT_Open_Args_ + { + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; + } FT_Open_Args; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face */ +/* */ +/* <Description> */ +/* This function calls @FT_Open_Face to open a font by its pathname. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library resource. */ +/* */ +/* <Input> */ +/* pathname :: A path to the font file. */ +/* */ +/* face_index :: The index of the face within the font. The first */ +/* face has index~0. */ +/* */ +/* <Output> */ +/* aface :: A handle to a new face object. If `face_index' is */ +/* greater than or equal to zero, it must be non-NULL. */ +/* See @FT_Open_Face for more details. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Face( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Memory_Face */ +/* */ +/* <Description> */ +/* This function calls @FT_Open_Face to open a font which has been */ +/* loaded into memory. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library resource. */ +/* */ +/* <Input> */ +/* file_base :: A pointer to the beginning of the font data. */ +/* */ +/* file_size :: The size of the memory chunk used by the font data. */ +/* */ +/* face_index :: The index of the face within the font. The first */ +/* face has index~0. */ +/* */ +/* <Output> */ +/* aface :: A handle to a new face object. If `face_index' is */ +/* greater than or equal to zero, it must be non-NULL. */ +/* See @FT_Open_Face for more details. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* You must not deallocate the memory before calling @FT_Done_Face. */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Open_Face */ +/* */ +/* <Description> */ +/* Create a face object from a given resource described by */ +/* @FT_Open_Args. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library resource. */ +/* */ +/* <Input> */ +/* args :: A pointer to an `FT_Open_Args' structure which must */ +/* be filled by the caller. */ +/* */ +/* face_index :: The index of the face within the font. The first */ +/* face has index~0. */ +/* */ +/* <Output> */ +/* aface :: A handle to a new face object. If `face_index' is */ +/* greater than or equal to zero, it must be non-NULL. */ +/* See note below. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* Unlike FreeType 1.x, this function automatically creates a glyph */ +/* slot for the face object which can be accessed directly through */ +/* `face->glyph'. */ +/* */ +/* FT_Open_Face can be used to quickly check whether the font */ +/* format of a given font resource is supported by FreeType. If the */ +/* `face_index' field is negative, the function's return value is~0 */ +/* if the font format is recognized, or non-zero otherwise; */ +/* the function returns a more or less empty face handle in `*aface' */ +/* (if `aface' isn't NULL). The only useful field in this special */ +/* case is `face->num_faces' which gives the number of faces within */ +/* the font file. After examination, the returned @FT_Face structure */ +/* should be deallocated with a call to @FT_Done_Face. */ +/* */ +/* Each new face object created with this function also owns a */ +/* default @FT_Size object, accessible as `face->size'. */ +/* */ +/* One @FT_Library instance can have multiple face objects, this is, */ +/* @FT_Open_Face and its siblings can be called multiple times using */ +/* the same `library' argument. */ +/* */ +/* See the discussion of reference counters in the description of */ +/* @FT_Reference_Face. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Attach_File */ +/* */ +/* <Description> */ +/* This function calls @FT_Attach_Stream to attach a file. */ +/* */ +/* <InOut> */ +/* face :: The target face object. */ +/* */ +/* <Input> */ +/* filepathname :: The pathname. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Attach_Stream */ +/* */ +/* <Description> */ +/* `Attach' data to a face object. Normally, this is used to read */ +/* additional information for the face object. For example, you can */ +/* attach an AFM file that comes with a Type~1 font to get the */ +/* kerning values and other metrics. */ +/* */ +/* <InOut> */ +/* face :: The target face object. */ +/* */ +/* <Input> */ +/* parameters :: A pointer to @FT_Open_Args which must be filled by */ +/* the caller. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The meaning of the `attach' (i.e., what really happens when the */ +/* new file is read) is not fixed by FreeType itself. It really */ +/* depends on the font format (and thus the font driver). */ +/* */ +/* Client applications are expected to know what they are doing */ +/* when invoking this function. Most drivers simply do not implement */ +/* file attachments. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Reference_Face */ +/* */ +/* <Description> */ +/* A counter gets initialized to~1 at the time an @FT_Face structure */ +/* is created. This function increments the counter. @FT_Done_Face */ +/* then only destroys a face if the counter is~1, otherwise it simply */ +/* decrements the counter. */ +/* */ +/* This function helps in managing life-cycles of structures which */ +/* reference @FT_Face objects. */ +/* */ +/* <Input> */ +/* face :: A handle to a target face object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Since> */ +/* 2.4.2 */ +/* */ + FT_EXPORT( FT_Error ) + FT_Reference_Face( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_Face */ +/* */ +/* <Description> */ +/* Discard a given face object, as well as all of its child slots and */ +/* sizes. */ +/* */ +/* <Input> */ +/* face :: A handle to a target face object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* See the discussion of reference counters in the description of */ +/* @FT_Reference_Face. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Done_Face( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Select_Size */ +/* */ +/* <Description> */ +/* Select a bitmap strike. */ +/* */ +/* <InOut> */ +/* face :: A handle to a target face object. */ +/* */ +/* <Input> */ +/* strike_index :: The index of the bitmap strike in the */ +/* `available_sizes' field of @FT_FaceRec structure. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Size_Request_Type */ +/* */ +/* <Description> */ +/* An enumeration type that lists the supported size request types. */ +/* */ +/* <Values> */ +/* FT_SIZE_REQUEST_TYPE_NOMINAL :: */ +/* The nominal size. The `units_per_EM' field of @FT_FaceRec is */ +/* used to determine both scaling values. */ +/* */ +/* FT_SIZE_REQUEST_TYPE_REAL_DIM :: */ +/* The real dimension. The sum of the the `ascender' and (minus */ +/* of) the `descender' fields of @FT_FaceRec are used to determine */ +/* both scaling values. */ +/* */ +/* FT_SIZE_REQUEST_TYPE_BBOX :: */ +/* The font bounding box. The width and height of the `bbox' field */ +/* of @FT_FaceRec are used to determine the horizontal and vertical */ +/* scaling value, respectively. */ +/* */ +/* FT_SIZE_REQUEST_TYPE_CELL :: */ +/* The `max_advance_width' field of @FT_FaceRec is used to */ +/* determine the horizontal scaling value; the vertical scaling */ +/* value is determined the same way as */ +/* @FT_SIZE_REQUEST_TYPE_REAL_DIM does. Finally, both scaling */ +/* values are set to the smaller one. This type is useful if you */ +/* want to specify the font size for, say, a window of a given */ +/* dimension and 80x24 cells. */ +/* */ +/* FT_SIZE_REQUEST_TYPE_SCALES :: */ +/* Specify the scaling values directly. */ +/* */ +/* <Note> */ +/* The above descriptions only apply to scalable formats. For bitmap */ +/* formats, the behaviour is up to the driver. */ +/* */ +/* See the note section of @FT_Size_Metrics if you wonder how size */ +/* requesting relates to scaling values. */ +/* */ + typedef enum FT_Size_Request_Type_ + { + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + FT_SIZE_REQUEST_TYPE_MAX + } FT_Size_Request_Type; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Size_RequestRec */ +/* */ +/* <Description> */ +/* A structure used to model a size request. */ +/* */ +/* <Fields> */ +/* type :: See @FT_Size_Request_Type. */ +/* */ +/* width :: The desired width. */ +/* */ +/* height :: The desired height. */ +/* */ +/* horiResolution :: The horizontal resolution. If set to zero, */ +/* `width' is treated as a 26.6 fractional pixel */ +/* value. */ +/* */ +/* vertResolution :: The vertical resolution. If set to zero, */ +/* `height' is treated as a 26.6 fractional pixel */ +/* value. */ +/* */ +/* <Note> */ +/* If `width' is zero, then the horizontal scaling value is set equal */ +/* to the vertical scaling value, and vice versa. */ +/* */ + typedef struct FT_Size_RequestRec_ + { + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; + } FT_Size_RequestRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Size_Request */ +/* */ +/* <Description> */ +/* A handle to a size request structure. */ +/* */ + typedef struct FT_Size_RequestRec_ *FT_Size_Request; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Request_Size */ +/* */ +/* <Description> */ +/* Resize the scale of the active @FT_Size object in a face. */ +/* */ +/* <InOut> */ +/* face :: A handle to a target face object. */ +/* */ +/* <Input> */ +/* req :: A pointer to a @FT_Size_RequestRec. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* Although drivers may select the bitmap strike matching the */ +/* request, you should not rely on this if you intend to select a */ +/* particular bitmap strike. Use @FT_Select_Size instead in that */ +/* case. */ +/* */ +/* The relation between the requested size and the resulting glyph */ +/* size is dependent entirely on how the size is defined in the */ +/* source face. The font designer chooses the final size of each */ +/* glyph relative to this size. For more information refer to */ +/* `http://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html' */ +/* */ + FT_EXPORT( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Char_Size */ +/* */ +/* <Description> */ +/* This function calls @FT_Request_Size to request the nominal size */ +/* (in points). */ +/* */ +/* <InOut> */ +/* face :: A handle to a target face object. */ +/* */ +/* <Input> */ +/* char_width :: The nominal width, in 26.6 fractional points. */ +/* */ +/* char_height :: The nominal height, in 26.6 fractional points. */ +/* */ +/* horz_resolution :: The horizontal resolution in dpi. */ +/* */ +/* vert_resolution :: The vertical resolution in dpi. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* If either the character width or height is zero, it is set equal */ +/* to the other value. */ +/* */ +/* If either the horizontal or vertical resolution is zero, it is set */ +/* equal to the other value. */ +/* */ +/* A character width or height smaller than 1pt is set to 1pt; if */ +/* both resolution values are zero, they are set to 72dpi. */ +/* */ +/* Don't use this function if you are using the FreeType cache API. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Pixel_Sizes */ +/* */ +/* <Description> */ +/* This function calls @FT_Request_Size to request the nominal size */ +/* (in pixels). */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Input> */ +/* pixel_width :: The nominal width, in pixels. */ +/* */ +/* pixel_height :: The nominal height, in pixels. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* You should not rely on the resulting glyphs matching, or being */ +/* constrained, to this pixel size. Refer to @FT_Request_Size to */ +/* understand how requested sizes relate to actual sizes. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Load_Glyph */ +/* */ +/* <Description> */ +/* A function used to load a single glyph into the glyph slot of a */ +/* face object. */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object where the glyph */ +/* is loaded. */ +/* */ +/* <Input> */ +/* glyph_index :: The index of the glyph in the font file. For */ +/* CID-keyed fonts (either in PS or in CFF format) */ +/* this argument specifies the CID value. */ +/* */ +/* load_flags :: A flag indicating what to load for this glyph. The */ +/* @FT_LOAD_XXX constants can be used to control the */ +/* glyph loading process (e.g., whether the outline */ +/* should be scaled, whether to load bitmaps or not, */ +/* whether to hint the outline, etc). */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The loaded glyph may be transformed. See @FT_Set_Transform for */ +/* the details. */ +/* */ +/* For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument' is */ +/* returned for invalid CID values (this is, for CID values which */ +/* don't have a corresponding glyph in the font). See the discussion */ +/* of the @FT_FACE_FLAG_CID_KEYED flag for more details. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Load_Char */ +/* */ +/* <Description> */ +/* A function used to load a single glyph into the glyph slot of a */ +/* face object, according to its character code. */ +/* */ +/* <InOut> */ +/* face :: A handle to a target face object where the glyph */ +/* is loaded. */ +/* */ +/* <Input> */ +/* char_code :: The glyph's character code, according to the */ +/* current charmap used in the face. */ +/* */ +/* load_flags :: A flag indicating what to load for this glyph. The */ +/* @FT_LOAD_XXX constants can be used to control the */ +/* glyph loading process (e.g., whether the outline */ +/* should be scaled, whether to load bitmaps or not, */ +/* whether to hint the outline, etc). */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* This function simply calls @FT_Get_Char_Index and @FT_Load_Glyph. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); +/************************************************************************* + * + * @enum: + * FT_LOAD_XXX + * + * @description: + * A list of bit-field constants used with @FT_Load_Glyph to indicate + * what kind of operations to perform during glyph loading. + * + * @values: + * FT_LOAD_DEFAULT :: + * Corresponding to~0, this value is used as the default glyph load + * operation. In this case, the following happens: + * + * 1. FreeType looks for a bitmap for the glyph corresponding to the + * face's current size. If one is found, the function returns. + * The bitmap data can be accessed from the glyph slot (see note + * below). + * + * 2. If no embedded bitmap is searched or found, FreeType looks for a + * scalable outline. If one is found, it is loaded from the font + * file, scaled to device pixels, then `hinted' to the pixel grid + * in order to optimize it. The outline data can be accessed from + * the glyph slot (see note below). + * + * Note that by default, the glyph loader doesn't render outlines into + * bitmaps. The following flags are used to modify this default + * behaviour to more specific and useful cases. + * + * FT_LOAD_NO_SCALE :: + * Don't scale the loaded outline glyph but keep it in font units. + * + * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and + * unsets @FT_LOAD_RENDER. + * + * If the font is `tricky' (see @FT_FACE_FLAG_TRICKY for more), using + * FT_LOAD_NO_SCALE usually yields meaningless outlines because the + * subglyphs must be scaled and positioned with hinting instructions. + * This can be solved by loading the font without FT_LOAD_NO_SCALE and + * setting the character size to `font->units_per_EM'. + * + * FT_LOAD_NO_HINTING :: + * Disable hinting. This generally generates `blurrier' bitmap glyphs + * when the glyph are rendered in any of the anti-aliased modes. See + * also the note below. + * + * This flag is implied by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_RENDER :: + * Call @FT_Render_Glyph after the glyph is loaded. By default, the + * glyph is rendered in @FT_RENDER_MODE_NORMAL mode. This can be + * overridden by @FT_LOAD_TARGET_XXX or @FT_LOAD_MONOCHROME. + * + * This flag is unset by @FT_LOAD_NO_SCALE. + * + * FT_LOAD_NO_BITMAP :: + * Ignore bitmap strikes when loading. Bitmap-only fonts ignore this + * flag. + * + * @FT_LOAD_NO_SCALE always sets this flag. + * + * FT_LOAD_VERTICAL_LAYOUT :: + * Load the glyph for vertical text layout. In particular, the + * `advance' value in the @FT_GlyphSlotRec structure is set to the + * `vertAdvance' value of the `metrics' field. + * + * In case @FT_HAS_VERTICAL doesn't return true, you shouldn't use + * this flag currently. Reason is that in this case vertical metrics + * get synthesized, and those values are not always consistent across + * various font formats. + * + * FT_LOAD_FORCE_AUTOHINT :: + * Indicates that the auto-hinter is preferred over the font's native + * hinter. See also the note below. + * + * FT_LOAD_CROP_BITMAP :: + * Indicates that the font driver should crop the loaded bitmap glyph + * (i.e., remove all space around its black bits). Not all drivers + * implement this. + * + * FT_LOAD_PEDANTIC :: + * Indicates that the font driver should perform pedantic verifications + * during glyph loading. This is mostly used to detect broken glyphs + * in fonts. By default, FreeType tries to handle broken fonts also. + * + * In particular, errors from the TrueType bytecode engine are not + * passed to the application if this flag is not set; this might + * result in partially hinted or distorted glyphs in case a glyph's + * bytecode is buggy. + * + * FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH :: + * Ignored. Deprecated. + * + * FT_LOAD_NO_RECURSE :: + * This flag is only used internally. It merely indicates that the + * font driver should not load composite glyphs recursively. Instead, + * it should set the `num_subglyph' and `subglyphs' values of the + * glyph slot accordingly, and set `glyph->format' to + * @FT_GLYPH_FORMAT_COMPOSITE. + * + * The description of sub-glyphs is not available to client + * applications for now. + * + * This flag implies @FT_LOAD_NO_SCALE and @FT_LOAD_IGNORE_TRANSFORM. + * + * FT_LOAD_IGNORE_TRANSFORM :: + * Indicates that the transform matrix set by @FT_Set_Transform should + * be ignored. + * + * FT_LOAD_MONOCHROME :: + * This flag is used with @FT_LOAD_RENDER to indicate that you want to + * render an outline glyph to a 1-bit monochrome bitmap glyph, with + * 8~pixels packed into each byte of the bitmap data. + * + * Note that this has no effect on the hinting algorithm used. You + * should rather use @FT_LOAD_TARGET_MONO so that the + * monochrome-optimized hinting algorithm is used. + * + * FT_LOAD_LINEAR_DESIGN :: + * Indicates that the `linearHoriAdvance' and `linearVertAdvance' + * fields of @FT_GlyphSlotRec should be kept in font units. See + * @FT_GlyphSlotRec for details. + * + * FT_LOAD_NO_AUTOHINT :: + * Disable auto-hinter. See also the note below. + * + * @note: + * By default, hinting is enabled and the font's native hinter (see + * @FT_FACE_FLAG_HINTER) is preferred over the auto-hinter. You can + * disable hinting by setting @FT_LOAD_NO_HINTING or change the + * precedence by setting @FT_LOAD_FORCE_AUTOHINT. You can also set + * @FT_LOAD_NO_AUTOHINT in case you don't want the auto-hinter to be + * used at all. + * + * See the description of @FT_FACE_FLAG_TRICKY for a special exception + * (affecting only a handful of Asian fonts). + * + * Besides deciding which hinter to use, you can also decide which + * hinting algorithm to use. See @FT_LOAD_TARGET_XXX for details. + * + * Note that the auto-hinter needs a valid Unicode cmap (either a native + * one or synthesized by FreeType) for producing correct results. If a + * font provides an incorrect mapping (for example, assigning the + * character code U+005A, LATIN CAPITAL LETTER Z, to a glyph depicting a + * mathematical integral sign), the auto-hinter might produce useless + * results. + * + */ +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE ( 1L << 0 ) +#define FT_LOAD_NO_HINTING ( 1L << 1 ) +#define FT_LOAD_RENDER ( 1L << 2 ) +#define FT_LOAD_NO_BITMAP ( 1L << 3 ) +#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) +#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) +#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) +#define FT_LOAD_PEDANTIC ( 1L << 7 ) +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) +#define FT_LOAD_NO_RECURSE ( 1L << 10 ) +#define FT_LOAD_IGNORE_TRANSFORM ( 1L << 11 ) +#define FT_LOAD_MONOCHROME ( 1L << 12 ) +#define FT_LOAD_LINEAR_DESIGN ( 1L << 13 ) +#define FT_LOAD_NO_AUTOHINT ( 1L << 15 ) +/* */ +/* used internally only by certain font drivers! */ +#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) +#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) +/************************************************************************** + * + * @enum: + * FT_LOAD_TARGET_XXX + * + * @description: + * A list of values that are used to select a specific hinting algorithm + * to use by the hinter. You should OR one of these values to your + * `load_flags' when calling @FT_Load_Glyph. + * + * Note that font's native hinters may ignore the hinting algorithm you + * have specified (e.g., the TrueType bytecode interpreter). You can set + * @FT_LOAD_FORCE_AUTOHINT to ensure that the auto-hinter is used. + * + * Also note that @FT_LOAD_TARGET_LIGHT is an exception, in that it + * always implies @FT_LOAD_FORCE_AUTOHINT. + * + * @values: + * FT_LOAD_TARGET_NORMAL :: + * This corresponds to the default hinting algorithm, optimized for + * standard gray-level rendering. For monochrome output, use + * @FT_LOAD_TARGET_MONO instead. + * + * FT_LOAD_TARGET_LIGHT :: + * A lighter hinting algorithm for non-monochrome modes. Many + * generated glyphs are more fuzzy but better resemble its original + * shape. A bit like rendering on Mac OS~X. + * + * As a special exception, this target implies @FT_LOAD_FORCE_AUTOHINT. + * + * FT_LOAD_TARGET_MONO :: + * Strong hinting algorithm that should only be used for monochrome + * output. The result is probably unpleasant if the glyph is rendered + * in non-monochrome modes. + * + * FT_LOAD_TARGET_LCD :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for horizontally + * decimated LCD displays. + * + * FT_LOAD_TARGET_LCD_V :: + * A variant of @FT_LOAD_TARGET_NORMAL optimized for vertically + * decimated LCD displays. + * + * @note: + * You should use only _one_ of the FT_LOAD_TARGET_XXX values in your + * `load_flags'. They can't be ORed. + * + * If @FT_LOAD_RENDER is also set, the glyph is rendered in the + * corresponding mode (i.e., the mode which matches the used algorithm + * best). An exeption is FT_LOAD_TARGET_MONO since it implies + * @FT_LOAD_MONOCHROME. + * + * You can use a hinting algorithm that doesn't correspond to the same + * rendering mode. As an example, it is possible to use the `light' + * hinting algorithm and have the results rendered in horizontal LCD + * pixel mode, with code like + * + * { + * FT_Load_Glyph( face, glyph_index, + * load_flags | FT_LOAD_TARGET_LIGHT ); + * + * FT_Render_Glyph( face->glyph, FT_RENDER_MODE_LCD ); + * } + * + */ +#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) +/************************************************************************** + * + * @macro: + * FT_LOAD_TARGET_MODE + * + * @description: + * Return the @FT_Render_Mode corresponding to a given + * @FT_LOAD_TARGET_XXX value. + * + */ +#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Transform */ +/* */ +/* <Description> */ +/* A function used to set the transformation that is applied to glyph */ +/* images when they are loaded into a glyph slot through */ +/* @FT_Load_Glyph. */ +/* */ +/* <InOut> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Input> */ +/* matrix :: A pointer to the transformation's 2x2 matrix. Use~0 for */ +/* the identity matrix. */ +/* delta :: A pointer to the translation vector. Use~0 for the null */ +/* vector. */ +/* */ +/* <Note> */ +/* The transformation is only applied to scalable image formats after */ +/* the glyph has been loaded. It means that hinting is unaltered by */ +/* the transformation and is performed on the character size given in */ +/* the last call to @FT_Set_Char_Size or @FT_Set_Pixel_Sizes. */ +/* */ +/* Note that this also transforms the `face.glyph.advance' field, but */ +/* *not* the values in `face.glyph.metrics'. */ +/* */ + FT_EXPORT( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Render_Mode */ +/* */ +/* <Description> */ +/* An enumeration type that lists the render modes supported by */ +/* FreeType~2. Each mode corresponds to a specific type of scanline */ +/* conversion performed on the outline. */ +/* */ +/* For bitmap fonts and embedded bitmaps the `bitmap->pixel_mode' */ +/* field in the @FT_GlyphSlotRec structure gives the format of the */ +/* returned bitmap. */ +/* */ +/* All modes except @FT_RENDER_MODE_MONO use 256 levels of opacity. */ +/* */ +/* <Values> */ +/* FT_RENDER_MODE_NORMAL :: */ +/* This is the default render mode; it corresponds to 8-bit */ +/* anti-aliased bitmaps. */ +/* */ +/* FT_RENDER_MODE_LIGHT :: */ +/* This is equivalent to @FT_RENDER_MODE_NORMAL. It is only */ +/* defined as a separate value because render modes are also used */ +/* indirectly to define hinting algorithm selectors. See */ +/* @FT_LOAD_TARGET_XXX for details. */ +/* */ +/* FT_RENDER_MODE_MONO :: */ +/* This mode corresponds to 1-bit bitmaps (with 2~levels of */ +/* opacity). */ +/* */ +/* FT_RENDER_MODE_LCD :: */ +/* This mode corresponds to horizontal RGB and BGR sub-pixel */ +/* displays like LCD screens. It produces 8-bit bitmaps that are */ +/* 3~times the width of the original glyph outline in pixels, and */ +/* which use the @FT_PIXEL_MODE_LCD mode. */ +/* */ +/* FT_RENDER_MODE_LCD_V :: */ +/* This mode corresponds to vertical RGB and BGR sub-pixel displays */ +/* (like PDA screens, rotated LCD displays, etc.). It produces */ +/* 8-bit bitmaps that are 3~times the height of the original */ +/* glyph outline in pixels and use the @FT_PIXEL_MODE_LCD_V mode. */ +/* */ +/* <Note> */ +/* The LCD-optimized glyph bitmaps produced by FT_Render_Glyph can be */ +/* filtered to reduce color-fringes by using @FT_Library_SetLcdFilter */ +/* (not active in the default builds). It is up to the caller to */ +/* either call @FT_Library_SetLcdFilter (if available) or do the */ +/* filtering itself. */ +/* */ +/* The selected render mode only affects vector glyphs of a font. */ +/* Embedded bitmaps often have a different pixel mode like */ +/* @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform */ +/* them into 8-bit pixmaps. */ +/* */ + typedef enum FT_Render_Mode_ + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + FT_RENDER_MODE_MAX + } FT_Render_Mode; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* ft_render_mode_xxx */ +/* */ +/* <Description> */ +/* These constants are deprecated. Use the corresponding */ +/* @FT_Render_Mode values instead. */ +/* */ +/* <Values> */ +/* ft_render_mode_normal :: see @FT_RENDER_MODE_NORMAL */ +/* ft_render_mode_mono :: see @FT_RENDER_MODE_MONO */ +/* */ +#define ft_render_mode_normal FT_RENDER_MODE_NORMAL +#define ft_render_mode_mono FT_RENDER_MODE_MONO +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Render_Glyph */ +/* */ +/* <Description> */ +/* Convert a given glyph image to a bitmap. It does so by inspecting */ +/* the glyph image format, finding the relevant renderer, and */ +/* invoking it. */ +/* */ +/* <InOut> */ +/* slot :: A handle to the glyph slot containing the image to */ +/* convert. */ +/* */ +/* <Input> */ +/* render_mode :: This is the render mode used to render the glyph */ +/* image into a bitmap. See @FT_Render_Mode for a */ +/* list of possible values. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Kerning_Mode */ +/* */ +/* <Description> */ +/* An enumeration used to specify which kerning values to return in */ +/* @FT_Get_Kerning. */ +/* */ +/* <Values> */ +/* FT_KERNING_DEFAULT :: Return scaled and grid-fitted kerning */ +/* distances (value is~0). */ +/* */ +/* FT_KERNING_UNFITTED :: Return scaled but un-grid-fitted kerning */ +/* distances. */ +/* */ +/* FT_KERNING_UNSCALED :: Return the kerning vector in original font */ +/* units. */ +/* */ + typedef enum FT_Kerning_Mode_ + { + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED + } FT_Kerning_Mode; +/*************************************************************************/ +/* */ +/* <Const> */ +/* ft_kerning_default */ +/* */ +/* <Description> */ +/* This constant is deprecated. Please use @FT_KERNING_DEFAULT */ +/* instead. */ +/* */ +#define ft_kerning_default FT_KERNING_DEFAULT +/*************************************************************************/ +/* */ +/* <Const> */ +/* ft_kerning_unfitted */ +/* */ +/* <Description> */ +/* This constant is deprecated. Please use @FT_KERNING_UNFITTED */ +/* instead. */ +/* */ +#define ft_kerning_unfitted FT_KERNING_UNFITTED +/*************************************************************************/ +/* */ +/* <Const> */ +/* ft_kerning_unscaled */ +/* */ +/* <Description> */ +/* This constant is deprecated. Please use @FT_KERNING_UNSCALED */ +/* instead. */ +/* */ +#define ft_kerning_unscaled FT_KERNING_UNSCALED +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Kerning */ +/* */ +/* <Description> */ +/* Return the kerning vector between two glyphs of a same face. */ +/* */ +/* <Input> */ +/* face :: A handle to a source face object. */ +/* */ +/* left_glyph :: The index of the left glyph in the kern pair. */ +/* */ +/* right_glyph :: The index of the right glyph in the kern pair. */ +/* */ +/* kern_mode :: See @FT_Kerning_Mode for more information. */ +/* Determines the scale and dimension of the returned */ +/* kerning vector. */ +/* */ +/* <Output> */ +/* akerning :: The kerning vector. This is either in font units */ +/* or in pixels (26.6 format) for scalable formats, */ +/* and in pixels for fixed-sizes formats. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* Only horizontal layouts (left-to-right & right-to-left) are */ +/* supported by this method. Other layouts, or more sophisticated */ +/* kernings, are out of the scope of this API function -- they can be */ +/* implemented through format-specific interfaces. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Track_Kerning */ +/* */ +/* <Description> */ +/* Return the track kerning for a given face object at a given size. */ +/* */ +/* <Input> */ +/* face :: A handle to a source face object. */ +/* */ +/* point_size :: The point size in 16.16 fractional points. */ +/* */ +/* degree :: The degree of tightness. Increasingly negative */ +/* values represent tighter track kerning, while */ +/* increasingly positive values represent looser track */ +/* kerning. Value zero means no track kerning. */ +/* */ +/* <Output> */ +/* akerning :: The kerning in 16.16 fractional points, to be */ +/* uniformly applied between all glyphs. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* Currently, only the Type~1 font driver supports track kerning, */ +/* using data from AFM files (if attached with @FT_Attach_File or */ +/* @FT_Attach_Stream). */ +/* */ +/* Only very few AFM files come with track kerning data; please refer */ +/* to the Adobe's AFM specification for more details. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Glyph_Name */ +/* */ +/* <Description> */ +/* Retrieve the ASCII name of a given glyph in a face. This only */ +/* works for those faces where @FT_HAS_GLYPH_NAMES(face) returns~1. */ +/* */ +/* <Input> */ +/* face :: A handle to a source face object. */ +/* */ +/* glyph_index :: The glyph index. */ +/* */ +/* buffer_max :: The maximum number of bytes available in the */ +/* buffer. */ +/* */ +/* <Output> */ +/* buffer :: A pointer to a target buffer where the name is */ +/* copied to. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* An error is returned if the face doesn't provide glyph names or if */ +/* the glyph index is invalid. In all cases of failure, the first */ +/* byte of `buffer' is set to~0 to indicate an empty name. */ +/* */ +/* The glyph name is truncated to fit within the buffer if it is too */ +/* long. The returned string is always zero-terminated. */ +/* */ +/* Be aware that FreeType reorders glyph indices internally so that */ +/* glyph index~0 always corresponds to the `missing glyph' (called */ +/* `.notdef'). */ +/* */ +/* This function is not compiled within the library if the config */ +/* macro `FT_CONFIG_OPTION_NO_GLYPH_NAMES' is defined in */ +/* `include/freetype/config/ftoptions.h'. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Postscript_Name */ +/* */ +/* <Description> */ +/* Retrieve the ASCII PostScript name of a given face, if available. */ +/* This only works with PostScript and TrueType fonts. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Return> */ +/* A pointer to the face's PostScript name. NULL if unavailable. */ +/* */ +/* <Note> */ +/* The returned pointer is owned by the face and is destroyed with */ +/* it. */ +/* */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Select_Charmap */ +/* */ +/* <Description> */ +/* Select a given charmap by its encoding tag (as listed in */ +/* `freetype.h'). */ +/* */ +/* <InOut> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Input> */ +/* encoding :: A handle to the selected encoding. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* This function returns an error if no charmap in the face */ +/* corresponds to the encoding queried here. */ +/* */ +/* Because many fonts contain more than a single cmap for Unicode */ +/* encoding, this function has some special code to select the one */ +/* which covers Unicode best (`best' in the sense that a UCS-4 cmap */ +/* is preferred to a UCS-2 cmap). It is thus preferable to */ +/* @FT_Set_Charmap in this case. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Charmap */ +/* */ +/* <Description> */ +/* Select a given charmap for character code to glyph index mapping. */ +/* */ +/* <InOut> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Input> */ +/* charmap :: A handle to the selected charmap. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* This function returns an error if the charmap is not part of */ +/* the face (i.e., if it is not listed in the `face->charmaps' */ +/* table). */ +/* */ +/* It also fails if a type~14 charmap is selected. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ); +/************************************************************************* + * + * @function: + * FT_Get_Charmap_Index + * + * @description: + * Retrieve index of a given charmap. + * + * @input: + * charmap :: + * A handle to a charmap. + * + * @return: + * The index into the array of character maps within the face to which + * `charmap' belongs. If an error occurs, -1 is returned. + * + */ + FT_EXPORT( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Char_Index */ +/* */ +/* <Description> */ +/* Return the glyph index of a given character code. This function */ +/* uses a charmap object to do the mapping. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* charcode :: The character code. */ +/* */ +/* <Return> */ +/* The glyph index. 0~means `undefined character code'. */ +/* */ +/* <Note> */ +/* If you use FreeType to manipulate the contents of font files */ +/* directly, be aware that the glyph index returned by this function */ +/* doesn't always correspond to the internal indices used within the */ +/* file. This is done to ensure that value~0 always corresponds to */ +/* the `missing glyph'. If the first glyph is not named `.notdef', */ +/* then for Type~1 and Type~42 fonts, `.notdef' will be moved into */ +/* the glyph ID~0 position, and whatever was there will be moved to */ +/* the position `.notdef' had. For Type~1 fonts, if there is no */ +/* `.notdef' glyph at all, then one will be created at index~0 and */ +/* whatever was there will be moved to the last index -- Type~42 */ +/* fonts are considered invalid under this condition. */ +/* */ + FT_EXPORT( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_First_Char */ +/* */ +/* <Description> */ +/* This function is used to return the first character code in the */ +/* current charmap of a given face. It also returns the */ +/* corresponding glyph index. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Output> */ +/* agindex :: Glyph index of first character code. 0~if charmap is */ +/* empty. */ +/* */ +/* <Return> */ +/* The charmap's first character code. */ +/* */ +/* <Note> */ +/* You should use this function with @FT_Get_Next_Char to be able to */ +/* parse all character codes available in a given charmap. The code */ +/* should look like this: */ +/* */ +/* { */ +/* FT_ULong charcode; */ +/* FT_UInt gindex; */ +/* */ +/* */ +/* charcode = FT_Get_First_Char( face, &gindex ); */ +/* while ( gindex != 0 ) */ +/* { */ +/* ... do something with (charcode,gindex) pair ... */ +/* */ +/* charcode = FT_Get_Next_Char( face, charcode, &gindex ); */ +/* } */ +/* } */ +/* */ +/* Note that `*agindex' is set to~0 if the charmap is empty. The */ +/* result itself can be~0 in two cases: if the charmap is empty or */ +/* if the value~0 is the first valid character code. */ +/* */ + FT_EXPORT( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Next_Char */ +/* */ +/* <Description> */ +/* This function is used to return the next character code in the */ +/* current charmap of a given face following the value `char_code', */ +/* as well as the corresponding glyph index. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* char_code :: The starting character code. */ +/* */ +/* <Output> */ +/* agindex :: Glyph index of next character code. 0~if charmap */ +/* is empty. */ +/* */ +/* <Return> */ +/* The charmap's next character code. */ +/* */ +/* <Note> */ +/* You should use this function with @FT_Get_First_Char to walk */ +/* over all character codes available in a given charmap. See the */ +/* note for this function for a simple code example. */ +/* */ +/* Note that `*agindex' is set to~0 when there are no more codes in */ +/* the charmap. */ +/* */ + FT_EXPORT( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong char_code, + FT_UInt *agindex ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Name_Index */ +/* */ +/* <Description> */ +/* Return the glyph index of a given glyph name. This function uses */ +/* driver specific objects to do the translation. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* glyph_name :: The glyph name. */ +/* */ +/* <Return> */ +/* The glyph index. 0~means `undefined character code'. */ +/* */ + FT_EXPORT( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + FT_String* glyph_name ); +/************************************************************************* + * + * @macro: + * FT_SUBGLYPH_FLAG_XXX + * + * @description: + * A list of constants used to describe subglyphs. Please refer to the + * TrueType specification for the meaning of the various flags. + * + * @values: + * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: + * FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES :: + * FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID :: + * FT_SUBGLYPH_FLAG_SCALE :: + * FT_SUBGLYPH_FLAG_XY_SCALE :: + * FT_SUBGLYPH_FLAG_2X2 :: + * FT_SUBGLYPH_FLAG_USE_MY_METRICS :: + * + */ +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 +/************************************************************************* + * + * @func: + * FT_Get_SubGlyph_Info + * + * @description: + * Retrieve a description of a given subglyph. Only use it if + * `glyph->format' is @FT_GLYPH_FORMAT_COMPOSITE; an error is + * returned otherwise. + * + * @input: + * glyph :: + * The source glyph slot. + * + * sub_index :: + * The index of the subglyph. Must be less than + * `glyph->num_subglyphs'. + * + * @output: + * p_index :: + * The glyph index of the subglyph. + * + * p_flags :: + * The subglyph flags, see @FT_SUBGLYPH_FLAG_XXX. + * + * p_arg1 :: + * The subglyph's first argument (if any). + * + * p_arg2 :: + * The subglyph's second argument (if any). + * + * p_transform :: + * The subglyph transformation (if any). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The values of `*p_arg1', `*p_arg2', and `*p_transform' must be + * interpreted depending on the flags returned in `*p_flags'. See the + * TrueType specification for details. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_FSTYPE_XXX */ +/* */ +/* <Description> */ +/* A list of bit flags used in the `fsType' field of the OS/2 table */ +/* in a TrueType or OpenType font and the `FSType' entry in a */ +/* PostScript font. These bit flags are returned by */ +/* @FT_Get_FSType_Flags; they inform client applications of embedding */ +/* and subsetting restrictions associated with a font. */ +/* */ +/* See http://www.adobe.com/devnet/acrobat/pdfs/FontPolicies.pdf for */ +/* more details. */ +/* */ +/* <Values> */ +/* FT_FSTYPE_INSTALLABLE_EMBEDDING :: */ +/* Fonts with no fsType bit set may be embedded and permanently */ +/* installed on the remote system by an application. */ +/* */ +/* FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING :: */ +/* Fonts that have only this bit set must not be modified, embedded */ +/* or exchanged in any manner without first obtaining permission of */ +/* the font software copyright owner. */ +/* */ +/* FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING :: */ +/* If this bit is set, the font may be embedded and temporarily */ +/* loaded on the remote system. Documents containing Preview & */ +/* Print fonts must be opened `read-only'; no edits can be applied */ +/* to the document. */ +/* */ +/* FT_FSTYPE_EDITABLE_EMBEDDING :: */ +/* If this bit is set, the font may be embedded but must only be */ +/* installed temporarily on other systems. In contrast to Preview */ +/* & Print fonts, documents containing editable fonts may be opened */ +/* for reading, editing is permitted, and changes may be saved. */ +/* */ +/* FT_FSTYPE_NO_SUBSETTING :: */ +/* If this bit is set, the font may not be subsetted prior to */ +/* embedding. */ +/* */ +/* FT_FSTYPE_BITMAP_EMBEDDING_ONLY :: */ +/* If this bit is set, only bitmaps contained in the font may be */ +/* embedded; no outline data may be embedded. If there are no */ +/* bitmaps available in the font, then the font is unembeddable. */ +/* */ +/* <Note> */ +/* While the fsType flags can indicate that a font may be embedded, a */ +/* license with the font vendor may be separately required to use the */ +/* font in this way. */ +/* */ +#define FT_FSTYPE_INSTALLABLE_EMBEDDING 0x0000 +#define FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING 0x0002 +#define FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING 0x0004 +#define FT_FSTYPE_EDITABLE_EMBEDDING 0x0008 +#define FT_FSTYPE_NO_SUBSETTING 0x0100 +#define FT_FSTYPE_BITMAP_EMBEDDING_ONLY 0x0200 +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_FSType_Flags */ +/* */ +/* <Description> */ +/* Return the fsType flags for a font. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Return> */ +/* The fsType flags, @FT_FSTYPE_XXX. */ +/* */ +/* <Note> */ +/* Use this function rather than directly reading the `fs_type' field */ +/* in the @PS_FontInfoRec structure which is only guaranteed to */ +/* return the correct results for Type~1 fonts. */ +/* */ +/* <Since> */ +/* 2.3.8 */ +/* */ + FT_EXPORT( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Section> */ +/* glyph_variants */ +/* */ +/* <Title> */ +/* Glyph Variants */ +/* */ +/* <Abstract> */ +/* The FreeType~2 interface to Unicode Ideographic Variation */ +/* Sequences (IVS), using the SFNT cmap format~14. */ +/* */ +/* <Description> */ +/* Many CJK characters have variant forms. They are a sort of grey */ +/* area somewhere between being totally irrelevant and semantically */ +/* distinct; for this reason, the Unicode consortium decided to */ +/* introduce Ideographic Variation Sequences (IVS), consisting of a */ +/* Unicode base character and one of 240 variant selectors */ +/* (U+E0100-U+E01EF), instead of further extending the already huge */ +/* code range for CJK characters. */ +/* */ +/* An IVS is registered and unique; for further details please refer */ +/* to Unicode Technical Standard #37, the Ideographic Variation */ +/* Database: */ +/* */ +/* http://www.unicode.org/reports/tr37/ */ +/* */ +/* To date (November 2012), the character with the most variants is */ +/* U+9089, having 31 such IVS. */ +/* */ +/* Adobe and MS decided to support IVS with a new cmap subtable */ +/* (format~14). It is an odd subtable because it is not a mapping of */ +/* input code points to glyphs, but contains lists of all variants */ +/* supported by the font. */ +/* */ +/* A variant may be either `default' or `non-default'. A default */ +/* variant is the one you will get for that code point if you look it */ +/* up in the standard Unicode cmap. A non-default variant is a */ +/* different glyph. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_GetCharVariantIndex */ +/* */ +/* <Description> */ +/* Return the glyph index of a given character code as modified by */ +/* the variation selector. */ +/* */ +/* <Input> */ +/* face :: */ +/* A handle to the source face object. */ +/* */ +/* charcode :: */ +/* The character code point in Unicode. */ +/* */ +/* variantSelector :: */ +/* The Unicode code point of the variation selector. */ +/* */ +/* <Return> */ +/* The glyph index. 0~means either `undefined character code', or */ +/* `undefined selector code', or `no variation selector cmap */ +/* subtable', or `current CharMap is not Unicode'. */ +/* */ +/* <Note> */ +/* If you use FreeType to manipulate the contents of font files */ +/* directly, be aware that the glyph index returned by this function */ +/* doesn't always correspond to the internal indices used within */ +/* the file. This is done to ensure that value~0 always corresponds */ +/* to the `missing glyph'. */ +/* */ +/* This function is only meaningful if */ +/* a) the font has a variation selector cmap sub table, */ +/* and */ +/* b) the current charmap has a Unicode encoding. */ +/* */ +/* <Since> */ +/* 2.3.6 */ +/* */ + FT_EXPORT( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_GetCharVariantIsDefault */ +/* */ +/* <Description> */ +/* Check whether this variant of this Unicode character is the one to */ +/* be found in the `cmap'. */ +/* */ +/* <Input> */ +/* face :: */ +/* A handle to the source face object. */ +/* */ +/* charcode :: */ +/* The character codepoint in Unicode. */ +/* */ +/* variantSelector :: */ +/* The Unicode codepoint of the variation selector. */ +/* */ +/* <Return> */ +/* 1~if found in the standard (Unicode) cmap, 0~if found in the */ +/* variation selector cmap, or -1 if it is not a variant. */ +/* */ +/* <Note> */ +/* This function is only meaningful if the font has a variation */ +/* selector cmap subtable. */ +/* */ +/* <Since> */ +/* 2.3.6 */ +/* */ + FT_EXPORT( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_GetVariantSelectors */ +/* */ +/* <Description> */ +/* Return a zero-terminated list of Unicode variant selectors found */ +/* in the font. */ +/* */ +/* <Input> */ +/* face :: */ +/* A handle to the source face object. */ +/* */ +/* <Return> */ +/* A pointer to an array of selector code points, or NULL if there is */ +/* no valid variant selector cmap subtable. */ +/* */ +/* <Note> */ +/* The last item in the array is~0; the array is owned by the */ +/* @FT_Face object but can be overwritten or released on the next */ +/* call to a FreeType function. */ +/* */ +/* <Since> */ +/* 2.3.6 */ +/* */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_GetVariantsOfChar */ +/* */ +/* <Description> */ +/* Return a zero-terminated list of Unicode variant selectors found */ +/* for the specified character code. */ +/* */ +/* <Input> */ +/* face :: */ +/* A handle to the source face object. */ +/* */ +/* charcode :: */ +/* The character codepoint in Unicode. */ +/* */ +/* <Return> */ +/* A pointer to an array of variant selector code points which are */ +/* active for the given character, or NULL if the corresponding list */ +/* is empty. */ +/* */ +/* <Note> */ +/* The last item in the array is~0; the array is owned by the */ +/* @FT_Face object but can be overwritten or released on the next */ +/* call to a FreeType function. */ +/* */ +/* <Since> */ +/* 2.3.6 */ +/* */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_GetCharsOfVariant */ +/* */ +/* <Description> */ +/* Return a zero-terminated list of Unicode character codes found for */ +/* the specified variant selector. */ +/* */ +/* <Input> */ +/* face :: */ +/* A handle to the source face object. */ +/* */ +/* variantSelector :: */ +/* The variant selector code point in Unicode. */ +/* */ +/* <Return> */ +/* A list of all the code points which are specified by this selector */ +/* (both default and non-default codes are returned) or NULL if there */ +/* is no valid cmap or the variant selector is invalid. */ +/* */ +/* <Note> */ +/* The last item in the array is~0; the array is owned by the */ +/* @FT_Face object but can be overwritten or released on the next */ +/* call to a FreeType function. */ +/* */ +/* <Since> */ +/* 2.3.6 */ +/* */ + FT_EXPORT( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ); +/*************************************************************************/ +/* */ +/* <Section> */ +/* computations */ +/* */ +/* <Title> */ +/* Computations */ +/* */ +/* <Abstract> */ +/* Crunching fixed numbers and vectors. */ +/* */ +/* <Description> */ +/* This section contains various functions used to perform */ +/* computations on 16.16 fixed-float numbers or 2d vectors. */ +/* */ +/* <Order> */ +/* FT_MulDiv */ +/* FT_MulFix */ +/* FT_DivFix */ +/* FT_RoundFix */ +/* FT_CeilFix */ +/* FT_FloorFix */ +/* FT_Vector_Transform */ +/* FT_Matrix_Multiply */ +/* FT_Matrix_Invert */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_MulDiv */ +/* */ +/* <Description> */ +/* A very simple function used to perform the computation `(a*b)/c' */ +/* with maximum accuracy (it uses a 64-bit intermediate integer */ +/* whenever necessary). */ +/* */ +/* This function isn't necessarily as fast as some processor specific */ +/* operations, but is at least completely portable. */ +/* */ +/* <Input> */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. */ +/* c :: The divisor. */ +/* */ +/* <Return> */ +/* The result of `(a*b)/c'. This function never traps when trying to */ +/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ +/* on the signs of `a' and `b'. */ +/* */ + FT_EXPORT( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ); +/* */ +/* The following #if 0 ... #endif is for the documentation formatter, */ +/* hiding the internal `FT_MULFIX_INLINED' macro. */ +#if 0 +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_MulFix */ +/* */ +/* <Description> */ +/* A very simple function used to perform the computation */ +/* `(a*b)/0x10000' with maximum accuracy. Most of the time this is */ +/* used to multiply a given value by a 16.16 fixed float factor. */ +/* */ +/* <Input> */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. Use a 16.16 factor here whenever */ +/* possible (see note below). */ +/* */ +/* <Return> */ +/* The result of `(a*b)/0x10000'. */ +/* */ +/* <Note> */ +/* This function has been optimized for the case where the absolute */ +/* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ +/* As this happens mainly when scaling from notional units to */ +/* fractional pixels in FreeType, it resulted in noticeable speed */ +/* improvements between versions 2.x and 1.x. */ +/* */ +/* As a conclusion, always try to place a 16.16 factor as the */ +/* _second_ argument of this function; this can make a great */ +/* difference. */ +/* */ + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); +/* */ +#endif +#ifdef FT_MULFIX_INLINED +#define FT_MulFix( a, b ) FT_MULFIX_INLINED( a, b ) +#else + FT_EXPORT( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ); +#endif +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_DivFix */ +/* */ +/* <Description> */ +/* A very simple function used to perform the computation */ +/* `(a*0x10000)/b' with maximum accuracy. Most of the time, this is */ +/* used to divide a given value by a 16.16 fixed float factor. */ +/* */ +/* <Input> */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. Use a 16.16 factor here whenever */ +/* possible (see note below). */ +/* */ +/* <Return> */ +/* The result of `(a*0x10000)/b'. */ +/* */ +/* <Note> */ +/* The optimization for FT_DivFix() is simple: If (a~<<~16) fits in */ +/* 32~bits, then the division is computed directly. Otherwise, we */ +/* use a specialized version of @FT_MulDiv. */ +/* */ + FT_EXPORT( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_RoundFix */ +/* */ +/* <Description> */ +/* A very simple function used to round a 16.16 fixed number. */ +/* */ +/* <Input> */ +/* a :: The number to be rounded. */ +/* */ +/* <Return> */ +/* The result of `(a + 0x8000) & -0x10000'. */ +/* */ + FT_EXPORT( FT_Fixed ) + FT_RoundFix( FT_Fixed a ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_CeilFix */ +/* */ +/* <Description> */ +/* A very simple function used to compute the ceiling function of a */ +/* 16.16 fixed number. */ +/* */ +/* <Input> */ +/* a :: The number for which the ceiling function is to be computed. */ +/* */ +/* <Return> */ +/* The result of `(a + 0x10000 - 1) & -0x10000'. */ +/* */ + FT_EXPORT( FT_Fixed ) + FT_CeilFix( FT_Fixed a ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_FloorFix */ +/* */ +/* <Description> */ +/* A very simple function used to compute the floor function of a */ +/* 16.16 fixed number. */ +/* */ +/* <Input> */ +/* a :: The number for which the floor function is to be computed. */ +/* */ +/* <Return> */ +/* The result of `a & -0x10000'. */ +/* */ + FT_EXPORT( FT_Fixed ) + FT_FloorFix( FT_Fixed a ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Vector_Transform */ +/* */ +/* <Description> */ +/* Transform a single vector through a 2x2 matrix. */ +/* */ +/* <InOut> */ +/* vector :: The target vector to transform. */ +/* */ +/* <Input> */ +/* matrix :: A pointer to the source 2x2 matrix. */ +/* */ +/* <Note> */ +/* The result is undefined if either `vector' or `matrix' is invalid. */ +/* */ + FT_EXPORT( void ) + FT_Vector_Transform( FT_Vector* vec, + const FT_Matrix* matrix ); +/*************************************************************************/ +/* */ +/* <Section> */ +/* version */ +/* */ +/* <Title> */ +/* FreeType Version */ +/* */ +/* <Abstract> */ +/* Functions and macros related to FreeType versions. */ +/* */ +/* <Description> */ +/* Note that those functions and macros are of limited use because */ +/* even a new release of FreeType with only documentation changes */ +/* increases the version number. */ +/* */ +/*************************************************************************/ +/************************************************************************* + * + * @enum: + * FREETYPE_XXX + * + * @description: + * These three macros identify the FreeType source code version. + * Use @FT_Library_Version to access them at runtime. + * + * @values: + * FREETYPE_MAJOR :: The major version number. + * FREETYPE_MINOR :: The minor version number. + * FREETYPE_PATCH :: The patch level. + * + * @note: + * The version number of FreeType if built as a dynamic link library + * with the `libtool' package is _not_ controlled by these three + * macros. + * + */ +#define FREETYPE_MAJOR 2 +#define FREETYPE_MINOR 4 +#define FREETYPE_PATCH 11 +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Library_Version */ +/* */ +/* <Description> */ +/* Return the version of the FreeType library being used. This is */ +/* useful when dynamically linking to the library, since one cannot */ +/* use the macros @FREETYPE_MAJOR, @FREETYPE_MINOR, and */ +/* @FREETYPE_PATCH. */ +/* */ +/* <Input> */ +/* library :: A source library handle. */ +/* */ +/* <Output> */ +/* amajor :: The major version number. */ +/* */ +/* aminor :: The minor version number. */ +/* */ +/* apatch :: The patch version number. */ +/* */ +/* <Note> */ +/* The reason why this function takes a `library' argument is because */ +/* certain programs implement library initialization in a custom way */ +/* that doesn't use @FT_Init_FreeType. */ +/* */ +/* In such cases, the library version might not be available before */ +/* the library object has been created. */ +/* */ + FT_EXPORT( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_CheckTrueTypePatents */ +/* */ +/* <Description> */ +/* Parse all bytecode instructions of a TrueType font file to check */ +/* whether any of the patented opcodes are used. This is only useful */ +/* if you want to be able to use the unpatented hinter with */ +/* fonts that do *not* use these opcodes. */ +/* */ +/* Note that this function parses *all* glyph instructions in the */ +/* font file, which may be slow. */ +/* */ +/* <Input> */ +/* face :: A face handle. */ +/* */ +/* <Return> */ +/* 1~if this is a TrueType font that uses one of the patented */ +/* opcodes, 0~otherwise. */ +/* */ +/* <Note> */ +/* Since May 2010, TrueType hinting is no longer patented. */ +/* */ +/* <Since> */ +/* 2.3.5 */ +/* */ + FT_EXPORT( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Face_SetUnpatentedHinting */ +/* */ +/* <Description> */ +/* Enable or disable the unpatented hinter for a given face. */ +/* Only enable it if you have determined that the face doesn't */ +/* use any patented opcodes (see @FT_Face_CheckTrueTypePatents). */ +/* */ +/* <Input> */ +/* face :: A face handle. */ +/* */ +/* value :: New boolean setting. */ +/* */ +/* <Return> */ +/* The old setting value. This will always be false if this is not */ +/* an SFNT font, or if the unpatented hinter is not compiled in this */ +/* instance of the library. */ +/* */ +/* <Note> */ +/* Since May 2010, TrueType hinting is no longer patented. */ +/* */ +/* <Since> */ +/* 2.3.5 */ +/* */ + FT_EXPORT( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ +/* is already defined; this simplifies the following #ifdefs */ +/* */ +/*************************************************************************/ +/* */ +/* Define the trace enums as well as the trace levels array when they */ +/* are needed. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Define the FT_TRACE macro */ +/* */ +/* IMPORTANT! */ +/* */ +/* Each component must define the macro FT_COMPONENT to a valid FT_Trace */ +/* value before using any TRACE macro. */ +/* */ +/*************************************************************************/ +/* nothing */ +#define FT_TRACE( level, varformat ) do { } while ( 0 ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Trace_Get_Count */ +/* */ +/* <Description> */ +/* Return the number of available trace components. */ +/* */ +/* <Return> */ +/* The number of trace components. 0 if FreeType 2 is not built with */ +/* FT_DEBUG_LEVEL_TRACE definition. */ +/* */ +/* <Note> */ +/* This function may be useful if you want to access elements of */ +/* the internal `ft_trace_levels' array by an index. */ +/* */ + FT_BASE( FT_Int ) + FT_Trace_Get_Count( void ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Trace_Get_Name */ +/* */ +/* <Description> */ +/* Return the name of a trace component. */ +/* */ +/* <Input> */ +/* The index of the trace component. */ +/* */ +/* <Return> */ +/* The name of the trace component. This is a statically allocated */ +/* C string, so do not free it after use. NULL if FreeType 2 is not */ +/* built with FT_DEBUG_LEVEL_TRACE definition. */ +/* */ +/* <Note> */ +/* Use @FT_Trace_Get_Count to get the number of available trace */ +/* components. */ +/* */ +/* This function may be useful if you want to control FreeType 2's */ +/* debug level in your application. */ +/* */ + FT_BASE( const char * ) + FT_Trace_Get_Name( FT_Int idx ); +/*************************************************************************/ +/* */ +/* You need two opening and closing parentheses! */ +/* */ +/* Example: FT_TRACE0(( "Value is %i", foo )) */ +/* */ +/* Output of the FT_TRACEX macros is sent to stderr. */ +/* */ +/*************************************************************************/ +#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat ) +#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat ) +#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat ) +#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat ) +#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat ) +#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat ) +#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat ) +#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat ) +/*************************************************************************/ +/* */ +/* Define the FT_ERROR macro. */ +/* */ +/* Output of this macro is sent to stderr. */ +/* */ +/*************************************************************************/ +/* nothing */ +#define FT_ERROR( varformat ) do { } while ( 0 ) +/*************************************************************************/ +/* */ +/* Define the FT_ASSERT macro. */ +/* */ +/*************************************************************************/ +#define FT_ASSERT( condition ) do { } while ( 0 ) +/*************************************************************************/ +/* */ +/* Define `FT_Message' and `FT_Panic' when needed. */ +/* */ +/*************************************************************************/ + FT_BASE( void ) + ft_debug_init( void ); +/* Visual C++ (and Intel C++) */ +#if defined( _MSC_VER ) +/* We disable the warning `conditional expression is constant' here */ +/* in order to compile cleanly with the maximum level of warnings. */ +#pragma warning( disable : 4127 ) +/* _MSC_VER */ +#endif +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftstream.h */ +/* */ +/* Stream handling (specification). */ +/* */ +/* Copyright 1996-2002, 2004-2006, 2011 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. */ +/* */ +/***************************************************************************/ +#define __FTSTREAM_H__ +/***************************************************************************/ +/* */ +/* ftobjs.h */ +/* */ +/* The FreeType private base classes (specification). */ +/* */ +/* Copyright 1996-2006, 2008, 2010, 2012 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 contains the definition of all internal FreeType classes. */ +/* */ +/*************************************************************************/ +#define __FTOBJS_H__ +/***************************************************************************/ +/* */ +/* ftrender.h */ +/* */ +/* FreeType renderer modules public interface (specification). */ +/* */ +/* Copyright 1996-2001, 2005, 2006, 2010 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. */ +/* */ +/***************************************************************************/ +#define __FTRENDER_H__ +/***************************************************************************/ +/* */ +/* ftmodapi.h */ +/* */ +/* FreeType modules public interface (specification). */ +/* */ +/* Copyright 1996-2003, 2006, 2008-2010, 2012 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. */ +/* */ +/***************************************************************************/ +#define __FTMODAPI_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* module_management */ +/* */ +/* <Title> */ +/* Module Management */ +/* */ +/* <Abstract> */ +/* How to add, upgrade, remove, and control modules from FreeType. */ +/* */ +/* <Description> */ +/* The definitions below are used to manage modules within FreeType. */ +/* Modules can be added, upgraded, and removed at runtime. */ +/* Additionally, some module properties can be controlled also. */ +/* */ +/* Here is a list of possible values of the `module_name' field in */ +/* the @FT_Module_Class structure. */ +/* */ +/* { */ +/* autofitter */ +/* bdf */ +/* cff */ +/* gxvalid */ +/* otvalid */ +/* pcf */ +/* pfr */ +/* psaux */ +/* pshinter */ +/* psnames */ +/* raster1, raster5 */ +/* sfnt */ +/* smooth, smooth-lcd, smooth-lcdv */ +/* truetype */ +/* type1 */ +/* type42 */ +/* t1cid */ +/* winfonts */ +/* } */ +/* */ +/* Note that the FreeType Cache sub-system is not a FreeType module. */ +/* */ +/*************************************************************************/ +/* module bit flags */ +/* this module is a font driver */ +#define FT_MODULE_FONT_DRIVER 1 +/* this module is a renderer */ +#define FT_MODULE_RENDERER 2 +/* this module is a glyph hinter */ +#define FT_MODULE_HINTER 4 +/* this module is a styler */ +#define FT_MODULE_STYLER 8 +/* the driver supports */ +#define FT_MODULE_DRIVER_SCALABLE 0x100 +/* scalable fonts */ +/* the driver does not */ +#define FT_MODULE_DRIVER_NO_OUTLINES 0x200 +/* support vector outlines */ +/* the driver provides its */ +#define FT_MODULE_DRIVER_HAS_HINTER 0x400 +/* own hinter */ +/* deprecated values */ +#define ft_module_font_driver FT_MODULE_FONT_DRIVER +#define ft_module_renderer FT_MODULE_RENDERER +#define ft_module_hinter FT_MODULE_HINTER +#define ft_module_styler FT_MODULE_STYLER +#define ft_module_driver_scalable FT_MODULE_DRIVER_SCALABLE +#define ft_module_driver_no_outlines FT_MODULE_DRIVER_NO_OUTLINES +#define ft_module_driver_has_hinter FT_MODULE_DRIVER_HAS_HINTER + typedef FT_Pointer FT_Module_Interface; +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Module_Constructor */ +/* */ +/* <Description> */ +/* A function used to initialize (not create) a new module object. */ +/* */ +/* <Input> */ +/* module :: The module to initialize. */ +/* */ + typedef FT_Error + (*FT_Module_Constructor)( FT_Module module ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Module_Destructor */ +/* */ +/* <Description> */ +/* A function used to finalize (not destroy) a given module object. */ +/* */ +/* <Input> */ +/* module :: The module to finalize. */ +/* */ + typedef void + (*FT_Module_Destructor)( FT_Module module ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_Module_Requester */ +/* */ +/* <Description> */ +/* A function used to query a given module for a specific interface. */ +/* */ +/* <Input> */ +/* module :: The module to be searched. */ +/* */ +/* name :: The name of the interface in the module. */ +/* */ + typedef FT_Module_Interface + (*FT_Module_Requester)( FT_Module module, + const char* name ); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Module_Class */ +/* */ +/* <Description> */ +/* The module class descriptor. */ +/* */ +/* <Fields> */ +/* module_flags :: Bit flags describing the module. */ +/* */ +/* module_size :: The size of one module object/instance in */ +/* bytes. */ +/* */ +/* module_name :: The name of the module. */ +/* */ +/* module_version :: The version, as a 16.16 fixed number */ +/* (major.minor). */ +/* */ +/* module_requires :: The version of FreeType this module requires, */ +/* as a 16.16 fixed number (major.minor). Starts */ +/* at version 2.0, i.e., 0x20000. */ +/* */ +/* module_init :: The initializing function. */ +/* */ +/* module_done :: The finalizing function. */ +/* */ +/* get_interface :: The interface requesting function. */ +/* */ + typedef struct FT_Module_Class_ + { + FT_ULong module_flags; + FT_Long module_size; + const FT_String* module_name; + FT_Fixed module_version; + FT_Fixed module_requires; + const void* module_interface; + FT_Module_Constructor module_init; + FT_Module_Destructor module_done; + FT_Module_Requester get_interface; + } FT_Module_Class; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Add_Module */ +/* */ +/* <Description> */ +/* Add a new module to a given library instance. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library object. */ +/* */ +/* <Input> */ +/* clazz :: A pointer to class descriptor for the module. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* An error will be returned if a module already exists by that name, */ +/* or if the module requires a version of FreeType that is too great. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Module */ +/* */ +/* <Description> */ +/* Find a module by its name. */ +/* */ +/* <Input> */ +/* library :: A handle to the library object. */ +/* */ +/* module_name :: The module's name (as an ASCII string). */ +/* */ +/* <Return> */ +/* A module handle. 0~if none was found. */ +/* */ +/* <Note> */ +/* FreeType's internal modules aren't documented very well, and you */ +/* should look up the source code for details. */ +/* */ + FT_EXPORT( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Remove_Module */ +/* */ +/* <Description> */ +/* Remove a given module from a library instance. */ +/* */ +/* <InOut> */ +/* library :: A handle to a library object. */ +/* */ +/* <Input> */ +/* module :: A handle to a module object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The module object is destroyed by the function in case of success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ); +/********************************************************************** + * + * @function: + * FT_Property_Set + * + * @description: + * Set a property for a given module. + * + * @input: + * library :: + * A handle to the library the module is part of. + * + * module_name :: + * The module name. + * + * property_name :: + * The property name. Properties are described in the `Synopsis' + * subsection of the module's documentation. + * + * Note that only a few modules have properties. + * + * value :: + * A generic pointer to a variable or structure which gives the new + * value of the property. The exact definition of `value' is + * dependent on the property; see the `Synopsis' subsection of the + * module's documentation. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `module_name' isn't a valid module name, or `property_name' + * doesn't specify a valid property, or if `value' doesn't represent a + * valid value for the given property, an error is returned. + * + * The following example sets property `bar' (a simple integer) in + * module `foo' to value~1. + * + * { + * FT_UInt bar; + * + * + * bar = 1; + * FT_Property_Set( library, "foo", "bar", &bar ); + * } + * + * It is not possible to set properties of the FreeType Cache + * sub-system with FT_Property_Set; use @FTC_Property_Set instead. + * + * @since: + * 2.4.11 + * + */ + FT_Error + FT_Property_Set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ); +/********************************************************************** + * + * @function: + * FT_Property_Get + * + * @description: + * Get a module's property value. + * + * @input: + * library :: + * A handle to the library the module is part of. + * + * module_name :: + * The module name. + * + * property_name :: + * The property name. Properties are described in the `Synopsis' + * subsection of the module's documentation. + * + * @inout: + * value :: + * A generic pointer to a variable or structure which gives the + * value of the property. The exact definition of `value' is + * dependent on the property; see the `Synopsis' subsection of the + * module's documentation. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `module_name' isn't a valid module name, or `property_name' + * doesn't specify a valid property, or if `value' doesn't represent a + * valid value for the given property, an error is returned. + * + * The following example gets property `baz' (a range) in module `foo'. + * + * { + * typedef range_ + * { + * FT_Int32 min; + * FT_Int32 max; + * + * } range; + * + * range baz; + * + * + * FT_Property_Get( library, "foo", "baz", &baz ); + * } + * + * It is not possible to retrieve properties of the FreeType Cache + * sub-system with FT_Property_Get; use @FTC_Property_Get instead. + * + * @since: + * 2.4.11 + * + */ + FT_Error + FT_Property_Get( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Reference_Library */ +/* */ +/* <Description> */ +/* A counter gets initialized to~1 at the time an @FT_Library */ +/* structure is created. This function increments the counter. */ +/* @FT_Done_Library then only destroys a library if the counter is~1, */ +/* otherwise it simply decrements the counter. */ +/* */ +/* This function helps in managing life-cycles of structures which */ +/* reference @FT_Library objects. */ +/* */ +/* <Input> */ +/* library :: A handle to a target library object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Since> */ +/* 2.4.2 */ +/* */ + FT_EXPORT( FT_Error ) + FT_Reference_Library( FT_Library library ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Library */ +/* */ +/* <Description> */ +/* This function is used to create a new FreeType library instance */ +/* from a given memory object. It is thus possible to use libraries */ +/* with distinct memory allocators within the same program. */ +/* */ +/* Normally, you would call this function (followed by a call to */ +/* @FT_Add_Default_Modules or a series of calls to @FT_Add_Module) */ +/* instead of @FT_Init_FreeType to initialize the FreeType library. */ +/* */ +/* Don't use @FT_Done_FreeType but @FT_Done_Library to destroy a */ +/* library instance. */ +/* */ +/* <Input> */ +/* memory :: A handle to the original memory object. */ +/* */ +/* <Output> */ +/* alibrary :: A pointer to handle of a new library object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* See the discussion of reference counters in the description of */ +/* @FT_Reference_Library. */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_Library */ +/* */ +/* <Description> */ +/* Discard a given library object. This closes all drivers and */ +/* discards all resource objects. */ +/* */ +/* <Input> */ +/* library :: A handle to the target library. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* See the discussion of reference counters in the description of */ +/* @FT_Reference_Library. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Done_Library( FT_Library library ); +/* */ + typedef void + (*FT_DebugHook_Func)( void* arg ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Debug_Hook */ +/* */ +/* <Description> */ +/* Set a debug hook function for debugging the interpreter of a font */ +/* format. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library object. */ +/* */ +/* <Input> */ +/* hook_index :: The index of the debug hook. You should use the */ +/* values defined in `ftobjs.h', e.g., */ +/* `FT_DEBUG_HOOK_TRUETYPE'. */ +/* */ +/* debug_hook :: The function used to debug the interpreter. */ +/* */ +/* <Note> */ +/* Currently, four debug hook slots are available, but only two (for */ +/* the TrueType and the Type~1 interpreter) are defined. */ +/* */ +/* Since the internal headers of FreeType are no longer installed, */ +/* the symbol `FT_DEBUG_HOOK_TRUETYPE' isn't available publicly. */ +/* This is a bug and will be fixed in a forthcoming release. */ +/* */ + FT_EXPORT( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Add_Default_Modules */ +/* */ +/* <Description> */ +/* Add the set of default drivers to a given library object. */ +/* This is only useful when you create a library object with */ +/* @FT_New_Library (usually to plug a custom memory manager). */ +/* */ +/* <InOut> */ +/* library :: A handle to a new library object. */ +/* */ + FT_EXPORT( void ) + FT_Add_Default_Modules( FT_Library library ); +/************************************************************************** + * + * @section: + * truetype_engine + * + * @title: + * The TrueType Engine + * + * @abstract: + * TrueType bytecode support. + * + * @description: + * This section contains a function used to query the level of TrueType + * bytecode support compiled in this version of the library. + * + */ +/************************************************************************** + * + * @enum: + * FT_TrueTypeEngineType + * + * @description: + * A list of values describing which kind of TrueType bytecode + * engine is implemented in a given FT_Library instance. It is used + * by the @FT_Get_TrueType_Engine_Type function. + * + * @values: + * FT_TRUETYPE_ENGINE_TYPE_NONE :: + * The library doesn't implement any kind of bytecode interpreter. + * + * FT_TRUETYPE_ENGINE_TYPE_UNPATENTED :: + * The library implements a bytecode interpreter that doesn't + * support the patented operations of the TrueType virtual machine. + * + * Its main use is to load certain Asian fonts which position and + * scale glyph components with bytecode instructions. It produces + * bad output for most other fonts. + * + * FT_TRUETYPE_ENGINE_TYPE_PATENTED :: + * The library implements a bytecode interpreter that covers + * the full instruction set of the TrueType virtual machine (this + * was governed by patents until May 2010, hence the name). + * + * @since: + * 2.2 + * + */ + typedef enum FT_TrueTypeEngineType_ + { + FT_TRUETYPE_ENGINE_TYPE_NONE = 0, + FT_TRUETYPE_ENGINE_TYPE_UNPATENTED, + FT_TRUETYPE_ENGINE_TYPE_PATENTED + } FT_TrueTypeEngineType; +/************************************************************************** + * + * @func: + * FT_Get_TrueType_Engine_Type + * + * @description: + * Return an @FT_TrueTypeEngineType value to indicate which level of + * the TrueType virtual machine a given library instance supports. + * + * @input: + * library :: + * A library instance. + * + * @return: + * A value indicating which level is supported. + * + * @since: + * 2.2 + * + */ + FT_EXPORT( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftglyph.h */ +/* */ +/* FreeType convenience functions to handle glyphs (specification). */ +/* */ +/* Copyright 1996-2003, 2006, 2008, 2009, 2011 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 contains the definition of several convenience functions */ +/* that can be used by client applications to easily retrieve glyph */ +/* bitmaps and outlines from a given face. */ +/* */ +/* These functions should be optional if you are writing a font server */ +/* or text layout engine on top of FreeType. However, they are pretty */ +/* handy for many other simple uses of the library. */ +/* */ +/*************************************************************************/ +#define __FTGLYPH_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* glyph_management */ +/* */ +/* <Title> */ +/* Glyph Management */ +/* */ +/* <Abstract> */ +/* Generic interface to manage individual glyph data. */ +/* */ +/* <Description> */ +/* This section contains definitions used to manage glyph data */ +/* through generic FT_Glyph objects. Each of them can contain a */ +/* bitmap, a vector outline, or even images in other formats. */ +/* */ +/*************************************************************************/ +/* forward declaration to a private type */ + typedef struct FT_Glyph_Class_ FT_Glyph_Class; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_Glyph */ +/* */ +/* <Description> */ +/* Handle to an object used to model generic glyph images. It is a */ +/* pointer to the @FT_GlyphRec structure and can contain a glyph */ +/* bitmap or pointer. */ +/* */ +/* <Note> */ +/* Glyph objects are not owned by the library. You must thus release */ +/* them manually (through @FT_Done_Glyph) _before_ calling */ +/* @FT_Done_FreeType. */ +/* */ + typedef struct FT_GlyphRec_* FT_Glyph; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_GlyphRec */ +/* */ +/* <Description> */ +/* The root glyph structure contains a given glyph image plus its */ +/* advance width in 16.16 fixed float format. */ +/* */ +/* <Fields> */ +/* library :: A handle to the FreeType library object. */ +/* */ +/* clazz :: A pointer to the glyph's class. Private. */ +/* */ +/* format :: The format of the glyph's image. */ +/* */ +/* advance :: A 16.16 vector that gives the glyph's advance width. */ +/* */ + typedef struct FT_GlyphRec_ + { + FT_Library library; + const FT_Glyph_Class* clazz; + FT_Glyph_Format format; + FT_Vector advance; + } FT_GlyphRec; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_BitmapGlyph */ +/* */ +/* <Description> */ +/* A handle to an object used to model a bitmap glyph image. This is */ +/* a sub-class of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */ +/* */ + typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_BitmapGlyphRec */ +/* */ +/* <Description> */ +/* A structure used for bitmap glyph images. This really is a */ +/* `sub-class' of @FT_GlyphRec. */ +/* */ +/* <Fields> */ +/* root :: The root @FT_Glyph fields. */ +/* */ +/* left :: The left-side bearing, i.e., the horizontal distance */ +/* from the current pen position to the left border of the */ +/* glyph bitmap. */ +/* */ +/* top :: The top-side bearing, i.e., the vertical distance from */ +/* the current pen position to the top border of the glyph */ +/* bitmap. This distance is positive for upwards~y! */ +/* */ +/* bitmap :: A descriptor for the bitmap. */ +/* */ +/* <Note> */ +/* You can typecast an @FT_Glyph to @FT_BitmapGlyph if you have */ +/* `glyph->format == FT_GLYPH_FORMAT_BITMAP'. This lets you access */ +/* the bitmap's contents easily. */ +/* */ +/* The corresponding pixel buffer is always owned by @FT_BitmapGlyph */ +/* and is thus created and destroyed with it. */ +/* */ + typedef struct FT_BitmapGlyphRec_ + { + FT_GlyphRec root; + FT_Int left; + FT_Int top; + FT_Bitmap bitmap; + } FT_BitmapGlyphRec; +/*************************************************************************/ +/* */ +/* <Type> */ +/* FT_OutlineGlyph */ +/* */ +/* <Description> */ +/* A handle to an object used to model an outline glyph image. This */ +/* is a sub-class of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */ +/* */ + typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_OutlineGlyphRec */ +/* */ +/* <Description> */ +/* A structure used for outline (vectorial) glyph images. This */ +/* really is a `sub-class' of @FT_GlyphRec. */ +/* */ +/* <Fields> */ +/* root :: The root @FT_Glyph fields. */ +/* */ +/* outline :: A descriptor for the outline. */ +/* */ +/* <Note> */ +/* You can typecast an @FT_Glyph to @FT_OutlineGlyph if you have */ +/* `glyph->format == FT_GLYPH_FORMAT_OUTLINE'. This lets you access */ +/* the outline's content easily. */ +/* */ +/* As the outline is extracted from a glyph slot, its coordinates are */ +/* expressed normally in 26.6 pixels, unless the flag */ +/* @FT_LOAD_NO_SCALE was used in @FT_Load_Glyph() or @FT_Load_Char(). */ +/* */ +/* The outline's tables are always owned by the object and are */ +/* destroyed with it. */ +/* */ + typedef struct FT_OutlineGlyphRec_ + { + FT_GlyphRec root; + FT_Outline outline; + } FT_OutlineGlyphRec; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Glyph */ +/* */ +/* <Description> */ +/* A function used to extract a glyph image from a slot. Note that */ +/* the created @FT_Glyph object must be released with @FT_Done_Glyph. */ +/* */ +/* <Input> */ +/* slot :: A handle to the source glyph slot. */ +/* */ +/* <Output> */ +/* aglyph :: A handle to the glyph object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Glyph_Copy */ +/* */ +/* <Description> */ +/* A function used to copy a glyph image. Note that the created */ +/* @FT_Glyph object must be released with @FT_Done_Glyph. */ +/* */ +/* <Input> */ +/* source :: A handle to the source glyph object. */ +/* */ +/* <Output> */ +/* target :: A handle to the target glyph object. 0~in case of */ +/* error. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Glyph_Transform */ +/* */ +/* <Description> */ +/* Transform a glyph image if its format is scalable. */ +/* */ +/* <InOut> */ +/* glyph :: A handle to the target glyph object. */ +/* */ +/* <Input> */ +/* matrix :: A pointer to a 2x2 matrix to apply. */ +/* */ +/* delta :: A pointer to a 2d vector to apply. Coordinates are */ +/* expressed in 1/64th of a pixel. */ +/* */ +/* <Return> */ +/* FreeType error code (if not 0, the glyph format is not scalable). */ +/* */ +/* <Note> */ +/* The 2x2 transformation matrix is also applied to the glyph's */ +/* advance vector. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Glyph_BBox_Mode */ +/* */ +/* <Description> */ +/* The mode how the values of @FT_Glyph_Get_CBox are returned. */ +/* */ +/* <Values> */ +/* FT_GLYPH_BBOX_UNSCALED :: */ +/* Return unscaled font units. */ +/* */ +/* FT_GLYPH_BBOX_SUBPIXELS :: */ +/* Return unfitted 26.6 coordinates. */ +/* */ +/* FT_GLYPH_BBOX_GRIDFIT :: */ +/* Return grid-fitted 26.6 coordinates. */ +/* */ +/* FT_GLYPH_BBOX_TRUNCATE :: */ +/* Return coordinates in integer pixels. */ +/* */ +/* FT_GLYPH_BBOX_PIXELS :: */ +/* Return grid-fitted pixel coordinates. */ +/* */ + typedef enum FT_Glyph_BBox_Mode_ + { + FT_GLYPH_BBOX_UNSCALED = 0, + FT_GLYPH_BBOX_SUBPIXELS = 0, + FT_GLYPH_BBOX_GRIDFIT = 1, + FT_GLYPH_BBOX_TRUNCATE = 2, + FT_GLYPH_BBOX_PIXELS = 3 + } FT_Glyph_BBox_Mode; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* ft_glyph_bbox_xxx */ +/* */ +/* <Description> */ +/* These constants are deprecated. Use the corresponding */ +/* @FT_Glyph_BBox_Mode values instead. */ +/* */ +/* <Values> */ +/* ft_glyph_bbox_unscaled :: See @FT_GLYPH_BBOX_UNSCALED. */ +/* ft_glyph_bbox_subpixels :: See @FT_GLYPH_BBOX_SUBPIXELS. */ +/* ft_glyph_bbox_gridfit :: See @FT_GLYPH_BBOX_GRIDFIT. */ +/* ft_glyph_bbox_truncate :: See @FT_GLYPH_BBOX_TRUNCATE. */ +/* ft_glyph_bbox_pixels :: See @FT_GLYPH_BBOX_PIXELS. */ +/* */ +#define ft_glyph_bbox_unscaled FT_GLYPH_BBOX_UNSCALED +#define ft_glyph_bbox_subpixels FT_GLYPH_BBOX_SUBPIXELS +#define ft_glyph_bbox_gridfit FT_GLYPH_BBOX_GRIDFIT +#define ft_glyph_bbox_truncate FT_GLYPH_BBOX_TRUNCATE +#define ft_glyph_bbox_pixels FT_GLYPH_BBOX_PIXELS +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Glyph_Get_CBox */ +/* */ +/* <Description> */ +/* Return a glyph's `control box'. The control box encloses all the */ +/* outline's points, including Bézier control points. Though it */ +/* coincides with the exact bounding box for most glyphs, it can be */ +/* slightly larger in some situations (like when rotating an outline */ +/* which contains Bézier outside arcs). */ +/* */ +/* Computing the control box is very fast, while getting the bounding */ +/* box can take much more time as it needs to walk over all segments */ +/* and arcs in the outline. To get the latter, you can use the */ +/* `ftbbox' component which is dedicated to this single task. */ +/* */ +/* <Input> */ +/* glyph :: A handle to the source glyph object. */ +/* */ +/* mode :: The mode which indicates how to interpret the returned */ +/* bounding box values. */ +/* */ +/* <Output> */ +/* acbox :: The glyph coordinate bounding box. Coordinates are */ +/* expressed in 1/64th of pixels if it is grid-fitted. */ +/* */ +/* <Note> */ +/* Coordinates are relative to the glyph origin, using the y~upwards */ +/* convention. */ +/* */ +/* If the glyph has been loaded with @FT_LOAD_NO_SCALE, `bbox_mode' */ +/* must be set to @FT_GLYPH_BBOX_UNSCALED to get unscaled font */ +/* units in 26.6 pixel format. The value @FT_GLYPH_BBOX_SUBPIXELS */ +/* is another name for this constant. */ +/* */ +/* If the font is tricky and the glyph has been loaded with */ +/* @FT_LOAD_NO_SCALE, the resulting CBox is meaningless. To get */ +/* reasonable values for the CBox it is necessary to load the glyph */ +/* at a large ppem value (so that the hinting instructions can */ +/* properly shift and scale the subglyphs), then extracting the CBox */ +/* which can be eventually converted back to font units. */ +/* */ +/* Note that the maximum coordinates are exclusive, which means that */ +/* one can compute the width and height of the glyph image (be it in */ +/* integer or 26.6 pixels) as: */ +/* */ +/* { */ +/* width = bbox.xMax - bbox.xMin; */ +/* height = bbox.yMax - bbox.yMin; */ +/* } */ +/* */ +/* Note also that for 26.6 coordinates, if `bbox_mode' is set to */ +/* @FT_GLYPH_BBOX_GRIDFIT, the coordinates will also be grid-fitted, */ +/* which corresponds to: */ +/* */ +/* { */ +/* bbox.xMin = FLOOR(bbox.xMin); */ +/* bbox.yMin = FLOOR(bbox.yMin); */ +/* bbox.xMax = CEILING(bbox.xMax); */ +/* bbox.yMax = CEILING(bbox.yMax); */ +/* } */ +/* */ +/* To get the bbox in pixel coordinates, set `bbox_mode' to */ +/* @FT_GLYPH_BBOX_TRUNCATE. */ +/* */ +/* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' */ +/* to @FT_GLYPH_BBOX_PIXELS. */ +/* */ + FT_EXPORT( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Glyph_To_Bitmap */ +/* */ +/* <Description> */ +/* Convert a given glyph object to a bitmap glyph object. */ +/* */ +/* <InOut> */ +/* the_glyph :: A pointer to a handle to the target glyph. */ +/* */ +/* <Input> */ +/* render_mode :: An enumeration that describes how the data is */ +/* rendered. */ +/* */ +/* origin :: A pointer to a vector used to translate the glyph */ +/* image before rendering. Can be~0 (if no */ +/* translation). The origin is expressed in */ +/* 26.6 pixels. */ +/* */ +/* destroy :: A boolean that indicates that the original glyph */ +/* image should be destroyed by this function. It is */ +/* never destroyed in case of error. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* This function does nothing if the glyph format isn't scalable. */ +/* */ +/* The glyph image is translated with the `origin' vector before */ +/* rendering. */ +/* */ +/* The first parameter is a pointer to an @FT_Glyph handle, that will */ +/* be _replaced_ by this function (with newly allocated data). */ +/* Typically, you would use (omitting error handling): */ +/* */ +/* */ +/* { */ +/* FT_Glyph glyph; */ +/* FT_BitmapGlyph glyph_bitmap; */ +/* */ +/* */ +/* // load glyph */ +/* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */ +/* */ +/* // extract glyph image */ +/* error = FT_Get_Glyph( face->glyph, &glyph ); */ +/* */ +/* // convert to a bitmap (default render mode + destroying old) */ +/* if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) */ +/* { */ +/* error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, */ +/* 0, 1 ); */ +/* if ( error ) // `glyph' unchanged */ +/* ... */ +/* } */ +/* */ +/* // access bitmap content by typecasting */ +/* glyph_bitmap = (FT_BitmapGlyph)glyph; */ +/* */ +/* // do funny stuff with it, like blitting/drawing */ +/* ... */ +/* */ +/* // discard glyph image (bitmap or not) */ +/* FT_Done_Glyph( glyph ); */ +/* } */ +/* */ +/* */ +/* Here another example, again without error handling: */ +/* */ +/* */ +/* { */ +/* FT_Glyph glyphs[MAX_GLYPHS] */ +/* */ +/* */ +/* ... */ +/* */ +/* for ( idx = 0; i < MAX_GLYPHS; i++ ) */ +/* error = FT_Load_Glyph( face, idx, FT_LOAD_DEFAULT ) || */ +/* FT_Get_Glyph ( face->glyph, &glyph[idx] ); */ +/* */ +/* ... */ +/* */ +/* for ( idx = 0; i < MAX_GLYPHS; i++ ) */ +/* { */ +/* FT_Glyph bitmap = glyphs[idx]; */ +/* */ +/* */ +/* ... */ +/* */ +/* // after this call, `bitmap' no longer points into */ +/* // the `glyphs' array (and the old value isn't destroyed) */ +/* FT_Glyph_To_Bitmap( &bitmap, FT_RENDER_MODE_MONO, 0, 0 ); */ +/* */ +/* ... */ +/* */ +/* FT_Done_Glyph( bitmap ); */ +/* } */ +/* */ +/* ... */ +/* */ +/* for ( idx = 0; i < MAX_GLYPHS; i++ ) */ +/* FT_Done_Glyph( glyphs[idx] ); */ +/* } */ +/* */ + FT_EXPORT( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + FT_Vector* origin, + FT_Bool destroy ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_Glyph */ +/* */ +/* <Description> */ +/* Destroy a given glyph. */ +/* */ +/* <Input> */ +/* glyph :: A handle to the target glyph object. */ +/* */ + FT_EXPORT( void ) + FT_Done_Glyph( FT_Glyph glyph ); +/* */ +/* other helpful functions */ +/*************************************************************************/ +/* */ +/* <Section> */ +/* computations */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Matrix_Multiply */ +/* */ +/* <Description> */ +/* Perform the matrix operation `b = a*b'. */ +/* */ +/* <Input> */ +/* a :: A pointer to matrix `a'. */ +/* */ +/* <InOut> */ +/* b :: A pointer to matrix `b'. */ +/* */ +/* <Note> */ +/* The result is undefined if either `a' or `b' is zero. */ +/* */ + FT_EXPORT( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix* b ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Matrix_Invert */ +/* */ +/* <Description> */ +/* Invert a 2x2 matrix. Return an error if it can't be inverted. */ +/* */ +/* <InOut> */ +/* matrix :: A pointer to the target matrix. Remains untouched in */ +/* case of error. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ); +/* */ +FT_END_HEADER +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* module_management */ +/* */ +/*************************************************************************/ +/* create a new glyph object */ + typedef FT_Error + (*FT_Glyph_InitFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); +/* destroys a given glyph object */ + typedef void + (*FT_Glyph_DoneFunc)( FT_Glyph glyph ); + typedef void + (*FT_Glyph_TransformFunc)( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); + typedef void + (*FT_Glyph_GetBBoxFunc)( FT_Glyph glyph, + FT_BBox* abbox ); + typedef FT_Error + (*FT_Glyph_CopyFunc)( FT_Glyph source, + FT_Glyph target ); + typedef FT_Error + (*FT_Glyph_PrepareFunc)( FT_Glyph glyph, + FT_GlyphSlot slot ); +/* deprecated */ +#define FT_Glyph_Init_Func FT_Glyph_InitFunc +#define FT_Glyph_Done_Func FT_Glyph_DoneFunc +#define FT_Glyph_Transform_Func FT_Glyph_TransformFunc +#define FT_Glyph_BBox_Func FT_Glyph_GetBBoxFunc +#define FT_Glyph_Copy_Func FT_Glyph_CopyFunc +#define FT_Glyph_Prepare_Func FT_Glyph_PrepareFunc + struct FT_Glyph_Class_ + { + FT_Long glyph_size; + FT_Glyph_Format glyph_format; + FT_Glyph_InitFunc glyph_init; + FT_Glyph_DoneFunc glyph_done; + FT_Glyph_CopyFunc glyph_copy; + FT_Glyph_TransformFunc glyph_transform; + FT_Glyph_GetBBoxFunc glyph_bbox; + FT_Glyph_PrepareFunc glyph_prepare; + }; + typedef FT_Error + (*FT_Renderer_RenderFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_UInt mode, + const FT_Vector* origin ); + typedef FT_Error + (*FT_Renderer_TransformFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ); + typedef void + (*FT_Renderer_GetCBoxFunc)( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_BBox* cbox ); + typedef FT_Error + (*FT_Renderer_SetModeFunc)( FT_Renderer renderer, + FT_ULong mode_tag, + FT_Pointer mode_ptr ); +/* deprecated identifiers */ +#define FTRenderer_render FT_Renderer_RenderFunc +#define FTRenderer_transform FT_Renderer_TransformFunc +#define FTRenderer_getCBox FT_Renderer_GetCBoxFunc +#define FTRenderer_setMode FT_Renderer_SetModeFunc +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Renderer_Class */ +/* */ +/* <Description> */ +/* The renderer module class descriptor. */ +/* */ +/* <Fields> */ +/* root :: The root @FT_Module_Class fields. */ +/* */ +/* glyph_format :: The glyph image format this renderer handles. */ +/* */ +/* render_glyph :: A method used to render the image that is in a */ +/* given glyph slot into a bitmap. */ +/* */ +/* transform_glyph :: A method used to transform the image that is in */ +/* a given glyph slot. */ +/* */ +/* get_glyph_cbox :: A method used to access the glyph's cbox. */ +/* */ +/* set_mode :: A method used to pass additional parameters. */ +/* */ +/* raster_class :: For @FT_GLYPH_FORMAT_OUTLINE renderers only. */ +/* This is a pointer to its raster's class. */ +/* */ + typedef struct FT_Renderer_Class_ + { + FT_Module_Class root; + FT_Glyph_Format glyph_format; + FT_Renderer_RenderFunc render_glyph; + FT_Renderer_TransformFunc transform_glyph; + FT_Renderer_GetCBoxFunc get_glyph_cbox; + FT_Renderer_SetModeFunc set_mode; + FT_Raster_Funcs* raster_class; + } FT_Renderer_Class; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Renderer */ +/* */ +/* <Description> */ +/* Retrieve the current renderer for a given glyph format. */ +/* */ +/* <Input> */ +/* library :: A handle to the library object. */ +/* */ +/* format :: The glyph format. */ +/* */ +/* <Return> */ +/* A renderer handle. 0~if none found. */ +/* */ +/* <Note> */ +/* An error will be returned if a module already exists by that name, */ +/* or if the module requires a version of FreeType that is too great. */ +/* */ +/* To add a new renderer, simply use @FT_Add_Module. To retrieve a */ +/* renderer by its name, use @FT_Get_Module. */ +/* */ + FT_EXPORT( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Renderer */ +/* */ +/* <Description> */ +/* Set the current renderer to use, and set additional mode. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library object. */ +/* */ +/* <Input> */ +/* renderer :: A handle to the renderer object. */ +/* */ +/* num_params :: The number of additional parameters. */ +/* */ +/* parameters :: Additional parameters. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* In case of success, the renderer will be used to convert glyph */ +/* images in the renderer's known format into bitmaps. */ +/* */ +/* This doesn't change the current renderer for other formats. */ +/* */ +/* Currently, only the B/W renderer, if compiled with */ +/* FT_RASTER_OPTION_ANTI_ALIASING (providing a 5-levels */ +/* anti-aliasing mode; this option must be set directly in */ +/* `ftraster.c' and is undefined by default) accepts a single tag */ +/* `pal5' to set its gray palette as a character string with */ +/* 5~elements. Consequently, the third and fourth argument are zero */ +/* normally. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftsizes.h */ +/* */ +/* FreeType size objects management (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2006, 2009 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* Typical application would normally not need to use these functions. */ +/* However, they have been placed in a public API for the rare cases */ +/* where they are needed. */ +/* */ +/*************************************************************************/ +#define __FTSIZES_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* sizes_management */ +/* */ +/* <Title> */ +/* Size Management */ +/* */ +/* <Abstract> */ +/* Managing multiple sizes per face. */ +/* */ +/* <Description> */ +/* When creating a new face object (e.g., with @FT_New_Face), an */ +/* @FT_Size object is automatically created and used to store all */ +/* pixel-size dependent information, available in the `face->size' */ +/* field. */ +/* */ +/* It is however possible to create more sizes for a given face, */ +/* mostly in order to manage several character pixel sizes of the */ +/* same font family and style. See @FT_New_Size and @FT_Done_Size. */ +/* */ +/* Note that @FT_Set_Pixel_Sizes and @FT_Set_Char_Size only */ +/* modify the contents of the current `active' size; you thus need */ +/* to use @FT_Activate_Size to change it. */ +/* */ +/* 99% of applications won't need the functions provided here, */ +/* especially if they use the caching sub-system, so be cautious */ +/* when using these. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Size */ +/* */ +/* <Description> */ +/* Create a new size object from a given face object. */ +/* */ +/* <Input> */ +/* face :: A handle to a parent face object. */ +/* */ +/* <Output> */ +/* asize :: A handle to a new size object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* You need to call @FT_Activate_Size in order to select the new size */ +/* for upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, */ +/* @FT_Load_Glyph, @FT_Load_Char, etc. */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size* size ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_Size */ +/* */ +/* <Description> */ +/* Discard a given size object. Note that @FT_Done_Face */ +/* automatically discards all size objects allocated with */ +/* @FT_New_Size. */ +/* */ +/* <Input> */ +/* size :: A handle to a target size object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Done_Size( FT_Size size ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Activate_Size */ +/* */ +/* <Description> */ +/* Even though it is possible to create several size objects for a */ +/* given face (see @FT_New_Size for details), functions like */ +/* @FT_Load_Glyph or @FT_Load_Char only use the one which has been */ +/* activated last to determine the `current character pixel size'. */ +/* */ +/* This function can be used to `activate' a previously created size */ +/* object. */ +/* */ +/* <Input> */ +/* size :: A handle to a target size object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* If `face' is the size's parent face object, this function changes */ +/* the value of `face->size' to the input size handle. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Activate_Size( FT_Size size ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftlcdfil.h */ +/* */ +/* FreeType API for color filtering of subpixel bitmap glyphs */ +/* (specification). */ +/* */ +/* Copyright 2006, 2007, 2008, 2010 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 __FT_LCD_FILTER_H__ +#define __FT_LCD_FILTER_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 +FT_BEGIN_HEADER +/*************************************************************************** + * + * @section: + * lcd_filtering + * + * @title: + * LCD Filtering + * + * @abstract: + * Reduce color fringes of LCD-optimized bitmaps. + * + * @description: + * The @FT_Library_SetLcdFilter API can be used to specify a low-pass + * filter which is then applied to LCD-optimized bitmaps generated + * through @FT_Render_Glyph. This is useful to reduce color fringes + * which would occur with unfiltered rendering. + * + * Note that no filter is active by default, and that this function is + * *not* implemented in default builds of the library. You need to + * #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING in your `ftoption.h' file + * in order to activate it. + */ +/**************************************************************************** + * + * @enum: + * FT_LcdFilter + * + * @description: + * A list of values to identify various types of LCD filters. + * + * @values: + * FT_LCD_FILTER_NONE :: + * Do not perform filtering. When used with subpixel rendering, this + * results in sometimes severe color fringes. + * + * FT_LCD_FILTER_DEFAULT :: + * The default filter reduces color fringes considerably, at the cost + * of a slight blurriness in the output. + * + * FT_LCD_FILTER_LIGHT :: + * The light filter is a variant that produces less blurriness at the + * cost of slightly more color fringes than the default one. It might + * be better, depending on taste, your monitor, or your personal vision. + * + * FT_LCD_FILTER_LEGACY :: + * This filter corresponds to the original libXft color filter. It + * provides high contrast output but can exhibit really bad color + * fringes if glyphs are not extremely well hinted to the pixel grid. + * In other words, it only works well if the TrueType bytecode + * interpreter is enabled *and* high-quality hinted fonts are used. + * + * This filter is only provided for comparison purposes, and might be + * disabled or stay unsupported in the future. + * + * @since: + * 2.3.0 + */ + typedef enum FT_LcdFilter_ + { + FT_LCD_FILTER_NONE = 0, + FT_LCD_FILTER_DEFAULT = 1, + FT_LCD_FILTER_LIGHT = 2, + FT_LCD_FILTER_LEGACY = 16, +/* do not remove */ + FT_LCD_FILTER_MAX + } FT_LcdFilter; +/************************************************************************** + * + * @func: + * FT_Library_SetLcdFilter + * + * @description: + * This function is used to apply color filtering to LCD decimated + * bitmaps, like the ones used when calling @FT_Render_Glyph with + * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. + * + * @input: + * library :: + * A handle to the target library instance. + * + * filter :: + * The filter type. + * + * You can use @FT_LCD_FILTER_NONE here to disable this feature, or + * @FT_LCD_FILTER_DEFAULT to use a default filter that should work + * well on most LCD screens. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This feature is always disabled by default. Clients must make an + * explicit call to this function with a `filter' value other than + * @FT_LCD_FILTER_NONE in order to enable it. + * + * Due to *PATENTS* covering subpixel rendering, this function doesn't + * do anything except returning `FT_Err_Unimplemented_Feature' if the + * configuration macro FT_CONFIG_OPTION_SUBPIXEL_RENDERING is not + * defined in your build of the library, which should correspond to all + * default builds of FreeType. + * + * The filter affects glyph bitmaps rendered through @FT_Render_Glyph, + * @FT_Outline_Get_Bitmap, @FT_Load_Glyph, and @FT_Load_Char. + * + * It does _not_ affect the output of @FT_Outline_Render and + * @FT_Outline_Get_Bitmap. + * + * If this feature is activated, the dimensions of LCD glyph bitmaps are + * either larger or taller than the dimensions of the corresponding + * outline with regards to the pixel grid. For example, for + * @FT_RENDER_MODE_LCD, the filter adds up to 3~pixels to the left, and + * up to 3~pixels to the right. + * + * The bitmap offset values are adjusted correctly, so clients shouldn't + * need to modify their layout and glyph positioning code when enabling + * the filter. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ); +/************************************************************************** + * + * @func: + * FT_Library_SetLcdFilterWeights + * + * @description: + * Use this function to override the filter weights selected by + * @FT_Library_SetLcdFilter. By default, FreeType uses the quintuple + * (0x00, 0x55, 0x56, 0x55, 0x00) for FT_LCD_FILTER_LIGHT, and (0x10, + * 0x40, 0x70, 0x40, 0x10) for FT_LCD_FILTER_DEFAULT and + * FT_LCD_FILTER_LEGACY. + * + * @input: + * library :: + * A handle to the target library instance. + * + * weights :: + * A pointer to an array; the function copies the first five bytes and + * uses them to specify the filter weights. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Due to *PATENTS* covering subpixel rendering, this function doesn't + * do anything except returning `FT_Err_Unimplemented_Feature' if the + * configuration macro FT_CONFIG_OPTION_SUBPIXEL_RENDERING is not + * defined in your build of the library, which should correspond to all + * default builds of FreeType. + * + * This function must be called after @FT_Library_SetLcdFilter to have + * any effect. + * + * @since: + * 2.4.0 + */ + FT_EXPORT( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ); +/* */ +FT_END_HEADER +/* __FT_LCD_FILTER_H__ */ +#endif +/* END */ +/***************************************************************************/ +/* */ +/* ftmemory.h */ +/* */ +/* The FreeType memory management macros (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2010 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. */ +/* */ +/***************************************************************************/ +#define __FTMEMORY_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_SET_ERROR */ +/* */ +/* <Description> */ +/* This macro is used to set an implicit `error' variable to a given */ +/* expression's value (usually a function call), and convert it to a */ +/* boolean which is set whenever the value is != 0. */ +/* */ +#undef FT_SET_ERROR +#define FT_SET_ERROR( expression ) \ + ( ( error = (expression) ) != 0 ) +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** M E M O R Y ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* + * C++ refuses to handle statements like p = (void*)anything, with `p' a + * typed pointer. Since we don't have a `typeof' operator in standard + * C++, we have to use a template to emulate it. + */ +#ifdef __cplusplus + extern "C++" + template <typename T> inline T* + cplusplus_typeof( T*, + void *v ) + { + return static_cast <T*> ( v ); + } +#define FT_ASSIGNP( p, val ) (p) = cplusplus_typeof( (p), (val) ) +#else +#define FT_ASSIGNP( p, val ) (p) = (val) +#endif +#define FT_DEBUG_INNER( exp ) (exp) +#define FT_ASSIGNP_INNER( p, exp ) FT_ASSIGNP( p, exp ) +/* + * The allocation functions return a pointer, and the error code + * is written to through the `p_error' parameter. See below for + * for documentation. + */ + FT_BASE( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + FT_BASE( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ); + FT_BASE( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + FT_BASE( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ); + FT_BASE( void ) + ft_mem_free( FT_Memory memory, + const void* P ); +#define FT_MEM_ALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_alloc( memory, (size), &error ) ) +#define FT_MEM_FREE( ptr ) \ + FT_BEGIN_STMNT \ + ft_mem_free( memory, (ptr) ); \ + (ptr) = NULL; \ + FT_END_STMNT +#define FT_MEM_NEW( ptr ) \ + FT_MEM_ALLOC( ptr, sizeof ( *(ptr) ) ) +#define FT_MEM_REALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, 1, \ + (cursz), (newsz), \ + (ptr), &error ) ) +#define FT_MEM_QALLOC( ptr, size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qalloc( memory, (size), &error ) ) +#define FT_MEM_QNEW( ptr ) \ + FT_MEM_QALLOC( ptr, sizeof ( *(ptr) ) ) +#define FT_MEM_QREALLOC( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, 1, \ + (cursz), (newsz), \ + (ptr), &error ) ) +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) +#define FT_MEM_ALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, (item_size), \ + 0, (count), \ + NULL, &error ) ) +#define FT_MEM_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, (itmsz), \ + (oldcnt), (newcnt), \ + (ptr), &error ) ) +#define FT_MEM_QALLOC_MULT( ptr, count, item_size ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, (item_size), \ + 0, (count), \ + NULL, &error ) ) +#define FT_MEM_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, (itmsz), \ + (oldcnt), (newcnt), \ + (ptr), &error ) ) +#define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) +#define FT_MEM_SET( dest, byte, count ) ft_memset( dest, byte, count ) +#define FT_MEM_COPY( dest, source, count ) ft_memcpy( dest, source, count ) +#define FT_MEM_MOVE( dest, source, count ) ft_memmove( dest, source, count ) +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) +#define FT_ARRAY_ZERO( dest, count ) \ + FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) ) +#define FT_ARRAY_COPY( dest, source, count ) \ + FT_MEM_COPY( dest, source, (count) * sizeof ( *(dest) ) ) +#define FT_ARRAY_MOVE( dest, source, count ) \ + FT_MEM_MOVE( dest, source, (count) * sizeof ( *(dest) ) ) +/* + * Return the maximum number of addressable elements in an array. + * We limit ourselves to INT_MAX, rather than UINT_MAX, to avoid + * any problems. + */ +#define FT_ARRAY_MAX( ptr ) ( FT_INT_MAX / sizeof ( *(ptr) ) ) +#define FT_ARRAY_CHECK( ptr, count ) ( (count) <= FT_ARRAY_MAX( ptr ) ) +/*************************************************************************/ +/* */ +/* The following functions macros expect that their pointer argument is */ +/* _typed_ in order to automatically compute array element sizes. */ +/* */ +#define FT_MEM_NEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, sizeof ( *(ptr) ), \ + 0, (count), \ + NULL, &error ) ) +#define FT_MEM_RENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_realloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) +#define FT_MEM_QNEW_ARRAY( ptr, count ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + 0, (count), \ + NULL, &error ) ) +#define FT_MEM_QRENEW_ARRAY( ptr, cursz, newsz ) \ + FT_ASSIGNP_INNER( ptr, ft_mem_qrealloc( memory, sizeof ( *(ptr) ), \ + (cursz), (newsz), \ + (ptr), &error ) ) +#define FT_ALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC( ptr, size ) ) +#define FT_REALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC( ptr, cursz, newsz ) ) +#define FT_ALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT( ptr, count, item_size ) ) +#define FT_REALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) +#define FT_QALLOC( ptr, size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC( ptr, size ) ) +#define FT_QREALLOC( ptr, cursz, newsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC( ptr, cursz, newsz ) ) +#define FT_QALLOC_MULT( ptr, count, item_size ) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC_MULT( ptr, count, item_size ) ) +#define FT_QREALLOC_MULT( ptr, oldcnt, newcnt, itmsz ) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC_MULT( ptr, oldcnt, \ + newcnt, itmsz ) ) +#define FT_FREE( ptr ) FT_MEM_FREE( ptr ) +#define FT_NEW( ptr ) FT_MEM_SET_ERROR( FT_MEM_NEW( ptr ) ) +#define FT_NEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) +#define FT_RENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) +#define FT_QNEW( ptr ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW( ptr ) ) +#define FT_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY( ptr, count ) ) +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) + FT_BASE( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ); + FT_BASE( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ); +#define FT_MEM_STRDUP( dst, str ) \ + (dst) = (char*)ft_mem_strdup( memory, (const char*)(str), &error ) +#define FT_STRDUP( dst, str ) \ + FT_MEM_SET_ERROR( FT_MEM_STRDUP( dst, str ) ) +#define FT_MEM_DUP( dst, address, size ) \ + (dst) = ft_mem_dup( memory, (address), (FT_ULong)(size), &error ) +#define FT_DUP( dst, address, size ) \ + FT_MEM_SET_ERROR( FT_MEM_DUP( dst, address, size ) ) +/* Return >= 1 if a truncation occurs. */ +/* Return 0 if the source string fits the buffer. */ +/* This is *not* the same as strlcpy(). */ + FT_BASE( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ); +#define FT_STRCPYN( dst, src, size ) \ + ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftgloadr.h */ +/* */ +/* The FreeType glyph loader (specification). */ +/* */ +/* Copyright 2002, 2003, 2005, 2006 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. */ +/* */ +/***************************************************************************/ +#define __FTGLOADR_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_GlyphLoader */ +/* */ +/* <Description> */ +/* The glyph loader is an internal object used to load several glyphs */ +/* together (for example, in the case of composites). */ +/* */ +/* <Note> */ +/* The glyph loader implementation is not part of the high-level API, */ +/* hence the forward structure declaration. */ +/* */ + typedef struct FT_GlyphLoaderRec_* FT_GlyphLoader ; +/* moved to freetype.h in version 2.2 */ +#if 0 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1 +#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2 +#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4 +#define FT_SUBGLYPH_FLAG_SCALE 8 +#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40 +#define FT_SUBGLYPH_FLAG_2X2 0x80 +#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200 +#endif + typedef struct FT_SubGlyphRec_ + { + FT_Int index; + FT_UShort flags; + FT_Int arg1; + FT_Int arg2; + FT_Matrix transform; + } FT_SubGlyphRec; + typedef struct FT_GlyphLoadRec_ + { +/* outline */ + FT_Outline outline; +/* extra points table */ + FT_Vector* extra_points; +/* second extra points table */ + FT_Vector* extra_points2; +/* number of subglyphs */ + FT_UInt num_subglyphs; +/* subglyphs */ + FT_SubGlyph subglyphs; + } FT_GlyphLoadRec, *FT_GlyphLoad; + typedef struct FT_GlyphLoaderRec_ + { + FT_Memory memory; + FT_UInt max_points; + FT_UInt max_contours; + FT_UInt max_subglyphs; + FT_Bool use_extra; + FT_GlyphLoadRec base; + FT_GlyphLoadRec current; +/* for possible future extension? */ + void* other; + } FT_GlyphLoaderRec; +/* create new empty glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ); +/* add an extra points table to a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ); +/* destroy a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ); +/* reset a glyph loader (frees everything int it) */ + FT_BASE( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ); +/* rewind a glyph loader */ + FT_BASE( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ); +/* check that there is enough space to add `n_points' and `n_contours' */ +/* to the glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ); +#define FT_GLYPHLOADER_CHECK_P( _loader, _count ) \ + ( (_count) == 0 || ((_loader)->base.outline.n_points + \ + (_loader)->current.outline.n_points + \ + (unsigned long)(_count)) <= (_loader)->max_points ) +#define FT_GLYPHLOADER_CHECK_C( _loader, _count ) \ + ( (_count) == 0 || ((_loader)->base.outline.n_contours + \ + (_loader)->current.outline.n_contours + \ + (unsigned long)(_count)) <= (_loader)->max_contours ) +#define FT_GLYPHLOADER_CHECK_POINTS( _loader, _points,_contours ) \ + ( ( FT_GLYPHLOADER_CHECK_P( _loader, _points ) && \ + FT_GLYPHLOADER_CHECK_C( _loader, _contours ) ) \ + ? 0 \ + : FT_GlyphLoader_CheckPoints( (_loader), (_points), (_contours) ) ) +/* check that there is enough space to add `n_subs' sub-glyphs to */ +/* a glyph loader */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ); +/* prepare a glyph loader, i.e. empty the current glyph */ + FT_BASE( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ); +/* add the current glyph to the base glyph */ + FT_BASE( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ); +/* copy points from one glyph loader to another */ + FT_BASE( FT_Error ) + FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, + FT_GlyphLoader source ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftdriver.h */ +/* */ +/* FreeType font driver interface (specification). */ +/* */ +/* Copyright 1996-2003, 2006, 2008, 2011-2012 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. */ +/* */ +/***************************************************************************/ +#define __FTDRIVER_H__ +FT_BEGIN_HEADER + typedef FT_Error + (*FT_Face_InitFunc)( FT_Stream stream, + FT_Face face, + FT_Int typeface_index, + FT_Int num_params, + FT_Parameter* parameters ); + typedef void + (*FT_Face_DoneFunc)( FT_Face face ); + typedef FT_Error + (*FT_Size_InitFunc)( FT_Size size ); + typedef void + (*FT_Size_DoneFunc)( FT_Size size ); + typedef FT_Error + (*FT_Slot_InitFunc)( FT_GlyphSlot slot ); + typedef void + (*FT_Slot_DoneFunc)( FT_GlyphSlot slot ); + typedef FT_Error + (*FT_Size_RequestFunc)( FT_Size size, + FT_Size_Request req ); + typedef FT_Error + (*FT_Size_SelectFunc)( FT_Size size, + FT_ULong size_index ); + typedef FT_Error + (*FT_Slot_LoadFunc)( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + typedef FT_UInt + (*FT_CharMap_CharIndexFunc)( FT_CharMap charmap, + FT_Long charcode ); + typedef FT_Long + (*FT_CharMap_CharNextFunc)( FT_CharMap charmap, + FT_Long charcode ); + typedef FT_Error + (*FT_Face_GetKerningFunc)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ); + typedef FT_Error + (*FT_Face_AttachFunc)( FT_Face face, + FT_Stream stream ); + typedef FT_Error + (*FT_Face_GetAdvancesFunc)( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Driver_ClassRec */ +/* */ +/* <Description> */ +/* The font driver class. This structure mostly contains pointers to */ +/* driver methods. */ +/* */ +/* <Fields> */ +/* root :: The parent module. */ +/* */ +/* face_object_size :: The size of a face object in bytes. */ +/* */ +/* size_object_size :: The size of a size object in bytes. */ +/* */ +/* slot_object_size :: The size of a glyph object in bytes. */ +/* */ +/* init_face :: The format-specific face constructor. */ +/* */ +/* done_face :: The format-specific face destructor. */ +/* */ +/* init_size :: The format-specific size constructor. */ +/* */ +/* done_size :: The format-specific size destructor. */ +/* */ +/* init_slot :: The format-specific slot constructor. */ +/* */ +/* done_slot :: The format-specific slot destructor. */ +/* */ +/* */ +/* load_glyph :: A function handle to load a glyph to a slot. */ +/* This field is mandatory! */ +/* */ +/* get_kerning :: A function handle to return the unscaled */ +/* kerning for a given pair of glyphs. Can be */ +/* set to 0 if the format doesn't support */ +/* kerning. */ +/* */ +/* attach_file :: This function handle is used to read */ +/* additional data for a face from another */ +/* file/stream. For example, this can be used to */ +/* add data from AFM or PFM files on a Type 1 */ +/* face, or a CIDMap on a CID-keyed face. */ +/* */ +/* get_advances :: A function handle used to return advance */ +/* widths of `count' glyphs (in font units), */ +/* starting at `first'. The `vertical' flag must */ +/* be set to get vertical advance heights. The */ +/* `advances' buffer is caller-allocated. */ +/* The idea of this function is to be able to */ +/* perform device-independent text layout without */ +/* loading a single glyph image. */ +/* */ +/* request_size :: A handle to a function used to request the new */ +/* character size. Can be set to 0 if the */ +/* scaling done in the base layer suffices. */ +/* */ +/* select_size :: A handle to a function used to select a new */ +/* fixed size. It is used only if */ +/* @FT_FACE_FLAG_FIXED_SIZES is set. Can be set */ +/* to 0 if the scaling done in the base layer */ +/* suffices. */ +/* <Note> */ +/* Most function pointers, with the exception of `load_glyph', can be */ +/* set to 0 to indicate a default behaviour. */ +/* */ + typedef struct FT_Driver_ClassRec_ + { + FT_Module_Class root; + FT_Long face_object_size; + FT_Long size_object_size; + FT_Long slot_object_size; + FT_Face_InitFunc init_face; + FT_Face_DoneFunc done_face; + FT_Size_InitFunc init_size; + FT_Size_DoneFunc done_size; + FT_Slot_InitFunc init_slot; + FT_Slot_DoneFunc done_slot; + FT_Slot_LoadFunc load_glyph; + FT_Face_GetKerningFunc get_kerning; + FT_Face_AttachFunc attach_file; + FT_Face_GetAdvancesFunc get_advances; +/* since version 2.2 */ + FT_Size_RequestFunc request_size; + FT_Size_SelectFunc select_size; + } FT_Driver_ClassRec, *FT_Driver_Class; +/* + * The following functions are used as stubs for `set_char_sizes' and + * `set_pixel_sizes'; the code uses `request_size' and `select_size' + * functions instead. + * + * Implementation is in `src/base/ftobjs.c'. + */ +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DECLARE_DRIVER */ +/* */ +/* <Description> */ +/* Used to create a forward declaration of an FT_Driver_ClassRec */ +/* struct instance. */ +/* */ +/* <Macro> */ +/* FT_DEFINE_DRIVER */ +/* */ +/* <Description> */ +/* Used to initialize an instance of FT_Driver_ClassRec struct. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is defined a `create' function has to be */ +/* called with a pointer where the allocated structure is returned. */ +/* And when it is no longer needed a `destroy' function needs to be */ +/* called to release that allocation. */ +/* */ +/* `fcinit.c' (ft_create_default_module_classes) already contains a */ +/* mechanism to call these functions for the default modules */ +/* described in `ftmodule.h'. */ +/* */ +/* Notice that the created `create' and `destroy' functions call */ +/* `pic_init' and `pic_free' to allow you to manually allocate and */ +/* initialize any additional global data, like a module specific */ +/* interface, and put them in the global pic container defined in */ +/* `ftpic.h'. If you don't need them just implement the functions as */ +/* empty to resolve the link error. Also the `pic_init' and */ +/* `pic_free' functions should be declared in `pic.h', to be referred */ +/* by driver definition calling `FT_DEFINE_DRIVER' in following. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ +/* allocated in the global scope (or the scope where the macro is */ +/* used). */ +/* */ +/* empty */ +#define FT_DEFINE_DRIVERS_OLD_INTERNALS( a_, b_ ) +#define FT_DECLARE_DRIVER( class_ ) \ + FT_CALLBACK_TABLE \ + const FT_Driver_ClassRec class_; +#define FT_DEFINE_DRIVER( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_, \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + init_face_, \ + done_face_, \ + init_size_, \ + done_size_, \ + init_slot_, \ + done_slot_, \ + old_set_char_sizes_, \ + old_set_pixel_sizes_, \ + load_glyph_, \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + request_size_, \ + select_size_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Driver_ClassRec class_ = \ + { \ + FT_DEFINE_ROOT_MODULE( flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + \ + face_object_size_, \ + size_object_size_, \ + slot_object_size_, \ + \ + init_face_, \ + done_face_, \ + \ + init_size_, \ + done_size_, \ + \ + init_slot_, \ + done_slot_, \ + \ + FT_DEFINE_DRIVERS_OLD_INTERNALS( old_set_char_sizes_, \ + old_set_pixel_sizes_ ) \ + \ + load_glyph_, \ + \ + get_kerning_, \ + attach_file_, \ + get_advances_, \ + \ + request_size_, \ + select_size_ \ + }; +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* autohint.h */ +/* */ +/* High-level `autohint' module-specific interface (specification). */ +/* */ +/* Copyright 1996-2002, 2007, 2009, 2012 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-hinter is used to load and automatically hint glyphs if a */ +/* format-specific hinter isn't available. */ +/* */ +/*************************************************************************/ +#define __AUTOHINT_H__ +/*************************************************************************/ +/* */ +/* A small technical note regarding automatic hinting in order to */ +/* clarify this module interface. */ +/* */ +/* An automatic hinter might compute two kinds of data for a given face: */ +/* */ +/* - global hints: Usually some metrics that describe global properties */ +/* of the face. It is computed by scanning more or less */ +/* aggressively the glyphs in the face, and thus can be */ +/* very slow to compute (even if the size of global */ +/* hints is really small). */ +/* */ +/* - glyph hints: These describe some important features of the glyph */ +/* outline, as well as how to align them. They are */ +/* generally much faster to compute than global hints. */ +/* */ +/* The current FreeType auto-hinter does a pretty good job while */ +/* performing fast computations for both global and glyph hints. */ +/* However, we might be interested in introducing more complex and */ +/* powerful algorithms in the future, like the one described in the John */ +/* D. Hobby paper, which unfortunately requires a lot more horsepower. */ +/* */ +/* Because a sufficiently sophisticated font management system would */ +/* typically implement an LRU cache of opened face objects to reduce */ +/* memory usage, it is a good idea to be able to avoid recomputing */ +/* global hints every time the same face is re-opened. */ +/* */ +/* We thus provide the ability to cache global hints outside of the face */ +/* object, in order to speed up font re-opening time. Of course, this */ +/* feature is purely optional, so most client programs won't even notice */ +/* it. */ +/* */ +/* I initially thought that it would be a good idea to cache the glyph */ +/* hints too. However, my general idea now is that if you really need */ +/* to cache these too, you are simply in need of a new font format, */ +/* where all this information could be stored within the font file and */ +/* decoded on the fly. */ +/* */ +/*************************************************************************/ +FT_BEGIN_HEADER + typedef struct FT_AutoHinterRec_ *FT_AutoHinter; +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_AutoHinter_GlobalGetFunc */ +/* */ +/* <Description> */ +/* Retrieve the global hints computed for a given face object. The */ +/* resulting data is dissociated from the face and will survive a */ +/* call to FT_Done_Face(). It must be discarded through the API */ +/* FT_AutoHinter_GlobalDoneFunc(). */ +/* */ +/* <Input> */ +/* hinter :: A handle to the source auto-hinter. */ +/* */ +/* face :: A handle to the source face object. */ +/* */ +/* <Output> */ +/* global_hints :: A typeless pointer to the global hints. */ +/* */ +/* global_len :: The size in bytes of the global hints. */ +/* */ + typedef void + (*FT_AutoHinter_GlobalGetFunc)( FT_AutoHinter hinter, + FT_Face face, + void** global_hints, + long* global_len ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_AutoHinter_GlobalDoneFunc */ +/* */ +/* <Description> */ +/* Discard the global hints retrieved through */ +/* FT_AutoHinter_GlobalGetFunc(). This is the only way these hints */ +/* are freed from memory. */ +/* */ +/* <Input> */ +/* hinter :: A handle to the auto-hinter module. */ +/* */ +/* global :: A pointer to retrieved global hints to discard. */ +/* */ + typedef void + (*FT_AutoHinter_GlobalDoneFunc)( FT_AutoHinter hinter, + void* global ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_AutoHinter_GlobalResetFunc */ +/* */ +/* <Description> */ +/* This function is used to recompute the global metrics in a given */ +/* font. This is useful when global font data changes (e.g. Multiple */ +/* Masters fonts where blend coordinates change). */ +/* */ +/* <Input> */ +/* hinter :: A handle to the source auto-hinter. */ +/* */ +/* face :: A handle to the face. */ +/* */ + typedef void + (*FT_AutoHinter_GlobalResetFunc)( FT_AutoHinter hinter, + FT_Face face ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_AutoHinter_GlyphLoadFunc */ +/* */ +/* <Description> */ +/* This function is used to load, scale, and automatically hint a */ +/* glyph from a given face. */ +/* */ +/* <Input> */ +/* face :: A handle to the face. */ +/* */ +/* glyph_index :: The glyph index. */ +/* */ +/* load_flags :: The load flags. */ +/* */ +/* <Note> */ +/* This function is capable of loading composite glyphs by hinting */ +/* each sub-glyph independently (which improves quality). */ +/* */ +/* It will call the font driver with @FT_Load_Glyph, with */ +/* @FT_LOAD_NO_SCALE set. */ +/* */ + typedef FT_Error + (*FT_AutoHinter_GlyphLoadFunc)( FT_AutoHinter hinter, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_AutoHinter_InterfaceRec */ +/* */ +/* <Description> */ +/* The auto-hinter module's interface. */ +/* */ + typedef struct FT_AutoHinter_InterfaceRec_ + { + FT_AutoHinter_GlobalResetFunc reset_face; + FT_AutoHinter_GlobalGetFunc get_global_hints; + FT_AutoHinter_GlobalDoneFunc done_global_hints; + FT_AutoHinter_GlyphLoadFunc load_glyph; + } FT_AutoHinter_InterfaceRec, *FT_AutoHinter_Interface; +#define FT_DEFINE_AUTOHINTER_INTERFACE( \ + class_, \ + reset_face_, \ + get_global_hints_, \ + done_global_hints_, \ + load_glyph_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_AutoHinter_InterfaceRec class_ = \ + { \ + reset_face_, \ + get_global_hints_, \ + done_global_hints_, \ + load_glyph_ \ + }; +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftserv.h */ +/* */ +/* The FreeType services (specification only). */ +/* */ +/* Copyright 2003-2007, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* Each module can export one or more `services'. Each service is */ +/* identified by a constant string and modeled by a pointer; the latter */ +/* generally corresponds to a structure containing function pointers. */ +/* */ +/* Note that a service's data cannot be a mere function pointer because */ +/* in C it is possible that function pointers might be implemented */ +/* differently than data pointers (e.g. 48 bits instead of 32). */ +/* */ +/*************************************************************************/ +#define __FTSERV_H__ +FT_BEGIN_HEADER +/* Visual C++ (and Intel C++) */ +#if defined( _MSC_VER ) +/* we disable the warning `conditional expression is constant' here */ +/* in order to compile cleanly with the maximum level of warnings */ +#pragma warning( disable : 4127 ) +/* _MSC_VER */ +#endif +/* + * @macro: + * FT_FACE_FIND_SERVICE + * + * @description: + * This macro is used to look up a service from a face's driver module. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's + * header files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * `multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_'. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be NULL + * if not found. + */ +#ifdef __cplusplus +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT +/* !C++ */ +#else +#define FT_FACE_FIND_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_ = NULL; \ + \ + if ( module->clazz->get_interface ) \ + _tmp_ = module->clazz->get_interface( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT +/* !C++ */ +#endif +/* + * @macro: + * FT_FACE_FIND_GLOBAL_SERVICE + * + * @description: + * This macro is used to look up a service from all modules. + * + * @input: + * face :: + * The source face handle. + * + * id :: + * A string describing the service as defined in the service's + * header files (e.g. FT_SERVICE_ID_MULTI_MASTERS which expands to + * `multi-masters'). It is automatically prefixed with + * `FT_SERVICE_ID_'. + * + * @output: + * ptr :: + * A variable that receives the service pointer. Will be NULL + * if not found. + */ +#ifdef __cplusplus +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + FT_Pointer* _pptr_ = (FT_Pointer*)&(ptr); \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ + *_pptr_ = _tmp_; \ + FT_END_STMNT +/* !C++ */ +#else +#define FT_FACE_FIND_GLOBAL_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Module module = FT_MODULE( FT_FACE( face )->driver ); \ + FT_Pointer _tmp_; \ + \ + \ + _tmp_ = ft_module_get_service( module, FT_SERVICE_ID_ ## id ); \ + ptr = _tmp_; \ + FT_END_STMNT +/* !C++ */ +#endif +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** S E R V I C E D E S C R I P T O R S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* + * The following structure is used to _describe_ a given service + * to the library. This is useful to build simple static service lists. + */ + typedef struct FT_ServiceDescRec_ + { +/* service name */ + const char* serv_id; +/* service pointer/data */ + const void* serv_data; + } FT_ServiceDescRec; + typedef const FT_ServiceDescRec* FT_ServiceDesc; +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DEFINE_SERVICEDESCREC1 */ +/* FT_DEFINE_SERVICEDESCREC2 */ +/* FT_DEFINE_SERVICEDESCREC3 */ +/* FT_DEFINE_SERVICEDESCREC4 */ +/* FT_DEFINE_SERVICEDESCREC5 */ +/* FT_DEFINE_SERVICEDESCREC6 */ +/* */ +/* <Description> */ +/* Used to initialize an array of FT_ServiceDescRec structures. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is defined a `create' function needs to */ +/* be called with a pointer to return an allocated array. As soon as */ +/* it is no longer needed, a `destroy' function needs to be called to */ +/* release that allocation. */ +/* */ +/* These functions should be manually called from the `pic_init' and */ +/* `pic_free' functions of your module (see FT_DEFINE_MODULE). */ +/* */ +/* When FT_CONFIG_OPTION_PIC is not defined the array will be */ +/* allocated in the global scope (or the scope where the macro is */ +/* used). */ +/* */ +#define FT_DEFINE_SERVICEDESCREC1( class_, \ + serv_id_1, serv_data_1 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { NULL, NULL } \ + }; +#define FT_DEFINE_SERVICEDESCREC2( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { NULL, NULL } \ + }; +#define FT_DEFINE_SERVICEDESCREC3( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { NULL, NULL } \ + }; +#define FT_DEFINE_SERVICEDESCREC4( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { NULL, NULL } \ + }; +#define FT_DEFINE_SERVICEDESCREC5( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { NULL, NULL } \ + }; +#define FT_DEFINE_SERVICEDESCREC6( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { NULL, NULL } \ + }; +/* + * Parse a list of FT_ServiceDescRec descriptors and look for + * a specific service by ID. Note that the last element in the + * array must be { NULL, NULL }, and that the function should + * return NULL if the service isn't available. + * + * This function can be used by modules to implement their + * `get_service' method. + */ + FT_BASE( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ); +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** S E R V I C E S C A C H E *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* + * This structure is used to store a cache for several frequently used + * services. It is the type of `face->internal->services'. You + * should only use FT_FACE_LOOKUP_SERVICE to access it. + * + * All fields should have the type FT_Pointer to relax compilation + * dependencies. We assume the developer isn't completely stupid. + * + * Each field must be named `service_XXXX' where `XXX' corresponds to + * the correct FT_SERVICE_ID_XXXX macro. See the definition of + * FT_FACE_LOOKUP_SERVICE below how this is implemented. + * + */ + typedef struct FT_ServiceCacheRec_ + { + FT_Pointer service_POSTSCRIPT_FONT_NAME; + FT_Pointer service_MULTI_MASTERS; + FT_Pointer service_GLYPH_DICT; + FT_Pointer service_PFR_METRICS; + FT_Pointer service_WINFNT; + } FT_ServiceCacheRec, *FT_ServiceCache; +/* + * A magic number used within the services cache. + */ +/* magic number */ +#define FT_SERVICE_UNAVAILABLE ((FT_Pointer)~1) +/* + * @macro: + * FT_FACE_LOOKUP_SERVICE + * + * @description: + * This macro is used to lookup a service from a face's driver module + * using its cache. + * + * @input: + * face:: + * The source face handle containing the cache. + * + * field :: + * The field name in the cache. + * + * id :: + * The service ID. + * + * @output: + * ptr :: + * A variable receiving the service data. NULL if not available. + */ +#ifdef __cplusplus +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + FT_Pointer* Pptr = (FT_Pointer*)&(ptr); \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + *Pptr = svc; \ + FT_END_STMNT +/* !C++ */ +#else +#define FT_FACE_LOOKUP_SERVICE( face, ptr, id ) \ + FT_BEGIN_STMNT \ + FT_Pointer svc; \ + \ + \ + svc = FT_FACE( face )->internal->services. service_ ## id; \ + if ( svc == FT_SERVICE_UNAVAILABLE ) \ + svc = NULL; \ + else if ( svc == NULL ) \ + { \ + FT_FACE_FIND_SERVICE( face, svc, id ); \ + \ + FT_FACE( face )->internal->services. service_ ## id = \ + (FT_Pointer)( svc != NULL ? svc \ + : FT_SERVICE_UNAVAILABLE ); \ + } \ + ptr = svc; \ + FT_END_STMNT +/* !C++ */ +#endif +/* + * A macro used to define new service structure types. + */ +#define FT_DEFINE_SERVICE( name ) \ + typedef struct FT_Service_ ## name ## Rec_ \ + FT_Service_ ## name ## Rec ; \ + typedef struct FT_Service_ ## name ## Rec_ \ + const * FT_Service_ ## name ; \ + struct FT_Service_ ## name ## Rec_ +/* */ +/* + * The header files containing the services. + */ +#define FT_SERVICE_BDF_H <freetype/internal/services/svbdf.h> +#define FT_SERVICE_CID_H <freetype/internal/services/svcid.h> +#define FT_SERVICE_GLYPH_DICT_H <freetype/internal/services/svgldict.h> +#define FT_SERVICE_GX_VALIDATE_H <freetype/internal/services/svgxval.h> +#define FT_SERVICE_KERNING_H <freetype/internal/services/svkern.h> +#define FT_SERVICE_MULTIPLE_MASTERS_H <freetype/internal/services/svmm.h> +#define FT_SERVICE_OPENTYPE_VALIDATE_H <freetype/internal/services/svotval.h> +#define FT_SERVICE_PFR_H <freetype/internal/services/svpfr.h> +#define FT_SERVICE_POSTSCRIPT_CMAPS_H <freetype/internal/services/svpscmap.h> +#define FT_SERVICE_POSTSCRIPT_INFO_H <freetype/internal/services/svpsinfo.h> +#define FT_SERVICE_POSTSCRIPT_NAME_H <freetype/internal/services/svpostnm.h> +#define FT_SERVICE_PROPERTIES_H <freetype/internal/services/svprop.h> +#define FT_SERVICE_SFNT_H <freetype/internal/services/svsfnt.h> +#define FT_SERVICE_TRUETYPE_ENGINE_H <freetype/internal/services/svtteng.h> +#define FT_SERVICE_TT_CMAP_H <freetype/internal/services/svttcmap.h> +#define FT_SERVICE_WINFNT_H <freetype/internal/services/svwinfnt.h> +#define FT_SERVICE_XFREE86_NAME_H <freetype/internal/services/svxf86nm.h> +#define FT_SERVICE_TRUETYPE_GLYF_H <freetype/internal/services/svttglyf.h> +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftpic.h */ +/* */ +/* The FreeType position independent code services (declaration). */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* Modules that ordinarily have const global data that need address */ +/* can instead define pointers here. */ +/* */ +/*************************************************************************/ +#define __FTPIC_H__ +FT_BEGIN_HEADER +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftincrem.h */ +/* */ +/* FreeType incremental loading (specification). */ +/* */ +/* Copyright 2002, 2003, 2006, 2007, 2008, 2010 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. */ +/* */ +/***************************************************************************/ +#define __FTINCREM_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 +FT_BEGIN_HEADER +/*************************************************************************** + * + * @section: + * incremental + * + * @title: + * Incremental Loading + * + * @abstract: + * Custom Glyph Loading. + * + * @description: + * This section contains various functions used to perform so-called + * `incremental' glyph loading. This is a mode where all glyphs loaded + * from a given @FT_Face are provided by the client application, + * + * Apart from that, all other tables are loaded normally from the font + * file. This mode is useful when FreeType is used within another + * engine, e.g., a PostScript Imaging Processor. + * + * To enable this mode, you must use @FT_Open_Face, passing an + * @FT_Parameter with the @FT_PARAM_TAG_INCREMENTAL tag and an + * @FT_Incremental_Interface value. See the comments for + * @FT_Incremental_InterfaceRec for an example. + * + */ +/*************************************************************************** + * + * @type: + * FT_Incremental + * + * @description: + * An opaque type describing a user-provided object used to implement + * `incremental' glyph loading within FreeType. This is used to support + * embedded fonts in certain environments (e.g., PostScript interpreters), + * where the glyph data isn't in the font file, or must be overridden by + * different values. + * + * @note: + * It is up to client applications to create and implement @FT_Incremental + * objects, as long as they provide implementations for the methods + * @FT_Incremental_GetGlyphDataFunc, @FT_Incremental_FreeGlyphDataFunc + * and @FT_Incremental_GetGlyphMetricsFunc. + * + * See the description of @FT_Incremental_InterfaceRec to understand how + * to use incremental objects with FreeType. + * + */ + typedef struct FT_IncrementalRec_* FT_Incremental; +/*************************************************************************** + * + * @struct: + * FT_Incremental_MetricsRec + * + * @description: + * A small structure used to contain the basic glyph metrics returned + * by the @FT_Incremental_GetGlyphMetricsFunc method. + * + * @fields: + * bearing_x :: + * Left bearing, in font units. + * + * bearing_y :: + * Top bearing, in font units. + * + * advance :: + * Horizontal component of glyph advance, in font units. + * + * advance_v :: + * Vertical component of glyph advance, in font units. + * + * @note: + * These correspond to horizontal or vertical metrics depending on the + * value of the `vertical' argument to the function + * @FT_Incremental_GetGlyphMetricsFunc. + * + */ + typedef struct FT_Incremental_MetricsRec_ + { + FT_Long bearing_x; + FT_Long bearing_y; + FT_Long advance; +/* since 2.3.12 */ + FT_Long advance_v; + } FT_Incremental_MetricsRec; +/*************************************************************************** + * + * @struct: + * FT_Incremental_Metrics + * + * @description: + * A handle to an @FT_Incremental_MetricsRec structure. + * + */ + typedef struct FT_Incremental_MetricsRec_* FT_Incremental_Metrics; +/*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphDataFunc + * + * @description: + * A function called by FreeType to access a given glyph's data bytes + * during @FT_Load_Glyph or @FT_Load_Char if incremental loading is + * enabled. + * + * Note that the format of the glyph's data bytes depends on the font + * file format. For TrueType, it must correspond to the raw bytes within + * the `glyf' table. For PostScript formats, it must correspond to the + * *unencrypted* charstring bytes, without any `lenIV' header. It is + * undefined for any other format. + * + * @input: + * incremental :: + * Handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * @output: + * adata :: + * A structure describing the returned glyph data bytes (which will be + * accessed as a read-only byte block). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If this function returns successfully the method + * @FT_Incremental_FreeGlyphDataFunc will be called later to release + * the data bytes. + * + * Nested calls to @FT_Incremental_GetGlyphDataFunc can happen for + * compound glyphs. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphDataFunc)( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Data* adata ); +/*************************************************************************** + * + * @type: + * FT_Incremental_FreeGlyphDataFunc + * + * @description: + * A function used to release the glyph data bytes returned by a + * successful call to @FT_Incremental_GetGlyphDataFunc. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * data :: + * A structure describing the glyph data bytes (which will be accessed + * as a read-only byte block). + * + */ + typedef void + (*FT_Incremental_FreeGlyphDataFunc)( FT_Incremental incremental, + FT_Data* data ); +/*************************************************************************** + * + * @type: + * FT_Incremental_GetGlyphMetricsFunc + * + * @description: + * A function used to retrieve the basic metrics of a given glyph index + * before accessing its data. This is necessary because, in certain + * formats like TrueType, the metrics are stored in a different place from + * the glyph images proper. + * + * @input: + * incremental :: + * A handle to an opaque @FT_Incremental handle provided by the client + * application. + * + * glyph_index :: + * Index of relevant glyph. + * + * vertical :: + * If true, return vertical metrics. + * + * ametrics :: + * This parameter is used for both input and output. + * The original glyph metrics, if any, in font units. If metrics are + * not available all the values must be set to zero. + * + * @output: + * ametrics :: + * The replacement glyph metrics in font units. + * + */ + typedef FT_Error + (*FT_Incremental_GetGlyphMetricsFunc) + ( FT_Incremental incremental, + FT_UInt glyph_index, + FT_Bool vertical, + FT_Incremental_MetricsRec *ametrics ); +/************************************************************************** + * + * @struct: + * FT_Incremental_FuncsRec + * + * @description: + * A table of functions for accessing fonts that load data + * incrementally. Used in @FT_Incremental_InterfaceRec. + * + * @fields: + * get_glyph_data :: + * The function to get glyph data. Must not be null. + * + * free_glyph_data :: + * The function to release glyph data. Must not be null. + * + * get_glyph_metrics :: + * The function to get glyph metrics. May be null if the font does + * not provide overriding glyph metrics. + * + */ + typedef struct FT_Incremental_FuncsRec_ + { + FT_Incremental_GetGlyphDataFunc get_glyph_data; + FT_Incremental_FreeGlyphDataFunc free_glyph_data; + FT_Incremental_GetGlyphMetricsFunc get_glyph_metrics; + } FT_Incremental_FuncsRec; +/*************************************************************************** + * + * @struct: + * FT_Incremental_InterfaceRec + * + * @description: + * A structure to be used with @FT_Open_Face to indicate that the user + * wants to support incremental glyph loading. You should use it with + * @FT_PARAM_TAG_INCREMENTAL as in the following example: + * + * { + * FT_Incremental_InterfaceRec inc_int; + * FT_Parameter parameter; + * FT_Open_Args open_args; + * + * + * // set up incremental descriptor + * inc_int.funcs = my_funcs; + * inc_int.object = my_object; + * + * // set up optional parameter + * parameter.tag = FT_PARAM_TAG_INCREMENTAL; + * parameter.data = &inc_int; + * + * // set up FT_Open_Args structure + * open_args.flags = FT_OPEN_PATHNAME | FT_OPEN_PARAMS; + * open_args.pathname = my_font_pathname; + * open_args.num_params = 1; + * open_args.params = ¶meter; // we use one optional argument + * + * // open the font + * error = FT_Open_Face( library, &open_args, index, &face ); + * ... + * } + * + */ + typedef struct FT_Incremental_InterfaceRec_ + { + const FT_Incremental_FuncsRec* funcs; + FT_Incremental object; + } FT_Incremental_InterfaceRec; +/*************************************************************************** + * + * @type: + * FT_Incremental_Interface + * + * @description: + * A pointer to an @FT_Incremental_InterfaceRec structure. + * + */ + typedef FT_Incremental_InterfaceRec* FT_Incremental_Interface; +/*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_INCREMENTAL + * + * @description: + * A constant used as the tag of @FT_Parameter structures to indicate + * an incremental loading object to be used by FreeType. + * + */ +#define FT_PARAM_TAG_INCREMENTAL FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* Some generic definitions. */ +/* */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef NULL +#define NULL (void*)0 +#endif +/*************************************************************************/ +/* */ +/* The min and max functions missing in C. As usual, be careful not to */ +/* write things like FT_MIN( a++, b++ ) to avoid side effects. */ +/* */ +#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) +#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) +#define FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) +#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ((n)/2), n ) +#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + ((n)-1), n ) +#define FT_PIX_FLOOR( x ) ( (x) & ~63 ) +#define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) +#define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) +/* + * Return the highest power of 2 that is <= value; this correspond to + * the highest bit in a given 32-bit value. + */ + FT_BASE( FT_UInt32 ) + ft_highpow2( FT_UInt32 value ); +/* + * character classification functions -- since these are used to parse + * font files, we must not use those in <ctypes.h> which are + * locale-dependent + */ +#define ft_isdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U ) +#define ft_isxdigit( x ) ( ( (unsigned)(x) - '0' ) < 10U || \ + ( (unsigned)(x) - 'a' ) < 6U || \ + ( (unsigned)(x) - 'A' ) < 6U ) +/* the next two macros assume ASCII representation */ +#define ft_isupper( x ) ( ( (unsigned)(x) - 'A' ) < 26U ) +#define ft_islower( x ) ( ( (unsigned)(x) - 'a' ) < 26U ) +#define ft_isalpha( x ) ( ft_isupper( x ) || ft_islower( x ) ) +#define ft_isalnum( x ) ( ft_isdigit( x ) || ft_isalpha( x ) ) +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** C H A R M A P S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* handle to internal charmap object */ + typedef struct FT_CMapRec_* FT_CMap; +/* handle to charmap class structure */ + typedef const struct FT_CMap_ClassRec_* FT_CMap_Class; +/* internal charmap object structure */ + typedef struct FT_CMapRec_ + { + FT_CharMapRec charmap; + FT_CMap_Class clazz; + } FT_CMapRec; +/* typecase any pointer to a charmap handle */ +#define FT_CMAP( x ) ((FT_CMap)( x )) +/* obvious macros */ +#define FT_CMAP_PLATFORM_ID( x ) FT_CMAP( x )->charmap.platform_id +#define FT_CMAP_ENCODING_ID( x ) FT_CMAP( x )->charmap.encoding_id +#define FT_CMAP_ENCODING( x ) FT_CMAP( x )->charmap.encoding +#define FT_CMAP_FACE( x ) FT_CMAP( x )->charmap.face +/* class method definitions */ + typedef FT_Error + (*FT_CMap_InitFunc)( FT_CMap cmap, + FT_Pointer init_data ); + typedef void + (*FT_CMap_DoneFunc)( FT_CMap cmap ); + typedef FT_UInt + (*FT_CMap_CharIndexFunc)( FT_CMap cmap, + FT_UInt32 char_code ); + typedef FT_UInt + (*FT_CMap_CharNextFunc)( FT_CMap cmap, + FT_UInt32 *achar_code ); + typedef FT_UInt + (*FT_CMap_CharVarIndexFunc)( FT_CMap cmap, + FT_CMap unicode_cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + typedef FT_Bool + (*FT_CMap_CharVarIsDefaultFunc)( FT_CMap cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ); + typedef FT_UInt32 * + (*FT_CMap_VariantListFunc)( FT_CMap cmap, + FT_Memory mem ); + typedef FT_UInt32 * + (*FT_CMap_CharVariantListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 char_code ); + typedef FT_UInt32 * + (*FT_CMap_VariantCharListFunc)( FT_CMap cmap, + FT_Memory mem, + FT_UInt32 variant_selector ); + typedef struct FT_CMap_ClassRec_ + { + FT_ULong size; + FT_CMap_InitFunc init; + FT_CMap_DoneFunc done; + FT_CMap_CharIndexFunc char_index; + FT_CMap_CharNextFunc char_next; +/* Subsequent entries are special ones for format 14 -- the variant */ +/* selector subtable which behaves like no other */ + FT_CMap_CharVarIndexFunc char_var_index; + FT_CMap_CharVarIsDefaultFunc char_var_default; + FT_CMap_VariantListFunc variant_list; + FT_CMap_CharVariantListFunc charvariant_list; + FT_CMap_VariantCharListFunc variantchar_list; + } FT_CMap_ClassRec; +#define FT_DECLARE_CMAP_CLASS( class_ ) \ + FT_CALLBACK_TABLE const FT_CMap_ClassRec class_; +#define FT_DEFINE_CMAP_CLASS( \ + class_, \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_CMap_ClassRec class_ = \ + { \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ \ + }; +/* create a new charmap and add it to charmap->face */ + FT_BASE( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ); +/* destroy a charmap and remove it from face's list */ + FT_BASE( void ) + FT_CMap_Done( FT_CMap cmap ); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Face_InternalRec */ +/* */ +/* <Description> */ +/* This structure contains the internal fields of each FT_Face */ +/* object. These fields may change between different releases of */ +/* FreeType. */ +/* */ +/* <Fields> */ +/* max_points :: */ +/* The maximum number of points used to store the vectorial outline */ +/* of any glyph in this face. If this value cannot be known in */ +/* advance, or if the face isn't scalable, this should be set to 0. */ +/* Only relevant for scalable formats. */ +/* */ +/* max_contours :: */ +/* The maximum number of contours used to store the vectorial */ +/* outline of any glyph in this face. If this value cannot be */ +/* known in advance, or if the face isn't scalable, this should be */ +/* set to 0. Only relevant for scalable formats. */ +/* */ +/* transform_matrix :: */ +/* A 2x2 matrix of 16.16 coefficients used to transform glyph */ +/* outlines after they are loaded from the font. Only used by the */ +/* convenience functions. */ +/* */ +/* transform_delta :: */ +/* A translation vector used to transform glyph outlines after they */ +/* are loaded from the font. Only used by the convenience */ +/* functions. */ +/* */ +/* transform_flags :: */ +/* Some flags used to classify the transform. Only used by the */ +/* convenience functions. */ +/* */ +/* services :: */ +/* A cache for frequently used services. It should be only */ +/* accessed with the macro `FT_FACE_LOOKUP_SERVICE'. */ +/* */ +/* incremental_interface :: */ +/* If non-null, the interface through which glyph data and metrics */ +/* are loaded incrementally for faces that do not provide all of */ +/* this data when first opened. This field exists only if */ +/* @FT_CONFIG_OPTION_INCREMENTAL is defined. */ +/* */ +/* ignore_unpatented_hinter :: */ +/* This boolean flag instructs the glyph loader to ignore the */ +/* native font hinter, if one is found. This is exclusively used */ +/* in the case when the unpatented hinter is compiled within the */ +/* library. */ +/* */ +/* refcount :: */ +/* A counter initialized to~1 at the time an @FT_Face structure is */ +/* created. @FT_Reference_Face increments this counter, and */ +/* @FT_Done_Face only destroys a face if the counter is~1, */ +/* otherwise it simply decrements it. */ +/* */ + typedef struct FT_Face_InternalRec_ + { + FT_Matrix transform_matrix; + FT_Vector transform_delta; + FT_Int transform_flags; + FT_ServiceCacheRec services; + FT_Incremental_InterfaceRec* incremental_interface; + FT_Bool ignore_unpatented_hinter; + FT_UInt refcount; + } FT_Face_InternalRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Slot_InternalRec */ +/* */ +/* <Description> */ +/* This structure contains the internal fields of each FT_GlyphSlot */ +/* object. These fields may change between different releases of */ +/* FreeType. */ +/* */ +/* <Fields> */ +/* loader :: The glyph loader object used to load outlines */ +/* into the glyph slot. */ +/* */ +/* flags :: Possible values are zero or */ +/* FT_GLYPH_OWN_BITMAP. The latter indicates */ +/* that the FT_GlyphSlot structure owns the */ +/* bitmap buffer. */ +/* */ +/* glyph_transformed :: Boolean. Set to TRUE when the loaded glyph */ +/* must be transformed through a specific */ +/* font transformation. This is _not_ the same */ +/* as the face transform set through */ +/* FT_Set_Transform(). */ +/* */ +/* glyph_matrix :: The 2x2 matrix corresponding to the glyph */ +/* transformation, if necessary. */ +/* */ +/* glyph_delta :: The 2d translation vector corresponding to */ +/* the glyph transformation, if necessary. */ +/* */ +/* glyph_hints :: Format-specific glyph hints management. */ +/* */ +#define FT_GLYPH_OWN_BITMAP 0x1 + typedef struct FT_Slot_InternalRec_ + { + FT_GlyphLoader loader; + FT_UInt flags; + FT_Bool glyph_transformed; + FT_Matrix glyph_matrix; + FT_Vector glyph_delta; + void* glyph_hints; + } FT_GlyphSlot_InternalRec; +#if 0 +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Size_InternalRec */ +/* */ +/* <Description> */ +/* This structure contains the internal fields of each FT_Size */ +/* object. Currently, it's empty. */ +/* */ +/*************************************************************************/ + typedef struct FT_Size_InternalRec_ + { +/* empty */ + } FT_Size_InternalRec; +#endif +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** M O D U L E S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_ModuleRec */ +/* */ +/* <Description> */ +/* A module object instance. */ +/* */ +/* <Fields> */ +/* clazz :: A pointer to the module's class. */ +/* */ +/* library :: A handle to the parent library object. */ +/* */ +/* memory :: A handle to the memory manager. */ +/* */ + typedef struct FT_ModuleRec_ + { + FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; + } FT_ModuleRec; +/* typecast an object to an FT_Module */ +#define FT_MODULE( x ) ((FT_Module)( x )) +#define FT_MODULE_CLASS( x ) FT_MODULE( x )->clazz +#define FT_MODULE_LIBRARY( x ) FT_MODULE( x )->library +#define FT_MODULE_MEMORY( x ) FT_MODULE( x )->memory +#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_FONT_DRIVER ) +#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_RENDERER ) +#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_HINTER ) +#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_STYLER ) +#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_SCALABLE ) +#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_NO_OUTLINES ) +#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \ + FT_MODULE_DRIVER_HAS_HINTER ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Module_Interface */ +/* */ +/* <Description> */ +/* Finds a module and returns its specific interface as a typeless */ +/* pointer. */ +/* */ +/* <Input> */ +/* library :: A handle to the library object. */ +/* */ +/* module_name :: The module's name (as an ASCII string). */ +/* */ +/* <Return> */ +/* A module-specific interface if available, 0 otherwise. */ +/* */ +/* <Note> */ +/* You should better be familiar with FreeType internals to know */ +/* which module to look for, and what its interface is :-) */ +/* */ + FT_BASE( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ); + FT_BASE( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id ); +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** F A C E, S I Z E & G L Y P H S L O T O B J E C T S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* a few macros used to perform easy typecasts with minimal brain damage */ +#define FT_FACE( x ) ((FT_Face)(x)) +#define FT_SIZE( x ) ((FT_Size)(x)) +#define FT_SLOT( x ) ((FT_GlyphSlot)(x)) +#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver +#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library +#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory +#define FT_FACE_STREAM( x ) FT_FACE( x )->stream +#define FT_SIZE_FACE( x ) FT_SIZE( x )->face +#define FT_SLOT_FACE( x ) FT_SLOT( x )->face +#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph +#define FT_FACE_SIZE( x ) FT_FACE( x )->size +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_GlyphSlot */ +/* */ +/* <Description> */ +/* It is sometimes useful to have more than one glyph slot for a */ +/* given face object. This function is used to create additional */ +/* slots. All of them are automatically discarded when the face is */ +/* destroyed. */ +/* */ +/* <Input> */ +/* face :: A handle to a parent face object. */ +/* */ +/* <Output> */ +/* aslot :: A handle to a new glyph slot object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_BASE( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_GlyphSlot */ +/* */ +/* <Description> */ +/* Destroys a given glyph slot. Remember however that all slots are */ +/* automatically destroyed with its parent. Using this function is */ +/* not always mandatory. */ +/* */ +/* <Input> */ +/* slot :: A handle to a target glyph slot. */ +/* */ + FT_BASE( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ); +/* */ +#define FT_REQUEST_WIDTH( req ) \ + ( (req)->horiResolution \ + ? (FT_Pos)( (req)->width * (req)->horiResolution + 36 ) / 72 \ + : (req)->width ) +#define FT_REQUEST_HEIGHT( req ) \ + ( (req)->vertResolution \ + ? (FT_Pos)( (req)->height * (req)->vertResolution + 36 ) / 72 \ + : (req)->height ) +/* Set the metrics according to a bitmap strike. */ + FT_BASE( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ); +/* Set the metrics according to a size request. */ + FT_BASE( void ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ); +/* Match a size request against `available_sizes'. */ + FT_BASE( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ); +/* Use the horizontal metrics to synthesize the vertical metrics. */ +/* If `advance' is zero, it is also synthesized. */ + FT_BASE( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ); +/* Free the bitmap of a given glyphslot when needed (i.e., only when it */ +/* was allocated with ft_glyphslot_alloc_bitmap). */ + FT_BASE( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ); +/* Allocate a new bitmap buffer in a glyph slot. */ + FT_BASE( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ); +/* Set the bitmap buffer in a glyph slot to a given pointer. The buffer */ +/* will not be freed by a later call to ft_glyphslot_free_bitmap. */ + FT_BASE( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ); +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** R E N D E R E R S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +#define FT_RENDERER( x ) ((FT_Renderer)( x )) +#define FT_GLYPH( x ) ((FT_Glyph)( x )) +#define FT_BITMAP_GLYPH( x ) ((FT_BitmapGlyph)( x )) +#define FT_OUTLINE_GLYPH( x ) ((FT_OutlineGlyph)( x )) + typedef struct FT_RendererRec_ + { + FT_ModuleRec root; + FT_Renderer_Class* clazz; + FT_Glyph_Format glyph_format; + FT_Glyph_Class glyph_class; + FT_Raster raster; + FT_Raster_Render_Func raster_render; + FT_Renderer_RenderFunc render; + } FT_RendererRec; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** F O N T D R I V E R S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* typecast a module into a driver easily */ +#define FT_DRIVER( x ) ((FT_Driver)(x)) +/* typecast a module as a driver, and get its driver class */ +#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_DriverRec */ +/* */ +/* <Description> */ +/* The root font driver class. A font driver is responsible for */ +/* managing and loading font files of a given format. */ +/* */ +/* <Fields> */ +/* root :: Contains the fields of the root module class. */ +/* */ +/* clazz :: A pointer to the font driver's class. Note that */ +/* this is NOT root.clazz. `class' wasn't used */ +/* as it is a reserved word in C++. */ +/* */ +/* faces_list :: The list of faces currently opened by this */ +/* driver. */ +/* */ +/* glyph_loader :: The glyph loader for all faces managed by this */ +/* driver. This object isn't defined for unscalable */ +/* formats. */ +/* */ + typedef struct FT_DriverRec_ + { + FT_ModuleRec root; + FT_Driver_Class clazz; + FT_ListRec faces_list; + FT_GlyphLoader glyph_loader; + } FT_DriverRec; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** L I B R A R I E S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* This hook is used by the TrueType debugger. It must be set to an */ +/* alternate truetype bytecode interpreter function. */ +#define FT_DEBUG_HOOK_TRUETYPE 0 +/* Set this debug hook to a non-null pointer to force unpatented hinting */ +/* for all faces when both TT_USE_BYTECODE_INTERPRETER and */ +/* TT_CONFIG_OPTION_UNPATENTED_HINTING are defined. This is only used */ +/* during debugging. */ +#define FT_DEBUG_HOOK_UNPATENTED_HINTING 1 + typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + FT_Library library ); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_LibraryRec */ +/* */ +/* <Description> */ +/* The FreeType library class. This is the root of all FreeType */ +/* data. Use FT_New_Library() to create a library object, and */ +/* FT_Done_Library() to discard it and all child objects. */ +/* */ +/* <Fields> */ +/* memory :: The library's memory object. Manages memory */ +/* allocation. */ +/* */ +/* version_major :: The major version number of the library. */ +/* */ +/* version_minor :: The minor version number of the library. */ +/* */ +/* version_patch :: The current patch level of the library. */ +/* */ +/* num_modules :: The number of modules currently registered */ +/* within this library. This is set to 0 for new */ +/* libraries. New modules are added through the */ +/* FT_Add_Module() API function. */ +/* */ +/* modules :: A table used to store handles to the currently */ +/* registered modules. Note that each font driver */ +/* contains a list of its opened faces. */ +/* */ +/* renderers :: The list of renderers currently registered */ +/* within the library. */ +/* */ +/* cur_renderer :: The current outline renderer. This is a */ +/* shortcut used to avoid parsing the list on */ +/* each call to FT_Outline_Render(). It is a */ +/* handle to the current renderer for the */ +/* FT_GLYPH_FORMAT_OUTLINE format. */ +/* */ +/* auto_hinter :: XXX */ +/* */ +/* raster_pool :: The raster object's render pool. This can */ +/* ideally be changed dynamically at run-time. */ +/* */ +/* raster_pool_size :: The size of the render pool in bytes. */ +/* */ +/* debug_hooks :: XXX */ +/* */ +/* lcd_filter :: If subpixel rendering is activated, the */ +/* selected LCD filter mode. */ +/* */ +/* lcd_extra :: If subpixel rendering is activated, the number */ +/* of extra pixels needed for the LCD filter. */ +/* */ +/* lcd_weights :: If subpixel rendering is activated, the LCD */ +/* filter weights, if any. */ +/* */ +/* lcd_filter_func :: If subpixel rendering is activated, the LCD */ +/* filtering callback function. */ +/* */ +/* pic_container :: Contains global structs and tables, instead */ +/* of defining them globallly. */ +/* */ +/* refcount :: A counter initialized to~1 at the time an */ +/* @FT_Library structure is created. */ +/* @FT_Reference_Library increments this counter, */ +/* and @FT_Done_Library only destroys a library */ +/* if the counter is~1, otherwise it simply */ +/* decrements it. */ +/* */ + typedef struct FT_LibraryRec_ + { +/* library's memory manager */ + FT_Memory memory; + FT_Int version_major; + FT_Int version_minor; + FT_Int version_patch; + FT_UInt num_modules; +/* module objects */ + FT_Module modules[FT_MAX_MODULES]; +/* list of renderers */ + FT_ListRec renderers; +/* current outline renderer */ + FT_Renderer cur_renderer; + FT_Module auto_hinter; +/* scan-line conversion */ + FT_Byte* raster_pool; +/* render pool */ +/* size of render pool in bytes */ + FT_ULong raster_pool_size; + FT_DebugHook_Func debug_hooks[4]; + FT_LcdFilter lcd_filter; +/* number of extra pixels */ + FT_Int lcd_extra; +/* filter weights, if any */ + FT_Byte lcd_weights[7]; +/* filtering callback */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; + FT_UInt refcount; + } FT_LibraryRec; + FT_BASE( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ); + FT_BASE( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ); + typedef const char* + (*FT_Face_GetPostscriptNameFunc)( FT_Face face ); + typedef FT_Error + (*FT_Face_GetGlyphNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + typedef FT_UInt + (*FT_Face_GetGlyphNameIndexFunc)( FT_Face face, + FT_String* glyph_name ); +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Memory */ +/* */ +/* <Description> */ +/* Creates a new memory object. */ +/* */ +/* <Return> */ +/* A pointer to the new memory object. 0 in case of error. */ +/* */ + FT_BASE( FT_Memory ) + FT_New_Memory( void ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Done_Memory */ +/* */ +/* <Description> */ +/* Discards memory manager. */ +/* */ +/* <Input> */ +/* memory :: A handle to the memory manager. */ +/* */ + FT_BASE( void ) + FT_Done_Memory( FT_Memory memory ); +/* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ +#endif +/* Define default raster's interface. The default raster is located in */ +/* `src/base/ftraster.c'. */ +/* */ +/* Client applications can register new rasters through the */ +/* FT_Set_Raster() API. */ +#ifndef FT_NO_DEFAULT_RASTER + FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster; +#endif +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** P I C S U P P O R T ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* PIC support macros for ftimage.h */ +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DEFINE_OUTLINE_FUNCS */ +/* */ +/* <Description> */ +/* Used to initialize an instance of FT_Outline_Funcs struct. */ +/* When FT_CONFIG_OPTION_PIC is defined an init funtion will need to */ +/* be called with a pre-allocated structure to be filled. */ +/* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ +/* allocated in the global scope (or the scope where the macro */ +/* is used). */ +/* */ +#define FT_DEFINE_OUTLINE_FUNCS( \ + class_, \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ ) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DEFINE_RASTER_FUNCS */ +/* */ +/* <Description> */ +/* Used to initialize an instance of FT_Raster_Funcs struct. */ +/* When FT_CONFIG_OPTION_PIC is defined an init funtion will need to */ +/* be called with a pre-allocated structure to be filled. */ +/* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ +/* allocated in the global scope (or the scope where the macro */ +/* is used). */ +/* */ +#define FT_DEFINE_RASTER_FUNCS( \ + class_, \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; +/* PIC support macros for ftrender.h */ +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DEFINE_GLYPH */ +/* */ +/* <Description> */ +/* Used to initialize an instance of FT_Glyph_Class struct. */ +/* When FT_CONFIG_OPTION_PIC is defined an init funtion will need to */ +/* be called with a pre-allocated stcture to be filled. */ +/* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ +/* allocated in the global scope (or the scope where the macro */ +/* is used). */ +/* */ +#define FT_DEFINE_GLYPH( \ + class_, \ + size_, \ + format_, \ + init_, \ + done_, \ + copy_, \ + transform_, \ + bbox_, \ + prepare_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Glyph_Class class_ = \ + { \ + size_, \ + format_, \ + init_, \ + done_, \ + copy_, \ + transform_, \ + bbox_, \ + prepare_ \ + }; +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DECLARE_RENDERER */ +/* */ +/* <Description> */ +/* Used to create a forward declaration of a */ +/* FT_Renderer_Class struct instance. */ +/* */ +/* <Macro> */ +/* FT_DEFINE_RENDERER */ +/* */ +/* <Description> */ +/* Used to initialize an instance of FT_Renderer_Class struct. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is defined a `create' funtion will need */ +/* to be called with a pointer where the allocated structure is */ +/* returned. And when it is no longer needed a `destroy' function */ +/* needs to be called to release that allocation. */ +/* `fcinit.c' (ft_create_default_module_classes) already contains */ +/* a mechanism to call these functions for the default modules */ +/* described in `ftmodule.h'. */ +/* */ +/* Notice that the created `create' and `destroy' functions call */ +/* `pic_init' and `pic_free' to allow you to manually allocate and */ +/* initialize any additional global data, like a module specific */ +/* interface, and put them in the global pic container defined in */ +/* `ftpic.h'. If you don't need them just implement the functions as */ +/* empty to resolve the link error. Also the `pic_init' and */ +/* `pic_free' functions should be declared in `pic.h', to be referred */ +/* by the renderer definition calling `FT_DEFINE_RENDERER' in the */ +/* following. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ +/* allocated in the global scope (or the scope where the macro */ +/* is used). */ +/* */ +#define FT_DECLARE_RENDERER( class_ ) \ + FT_EXPORT_VAR( const FT_Renderer_Class ) class_; +#define FT_DEFINE_RENDERER( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_, \ + glyph_format_, \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + raster_class_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Renderer_Class class_ = \ + { \ + FT_DEFINE_ROOT_MODULE( flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + glyph_format_, \ + \ + render_glyph_, \ + transform_glyph_, \ + get_glyph_cbox_, \ + set_mode_, \ + \ + raster_class_ \ + }; +/* PIC support macros for ftmodapi.h **/ +/*************************************************************************/ +/* */ +/* <Macro> */ +/* FT_DECLARE_MODULE */ +/* */ +/* <Description> */ +/* Used to create a forward declaration of a */ +/* FT_Module_Class struct instance. */ +/* */ +/* <Macro> */ +/* FT_DEFINE_MODULE */ +/* */ +/* <Description> */ +/* Used to initialize an instance of an FT_Module_Class struct. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is defined a `create' funtion needs to */ +/* be called with a pointer where the allocated structure is */ +/* returned. And when it is no longer needed a `destroy' function */ +/* needs to be called to release that allocation. */ +/* `fcinit.c' (ft_create_default_module_classes) already contains */ +/* a mechanism to call these functions for the default modules */ +/* described in `ftmodule.h'. */ +/* */ +/* Notice that the created `create' and `destroy' functions call */ +/* `pic_init' and `pic_free' to allow you to manually allocate and */ +/* initialize any additional global data, like a module specific */ +/* interface, and put them in the global pic container defined in */ +/* `ftpic.h'. If you don't need them just implement the functions as */ +/* empty to resolve the link error. Also the `pic_init' and */ +/* `pic_free' functions should be declared in `pic.h', to be referred */ +/* by the module definition calling `FT_DEFINE_MODULE' in the */ +/* following. */ +/* */ +/* When FT_CONFIG_OPTION_PIC is not defined the struct will be */ +/* allocated in the global scope (or the scope where the macro */ +/* is used). */ +/* */ +/* <Macro> */ +/* FT_DEFINE_ROOT_MODULE */ +/* */ +/* <Description> */ +/* Used to initialize an instance of an FT_Module_Class struct inside */ +/* another struct that contains it or in a function that initializes */ +/* that containing struct. */ +/* */ +#define FT_DECLARE_MODULE( class_ ) \ + FT_CALLBACK_TABLE \ + const FT_Module_Class class_; +#define FT_DEFINE_ROOT_MODULE( \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }, +#define FT_DEFINE_MODULE( \ + class_, \ + flags_, \ + size_, \ + name_, \ + version_, \ + requires_, \ + interface_, \ + init_, \ + done_, \ + get_interface_ ) \ + FT_CALLBACK_TABLE_DEF \ + const FT_Module_Class class_ = \ + { \ + flags_, \ + size_, \ + \ + name_, \ + version_, \ + requires_, \ + \ + interface_, \ + \ + init_, \ + done_, \ + get_interface_, \ + }; +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/* format of an 8-bit frame_op value: */ +/* */ +/* bit 76543210 */ +/* xxxxxxes */ +/* */ +/* s is set to 1 if the value is signed. */ +/* e is set to 1 if the value is little-endian. */ +/* xxx is a command. */ +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT ) +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign ) +#define FT_FRAME_OP_END 0 +/* start a new frame */ +#define FT_FRAME_OP_START 1 +/* read 1-byte value */ +#define FT_FRAME_OP_BYTE 2 +/* read 2-byte value */ +#define FT_FRAME_OP_SHORT 3 +/* read 4-byte value */ +#define FT_FRAME_OP_LONG 4 +/* read 3-byte value */ +#define FT_FRAME_OP_OFF3 5 +/* read a bytes sequence */ +#define FT_FRAME_OP_BYTES 6 + typedef enum FT_Frame_Op_ + { + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ), + ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 ) + } FT_Frame_Op; + typedef struct FT_Frame_Field_ + { + FT_Byte value; + FT_Byte size; + FT_UShort offset; + } FT_Frame_Field; +/* Construct an FT_Frame_Field out of a structure type and a field name. */ +/* The structure type must be set in the FT_STRUCTURE macro before */ +/* calling the FT_FRAME_START() macro. */ +/* */ +#define FT_FIELD_SIZE( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f ) +#define FT_FIELD_SIZE_DELTA( f ) \ + (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] ) +#define FT_FIELD_OFFSET( f ) \ + (FT_UShort)( offsetof( FT_STRUCTURE, f ) ) +#define FT_FRAME_FIELD( frame_op, field ) \ + { \ + frame_op, \ + FT_FIELD_SIZE( field ), \ + FT_FIELD_OFFSET( field ) \ + } +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } +#define FT_FRAME_START( size ) { ft_frame_start, 0, size } +#define FT_FRAME_END { ft_frame_end, 0, 0 } +#define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f ) +#define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f ) +#define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f ) +#define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f ) +#define FT_FRAME_OFF3( f ) FT_FRAME_FIELD( ft_frame_off3_be, f ) +#define FT_FRAME_UOFF3( f ) FT_FRAME_FIELD( ft_frame_uoff3_be, f ) +#define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f ) +#define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f ) +#define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f ) +#define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f ) +#define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f ) +#define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f ) +#define FT_FRAME_OFF3_LE( f ) FT_FRAME_FIELD( ft_frame_off3_le, f ) +#define FT_FRAME_UOFF3_LE( f ) FT_FRAME_FIELD( ft_frame_uoff3_le, f ) +#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 } +#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 } +#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 } +#define FT_FRAME_BYTES( field, count ) \ + { \ + ft_frame_bytes, \ + count, \ + FT_FIELD_OFFSET( field ) \ + } +#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 } +/*************************************************************************/ +/* */ +/* Integer extraction macros -- the `buffer' parameter must ALWAYS be of */ +/* type `char*' or equivalent (1-byte elements). */ +/* */ +#define FT_BYTE_( p, i ) ( ((const FT_Byte*)(p))[(i)] ) +#define FT_INT8_( p, i ) ( ((const FT_Char*)(p))[(i)] ) +#define FT_INT16( x ) ( (FT_Int16)(x) ) +#define FT_UINT16( x ) ( (FT_UInt16)(x) ) +#define FT_INT32( x ) ( (FT_Int32)(x) ) +#define FT_UINT32( x ) ( (FT_UInt32)(x) ) +#define FT_BYTE_I16( p, i, s ) ( FT_INT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U16( p, i, s ) ( FT_UINT16( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_I32( p, i, s ) ( FT_INT32( FT_BYTE_( p, i ) ) << (s) ) +#define FT_BYTE_U32( p, i, s ) ( FT_UINT32( FT_BYTE_( p, i ) ) << (s) ) +#define FT_INT8_I16( p, i, s ) ( FT_INT16( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_U16( p, i, s ) ( FT_UINT16( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_I32( p, i, s ) ( FT_INT32( FT_INT8_( p, i ) ) << (s) ) +#define FT_INT8_U32( p, i, s ) ( FT_UINT32( FT_INT8_( p, i ) ) << (s) ) +#define FT_PEEK_SHORT( p ) FT_INT16( FT_INT8_I16( p, 0, 8) | \ + FT_BYTE_I16( p, 1, 0) ) +#define FT_PEEK_USHORT( p ) FT_UINT16( FT_BYTE_U16( p, 0, 8 ) | \ + FT_BYTE_U16( p, 1, 0 ) ) +#define FT_PEEK_LONG( p ) FT_INT32( FT_INT8_I32( p, 0, 24 ) | \ + FT_BYTE_I32( p, 1, 16 ) | \ + FT_BYTE_I32( p, 2, 8 ) | \ + FT_BYTE_I32( p, 3, 0 ) ) +#define FT_PEEK_ULONG( p ) FT_UINT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) | \ + FT_BYTE_U32( p, 3, 0 ) ) +#define FT_PEEK_OFF3( p ) FT_INT32( FT_INT8_I32( p, 0, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 2, 0 ) ) +#define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 2, 0 ) ) +#define FT_PEEK_SHORT_LE( p ) FT_INT16( FT_INT8_I16( p, 1, 8 ) | \ + FT_BYTE_I16( p, 0, 0 ) ) +#define FT_PEEK_USHORT_LE( p ) FT_UINT16( FT_BYTE_U16( p, 1, 8 ) | \ + FT_BYTE_U16( p, 0, 0 ) ) +#define FT_PEEK_LONG_LE( p ) FT_INT32( FT_INT8_I32( p, 3, 24 ) | \ + FT_BYTE_I32( p, 2, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 0, 0 ) ) +#define FT_PEEK_ULONG_LE( p ) FT_UINT32( FT_BYTE_U32( p, 3, 24 ) | \ + FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) +#define FT_PEEK_OFF3_LE( p ) FT_INT32( FT_INT8_I32( p, 2, 16 ) | \ + FT_BYTE_I32( p, 1, 8 ) | \ + FT_BYTE_I32( p, 0, 0 ) ) +#define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ + FT_BYTE_U32( p, 1, 8 ) | \ + FT_BYTE_U32( p, 0, 0 ) ) +#define FT_NEXT_CHAR( buffer ) \ + ( (signed char)*buffer++ ) +#define FT_NEXT_BYTE( buffer ) \ + ( (unsigned char)*buffer++ ) +#define FT_NEXT_SHORT( buffer ) \ + ( (short)( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) ) +#define FT_NEXT_USHORT( buffer ) \ + ( (unsigned short)( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) ) +#define FT_NEXT_OFF3( buffer ) \ + ( (long)( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) ) +#define FT_NEXT_UOFF3( buffer ) \ + ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) ) +#define FT_NEXT_LONG( buffer ) \ + ( (long)( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) ) +#define FT_NEXT_ULONG( buffer ) \ + ( (unsigned long)( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) ) +#define FT_NEXT_SHORT_LE( buffer ) \ + ( (short)( buffer += 2, FT_PEEK_SHORT_LE( buffer - 2 ) ) ) +#define FT_NEXT_USHORT_LE( buffer ) \ + ( (unsigned short)( buffer += 2, FT_PEEK_USHORT_LE( buffer - 2 ) ) ) +#define FT_NEXT_OFF3_LE( buffer ) \ + ( (long)( buffer += 3, FT_PEEK_OFF3_LE( buffer - 3 ) ) ) +#define FT_NEXT_UOFF3_LE( buffer ) \ + ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3_LE( buffer - 3 ) ) ) +#define FT_NEXT_LONG_LE( buffer ) \ + ( (long)( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) ) +#define FT_NEXT_ULONG_LE( buffer ) \ + ( (unsigned long)( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) ) +/*************************************************************************/ +/* */ +/* Each GET_xxxx() macro uses an implicit `stream' variable. */ +/* */ +#if 0 +#define FT_GET_MACRO( type ) FT_NEXT_ ## type ( stream->cursor ) +#define FT_GET_CHAR() FT_GET_MACRO( CHAR ) +#define FT_GET_BYTE() FT_GET_MACRO( BYTE ) +#define FT_GET_SHORT() FT_GET_MACRO( SHORT ) +#define FT_GET_USHORT() FT_GET_MACRO( USHORT ) +#define FT_GET_OFF3() FT_GET_MACRO( OFF3 ) +#define FT_GET_UOFF3() FT_GET_MACRO( UOFF3 ) +#define FT_GET_LONG() FT_GET_MACRO( LONG ) +#define FT_GET_ULONG() FT_GET_MACRO( ULONG ) +#define FT_GET_TAG4() FT_GET_MACRO( ULONG ) +#define FT_GET_SHORT_LE() FT_GET_MACRO( SHORT_LE ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( USHORT_LE ) +#define FT_GET_LONG_LE() FT_GET_MACRO( LONG_LE ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( ULONG_LE ) +#else +#define FT_GET_MACRO( func, type ) ( (type)func( stream ) ) +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetChar, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetChar, FT_Byte ) +#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Short ) +#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UShort ) +#define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_Long ) +#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_ULong ) +#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Long ) +#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) +#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) +#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Short ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UShort ) +#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Long ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_ULong ) +#endif +#define FT_READ_MACRO( func, type, var ) \ + ( var = (type)func( stream, &error ), \ + error != FT_Err_Ok ) +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadChar, FT_Char, var ) +#define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_Short, var ) +#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UShort, var ) +#define FT_READ_OFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_Long, var ) +#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_ULong, var ) +#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Long, var ) +#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_ULong, var ) +#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_Short, var ) +#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_UShort, var ) +#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_Long, var ) +#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_ULong, var ) +#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM +/* initialize a stream for reading a regular system stream */ + FT_BASE( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ); +/* FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */ +#endif +/* create a new (input) stream from an FT_Open_Args structure */ + FT_BASE( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ); +/* free a stream */ + FT_BASE( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ); +/* initialize a stream for reading in-memory data */ + FT_BASE( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ); +/* close a stream (does not destroy the stream structure) */ + FT_BASE( void ) + FT_Stream_Close( FT_Stream stream ); +/* seek within a stream. position is relative to start of stream */ + FT_BASE( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ); +/* skip bytes in a stream */ + FT_BASE( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ); +/* return current stream position */ + FT_BASE( FT_Long ) + FT_Stream_Pos( FT_Stream stream ); +/* read bytes from a stream into a user-allocated buffer, returns an */ +/* error if not all bytes could be read. */ + FT_BASE( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); +/* read bytes from a stream at a given position */ + FT_BASE( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ); +/* try to read bytes at the end of a stream; return number of bytes */ +/* really available */ + FT_BASE( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ); +/* Enter a frame of `count' consecutive bytes in a stream. Returns an */ +/* error if the frame could not be read/accessed. The caller can use */ +/* the FT_Stream_Get_XXX functions to retrieve frame data without */ +/* error checks. */ +/* */ +/* You must _always_ call FT_Stream_ExitFrame() once you have entered */ +/* a stream frame! */ +/* */ + FT_BASE( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ); +/* exit a stream frame */ + FT_BASE( void ) + FT_Stream_ExitFrame( FT_Stream stream ); +/* Extract a stream frame. If the stream is disk-based, a heap block */ +/* is allocated and the frame bytes are read into it. If the stream */ +/* is memory-based, this function simply set a pointer to the data. */ +/* */ +/* Useful to optimize access to memory-based streams transparently. */ +/* */ +/* All extracted frames must be `freed' with a call to the function */ +/* FT_Stream_ReleaseFrame(). */ +/* */ + FT_BASE( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ); +/* release an extract frame (see FT_Stream_ExtractFrame) */ + FT_BASE( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ); +/* read a byte from an entered frame */ + FT_BASE( FT_Char ) + FT_Stream_GetChar( FT_Stream stream ); +/* read a 16-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_UShort ) + FT_Stream_GetUShort( FT_Stream stream ); +/* read a 24-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_ULong ) + FT_Stream_GetUOffset( FT_Stream stream ); +/* read a 32-bit big-endian unsigned integer from an entered frame */ + FT_BASE( FT_ULong ) + FT_Stream_GetULong( FT_Stream stream ); +/* read a 16-bit little-endian unsigned integer from an entered frame */ + FT_BASE( FT_UShort ) + FT_Stream_GetUShortLE( FT_Stream stream ); +/* read a 32-bit little-endian unsigned integer from an entered frame */ + FT_BASE( FT_ULong ) + FT_Stream_GetULongLE( FT_Stream stream ); +/* read a byte from a stream */ + FT_BASE( FT_Char ) + FT_Stream_ReadChar( FT_Stream stream, + FT_Error* error ); +/* read a 16-bit big-endian unsigned integer from a stream */ + FT_BASE( FT_UShort ) + FT_Stream_ReadUShort( FT_Stream stream, + FT_Error* error ); +/* read a 24-bit big-endian unsigned integer from a stream */ + FT_BASE( FT_ULong ) + FT_Stream_ReadUOffset( FT_Stream stream, + FT_Error* error ); +/* read a 32-bit big-endian integer from a stream */ + FT_BASE( FT_ULong ) + FT_Stream_ReadULong( FT_Stream stream, + FT_Error* error ); +/* read a 16-bit little-endian unsigned integer from a stream */ + FT_BASE( FT_UShort ) + FT_Stream_ReadUShortLE( FT_Stream stream, + FT_Error* error ); +/* read a 32-bit little-endian unsigned integer from a stream */ + FT_BASE( FT_ULong ) + FT_Stream_ReadULongLE( FT_Stream stream, + FT_Error* error ); +/* Read a structure from a stream. The structure must be described */ +/* by an array of FT_Frame_Field records. */ + FT_BASE( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); +#define FT_STREAM_POS() \ + FT_Stream_Pos( stream ) +#define FT_STREAM_SEEK( position ) \ + FT_SET_ERROR( FT_Stream_Seek( stream, position ) ) +#define FT_STREAM_SKIP( distance ) \ + FT_SET_ERROR( FT_Stream_Skip( stream, distance ) ) +#define FT_STREAM_READ( buffer, count ) \ + FT_SET_ERROR( FT_Stream_Read( stream, \ + (FT_Byte*)buffer, \ + count ) ) +#define FT_STREAM_READ_AT( position, buffer, count ) \ + FT_SET_ERROR( FT_Stream_ReadAt( stream, \ + position, \ + (FT_Byte*)buffer, \ + count ) ) +#define FT_STREAM_READ_FIELDS( fields, object ) \ + FT_SET_ERROR( FT_Stream_ReadFields( stream, fields, object ) ) +#define FT_FRAME_ENTER( size ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_EnterFrame( stream, size ) ) ) +#define FT_FRAME_EXIT() \ + FT_DEBUG_INNER( FT_Stream_ExitFrame( stream ) ) +#define FT_FRAME_EXTRACT( size, bytes ) \ + FT_SET_ERROR( \ + FT_DEBUG_INNER( FT_Stream_ExtractFrame( stream, size, \ + (FT_Byte**)&(bytes) ) ) ) +#define FT_FRAME_RELEASE( bytes ) \ + FT_DEBUG_INNER( FT_Stream_ReleaseFrame( stream, \ + (FT_Byte**)&(bytes) ) ) +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/*************************************************************************/ +/* */ +/* MEMORY MANAGEMENT INTERFACE */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* It is not necessary to do any error checking for the */ +/* allocation-related functions. This will be done by the higher level */ +/* routines like ft_mem_alloc() or ft_mem_realloc(). */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_alloc */ +/* */ +/* <Description> */ +/* The memory allocation function. */ +/* */ +/* <Input> */ +/* memory :: A pointer to the memory object. */ +/* */ +/* size :: The requested size in bytes. */ +/* */ +/* <Return> */ +/* The address of newly allocated block. */ +/* */ + FT_CALLBACK_DEF( void* ) + ft_alloc( FT_Memory memory, + long size ) + { + FT_UNUSED( memory ); + return ft_smalloc( size ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_realloc */ +/* */ +/* <Description> */ +/* The memory reallocation function. */ +/* */ +/* <Input> */ +/* memory :: A pointer to the memory object. */ +/* */ +/* cur_size :: The current size of the allocated memory block. */ +/* */ +/* new_size :: The newly requested size in bytes. */ +/* */ +/* block :: The current address of the block in memory. */ +/* */ +/* <Return> */ +/* The address of the reallocated memory block. */ +/* */ + FT_CALLBACK_DEF( void* ) + ft_realloc( FT_Memory memory, + long cur_size, + long new_size, + void* block ) + { + FT_UNUSED( memory ); + FT_UNUSED( cur_size ); + return ft_srealloc( block, new_size ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_free */ +/* */ +/* <Description> */ +/* The memory release function. */ +/* */ +/* <Input> */ +/* memory :: A pointer to the memory object. */ +/* */ +/* block :: The address of block in memory to be freed. */ +/* */ + FT_CALLBACK_DEF( void ) + ft_free( FT_Memory memory, + void* block ) + { + FT_UNUSED( memory ); + ft_sfree( block ); + } +/*************************************************************************/ +/* */ +/* RESOURCE MANAGEMENT INTERFACE */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* 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 trace_io +/* We use the macro STREAM_FILE for convenience to extract the */ +/* system-specific stream handle from a given FreeType stream object */ +#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_ansi_stream_close */ +/* */ +/* <Description> */ +/* The function to close a stream. */ +/* */ +/* <Input> */ +/* stream :: A pointer to the stream object. */ +/* */ + FT_CALLBACK_DEF( void ) + ft_ansi_stream_close( FT_Stream stream ) + { + ft_fclose( STREAM_FILE( stream ) ); + stream->descriptor.pointer = NULL; + stream->size = 0; + stream->base = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_ansi_stream_io */ +/* */ +/* <Description> */ +/* The function to open a stream. */ +/* */ +/* <Input> */ +/* stream :: A pointer to the stream object. */ +/* */ +/* offset :: The position in the data stream to start reading. */ +/* */ +/* buffer :: The address of buffer to store the read data. */ +/* */ +/* count :: The number of bytes to read from the stream. */ +/* */ +/* <Return> */ +/* The number of bytes actually read. If `count' is zero (this is, */ +/* the function is used for seeking), a non-zero return value */ +/* indicates an error. */ +/* */ + FT_CALLBACK_DEF( unsigned long ) + ft_ansi_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_FILE* file; + if ( !count && offset > stream->size ) + return 1; + file = STREAM_FILE( stream ); + if ( stream->pos != offset ) + ft_fseek( file, offset, SEEK_SET ); + return (unsigned long)ft_fread( buffer, 1, count, file ); + } +/* documentation is in ftstream.h */ + FT_BASE_DEF( FT_Error ) + FT_Stream_Open( FT_Stream stream, + const char* filepathname ) + { + FT_FILE* file; + if ( !stream ) + return FT_Err_Invalid_Stream_Handle; + stream->descriptor.pointer = NULL; + stream->pathname.pointer = (char*)filepathname; + stream->base = 0; + stream->pos = 0; + stream->read = NULL; + stream->close = NULL; + file = ft_fopen( filepathname, "rb" ); + if ( !file ) + { + FT_ERROR(( "FT_Stream_Open:" + " could not open `%s'\n", filepathname )); + return FT_Err_Cannot_Open_Resource; + } + ft_fseek( file, 0, SEEK_END ); + stream->size = ft_ftell( file ); + if ( !stream->size ) + { + FT_ERROR(( "FT_Stream_Open:" )); + FT_ERROR(( " opened `%s' but zero-sized\n", filepathname )); + ft_fclose( file ); + return FT_Err_Cannot_Open_Stream; + } + ft_fseek( file, 0, SEEK_SET ); + stream->descriptor.pointer = file; + stream->read = ft_ansi_stream_io; + stream->close = ft_ansi_stream_close; + FT_TRACE1(( "FT_Stream_Open:" )); + FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + filepathname, stream->size )); + return FT_Err_Ok; + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( FT_Memory ) + FT_New_Memory( void ) + { + FT_Memory memory; + memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) ); + if ( memory ) + { + memory->user = 0; + memory->alloc = ft_alloc; + memory->realloc = ft_realloc; + memory->free = ft_free; + } + return memory; + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( void ) + FT_Done_Memory( FT_Memory memory ) + { + ft_sfree( memory ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ftinit.c */ +/* */ +/* FreeType initialization layer (body). */ +/* */ +/* Copyright 1996-2002, 2005, 2007, 2009, 2012 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 purpose of this file is to implement the following two */ +/* functions: */ +/* */ +/* FT_Add_Default_Modules(): */ +/* This function is used to add the set of default modules to a */ +/* fresh new library object. The set is taken from the header file */ +/* `freetype/config/ftmodule.h'. See the document `FreeType 2.0 */ +/* Build System' for more information. */ +/* */ +/* FT_Init_FreeType(): */ +/* This function creates a system object for the current platform, */ +/* builds a library out of it, then calls FT_Default_Drivers(). */ +/* */ +/* Note that even if FT_Init_FreeType() uses the implementation of the */ +/* system object defined at build time, client applications are still */ +/* able to provide their own `ftsystem.c'. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* basepic.h */ +/* */ +/* The FreeType position independent code services for base. */ +/* */ +/* Copyright 2009 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __BASEPIC_H__ +FT_BEGIN_HEADER +#define FT_OUTLINE_GLYPH_CLASS_GET &ft_outline_glyph_class +#define FT_BITMAP_GLYPH_CLASS_GET &ft_bitmap_glyph_class +#define FT_DEFAULT_MODULES_GET ft_default_modules +#define FT_RACCESS_GUESS_TABLE_GET ft_raccess_guess_table +/* */ +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_init +#undef FT_USE_MODULE +#ifdef __cplusplus +#define FT_USE_MODULE( type, x ) extern "C" const type x; +#else +#define FT_USE_MODULE( type, x ) extern const type x; +#endif +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `<topdir>/objs/') based on information + * from `<topdir>/modules.cfg'. + * + * Please read `docs/INSTALL.ANY' and `docs/CUSTOMIZE' how to compile + * FreeType without GNU make. + * + */ +FT_USE_MODULE( FT_Module_Class, autofit_module_class ) +FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +FT_USE_MODULE( FT_Module_Class, psaux_module_class ) +FT_USE_MODULE( FT_Module_Class, psnames_module_class ) +FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcd_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcdv_renderer_class ) +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +/* EOF */ +#undef FT_USE_MODULE +#define FT_USE_MODULE( type, x ) (const FT_Module_Class*)&(x), + static + const FT_Module_Class* const ft_default_modules[] = + { +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `<topdir>/objs/') based on information + * from `<topdir>/modules.cfg'. + * + * Please read `docs/INSTALL.ANY' and `docs/CUSTOMIZE' how to compile + * FreeType without GNU make. + * + */ +FT_USE_MODULE( FT_Module_Class, autofit_module_class ) +FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +FT_USE_MODULE( FT_Module_Class, psaux_module_class ) +FT_USE_MODULE( FT_Module_Class, psnames_module_class ) +FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcd_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcdv_renderer_class ) +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +/* EOF */ + 0 + }; +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( void ) + FT_Add_Default_Modules( FT_Library library ) + { + FT_Error error; + const FT_Module_Class* const* cur; +/* FT_DEFAULT_MODULES_GET dereferences `library' in PIC mode */ +/* GCC 4.6 warns the type difference: + * FT_Module_Class** != const FT_Module_Class* const* + */ + cur = (const FT_Module_Class* const*)FT_DEFAULT_MODULES_GET; +/* test for valid `library' delayed to FT_Add_Module() */ + while ( *cur ) + { + error = FT_Add_Module( library, *cur ); +/* notify errors, but don't stop */ + if ( error ) + FT_TRACE0(( "FT_Add_Default_Module:" + " Cannot install `%s', error = 0x%x\n", + (*cur)->module_name, error )); + cur++; + } + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Init_FreeType( FT_Library *alibrary ) + { + FT_Error error; + FT_Memory memory; +/* First of all, allocate a new system object -- this function is part */ +/* of the system-specific component, i.e. `ftsystem.c'. */ + memory = FT_New_Memory(); + if ( !memory ) + { + FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" )); + return FT_Err_Unimplemented_Feature; + } +/* build a library out of it, then fill it with the set of */ +/* default drivers. */ + error = FT_New_Library( memory, alibrary ); + if ( error ) + FT_Done_Memory( memory ); + else + FT_Add_Default_Modules( *alibrary ); + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Done_FreeType( FT_Library library ) + { + if ( library ) + { + FT_Memory memory = library->memory; +/* Discard the library object */ + FT_Done_Library( library ); +/* discard memory manager */ + FT_Done_Memory( memory ); + } + return FT_Err_Ok; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftdebug.c */ +/* */ +/* Debugging and logging component (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2008 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 contains various macros and functions used to ease the */ +/* debugging of the FreeType engine. Its main purpose is in assertion */ +/* checking, tracing, and error detection. */ +/* */ +/* There are now three debugging modes: */ +/* */ +/* - trace mode */ +/* */ +/* Error and trace messages are sent to the log file (which can be the */ +/* standard error output). */ +/* */ +/* - error mode */ +/* */ +/* Only error messages are generated. */ +/* */ +/* - release mode: */ +/* */ +/* No error message is sent or generated. The code is free from any */ +/* debugging parts. */ +/* */ +/*************************************************************************/ + FT_BASE_DEF( void ) + ft_debug_init( void ) + { +/* nothing */ + } + FT_BASE_DEF( FT_Int ) + FT_Trace_Get_Count( void ) + { + return 0; + } + FT_BASE_DEF( const char * ) + FT_Trace_Get_Name( FT_Int idx ) + { + FT_UNUSED( idx ); + return NULL; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftbase.c */ +/* */ +/* Single object library component (body only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* ftpic.c */ +/* */ +/* The FreeType position independent code services (body). */ +/* */ +/* Copyright 2009 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/* END */ +/***************************************************************************/ +/* */ +/* basepic.c */ +/* */ +/* The FreeType position independent code services for base. */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/* END */ +/***************************************************************************/ +/* */ +/* ftadvanc.c */ +/* */ +/* Quick computation of advance widths (body). */ +/* */ +/* Copyright 2008, 2009, 2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftadvanc.h */ +/* */ +/* Quick computation of advance widths (specification only). */ +/* */ +/* Copyright 2008 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. */ +/* */ +/***************************************************************************/ +#define __FTADVANC_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 +FT_BEGIN_HEADER +/************************************************************************** + * + * @section: + * quick_advance + * + * @title: + * Quick retrieval of advance values + * + * @abstract: + * Retrieve horizontal and vertical advance values without processing + * glyph outlines, if possible. + * + * @description: + * This section contains functions to quickly extract advance values + * without handling glyph outlines, if possible. + */ +/*************************************************************************/ +/* */ +/* <Const> */ +/* FT_ADVANCE_FLAG_FAST_ONLY */ +/* */ +/* <Description> */ +/* A bit-flag to be OR-ed with the `flags' parameter of the */ +/* @FT_Get_Advance and @FT_Get_Advances functions. */ +/* */ +/* If set, it indicates that you want these functions to fail if the */ +/* corresponding hinting mode or font driver doesn't allow for very */ +/* quick advance computation. */ +/* */ +/* Typically, glyphs which are either unscaled, unhinted, bitmapped, */ +/* or light-hinted can have their advance width computed very */ +/* quickly. */ +/* */ +/* Normal and bytecode hinted modes, which require loading, scaling, */ +/* and hinting of the glyph outline, are extremely slow by */ +/* comparison. */ +/* */ +#define FT_ADVANCE_FLAG_FAST_ONLY 0x20000000UL +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Advance */ +/* */ +/* <Description> */ +/* Retrieve the advance value of a given glyph outline in an */ +/* @FT_Face. By default, the unhinted advance is returned in font */ +/* units. */ +/* */ +/* <Input> */ +/* face :: The source @FT_Face handle. */ +/* */ +/* gindex :: The glyph index. */ +/* */ +/* load_flags :: A set of bit flags similar to those used when */ +/* calling @FT_Load_Glyph, used to determine what kind */ +/* of advances you need. */ +/* <Output> */ +/* padvance :: The advance value, in either font units or 16.16 */ +/* format. */ +/* */ +/* If @FT_LOAD_VERTICAL_LAYOUT is set, this is the */ +/* vertical advance corresponding to a vertical layout. */ +/* Otherwise, it is the horizontal advance in a */ +/* horizontal layout. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and */ +/* if the corresponding font backend doesn't have a quick way to */ +/* retrieve the advances. */ +/* */ +/* A scaled advance is returned in 16.16 format but isn't transformed */ +/* by the affine transformation specified by @FT_Set_Transform. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Advance( FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags, + FT_Fixed *padvance ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Advances */ +/* */ +/* <Description> */ +/* Retrieve the advance values of several glyph outlines in an */ +/* @FT_Face. By default, the unhinted advances are returned in font */ +/* units. */ +/* */ +/* <Input> */ +/* face :: The source @FT_Face handle. */ +/* */ +/* start :: The first glyph index. */ +/* */ +/* count :: The number of advance values you want to retrieve. */ +/* */ +/* load_flags :: A set of bit flags similar to those used when */ +/* calling @FT_Load_Glyph. */ +/* */ +/* <Output> */ +/* padvance :: The advances, in either font units or 16.16 format. */ +/* This array must contain at least `count' elements. */ +/* */ +/* If @FT_LOAD_VERTICAL_LAYOUT is set, these are the */ +/* vertical advances corresponding to a vertical layout. */ +/* Otherwise, they are the horizontal advances in a */ +/* horizontal layout. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* This function may fail if you use @FT_ADVANCE_FLAG_FAST_ONLY and */ +/* if the corresponding font backend doesn't have a quick way to */ +/* retrieve the advances. */ +/* */ +/* Scaled advances are returned in 16.16 format but aren't */ +/* transformed by the affine transformation specified by */ +/* @FT_Set_Transform. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed *padvances ); +/* */ +FT_END_HEADER +/* END */ + 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 == NULL ) + return FT_Err_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 */ +#define LOAD_ADVANCE_FAST_CHECK( 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_Err_Invalid_Face_Handle; + if ( gindex >= (FT_UInt)face->num_glyphs ) + return FT_Err_Invalid_Glyph_Index; + func = face->driver->clazz->get_advances; + if ( func && LOAD_ADVANCE_FAST_CHECK( flags ) ) + { + FT_Error error; + error = func( face, gindex, 1, flags, padvance ); + if ( !error ) + return _ft_face_scale_advances( face, padvance, 1, flags ); + if ( error != FT_ERROR_BASE( FT_Err_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_Face_GetAdvancesFunc func; + FT_UInt num, end, nn; + FT_Error error = FT_Err_Ok; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + num = (FT_UInt)face->num_glyphs; + end = start + count; + if ( start >= num || end < start || end > num ) + return FT_Err_Invalid_Glyph_Index; + if ( count == 0 ) + return FT_Err_Ok; + func = face->driver->clazz->get_advances; + if ( func && LOAD_ADVANCE_FAST_CHECK( flags ) ) + { + error = func( face, start, count, flags, padvances ); + if ( !error ) + return _ft_face_scale_advances( face, padvances, count, flags ); + if ( error != FT_ERROR_BASE( FT_Err_Unimplemented_Feature ) ) + return error; + } + error = FT_Err_Ok; + if ( flags & FT_ADVANCE_FLAG_FAST_ONLY ) + return FT_Err_Unimplemented_Feature; + flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; + for ( nn = 0; nn < count; nn++ ) + { + error = FT_Load_Glyph( face, start + nn, flags ); + if ( error ) + break; +/* scale from 26.6 to 16.16 */ + padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) + ? face->glyph->advance.y << 10 + : face->glyph->advance.x << 10; + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftcalc.c */ +/* */ +/* Arithmetic computations (body). */ +/* */ +/* Copyright 1996-2006, 2008, 2012 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* Support for 1-complement arithmetic has been totally dropped in this */ +/* release. You can still write your own code if you need it. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Implementing basic computation routines. */ +/* */ +/* FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), */ +/* and FT_FloorFix() are declared in freetype.h. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* ftcalc.h */ +/* */ +/* Arithmetic computations (specification). */ +/* */ +/* Copyright 1996-2006, 2008, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __FTCALC_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_FixedSqrt */ +/* */ +/* <Description> */ +/* Computes the square root of a 16.16 fixed point value. */ +/* */ +/* <Input> */ +/* x :: The value to compute the root for. */ +/* */ +/* <Return> */ +/* The result of `sqrt(x)'. */ +/* */ +/* <Note> */ +/* This function is not very fast. */ +/* */ + FT_BASE( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ); +/*************************************************************************/ +/* */ +/* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_MulDiv_No_Round */ +/* */ +/* <Description> */ +/* A very simple function used to perform the computation `(a*b)/c' */ +/* (without rounding) with maximum accuracy (it uses a 64-bit */ +/* intermediate integer whenever necessary). */ +/* */ +/* This function isn't necessarily as fast as some processor specific */ +/* operations, but is at least completely portable. */ +/* */ +/* <Input> */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. */ +/* c :: The divisor. */ +/* */ +/* <Return> */ +/* The result of `(a*b)/c'. This function never traps when trying to */ +/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ +/* on the signs of `a' and `b'. */ +/* */ + FT_BASE( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ); +/* + * A variant of FT_Matrix_Multiply which scales its result afterwards. + * The idea is that both `a' and `b' are scaled by factors of 10 so that + * the values are as precise as possible to get a correct result during + * the 64bit multiplication. Let `sa' and `sb' be the scaling factors of + * `a' and `b', respectively, then the scaling factor of the result is + * `sa*sb'. + */ + FT_BASE( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ); +/* + * A variant of FT_Vector_Transform. See comments for + * FT_Matrix_Multiply_Scaled. + */ + FT_BASE( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ); +/* + * Return -1, 0, or +1, depending on the orientation of a given corner. + * We use the Cartesian coordinate system, with positive vertical values + * going upwards. The function returns +1 if the corner turns to the + * left, -1 to the right, and 0 for undecidable cases. + */ + FT_BASE( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); +/* + * Return TRUE if a corner is flat or nearly flat. This is equivalent to + * saying that the angle difference between the `in' and `out' vectors is + * very small. + */ + FT_BASE( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ); +#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 ) +#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 ) +#define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 ) +#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) << 2 ) +#define FLOAT_TO_FIXED( x ) ( (FT_Long)( x * 65536.0 ) ) +#define FIXED_TO_INT( x ) ( FT_RoundFix( x ) >> 16 ) +#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \ + : ( -( ( 32 - (x) ) & -64 ) ) ) +FT_END_HEADER +/* END */ +#ifdef FT_MULFIX_INLINED +#undef FT_MulFix +#endif +/* we need to define a 64-bits data type here */ +#ifdef FT_LONG64 + typedef FT_INT64 FT_Int64; +#else + typedef struct FT_Int64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + } FT_Int64; +/* FT_LONG64 */ +#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 trace_calc +/* The following three functions are available regardless of whether */ +/* FT_LONG64 is defined. */ +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_RoundFix( FT_Fixed a ) + { + return ( a >= 0 ) ? ( a + 0x8000L ) & ~0xFFFFL + : -((-a + 0x8000L ) & ~0xFFFFL ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_CeilFix( FT_Fixed a ) + { + return ( a >= 0 ) ? ( a + 0xFFFFL ) & ~0xFFFFL + : -((-a + 0xFFFFL ) & ~0xFFFFL ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_FloorFix( FT_Fixed a ) + { + return ( a >= 0 ) ? a & ~0xFFFFL + : -((-a) & ~0xFFFFL ); + } +#ifdef FT_LONG64 +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFL ); + return ( s > 0 ) ? d : -d; + } +/* documentation is in ftcalc.h */ + FT_BASE_DEF( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + d = (FT_Long)( c > 0 ? (FT_Int64)a * b / c + : 0x7FFFFFFFL ); + return ( s > 0 ) ? d : -d; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ) + { +#ifdef FT_MULFIX_ASSEMBLER + return FT_MULFIX_ASSEMBLER( a, b ); +#else + FT_Int s = 1; + FT_Long c; + if ( a < 0 ) + { + a = -a; + s = -1; + } + if ( b < 0 ) + { + b = -b; + s = -s; + } + c = (FT_Long)( ( (FT_Int64)a * b + 0x8000L ) >> 16 ); + return ( s > 0 ) ? c : -c; +/* FT_MULFIX_ASSEMBLER */ +#endif + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ) + { + FT_Int32 s; + FT_UInt32 q; + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( b == 0 ) +/* check for division by 0 */ + q = 0x7FFFFFFFL; + else +/* compute result directly */ + q = (FT_UInt32)( ( ( (FT_Int64)a << 16 ) + ( b >> 1 ) ) / b ); + return ( s < 0 ? -(FT_Long)q : (FT_Long)q ); + } +/* !FT_LONG64 */ +#else + static void + ft_multo64( FT_UInt32 x, + FT_UInt32 y, + FT_Int64 *z ) + { + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + lo1 = x & 0x0000FFFFU; hi1 = x >> 16; + lo2 = y & 0x0000FFFFU; hi2 = y >> 16; + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; +/* Check carry overflow of i1 + i2 */ + i1 += i2; + hi += (FT_UInt32)( i1 < i2 ) << 16; + hi += i1 >> 16; + i1 = i1 << 16; +/* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + z->lo = lo; + z->hi = hi; + } + static FT_UInt32 + ft_div64by32( FT_UInt32 hi, + FT_UInt32 lo, + FT_UInt32 y ) + { + FT_UInt32 r, q; + FT_Int i; + q = 0; + r = hi; + if ( r >= y ) + return (FT_UInt32)0x7FFFFFFFL; + i = 32; + do + { + r <<= 1; + q <<= 1; + r |= lo >> 31; + if ( r >= y ) + { + r -= y; + q |= 1; + } + lo <<= 1; + } while ( --i ); + return q; + } + static void + FT_Add64( FT_Int64* x, + FT_Int64* y, + FT_Int64 *z ) + { + register FT_UInt32 lo, hi; + lo = x->lo + y->lo; + hi = x->hi + y->hi + ( lo < x->lo ); + z->lo = lo; + z->hi = hi; + } +/* documentation is in freetype.h */ +/* The FT_MulDiv function has been optimized thanks to ideas from */ +/* Graham Asher. The trick is to optimize computation when everything */ +/* fits within 32-bits (a rather common case). */ +/* */ +/* we compute 'a*b+c/2', then divide it by 'c'. (positive values) */ +/* */ +/* 46340 is FLOOR(SQRT(2^31-1)). */ +/* */ +/* if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 ) */ +/* */ +/* 0x7FFFFFFF - 0x7FFEA810 = 0x157F0 */ +/* */ +/* if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF ) */ +/* */ +/* and 2*0x157F0 = 176096 */ +/* */ + FT_EXPORT_DEF( FT_Long ) + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + long s; +/* XXX: this function does not allow 64-bit arguments */ + if ( a == 0 || b == c ) + return a; + s = a; a = FT_ABS( a ); + s ^= b; b = FT_ABS( b ); + s ^= c; c = FT_ABS( c ); + if ( a <= 46340L && b <= 46340L && c <= 176095L && c > 0 ) + a = ( a * b + ( c >> 1 ) ) / c; + else if ( (FT_Int32)c > 0 ) + { + FT_Int64 temp, temp2; + ft_multo64( (FT_Int32)a, (FT_Int32)b, &temp ); + temp2.hi = 0; + temp2.lo = (FT_UInt32)(c >> 1); + FT_Add64( &temp, &temp2, &temp ); + a = ft_div64by32( temp.hi, temp.lo, (FT_Int32)c ); + } + else + a = 0x7FFFFFFFL; + return ( s < 0 ? -a : a ); + } + FT_BASE_DEF( FT_Long ) + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ) + { + long s; + if ( a == 0 || b == c ) + return a; + s = a; a = FT_ABS( a ); + s ^= b; b = FT_ABS( b ); + s ^= c; c = FT_ABS( c ); + if ( a <= 46340L && b <= 46340L && c > 0 ) + a = a * b / c; + else if ( (FT_Int32)c > 0 ) + { + FT_Int64 temp; + ft_multo64( (FT_Int32)a, (FT_Int32)b, &temp ); + a = ft_div64by32( temp.hi, temp.lo, (FT_Int32)c ); + } + else + a = 0x7FFFFFFFL; + return ( s < 0 ? -a : a ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Long ) + FT_MulFix( FT_Long a, + FT_Long b ) + { +#ifdef FT_MULFIX_ASSEMBLER + return FT_MULFIX_ASSEMBLER( a, b ); +#elif 0 +/* + * This code is nonportable. See comment below. + * + * However, on a platform where right-shift of a signed quantity fills + * the leftmost bits by copying the sign bit, it might be faster. + */ + FT_Long sa, sb; + FT_ULong ua, ub; + if ( a == 0 || b == 0x10000L ) + return a; +/* + * This is a clever way of converting a signed number `a' into its + * absolute value (stored back into `a') and its sign. The sign is + * stored in `sa'; 0 means `a' was positive or zero, and -1 means `a' + * was negative. (Similarly for `b' and `sb'). + * + * Unfortunately, it doesn't work (at least not portably). + * + * It makes the assumption that right-shift on a negative signed value + * fills the leftmost bits by copying the sign bit. This is wrong. + * According to K&R 2nd ed, section `A7.8 Shift Operators' on page 206, + * the result of right-shift of a negative signed value is + * implementation-defined. At least one implementation fills the + * leftmost bits with 0s (i.e., it is exactly the same as an unsigned + * right shift). This means that when `a' is negative, `sa' ends up + * with the value 1 rather than -1. After that, everything else goes + * wrong. + */ + sa = ( a >> ( sizeof ( a ) * 8 - 1 ) ); + a = ( a ^ sa ) - sa; + sb = ( b >> ( sizeof ( b ) * 8 - 1 ) ); + b = ( b ^ sb ) - sb; + ua = (FT_ULong)a; + ub = (FT_ULong)b; + if ( ua <= 2048 && ub <= 1048576L ) + ua = ( ua * ub + 0x8000U ) >> 16; + else + { + FT_ULong al = ua & 0xFFFFU; + ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) + + ( ( al * ( ub & 0xFFFFU ) + 0x8000U ) >> 16 ); + } + sa ^= sb, + ua = (FT_ULong)(( ua ^ sa ) - sa); + return (FT_Long)ua; +/* 0 */ +#else + FT_Long s; + FT_ULong ua, ub; + if ( a == 0 || b == 0x10000L ) + return a; + s = a; a = FT_ABS( a ); + s ^= b; b = FT_ABS( b ); + ua = (FT_ULong)a; + ub = (FT_ULong)b; + if ( ua <= 2048 && ub <= 1048576L ) + ua = ( ua * ub + 0x8000UL ) >> 16; + else + { + FT_ULong al = ua & 0xFFFFUL; + ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) + + ( ( al * ( ub & 0xFFFFUL ) + 0x8000UL ) >> 16 ); + } + return ( s < 0 ? -(FT_Long)ua : (FT_Long)ua ); +/* 0 */ +#endif + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Long ) + FT_DivFix( FT_Long a, + FT_Long b ) + { + FT_Int32 s; + FT_UInt32 q; +/* XXX: this function does not allow 64-bit arguments */ + s = (FT_Int32)a; a = FT_ABS( a ); + s ^= (FT_Int32)b; b = FT_ABS( b ); + if ( (FT_UInt32)b == 0 ) + { +/* check for division by 0 */ + q = (FT_UInt32)0x7FFFFFFFL; + } + else if ( ( a >> 16 ) == 0 ) + { +/* compute result directly */ + q = (FT_UInt32)( ( a << 16 ) + ( b >> 1 ) ) / (FT_UInt32)b; + } + else + { +/* we need more bits; we have to do it by hand */ + FT_Int64 temp, temp2; + temp.hi = (FT_Int32) ( a >> 16 ); + temp.lo = (FT_UInt32)( a << 16 ); + temp2.hi = 0; + temp2.lo = (FT_UInt32)( b >> 1 ); + FT_Add64( &temp, &temp2, &temp ); + q = ft_div64by32( temp.hi, temp.lo, (FT_Int32)b ); + } + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } +#if 0 +/* documentation is in ftcalc.h */ + FT_EXPORT_DEF( void ) + FT_MulTo64( FT_Int32 x, + FT_Int32 y, + FT_Int64 *z ) + { + FT_Int32 s; + s = x; x = FT_ABS( x ); + s ^= y; y = FT_ABS( y ); + ft_multo64( x, y, z ); + if ( s < 0 ) + { + z->lo = (FT_UInt32)-(FT_Int32)z->lo; + z->hi = ~z->hi + !( z->lo ); + } + } +/* apparently, the second version of this code is not compiled correctly */ +/* on Mac machines with the MPW C compiler.. tsk, tsk, tsk... */ +#if 1 + FT_EXPORT_DEF( FT_Int32 ) + FT_Div64by32( FT_Int64* x, + FT_Int32 y ) + { + FT_Int32 s; + FT_UInt32 q, r, i, lo; + s = x->hi; + if ( s < 0 ) + { + x->lo = (FT_UInt32)-(FT_Int32)x->lo; + x->hi = ~x->hi + !x->lo; + } + s ^= y; y = FT_ABS( y ); +/* Shortcut */ + if ( x->hi == 0 ) + { + if ( y > 0 ) + q = x->lo / y; + else + q = 0x7FFFFFFFL; + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } + r = x->hi; + lo = x->lo; +/* we know y is to be treated as unsigned here */ + if ( r >= (FT_UInt32)y ) + return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL ); +/* Return Max/Min Int32 if division overflow. */ +/* This includes division by zero! */ + q = 0; + for ( i = 0; i < 32; i++ ) + { + r <<= 1; + q <<= 1; + r |= lo >> 31; + if ( r >= (FT_UInt32)y ) + { + r -= y; + q |= 1; + } + lo <<= 1; + } + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } +/* 0 */ +#else + FT_EXPORT_DEF( FT_Int32 ) + FT_Div64by32( FT_Int64* x, + FT_Int32 y ) + { + FT_Int32 s; + FT_UInt32 q; + s = x->hi; + if ( s < 0 ) + { + x->lo = (FT_UInt32)-(FT_Int32)x->lo; + x->hi = ~x->hi + !x->lo; + } + s ^= y; y = FT_ABS( y ); +/* Shortcut */ + if ( x->hi == 0 ) + { + if ( y > 0 ) + q = ( x->lo + ( y >> 1 ) ) / y; + else + q = 0x7FFFFFFFL; + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } + q = ft_div64by32( x->hi, x->lo, y ); + return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); + } +/* 0 */ +#endif +/* 0 */ +#endif +/* FT_LONG64 */ +#endif +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( void ) + FT_Matrix_Multiply( const FT_Matrix* a, + FT_Matrix *b ) + { + FT_Fixed xx, xy, yx, yy; + if ( !a || !b ) + return; + xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx ); + xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy ); + yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx ); + yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy ); + b->xx = xx; b->xy = xy; + b->yx = yx; b->yy = yy; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Matrix_Invert( FT_Matrix* matrix ) + { + FT_Pos delta, xx, yy; + if ( !matrix ) + return FT_Err_Invalid_Argument; +/* compute discriminant */ + delta = FT_MulFix( matrix->xx, matrix->yy ) - + FT_MulFix( matrix->xy, matrix->yx ); + if ( !delta ) +/* matrix can't be inverted */ + return FT_Err_Invalid_Argument; + matrix->xy = - FT_DivFix( matrix->xy, delta ); + matrix->yx = - FT_DivFix( matrix->yx, delta ); + xx = matrix->xx; + yy = matrix->yy; + matrix->xx = FT_DivFix( yy, delta ); + matrix->yy = FT_DivFix( xx, delta ); + return FT_Err_Ok; + } +/* documentation is in ftcalc.h */ + FT_BASE_DEF( void ) + FT_Matrix_Multiply_Scaled( const FT_Matrix* a, + FT_Matrix *b, + FT_Long scaling ) + { + FT_Fixed xx, xy, yx, yy; + FT_Long val = 0x10000L * scaling; + if ( !a || !b ) + return; + xx = FT_MulDiv( a->xx, b->xx, val ) + FT_MulDiv( a->xy, b->yx, val ); + xy = FT_MulDiv( a->xx, b->xy, val ) + FT_MulDiv( a->xy, b->yy, val ); + yx = FT_MulDiv( a->yx, b->xx, val ) + FT_MulDiv( a->yy, b->yx, val ); + yy = FT_MulDiv( a->yx, b->xy, val ) + FT_MulDiv( a->yy, b->yy, val ); + b->xx = xx; b->xy = xy; + b->yx = yx; b->yy = yy; + } +/* documentation is in ftcalc.h */ + FT_BASE_DEF( void ) + FT_Vector_Transform_Scaled( FT_Vector* vector, + const FT_Matrix* matrix, + FT_Long scaling ) + { + FT_Pos xz, yz; + FT_Long val = 0x10000L * scaling; + if ( !vector || !matrix ) + return; + xz = FT_MulDiv( vector->x, matrix->xx, val ) + + FT_MulDiv( vector->y, matrix->xy, val ); + yz = FT_MulDiv( vector->x, matrix->yx, val ) + + FT_MulDiv( vector->y, matrix->yy, val ); + vector->x = xz; + vector->y = yz; + } +/* documentation is in ftcalc.h */ + FT_BASE_DEF( FT_Int32 ) + FT_SqrtFixed( FT_Int32 x ) + { + FT_UInt32 root, rem_hi, rem_lo, test_div; + FT_Int count; + root = 0; + if ( x > 0 ) + { + rem_hi = 0; + rem_lo = x; + count = 24; + do + { + rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 ); + rem_lo <<= 2; + root <<= 1; + test_div = ( root << 1 ) + 1; + if ( rem_hi >= test_div ) + { + rem_hi -= test_div; + root += 1; + } + } while ( --count ); + } + return (FT_Int32)root; + } +/* documentation is in ftcalc.h */ + FT_BASE_DEF( FT_Int ) + ft_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { +/* avoid overflow on 16-bit system */ + FT_Long result; +/* deal with the trivial cases quickly */ + if ( in_y == 0 ) + { + if ( in_x >= 0 ) + result = out_y; + else + result = -out_y; + } + else if ( in_x == 0 ) + { + if ( in_y >= 0 ) + result = -out_x; + else + result = out_x; + } + else if ( out_y == 0 ) + { + if ( out_x >= 0 ) + result = in_y; + else + result = -in_y; + } + else if ( out_x == 0 ) + { + if ( out_y >= 0 ) + result = -in_x; + else + result = in_x; + } +/* general case */ + else + { +#ifdef FT_LONG64 + FT_Int64 delta = (FT_Int64)in_x * out_y - (FT_Int64)in_y * out_x; + if ( delta == 0 ) + result = 0; + else + result = 1 - 2 * ( delta < 0 ); +#else + FT_Int64 z1, z2; +/* XXX: this function does not allow 64-bit arguments */ + ft_multo64( (FT_Int32)in_x, (FT_Int32)out_y, &z1 ); + ft_multo64( (FT_Int32)in_y, (FT_Int32)out_x, &z2 ); + if ( z1.hi > z2.hi ) + result = +1; + else if ( z1.hi < z2.hi ) + result = -1; + else if ( z1.lo > z2.lo ) + result = +1; + else if ( z1.lo < z2.lo ) + result = -1; + else + result = 0; +#endif + } +/* XXX: only the sign of return value, +1/0/-1 must be used */ + return (FT_Int)result; + } +/* documentation is in ftcalc.h */ + FT_BASE_DEF( FT_Int ) + ft_corner_is_flat( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { + FT_Pos ax = in_x; + FT_Pos ay = in_y; + FT_Pos d_in, d_out, d_corner; + if ( ax < 0 ) + ax = -ax; + if ( ay < 0 ) + ay = -ay; + d_in = ax + ay; + ax = out_x; + if ( ax < 0 ) + ax = -ax; + ay = out_y; + if ( ay < 0 ) + ay = -ay; + d_out = ax + ay; + ax = out_x + in_x; + if ( ax < 0 ) + ax = -ax; + ay = out_y + in_y; + if ( ay < 0 ) + ay = -ay; + d_corner = ax + ay; + return ( d_in + d_out - d_corner ) < ( d_corner >> 4 ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ftdbgmem.c */ +/* */ +/* Memory debugger (body). */ +/* */ +/* Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* ANSI C doesn't like empty source files */ + typedef int _debug_mem_dummy; +/* END */ +/***************************************************************************/ +/* */ +/* ftgloadr.c */ +/* */ +/* The FreeType glyph loader (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2010 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_COMPONENT +#define FT_COMPONENT trace_gloader +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** *****/ +/***** G L Y P H L O A D E R *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* The glyph loader is a simple object which is used to load a set of */ +/* glyphs easily. It is critical for the correct loading of composites. */ +/* */ +/* Ideally, one can see it as a stack of abstract `glyph' objects. */ +/* */ +/* loader.base Is really the bottom of the stack. It describes a */ +/* single glyph image made of the juxtaposition of */ +/* several glyphs (those `in the stack'). */ +/* */ +/* loader.current Describes the top of the stack, on which a new */ +/* glyph can be loaded. */ +/* */ +/* Rewind Clears the stack. */ +/* Prepare Set up `loader.current' for addition of a new glyph */ +/* image. */ +/* Add Add the `current' glyph image to the `base' one, */ +/* and prepare for another one. */ +/* */ +/* The glyph loader is now a base object. Each driver used to */ +/* re-implement it in one way or the other, which wasted code and */ +/* energy. */ +/* */ +/*************************************************************************/ +/* create a new glyph loader */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_New( FT_Memory memory, + FT_GlyphLoader *aloader ) + { + FT_GlyphLoader loader = NULL; + FT_Error error; + if ( !FT_NEW( loader ) ) + { + loader->memory = memory; + *aloader = loader; + } + return error; + } +/* rewind the glyph loader - reset counters to 0 */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Rewind( FT_GlyphLoader loader ) + { + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + base->outline.n_points = 0; + base->outline.n_contours = 0; + base->num_subglyphs = 0; + *current = *base; + } +/* reset the glyph loader, frees all allocated tables */ +/* and starts from zero */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Reset( FT_GlyphLoader loader ) + { + FT_Memory memory = loader->memory; + FT_FREE( loader->base.outline.points ); + FT_FREE( loader->base.outline.tags ); + FT_FREE( loader->base.outline.contours ); + FT_FREE( loader->base.extra_points ); + FT_FREE( loader->base.subglyphs ); + loader->base.extra_points2 = NULL; + loader->max_points = 0; + loader->max_contours = 0; + loader->max_subglyphs = 0; + FT_GlyphLoader_Rewind( loader ); + } +/* delete a glyph loader */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Done( FT_GlyphLoader loader ) + { + if ( loader ) + { + FT_Memory memory = loader->memory; + FT_GlyphLoader_Reset( loader ); + FT_FREE( loader ); + } + } +/* re-adjust the `current' outline fields */ + static void + FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader ) + { + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + current->points = base->points + base->n_points; + current->tags = base->tags + base->n_points; + current->contours = base->contours + base->n_contours; +/* handle extra points table - if any */ + if ( loader->use_extra ) + { + loader->current.extra_points = loader->base.extra_points + + base->n_points; + loader->current.extra_points2 = loader->base.extra_points2 + + base->n_points; + } + } + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader ) + { + FT_Error error; + FT_Memory memory = loader->memory; + if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) + { + loader->use_extra = 1; + loader->base.extra_points2 = loader->base.extra_points + + loader->max_points; + FT_GlyphLoader_Adjust_Points( loader ); + } + return error; + } +/* re-adjust the `current' subglyphs field */ + static void + FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader ) + { + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + current->subglyphs = base->subglyphs + base->num_subglyphs; + } +/* Ensure that we can add `n_points' and `n_contours' to our glyph. */ +/* This function reallocates its outline tables if necessary. Note that */ +/* it DOESN'T change the number of points within the loader! */ +/* */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader, + FT_UInt n_points, + FT_UInt n_contours ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_Outline* base = &loader->base.outline; + FT_Outline* current = &loader->current.outline; + FT_Bool adjust = 0; + FT_UInt new_max, old_max; +/* check points & tags */ + new_max = base->n_points + current->n_points + n_points; + old_max = loader->max_points; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( new_max > FT_OUTLINE_POINTS_MAX ) + return FT_Err_Array_Too_Large; + if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || + FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) + goto Exit; + if ( loader->use_extra ) + { + if ( FT_RENEW_ARRAY( loader->base.extra_points, + old_max * 2, new_max * 2 ) ) + goto Exit; + FT_ARRAY_MOVE( loader->base.extra_points + new_max, + loader->base.extra_points + old_max, + old_max ); + loader->base.extra_points2 = loader->base.extra_points + new_max; + } + adjust = 1; + loader->max_points = new_max; + } +/* check contours */ + old_max = loader->max_contours; + new_max = base->n_contours + current->n_contours + + n_contours; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 4 ); + if ( new_max > FT_OUTLINE_CONTOURS_MAX ) + return FT_Err_Array_Too_Large; + if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) + goto Exit; + adjust = 1; + loader->max_contours = new_max; + } + if ( adjust ) + FT_GlyphLoader_Adjust_Points( loader ); + Exit: + return error; + } +/* Ensure that we can add `n_subglyphs' to our glyph. this function */ +/* reallocates its subglyphs table if necessary. Note that it DOES */ +/* NOT change the number of subglyphs within the loader! */ +/* */ + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader, + FT_UInt n_subs ) + { + FT_Memory memory = loader->memory; + FT_Error error = FT_Err_Ok; + FT_UInt new_max, old_max; + FT_GlyphLoad base = &loader->base; + FT_GlyphLoad current = &loader->current; + new_max = base->num_subglyphs + current->num_subglyphs + n_subs; + old_max = loader->max_subglyphs; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 2 ); + if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) ) + goto Exit; + loader->max_subglyphs = new_max; + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } + Exit: + return error; + } +/* prepare loader for the addition of a new glyph on top of the base one */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Prepare( FT_GlyphLoader loader ) + { + FT_GlyphLoad current = &loader->current; + current->outline.n_points = 0; + current->outline.n_contours = 0; + current->num_subglyphs = 0; + FT_GlyphLoader_Adjust_Points ( loader ); + FT_GlyphLoader_Adjust_Subglyphs( loader ); + } +/* add current glyph to the base image -- and prepare for another */ + FT_BASE_DEF( void ) + FT_GlyphLoader_Add( FT_GlyphLoader loader ) + { + FT_GlyphLoad base; + FT_GlyphLoad current; + FT_UInt n_curr_contours; + FT_UInt n_base_points; + FT_UInt n; + if ( !loader ) + return; + base = &loader->base; + current = &loader->current; + n_curr_contours = current->outline.n_contours; + n_base_points = base->outline.n_points; + base->outline.n_points = + (short)( base->outline.n_points + current->outline.n_points ); + base->outline.n_contours = + (short)( base->outline.n_contours + current->outline.n_contours ); + base->num_subglyphs += current->num_subglyphs; +/* adjust contours count in newest outline */ + for ( n = 0; n < n_curr_contours; n++ ) + current->outline.contours[n] = + (short)( current->outline.contours[n] + n_base_points ); +/* prepare for another new glyph image */ + FT_GlyphLoader_Prepare( loader ); + } + FT_BASE_DEF( FT_Error ) + FT_GlyphLoader_CopyPoints( FT_GlyphLoader target, + FT_GlyphLoader source ) + { + FT_Error error; + FT_UInt num_points = source->base.outline.n_points; + FT_UInt num_contours = source->base.outline.n_contours; + error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours ); + if ( !error ) + { + FT_Outline* out = &target->base.outline; + FT_Outline* in = &source->base.outline; + FT_ARRAY_COPY( out->points, in->points, + num_points ); + FT_ARRAY_COPY( out->tags, in->tags, + num_points ); + FT_ARRAY_COPY( out->contours, in->contours, + num_contours ); +/* do we need to copy the extra points? */ + if ( target->use_extra && source->use_extra ) + { + FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points, + num_points ); + FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2, + num_points ); + } + out->n_points = (short)num_points; + out->n_contours = (short)num_contours; + FT_GlyphLoader_Adjust_Points( target ); + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftobjs.c */ +/* */ +/* The FreeType private base classes (body). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftlist.h */ +/* */ +/* Generic list support for FreeType (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2007, 2010 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 implements functions relative to list processing. Its */ +/* data structures are defined in `freetype.h'. */ +/* */ +/*************************************************************************/ +#define __FTLIST_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* list_processing */ +/* */ +/* <Title> */ +/* List Processing */ +/* */ +/* <Abstract> */ +/* Simple management of lists. */ +/* */ +/* <Description> */ +/* This section contains various definitions related to list */ +/* processing using doubly-linked nodes. */ +/* */ +/* <Order> */ +/* FT_List */ +/* FT_ListNode */ +/* FT_ListRec */ +/* FT_ListNodeRec */ +/* */ +/* FT_List_Add */ +/* FT_List_Insert */ +/* FT_List_Find */ +/* FT_List_Remove */ +/* FT_List_Up */ +/* FT_List_Iterate */ +/* FT_List_Iterator */ +/* FT_List_Finalize */ +/* FT_List_Destructor */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Find */ +/* */ +/* <Description> */ +/* Find the list node for a given listed object. */ +/* */ +/* <Input> */ +/* list :: A pointer to the parent list. */ +/* data :: The address of the listed object. */ +/* */ +/* <Return> */ +/* List node. NULL if it wasn't found. */ +/* */ + FT_EXPORT( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Add */ +/* */ +/* <Description> */ +/* Append an element to the end of a list. */ +/* */ +/* <InOut> */ +/* list :: A pointer to the parent list. */ +/* node :: The node to append. */ +/* */ + FT_EXPORT( void ) + FT_List_Add( FT_List list, + FT_ListNode node ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Insert */ +/* */ +/* <Description> */ +/* Insert an element at the head of a list. */ +/* */ +/* <InOut> */ +/* list :: A pointer to parent list. */ +/* node :: The node to insert. */ +/* */ + FT_EXPORT( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Remove */ +/* */ +/* <Description> */ +/* Remove a node from a list. This function doesn't check whether */ +/* the node is in the list! */ +/* */ +/* <Input> */ +/* node :: The node to remove. */ +/* */ +/* <InOut> */ +/* list :: A pointer to the parent list. */ +/* */ + FT_EXPORT( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Up */ +/* */ +/* <Description> */ +/* Move a node to the head/top of a list. Used to maintain LRU */ +/* lists. */ +/* */ +/* <InOut> */ +/* list :: A pointer to the parent list. */ +/* node :: The node to move. */ +/* */ + FT_EXPORT( void ) + FT_List_Up( FT_List list, + FT_ListNode node ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_List_Iterator */ +/* */ +/* <Description> */ +/* An FT_List iterator function which is called during a list parse */ +/* by @FT_List_Iterate. */ +/* */ +/* <Input> */ +/* node :: The current iteration list node. */ +/* */ +/* user :: A typeless pointer passed to @FT_List_Iterate. */ +/* Can be used to point to the iteration's state. */ +/* */ + typedef FT_Error + (*FT_List_Iterator)( FT_ListNode node, + void* user ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Iterate */ +/* */ +/* <Description> */ +/* Parse a list and calls a given iterator function on each element. */ +/* Note that parsing is stopped as soon as one of the iterator calls */ +/* returns a non-zero value. */ +/* */ +/* <Input> */ +/* list :: A handle to the list. */ +/* iterator :: An iterator function, called on each node of the list. */ +/* user :: A user-supplied field which is passed as the second */ +/* argument to the iterator. */ +/* */ +/* <Return> */ +/* The result (a FreeType error code) of the last iterator call. */ +/* */ + FT_EXPORT( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* FT_List_Destructor */ +/* */ +/* <Description> */ +/* An @FT_List iterator function which is called during a list */ +/* finalization by @FT_List_Finalize to destroy all elements in a */ +/* given list. */ +/* */ +/* <Input> */ +/* system :: The current system object. */ +/* */ +/* data :: The current object to destroy. */ +/* */ +/* user :: A typeless pointer passed to @FT_List_Iterate. It can */ +/* be used to point to the iteration's state. */ +/* */ + typedef void + (*FT_List_Destructor)( FT_Memory memory, + void* data, + void* user ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_List_Finalize */ +/* */ +/* <Description> */ +/* Destroy all elements in the list as well as the list itself. */ +/* */ +/* <Input> */ +/* list :: A handle to the list. */ +/* */ +/* destroy :: A list destructor that will be applied to each element */ +/* of the list. */ +/* */ +/* memory :: The current memory object which handles deallocation. */ +/* */ +/* user :: A user-supplied field which is passed as the last */ +/* argument to the destructor. */ +/* */ +/* <Note> */ +/* This function expects that all nodes added by @FT_List_Add or */ +/* @FT_List_Insert have been dynamically allocated. */ +/* */ + FT_EXPORT( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftoutln.h */ +/* */ +/* Support for the FT_Outline type used to store glyph shapes of */ +/* most scalable font formats (specification). */ +/* */ +/* Copyright 1996-2003, 2005-2012 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. */ +/* */ +/***************************************************************************/ +#define __FTOUTLN_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* outline_processing */ +/* */ +/* <Title> */ +/* Outline Processing */ +/* */ +/* <Abstract> */ +/* Functions to create, transform, and render vectorial glyph images. */ +/* */ +/* <Description> */ +/* This section contains routines used to create and destroy scalable */ +/* glyph images known as `outlines'. These can also be measured, */ +/* transformed, and converted into bitmaps and pixmaps. */ +/* */ +/* <Order> */ +/* FT_Outline */ +/* FT_OUTLINE_FLAGS */ +/* FT_Outline_New */ +/* FT_Outline_Done */ +/* FT_Outline_Copy */ +/* FT_Outline_Translate */ +/* FT_Outline_Transform */ +/* FT_Outline_Embolden */ +/* FT_Outline_EmboldenXY */ +/* FT_Outline_Reverse */ +/* FT_Outline_Check */ +/* */ +/* FT_Outline_Get_CBox */ +/* FT_Outline_Get_BBox */ +/* */ +/* FT_Outline_Get_Bitmap */ +/* FT_Outline_Render */ +/* */ +/* FT_Outline_Decompose */ +/* FT_Outline_Funcs */ +/* FT_Outline_MoveTo_Func */ +/* FT_Outline_LineTo_Func */ +/* FT_Outline_ConicTo_Func */ +/* FT_Outline_CubicTo_Func */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Decompose */ +/* */ +/* <Description> */ +/* Walk over an outline's structure to decompose it into individual */ +/* segments and Bézier arcs. This function also emits `move to' */ +/* operations to indicate the start of new contours in the outline. */ +/* */ +/* <Input> */ +/* outline :: A pointer to the source target. */ +/* */ +/* func_interface :: A table of `emitters', i.e., function pointers */ +/* called during decomposition to indicate path */ +/* operations. */ +/* */ +/* <InOut> */ +/* user :: A typeless pointer which is passed to each */ +/* emitter during the decomposition. It can be */ +/* used to store the state during the */ +/* decomposition. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_New */ +/* */ +/* <Description> */ +/* Create a new outline of a given size. */ +/* */ +/* <Input> */ +/* library :: A handle to the library object from where the */ +/* outline is allocated. Note however that the new */ +/* outline will *not* necessarily be *freed*, when */ +/* destroying the library, by @FT_Done_FreeType. */ +/* */ +/* numPoints :: The maximum number of points within the outline. */ +/* */ +/* numContours :: The maximum number of contours within the outline. */ +/* */ +/* <Output> */ +/* anoutline :: A handle to the new outline. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The reason why this function takes a `library' parameter is simply */ +/* to use the library's memory allocator. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); + FT_EXPORT( FT_Error ) + FT_Outline_New_Internal( FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Done */ +/* */ +/* <Description> */ +/* Destroy an outline created with @FT_Outline_New. */ +/* */ +/* <Input> */ +/* library :: A handle of the library object used to allocate the */ +/* outline. */ +/* */ +/* outline :: A pointer to the outline object to be discarded. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* If the outline's `owner' field is not set, only the outline */ +/* descriptor will be released. */ +/* */ +/* The reason why this function takes an `library' parameter is */ +/* simply to use ft_mem_free(). */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ); + FT_EXPORT( FT_Error ) + FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Check */ +/* */ +/* <Description> */ +/* Check the contents of an outline descriptor. */ +/* */ +/* <Input> */ +/* outline :: A handle to a source outline. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Check( FT_Outline* outline ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Get_CBox */ +/* */ +/* <Description> */ +/* Return an outline's `control box'. The control box encloses all */ +/* the outline's points, including Bézier control points. Though it */ +/* coincides with the exact bounding box for most glyphs, it can be */ +/* slightly larger in some situations (like when rotating an outline */ +/* which contains Bézier outside arcs). */ +/* */ +/* Computing the control box is very fast, while getting the bounding */ +/* box can take much more time as it needs to walk over all segments */ +/* and arcs in the outline. To get the latter, you can use the */ +/* `ftbbox' component which is dedicated to this single task. */ +/* */ +/* <Input> */ +/* outline :: A pointer to the source outline descriptor. */ +/* */ +/* <Output> */ +/* acbox :: The outline's control box. */ +/* */ +/* <Note> */ +/* See @FT_Glyph_Get_CBox for a discussion of tricky fonts. */ +/* */ + FT_EXPORT( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Translate */ +/* */ +/* <Description> */ +/* Apply a simple translation to the points of an outline. */ +/* */ +/* <InOut> */ +/* outline :: A pointer to the target outline descriptor. */ +/* */ +/* <Input> */ +/* xOffset :: The horizontal offset. */ +/* */ +/* yOffset :: The vertical offset. */ +/* */ + FT_EXPORT( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Copy */ +/* */ +/* <Description> */ +/* Copy an outline into another one. Both objects must have the */ +/* same sizes (number of points & number of contours) when this */ +/* function is called. */ +/* */ +/* <Input> */ +/* source :: A handle to the source outline. */ +/* */ +/* <Output> */ +/* target :: A handle to the target outline. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Transform */ +/* */ +/* <Description> */ +/* Apply a simple 2x2 matrix to all of an outline's points. Useful */ +/* for applying rotations, slanting, flipping, etc. */ +/* */ +/* <InOut> */ +/* outline :: A pointer to the target outline descriptor. */ +/* */ +/* <Input> */ +/* matrix :: A pointer to the transformation matrix. */ +/* */ +/* <Note> */ +/* You can use @FT_Outline_Translate if you need to translate the */ +/* outline's points. */ +/* */ + FT_EXPORT( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Embolden */ +/* */ +/* <Description> */ +/* Embolden an outline. The new outline will be at most 4~times */ +/* `strength' pixels wider and higher. You may think of the left and */ +/* bottom borders as unchanged. */ +/* */ +/* Negative `strength' values to reduce the outline thickness are */ +/* possible also. */ +/* */ +/* <InOut> */ +/* outline :: A handle to the target outline. */ +/* */ +/* <Input> */ +/* strength :: How strong the glyph is emboldened. Expressed in */ +/* 26.6 pixel format. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The used algorithm to increase or decrease the thickness of the */ +/* glyph doesn't change the number of points; this means that certain */ +/* situations like acute angles or intersections are sometimes */ +/* handled incorrectly. */ +/* */ +/* If you need `better' metrics values you should call */ +/* @FT_Outline_Get_CBox or @FT_Outline_Get_BBox. */ +/* */ +/* Example call: */ +/* */ +/* { */ +/* FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); */ +/* if ( face->slot->format == FT_GLYPH_FORMAT_OUTLINE ) */ +/* FT_Outline_Embolden( &face->slot->outline, strength ); */ +/* } */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_EmboldenXY */ +/* */ +/* <Description> */ +/* Embolden an outline. The new outline will be `xstrength' pixels */ +/* wider and `ystrength' pixels higher. Otherwise, it is similar to */ +/* @FT_Outline_Embolden, which uses the same strength in both */ +/* directions. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_EmboldenXY( FT_Outline* outline, + FT_Pos xstrength, + FT_Pos ystrength ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Reverse */ +/* */ +/* <Description> */ +/* Reverse the drawing direction of an outline. This is used to */ +/* ensure consistent fill conventions for mirrored glyphs. */ +/* */ +/* <InOut> */ +/* outline :: A pointer to the target outline descriptor. */ +/* */ +/* <Note> */ +/* This function toggles the bit flag @FT_OUTLINE_REVERSE_FILL in */ +/* the outline's `flags' field. */ +/* */ +/* It shouldn't be used by a normal client application, unless it */ +/* knows what it is doing. */ +/* */ + FT_EXPORT( void ) + FT_Outline_Reverse( FT_Outline* outline ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Get_Bitmap */ +/* */ +/* <Description> */ +/* Render an outline within a bitmap. The outline's image is simply */ +/* OR-ed to the target bitmap. */ +/* */ +/* <Input> */ +/* library :: A handle to a FreeType library object. */ +/* */ +/* outline :: A pointer to the source outline descriptor. */ +/* */ +/* <InOut> */ +/* abitmap :: A pointer to the target bitmap descriptor. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* This function does NOT CREATE the bitmap, it only renders an */ +/* outline image within the one you pass to it! Consequently, the */ +/* various fields in `abitmap' should be set accordingly. */ +/* */ +/* It will use the raster corresponding to the default glyph format. */ +/* */ +/* The value of the `num_grays' field in `abitmap' is ignored. If */ +/* you select the gray-level rasterizer, and you want less than 256 */ +/* gray levels, you have to use @FT_Outline_Render directly. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Render */ +/* */ +/* <Description> */ +/* Render an outline within a bitmap using the current scan-convert. */ +/* This function uses an @FT_Raster_Params structure as an argument, */ +/* allowing advanced features like direct composition, translucency, */ +/* etc. */ +/* */ +/* <Input> */ +/* library :: A handle to a FreeType library object. */ +/* */ +/* outline :: A pointer to the source outline descriptor. */ +/* */ +/* <InOut> */ +/* params :: A pointer to an @FT_Raster_Params structure used to */ +/* describe the rendering operation. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* You should know what you are doing and how @FT_Raster_Params works */ +/* to use this function. */ +/* */ +/* The field `params.source' will be set to `outline' before the scan */ +/* converter is called, which means that the value you give to it is */ +/* actually ignored. */ +/* */ +/* The gray-level rasterizer always uses 256 gray levels. If you */ +/* want less gray levels, you have to provide your own span callback. */ +/* See the @FT_RASTER_FLAG_DIRECT value of the `flags' field in the */ +/* @FT_Raster_Params structure for more details. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ); +/************************************************************************** + * + * @enum: + * FT_Orientation + * + * @description: + * A list of values used to describe an outline's contour orientation. + * + * The TrueType and PostScript specifications use different conventions + * to determine whether outline contours should be filled or unfilled. + * + * @values: + * FT_ORIENTATION_TRUETYPE :: + * According to the TrueType specification, clockwise contours must + * be filled, and counter-clockwise ones must be unfilled. + * + * FT_ORIENTATION_POSTSCRIPT :: + * According to the PostScript specification, counter-clockwise contours + * must be filled, and clockwise ones must be unfilled. + * + * FT_ORIENTATION_FILL_RIGHT :: + * This is identical to @FT_ORIENTATION_TRUETYPE, but is used to + * remember that in TrueType, everything that is to the right of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_FILL_LEFT :: + * This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to + * remember that in PostScript, everything that is to the left of + * the drawing direction of a contour must be filled. + * + * FT_ORIENTATION_NONE :: + * The orientation cannot be determined. That is, different parts of + * the glyph have different orientation. + * + */ + typedef enum FT_Orientation_ + { + FT_ORIENTATION_TRUETYPE = 0, + FT_ORIENTATION_POSTSCRIPT = 1, + FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE, + FT_ORIENTATION_FILL_LEFT = FT_ORIENTATION_POSTSCRIPT, + FT_ORIENTATION_NONE + } FT_Orientation; +/************************************************************************** + * + * @function: + * FT_Outline_Get_Orientation + * + * @description: + * This function analyzes a glyph outline and tries to compute its + * fill orientation (see @FT_Orientation). This is done by computing + * the direction of each global horizontal and/or vertical extrema + * within the outline. + * + * Note that this will return @FT_ORIENTATION_TRUETYPE for empty + * outlines. + * + * @input: + * outline :: + * A handle to the source outline. + * + * @return: + * The orientation. + * + */ + FT_EXPORT( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ); +/* */ +FT_END_HEADER +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ +/***************************************************************************/ +/* */ +/* ftvalid.h */ +/* */ +/* FreeType validation support (specification). */ +/* */ +/* Copyright 2004 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. */ +/* */ +/***************************************************************************/ +#define __FTVALID_H__ +/* for ft_setjmp and ft_longjmp */ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** V A L I D A T I O N ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* handle to a validation object */ + typedef struct FT_ValidatorRec_ volatile* FT_Validator; +/*************************************************************************/ +/* */ +/* There are three distinct validation levels defined here: */ +/* */ +/* FT_VALIDATE_DEFAULT :: */ +/* A table that passes this validation level can be used reliably by */ +/* FreeType. It generally means that all offsets have been checked to */ +/* prevent out-of-bound reads, that array counts are correct, etc. */ +/* */ +/* FT_VALIDATE_TIGHT :: */ +/* A table that passes this validation level can be used reliably and */ +/* doesn't contain invalid data. For example, a charmap table that */ +/* returns invalid glyph indices will not pass, even though it can */ +/* be used with FreeType in default mode (the library will simply */ +/* return an error later when trying to load the glyph). */ +/* */ +/* It also checks that fields which must be a multiple of 2, 4, or 8, */ +/* don't have incorrect values, etc. */ +/* */ +/* FT_VALIDATE_PARANOID :: */ +/* Only for font debugging. Checks that a table follows the */ +/* specification by 100%. Very few fonts will be able to pass this */ +/* level anyway but it can be useful for certain tools like font */ +/* editors/converters. */ +/* */ + typedef enum FT_ValidationLevel_ + { + FT_VALIDATE_DEFAULT = 0, + FT_VALIDATE_TIGHT, + FT_VALIDATE_PARANOID + } FT_ValidationLevel; +/* validator structure */ + typedef struct FT_ValidatorRec_ + { +/* address of table in memory */ + const FT_Byte* base; +/* `base' + sizeof(table) in memory */ + const FT_Byte* limit; +/* validation level */ + FT_ValidationLevel level; +/* error returned. 0 means success */ + FT_Error error; +/* used for exception handling */ + ft_jmp_buf jump_buffer; + } FT_ValidatorRec; +#define FT_VALIDATOR( x ) ((FT_Validator)( x )) + FT_BASE( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ); +/* Do not use this. It's broken and will cause your validator to crash */ +/* if you run it on an invalid font. */ + FT_BASE( FT_Int ) + ft_validator_run( FT_Validator valid ); +/* Sets the error field in a validator, then calls `longjmp' to return */ +/* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ +/* error checks within the validation routines. */ +/* */ + FT_BASE( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ); +/* Calls ft_validate_error. Assumes that the `valid' local variable */ +/* holds a pointer to the current validator object. */ +/* */ +/* Use preprocessor prescan to pass FT_ERR_PREFIX. */ +/* */ +#define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid, _prefix ## _error ) +/* called when a broken table is detected */ +#define FT_INVALID_TOO_SHORT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) +/* called when an invalid offset is detected */ +#define FT_INVALID_OFFSET \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) +/* called when an invalid format/value is detected */ +#define FT_INVALID_FORMAT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) +/* called when an invalid glyph index is detected */ +#define FT_INVALID_GLYPH_ID \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) +/* called when an invalid field value is detected */ +#define FT_INVALID_DATA \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftrfork.h */ +/* */ +/* Embedded resource forks accessor (specification). */ +/* */ +/* Copyright 2004, 2006, 2007, 2012 by */ +/* Masatake YAMATO and Redhat K.K. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* Development of the code in this file is support of */ +/* Information-technology Promotion Agency, Japan. */ +/***************************************************************************/ +#define __FTRFORK_H__ +FT_BEGIN_HEADER +/* Number of guessing rules supported in `FT_Raccess_Guess'. */ +/* Don't forget to increment the number if you add a new guessing rule. */ +#define FT_RACCESS_N_RULES 9 +/* A structure to describe a reference in a resource by its resource ID */ +/* and internal offset. The `POST' resource expects to be concatenated */ +/* by the order of resource IDs instead of its appearance in the file. */ + typedef struct FT_RFork_Ref_ + { + FT_UShort res_id; + FT_ULong offset; + } FT_RFork_Ref; + typedef FT_Error + (*ft_raccess_guess_func)( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + typedef enum FT_RFork_Rule_ { + FT_RFork_Rule_invalid = -2, +/* -1 */ + FT_RFork_Rule_uknown, + FT_RFork_Rule_apple_double, + FT_RFork_Rule_apple_single, + FT_RFork_Rule_darwin_ufs_export, + FT_RFork_Rule_darwin_newvfs, + FT_RFork_Rule_darwin_hfsplus, + FT_RFork_Rule_vfat, + FT_RFork_Rule_linux_cap, + FT_RFork_Rule_linux_double, + FT_RFork_Rule_linux_netatalk + } FT_RFork_Rule; +/* For fast translation between rule index and rule type, + * the macros FT_RFORK_xxx should be kept consistent with + * the raccess_guess_funcs table + */ + typedef struct ft_raccess_guess_rec_ { + ft_raccess_guess_func func; + FT_RFork_Rule type; + } ft_raccess_guess_rec; +/* this array is a storage in non-PIC mode, so ; is needed in END */ +#define CONST_FT_RFORK_RULE_ARRAY_BEGIN( name, type ) \ + const type name[] = { +#define CONST_FT_RFORK_RULE_ARRAY_ENTRY( func_suffix, type_suffix ) \ + { raccess_guess_ ## func_suffix, \ + FT_RFork_Rule_ ## type_suffix }, +#define CONST_FT_RFORK_RULE_ARRAY_END }; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Raccess_Guess */ +/* */ +/* <Description> */ +/* Guess a file name and offset where the actual resource fork is */ +/* stored. The macro FT_RACCESS_N_RULES holds the number of */ +/* guessing rules; the guessed result for the Nth rule is */ +/* represented as a triplet: a new file name (new_names[N]), a file */ +/* offset (offsets[N]), and an error code (errors[N]). */ +/* */ +/* <Input> */ +/* library :: */ +/* A FreeType library instance. */ +/* */ +/* stream :: */ +/* A file stream containing the resource fork. */ +/* */ +/* base_name :: */ +/* The (base) file name of the resource fork used for some */ +/* guessing rules. */ +/* */ +/* <Output> */ +/* new_names :: */ +/* An array of guessed file names in which the resource forks may */ +/* exist. If `new_names[N]' is NULL, the guessed file name is */ +/* equal to `base_name'. */ +/* */ +/* offsets :: */ +/* An array of guessed file offsets. `offsets[N]' holds the file */ +/* offset of the possible start of the resource fork in file */ +/* `new_names[N]'. */ +/* */ +/* errors :: */ +/* An array of FreeType error codes. `errors[N]' is the error */ +/* code of Nth guessing rule function. If `errors[N]' is not */ +/* FT_Err_Ok, `new_names[N]' and `offsets[N]' are meaningless. */ +/* */ + FT_BASE( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char** new_names, + FT_Long* offsets, + FT_Error* errors ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Raccess_Get_HeaderInfo */ +/* */ +/* <Description> */ +/* Get the information from the header of resource fork. The */ +/* information includes the file offset where the resource map */ +/* starts, and the file offset where the resource data starts. */ +/* `FT_Raccess_Get_DataOffsets' requires these two data. */ +/* */ +/* <Input> */ +/* library :: */ +/* A FreeType library instance. */ +/* */ +/* stream :: */ +/* A file stream containing the resource fork. */ +/* */ +/* rfork_offset :: */ +/* The file offset where the resource fork starts. */ +/* */ +/* <Output> */ +/* map_offset :: */ +/* The file offset where the resource map starts. */ +/* */ +/* rdata_pos :: */ +/* The file offset where the resource data starts. */ +/* */ +/* <Return> */ +/* FreeType error code. FT_Err_Ok means success. */ +/* */ + FT_BASE( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Raccess_Get_DataOffsets */ +/* */ +/* <Description> */ +/* Get the data offsets for a tag in a resource fork. Offsets are */ +/* stored in an array because, in some cases, resources in a resource */ +/* fork have the same tag. */ +/* */ +/* <Input> */ +/* library :: */ +/* A FreeType library instance. */ +/* */ +/* stream :: */ +/* A file stream containing the resource fork. */ +/* */ +/* map_offset :: */ +/* The file offset where the resource map starts. */ +/* */ +/* rdata_pos :: */ +/* The file offset where the resource data starts. */ +/* */ +/* tag :: */ +/* The resource tag. */ +/* */ +/* <Output> */ +/* offsets :: */ +/* The stream offsets for the resource data specified by `tag'. */ +/* This array is allocated by the function, so you have to call */ +/* @ft_mem_free after use. */ +/* */ +/* count :: */ +/* The length of offsets array. */ +/* */ +/* <Return> */ +/* FreeType error code. FT_Err_Ok means success. */ +/* */ +/* <Note> */ +/* Normally you should use `FT_Raccess_Get_HeaderInfo' to get the */ +/* value for `map_offset' and `rdata_pos'. */ +/* */ + FT_BASE( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Long **offsets, + FT_Long *count ); +FT_END_HEADER +/* END */ +/* for SFNT_Load_Table_Func */ +/***************************************************************************/ +/* */ +/* sfnt.h */ +/* */ +/* High-level `sfnt' driver interface (specification). */ +/* */ +/* Copyright 1996-2006, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SFNT_H__ +/***************************************************************************/ +/* */ +/* tttypes.h */ +/* */ +/* Basic SFNT/TrueType type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2002, 2004-2008, 2012 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. */ +/* */ +/***************************************************************************/ +#define __TTTYPES_H__ +/***************************************************************************/ +/* */ +/* tttables.h */ +/* */ +/* Basic SFNT/TrueType tables definitions and interface */ +/* (specification only). */ +/* */ +/* Copyright 1996-2005, 2008-2012 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. */ +/* */ +/***************************************************************************/ +#define __TTTABLES_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* truetype_tables */ +/* */ +/* <Title> */ +/* TrueType Tables */ +/* */ +/* <Abstract> */ +/* TrueType specific table types and functions. */ +/* */ +/* <Description> */ +/* This section contains the definition of TrueType-specific tables */ +/* as well as some routines used to access and process them. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_Header */ +/* */ +/* <Description> */ +/* A structure used to model a TrueType font header table. All */ +/* fields follow the TrueType specification. */ +/* */ + typedef struct TT_Header_ + { + FT_Fixed Table_Version; + FT_Fixed Font_Revision; + FT_Long CheckSum_Adjust; + FT_Long Magic_Number; + FT_UShort Flags; + FT_UShort Units_Per_EM; + FT_Long Created [2]; + FT_Long Modified[2]; + FT_Short xMin; + FT_Short yMin; + FT_Short xMax; + FT_Short yMax; + FT_UShort Mac_Style; + FT_UShort Lowest_Rec_PPEM; + FT_Short Font_Direction; + FT_Short Index_To_Loc_Format; + FT_Short Glyph_Data_Format; + } TT_Header; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_HoriHeader */ +/* */ +/* <Description> */ +/* A structure used to model a TrueType horizontal header, the `hhea' */ +/* table, as well as the corresponding horizontal metrics table, */ +/* i.e., the `hmtx' table. */ +/* */ +/* <Fields> */ +/* Version :: The table version. */ +/* */ +/* Ascender :: The font's ascender, i.e., the distance */ +/* from the baseline to the top-most of all */ +/* glyph points found in the font. */ +/* */ +/* This value is invalid in many fonts, as */ +/* it is usually set by the font designer, */ +/* and often reflects only a portion of the */ +/* glyphs found in the font (maybe ASCII). */ +/* */ +/* You should use the `sTypoAscender' field */ +/* of the OS/2 table instead if you want */ +/* the correct one. */ +/* */ +/* Descender :: The font's descender, i.e., the distance */ +/* from the baseline to the bottom-most of */ +/* all glyph points found in the font. It */ +/* is negative. */ +/* */ +/* This value is invalid in many fonts, as */ +/* it is usually set by the font designer, */ +/* and often reflects only a portion of the */ +/* glyphs found in the font (maybe ASCII). */ +/* */ +/* You should use the `sTypoDescender' */ +/* field of the OS/2 table instead if you */ +/* want the correct one. */ +/* */ +/* Line_Gap :: The font's line gap, i.e., the distance */ +/* to add to the ascender and descender to */ +/* get the BTB, i.e., the */ +/* baseline-to-baseline distance for the */ +/* font. */ +/* */ +/* advance_Width_Max :: This field is the maximum of all advance */ +/* widths found in the font. It can be */ +/* used to compute the maximum width of an */ +/* arbitrary string of text. */ +/* */ +/* min_Left_Side_Bearing :: The minimum left side bearing of all */ +/* glyphs within the font. */ +/* */ +/* min_Right_Side_Bearing :: The minimum right side bearing of all */ +/* glyphs within the font. */ +/* */ +/* xMax_Extent :: The maximum horizontal extent (i.e., the */ +/* `width' of a glyph's bounding box) for */ +/* all glyphs in the font. */ +/* */ +/* caret_Slope_Rise :: The rise coefficient of the cursor's */ +/* slope of the cursor (slope=rise/run). */ +/* */ +/* caret_Slope_Run :: The run coefficient of the cursor's */ +/* slope. */ +/* */ +/* Reserved :: 8~reserved bytes. */ +/* */ +/* metric_Data_Format :: Always~0. */ +/* */ +/* number_Of_HMetrics :: Number of HMetrics entries in the `hmtx' */ +/* table -- this value can be smaller than */ +/* the total number of glyphs in the font. */ +/* */ +/* long_metrics :: A pointer into the `hmtx' table. */ +/* */ +/* short_metrics :: A pointer into the `hmtx' table. */ +/* */ +/* <Note> */ +/* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ +/* be identical except for the names of their fields which */ +/* are different. */ +/* */ +/* This ensures that a single function in the `ttload' */ +/* module is able to read both the horizontal and vertical */ +/* headers. */ +/* */ + typedef struct TT_HoriHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; +/* advance width maximum */ + FT_UShort advance_Width_Max; +/* minimum left-sb */ + FT_Short min_Left_Side_Bearing; +/* minimum right-sb */ + FT_Short min_Right_Side_Bearing; +/* xmax extents */ + FT_Short xMax_Extent; + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + FT_Short Reserved[4]; + FT_Short metric_Data_Format; + FT_UShort number_Of_HMetrics; +/* The following fields are not defined by the TrueType specification */ +/* but they are used to connect the metrics header to the relevant */ +/* `HMTX' table. */ + void* long_metrics; + void* short_metrics; + } TT_HoriHeader; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_VertHeader */ +/* */ +/* <Description> */ +/* A structure used to model a TrueType vertical header, the `vhea' */ +/* table, as well as the corresponding vertical metrics table, i.e., */ +/* the `vmtx' table. */ +/* */ +/* <Fields> */ +/* Version :: The table version. */ +/* */ +/* Ascender :: The font's ascender, i.e., the distance */ +/* from the baseline to the top-most of */ +/* all glyph points found in the font. */ +/* */ +/* This value is invalid in many fonts, as */ +/* it is usually set by the font designer, */ +/* and often reflects only a portion of */ +/* the glyphs found in the font (maybe */ +/* ASCII). */ +/* */ +/* You should use the `sTypoAscender' */ +/* field of the OS/2 table instead if you */ +/* want the correct one. */ +/* */ +/* Descender :: The font's descender, i.e., the */ +/* distance from the baseline to the */ +/* bottom-most of all glyph points found */ +/* in the font. It is negative. */ +/* */ +/* This value is invalid in many fonts, as */ +/* it is usually set by the font designer, */ +/* and often reflects only a portion of */ +/* the glyphs found in the font (maybe */ +/* ASCII). */ +/* */ +/* You should use the `sTypoDescender' */ +/* field of the OS/2 table instead if you */ +/* want the correct one. */ +/* */ +/* Line_Gap :: The font's line gap, i.e., the distance */ +/* to add to the ascender and descender to */ +/* get the BTB, i.e., the */ +/* baseline-to-baseline distance for the */ +/* font. */ +/* */ +/* advance_Height_Max :: This field is the maximum of all */ +/* advance heights found in the font. It */ +/* can be used to compute the maximum */ +/* height of an arbitrary string of text. */ +/* */ +/* min_Top_Side_Bearing :: The minimum top side bearing of all */ +/* glyphs within the font. */ +/* */ +/* min_Bottom_Side_Bearing :: The minimum bottom side bearing of all */ +/* glyphs within the font. */ +/* */ +/* yMax_Extent :: The maximum vertical extent (i.e., the */ +/* `height' of a glyph's bounding box) for */ +/* all glyphs in the font. */ +/* */ +/* caret_Slope_Rise :: The rise coefficient of the cursor's */ +/* slope of the cursor (slope=rise/run). */ +/* */ +/* caret_Slope_Run :: The run coefficient of the cursor's */ +/* slope. */ +/* */ +/* caret_Offset :: The cursor's offset for slanted fonts. */ +/* This value is `reserved' in vmtx */ +/* version 1.0. */ +/* */ +/* Reserved :: 8~reserved bytes. */ +/* */ +/* metric_Data_Format :: Always~0. */ +/* */ +/* number_Of_HMetrics :: Number of VMetrics entries in the */ +/* `vmtx' table -- this value can be */ +/* smaller than the total number of glyphs */ +/* in the font. */ +/* */ +/* long_metrics :: A pointer into the `vmtx' table. */ +/* */ +/* short_metrics :: A pointer into the `vmtx' table. */ +/* */ +/* <Note> */ +/* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */ +/* be identical except for the names of their fields which */ +/* are different. */ +/* */ +/* This ensures that a single function in the `ttload' */ +/* module is able to read both the horizontal and vertical */ +/* headers. */ +/* */ + typedef struct TT_VertHeader_ + { + FT_Fixed Version; + FT_Short Ascender; + FT_Short Descender; + FT_Short Line_Gap; +/* advance height maximum */ + FT_UShort advance_Height_Max; +/* minimum left-sb or top-sb */ + FT_Short min_Top_Side_Bearing; +/* minimum right-sb or bottom-sb */ + FT_Short min_Bottom_Side_Bearing; +/* xmax or ymax extents */ + FT_Short yMax_Extent; + FT_Short caret_Slope_Rise; + FT_Short caret_Slope_Run; + FT_Short caret_Offset; + FT_Short Reserved[4]; + FT_Short metric_Data_Format; + FT_UShort number_Of_VMetrics; +/* The following fields are not defined by the TrueType specification */ +/* but they're used to connect the metrics header to the relevant */ +/* `HMTX' or `VMTX' table. */ + void* long_metrics; + void* short_metrics; + } TT_VertHeader; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_OS2 */ +/* */ +/* <Description> */ +/* A structure used to model a TrueType OS/2 table. This is the long */ +/* table version. All fields comply to the TrueType specification. */ +/* */ +/* Note that we now support old Mac fonts which do not include an */ +/* OS/2 table. In this case, the `version' field is always set to */ +/* 0xFFFF. */ +/* */ + typedef struct TT_OS2_ + { +/* 0x0001 - more or 0xFFFF */ + FT_UShort version; + FT_Short xAvgCharWidth; + FT_UShort usWeightClass; + FT_UShort usWidthClass; + FT_Short fsType; + FT_Short ySubscriptXSize; + FT_Short ySubscriptYSize; + FT_Short ySubscriptXOffset; + FT_Short ySubscriptYOffset; + FT_Short ySuperscriptXSize; + FT_Short ySuperscriptYSize; + FT_Short ySuperscriptXOffset; + FT_Short ySuperscriptYOffset; + FT_Short yStrikeoutSize; + FT_Short yStrikeoutPosition; + FT_Short sFamilyClass; + FT_Byte panose[10]; +/* Bits 0-31 */ + FT_ULong ulUnicodeRange1; +/* Bits 32-63 */ + FT_ULong ulUnicodeRange2; +/* Bits 64-95 */ + FT_ULong ulUnicodeRange3; +/* Bits 96-127 */ + FT_ULong ulUnicodeRange4; + FT_Char achVendID[4]; + FT_UShort fsSelection; + FT_UShort usFirstCharIndex; + FT_UShort usLastCharIndex; + FT_Short sTypoAscender; + FT_Short sTypoDescender; + FT_Short sTypoLineGap; + FT_UShort usWinAscent; + FT_UShort usWinDescent; +/* only version 1 tables: */ +/* Bits 0-31 */ + FT_ULong ulCodePageRange1; +/* Bits 32-63 */ + FT_ULong ulCodePageRange2; +/* only version 2 tables: */ + FT_Short sxHeight; + FT_Short sCapHeight; + FT_UShort usDefaultChar; + FT_UShort usBreakChar; + FT_UShort usMaxContext; + } TT_OS2; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_Postscript */ +/* */ +/* <Description> */ +/* A structure used to model a TrueType PostScript table. All fields */ +/* comply to the TrueType specification. This structure does not */ +/* reference the PostScript glyph names, which can be nevertheless */ +/* accessed with the `ttpost' module. */ +/* */ + typedef struct TT_Postscript_ + { + FT_Fixed FormatType; + FT_Fixed italicAngle; + FT_Short underlinePosition; + FT_Short underlineThickness; + FT_ULong isFixedPitch; + FT_ULong minMemType42; + FT_ULong maxMemType42; + FT_ULong minMemType1; + FT_ULong maxMemType1; +/* Glyph names follow in the file, but we don't */ +/* load them by default. See the ttpost.c file. */ + } TT_Postscript; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_PCLT */ +/* */ +/* <Description> */ +/* A structure used to model a TrueType PCLT table. All fields */ +/* comply to the TrueType specification. */ +/* */ + typedef struct TT_PCLT_ + { + FT_Fixed Version; + FT_ULong FontNumber; + FT_UShort Pitch; + FT_UShort xHeight; + FT_UShort Style; + FT_UShort TypeFamily; + FT_UShort CapHeight; + FT_UShort SymbolSet; + FT_Char TypeFace[16]; + FT_Char CharacterComplement[8]; + FT_Char FileName[6]; + FT_Char StrokeWeight; + FT_Char WidthType; + FT_Byte SerifStyle; + FT_Byte Reserved; + } TT_PCLT; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_MaxProfile */ +/* */ +/* <Description> */ +/* The maximum profile is a table containing many max values which */ +/* can be used to pre-allocate arrays. This ensures that no memory */ +/* allocation occurs during a glyph load. */ +/* */ +/* <Fields> */ +/* version :: The version number. */ +/* */ +/* numGlyphs :: The number of glyphs in this TrueType */ +/* font. */ +/* */ +/* maxPoints :: The maximum number of points in a */ +/* non-composite TrueType glyph. See also */ +/* the structure element */ +/* `maxCompositePoints'. */ +/* */ +/* maxContours :: The maximum number of contours in a */ +/* non-composite TrueType glyph. See also */ +/* the structure element */ +/* `maxCompositeContours'. */ +/* */ +/* maxCompositePoints :: The maximum number of points in a */ +/* composite TrueType glyph. See also the */ +/* structure element `maxPoints'. */ +/* */ +/* maxCompositeContours :: The maximum number of contours in a */ +/* composite TrueType glyph. See also the */ +/* structure element `maxContours'. */ +/* */ +/* maxZones :: The maximum number of zones used for */ +/* glyph hinting. */ +/* */ +/* maxTwilightPoints :: The maximum number of points in the */ +/* twilight zone used for glyph hinting. */ +/* */ +/* maxStorage :: The maximum number of elements in the */ +/* storage area used for glyph hinting. */ +/* */ +/* maxFunctionDefs :: The maximum number of function */ +/* definitions in the TrueType bytecode for */ +/* this font. */ +/* */ +/* maxInstructionDefs :: The maximum number of instruction */ +/* definitions in the TrueType bytecode for */ +/* this font. */ +/* */ +/* maxStackElements :: The maximum number of stack elements used */ +/* during bytecode interpretation. */ +/* */ +/* maxSizeOfInstructions :: The maximum number of TrueType opcodes */ +/* used for glyph hinting. */ +/* */ +/* maxComponentElements :: The maximum number of simple (i.e., non- */ +/* composite) glyphs in a composite glyph. */ +/* */ +/* maxComponentDepth :: The maximum nesting depth of composite */ +/* glyphs. */ +/* */ +/* <Note> */ +/* This structure is only used during font loading. */ +/* */ + typedef struct TT_MaxProfile_ + { + FT_Fixed version; + FT_UShort numGlyphs; + FT_UShort maxPoints; + FT_UShort maxContours; + FT_UShort maxCompositePoints; + FT_UShort maxCompositeContours; + FT_UShort maxZones; + FT_UShort maxTwilightPoints; + FT_UShort maxStorage; + FT_UShort maxFunctionDefs; + FT_UShort maxInstructionDefs; + FT_UShort maxStackElements; + FT_UShort maxSizeOfInstructions; + FT_UShort maxComponentElements; + FT_UShort maxComponentDepth; + } TT_MaxProfile; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* FT_Sfnt_Tag */ +/* */ +/* <Description> */ +/* An enumeration used to specify the index of an SFNT table. */ +/* Used in the @FT_Get_Sfnt_Table API function. */ +/* */ + typedef enum FT_Sfnt_Tag_ + { +/* TT_Header */ + ft_sfnt_head = 0, +/* TT_MaxProfile */ + ft_sfnt_maxp = 1, +/* TT_OS2 */ + ft_sfnt_os2 = 2, +/* TT_HoriHeader */ + ft_sfnt_hhea = 3, +/* TT_VertHeader */ + ft_sfnt_vhea = 4, +/* TT_Postscript */ + ft_sfnt_post = 5, +/* TT_PCLT */ + ft_sfnt_pclt = 6, +/* internal end mark */ + sfnt_max + } FT_Sfnt_Tag; +/* */ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Sfnt_Table */ +/* */ +/* <Description> */ +/* Return a pointer to a given SFNT table within a face. */ +/* */ +/* <Input> */ +/* face :: A handle to the source. */ +/* */ +/* tag :: The index of the SFNT table. */ +/* */ +/* <Return> */ +/* A type-less pointer to the table. This will be~0 in case of */ +/* error, or if the corresponding table was not found *OR* loaded */ +/* from the file. */ +/* */ +/* Use a typecast according to `tag' to access the structure */ +/* elements. */ +/* */ +/* <Note> */ +/* The table is owned by the face object and disappears with it. */ +/* */ +/* This function is only useful to access SFNT tables that are loaded */ +/* by the sfnt, truetype, and opentype drivers. See @FT_Sfnt_Tag for */ +/* a list. */ +/* */ +/* Here an example how to access the `vhea' table: */ +/* */ +/* { */ +/* TT_VertHeader* vert_header; */ +/* */ +/* */ +/* vert_header = */ +/* (TT_VertHeader*)FT_Get_Sfnt_Table( face, ft_sfnt_vhea ); */ +/* } */ +/* */ + FT_EXPORT( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ); +/************************************************************************** + * + * @function: + * FT_Load_Sfnt_Table + * + * @description: + * Load any font table into client memory. + * + * @input: + * face :: + * A handle to the source face. + * + * tag :: + * The four-byte tag of the table to load. Use the value~0 if you want + * to access the whole font file. Otherwise, you can use one of the + * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new + * one with @FT_MAKE_TAG. + * + * offset :: + * The starting offset in the table (or file if tag == 0). + * + * @output: + * buffer :: + * The target buffer address. The client must ensure that the memory + * array is big enough to hold the data. + * + * @inout: + * length :: + * If the `length' parameter is NULL, then try to load the whole table. + * Return an error code if it fails. + * + * Else, if `*length' is~0, exit immediately while returning the + * table's (or file) full size in it. + * + * Else the number of bytes to read from the table or file, from the + * starting offset. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If you need to determine the table's length you should first call this + * function with `*length' set to~0, as in the following example: + * + * { + * FT_ULong length = 0; + * + * + * error = FT_Load_Sfnt_Table( face, tag, 0, NULL, &length ); + * if ( error ) { ... table does not exist ... } + * + * buffer = malloc( length ); + * if ( buffer == NULL ) { ... not enough memory ... } + * + * error = FT_Load_Sfnt_Table( face, tag, 0, buffer, &length ); + * if ( error ) { ... could not load table ... } + * } + */ + FT_EXPORT( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); +/************************************************************************** + * + * @function: + * FT_Sfnt_Table_Info + * + * @description: + * Return information on an SFNT table. + * + * @input: + * face :: + * A handle to the source face. + * + * table_index :: + * The index of an SFNT table. The function returns + * FT_Err_Table_Missing for an invalid value. + * + * @inout: + * tag :: + * The name tag of the SFNT table. If the value is NULL, `table_index' + * is ignored, and `length' returns the number of SFNT tables in the + * font. + * + * @output: + * length :: + * The length of the SFNT table (or the number of SFNT tables, depending + * on `tag'). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * While parsing fonts, FreeType handles SFNT tables with length zero as + * missing. + * + */ + FT_EXPORT( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_CMap_Language_ID */ +/* */ +/* <Description> */ +/* Return TrueType/sfnt specific cmap language ID. Definitions of */ +/* language ID values are in `freetype/ttnameid.h'. */ +/* */ +/* <Input> */ +/* charmap :: */ +/* The target charmap. */ +/* */ +/* <Return> */ +/* The language ID of `charmap'. If `charmap' doesn't belong to a */ +/* TrueType/sfnt face, just return~0 as the default value. */ +/* */ +/* For a format~14 cmap (to access Unicode IVS), the return value is */ +/* 0xFFFFFFFF. */ +/* */ + FT_EXPORT( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_CMap_Format */ +/* */ +/* <Description> */ +/* Return TrueType/sfnt specific cmap format. */ +/* */ +/* <Input> */ +/* charmap :: */ +/* The target charmap. */ +/* */ +/* <Return> */ +/* The format of `charmap'. If `charmap' doesn't belong to a */ +/* TrueType/sfnt face, return -1. */ +/* */ + FT_EXPORT( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftmm.h */ +/* */ +/* FreeType Multiple Master font interface (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2006, 2009 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. */ +/* */ +/***************************************************************************/ +#define __FTMM_H__ +/***************************************************************************/ +/* */ +/* t1tables.h */ +/* */ +/* Basic Type 1/Type 2 tables definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2004, 2006, 2008, 2009, 2011 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. */ +/* */ +/***************************************************************************/ +#define __T1TABLES_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* type1_tables */ +/* */ +/* <Title> */ +/* Type 1 Tables */ +/* */ +/* <Abstract> */ +/* Type~1 (PostScript) specific font tables. */ +/* */ +/* <Description> */ +/* This section contains the definition of Type 1-specific tables, */ +/* including structures related to other PostScript font formats. */ +/* */ +/*************************************************************************/ +/* Note that we separate font data in PS_FontInfoRec and PS_PrivateRec */ +/* structures in order to support Multiple Master fonts. */ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_FontInfoRec */ +/* */ +/* <Description> */ +/* A structure used to model a Type~1 or Type~2 FontInfo dictionary. */ +/* Note that for Multiple Master fonts, each instance has its own */ +/* FontInfo dictionary. */ +/* */ + typedef struct PS_FontInfoRec_ + { + FT_String* version; + FT_String* notice; + FT_String* full_name; + FT_String* family_name; + FT_String* weight; + FT_Long italic_angle; + FT_Bool is_fixed_pitch; + FT_Short underline_position; + FT_UShort underline_thickness; + } PS_FontInfoRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_FontInfo */ +/* */ +/* <Description> */ +/* A handle to a @PS_FontInfoRec structure. */ +/* */ + typedef struct PS_FontInfoRec_* PS_FontInfo; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* T1_FontInfo */ +/* */ +/* <Description> */ +/* This type is equivalent to @PS_FontInfoRec. It is deprecated but */ +/* kept to maintain source compatibility between various versions of */ +/* FreeType. */ +/* */ + typedef PS_FontInfoRec T1_FontInfo; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_PrivateRec */ +/* */ +/* <Description> */ +/* A structure used to model a Type~1 or Type~2 private dictionary. */ +/* Note that for Multiple Master fonts, each instance has its own */ +/* Private dictionary. */ +/* */ + typedef struct PS_PrivateRec_ + { + FT_Int unique_id; + FT_Int lenIV; + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + FT_Short blue_values[14]; + FT_Short other_blues[10]; + FT_Short family_blues [14]; + FT_Short family_other_blues[10]; + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_fuzz; + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Bool force_bold; + FT_Bool round_stem_up; +/* including std width */ + FT_Short snap_widths [13]; +/* including std height */ + FT_Short snap_heights[13]; + FT_Fixed expansion_factor; + FT_Long language_group; + FT_Long password; + FT_Short min_feature[2]; + } PS_PrivateRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_Private */ +/* */ +/* <Description> */ +/* A handle to a @PS_PrivateRec structure. */ +/* */ + typedef struct PS_PrivateRec_* PS_Private; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* T1_Private */ +/* */ +/* <Description> */ +/* This type is equivalent to @PS_PrivateRec. It is deprecated but */ +/* kept to maintain source compatibility between various versions of */ +/* FreeType. */ +/* */ + typedef PS_PrivateRec T1_Private; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* T1_Blend_Flags */ +/* */ +/* <Description> */ +/* A set of flags used to indicate which fields are present in a */ +/* given blend dictionary (font info or private). Used to support */ +/* Multiple Masters fonts. */ +/* */ + typedef enum T1_Blend_Flags_ + { +/*# required fields in a FontInfo blend dictionary */ + T1_BLEND_UNDERLINE_POSITION = 0, + T1_BLEND_UNDERLINE_THICKNESS, + T1_BLEND_ITALIC_ANGLE, +/*# required fields in a Private blend dictionary */ + T1_BLEND_BLUE_VALUES, + T1_BLEND_OTHER_BLUES, + T1_BLEND_STANDARD_WIDTH, + T1_BLEND_STANDARD_HEIGHT, + T1_BLEND_STEM_SNAP_WIDTHS, + T1_BLEND_STEM_SNAP_HEIGHTS, + T1_BLEND_BLUE_SCALE, + T1_BLEND_BLUE_SHIFT, + T1_BLEND_FAMILY_BLUES, + T1_BLEND_FAMILY_OTHER_BLUES, + T1_BLEND_FORCE_BOLD, +/*# never remove */ + T1_BLEND_MAX + } T1_Blend_Flags; +/* */ +/*# backwards compatible definitions */ +#define t1_blend_underline_position T1_BLEND_UNDERLINE_POSITION +#define t1_blend_underline_thickness T1_BLEND_UNDERLINE_THICKNESS +#define t1_blend_italic_angle T1_BLEND_ITALIC_ANGLE +#define t1_blend_blue_values T1_BLEND_BLUE_VALUES +#define t1_blend_other_blues T1_BLEND_OTHER_BLUES +#define t1_blend_standard_widths T1_BLEND_STANDARD_WIDTH +#define t1_blend_standard_height T1_BLEND_STANDARD_HEIGHT +#define t1_blend_stem_snap_widths T1_BLEND_STEM_SNAP_WIDTHS +#define t1_blend_stem_snap_heights T1_BLEND_STEM_SNAP_HEIGHTS +#define t1_blend_blue_scale T1_BLEND_BLUE_SCALE +#define t1_blend_blue_shift T1_BLEND_BLUE_SHIFT +#define t1_blend_family_blues T1_BLEND_FAMILY_BLUES +#define t1_blend_family_other_blues T1_BLEND_FAMILY_OTHER_BLUES +#define t1_blend_force_bold T1_BLEND_FORCE_BOLD +#define t1_blend_max T1_BLEND_MAX +/* maximum number of Multiple Masters designs, as defined in the spec */ +#define T1_MAX_MM_DESIGNS 16 +/* maximum number of Multiple Masters axes, as defined in the spec */ +#define T1_MAX_MM_AXIS 4 +/* maximum number of elements in a design map */ +#define T1_MAX_MM_MAP_POINTS 20 +/* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct PS_DesignMap_ + { + FT_Byte num_points; + FT_Long* design_points; + FT_Fixed* blend_points; + } PS_DesignMapRec, *PS_DesignMap; +/* backwards-compatible definition */ + typedef PS_DesignMapRec T1_DesignMap; + typedef struct PS_BlendRec_ + { + FT_UInt num_designs; + FT_UInt num_axis; + FT_String* axis_names[T1_MAX_MM_AXIS]; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; + PS_DesignMapRec design_map[T1_MAX_MM_AXIS]; + FT_Fixed* weight_vector; + FT_Fixed* default_weight_vector; + PS_FontInfo font_infos[T1_MAX_MM_DESIGNS + 1]; + PS_Private privates [T1_MAX_MM_DESIGNS + 1]; + FT_ULong blend_bitflags; + FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; +/* since 2.3.0 */ +/* undocumented, optional: the default design instance; */ +/* corresponds to default_weight_vector -- */ +/* num_default_design_vector == 0 means it is not present */ +/* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + } PS_BlendRec, *PS_Blend; +/* backwards-compatible definition */ + typedef PS_BlendRec T1_Blend; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* CID_FaceDictRec */ +/* */ +/* <Description> */ +/* A structure used to represent data in a CID top-level dictionary. */ +/* */ + typedef struct CID_FaceDictRec_ + { + PS_PrivateRec private_dict; + FT_UInt len_buildchar; + FT_Fixed forcebold_threshold; + FT_Pos stroke_width; + FT_Fixed expansion_factor; + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_UInt num_subrs; + FT_ULong subrmap_offset; + FT_Int sd_bytes; + } CID_FaceDictRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* CID_FaceDict */ +/* */ +/* <Description> */ +/* A handle to a @CID_FaceDictRec structure. */ +/* */ + typedef struct CID_FaceDictRec_* CID_FaceDict; +/* */ +/* backwards-compatible definition */ + typedef CID_FaceDictRec CID_FontDict; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* CID_FaceInfoRec */ +/* */ +/* <Description> */ +/* A structure used to represent CID Face information. */ +/* */ + typedef struct CID_FaceInfoRec_ + { + FT_String* cid_font_name; + FT_Fixed cid_version; + FT_Int cid_font_type; + FT_String* registry; + FT_String* ordering; + FT_Int supplement; + PS_FontInfoRec font_info; + FT_BBox font_bbox; + FT_ULong uid_base; + FT_Int num_xuid; + FT_ULong xuid[16]; + FT_ULong cidmap_offset; + FT_Int fd_bytes; + FT_Int gd_bytes; + FT_ULong cid_count; + FT_Int num_dicts; + CID_FaceDict font_dicts; + FT_ULong data_offset; + } CID_FaceInfoRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* CID_FaceInfo */ +/* */ +/* <Description> */ +/* A handle to a @CID_FaceInfoRec structure. */ +/* */ + typedef struct CID_FaceInfoRec_* CID_FaceInfo; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* CID_Info */ +/* */ +/* <Description> */ +/* This type is equivalent to @CID_FaceInfoRec. It is deprecated but */ +/* kept to maintain source compatibility between various versions of */ +/* FreeType. */ +/* */ + typedef CID_FaceInfoRec CID_Info; +/************************************************************************ + * + * @function: + * FT_Has_PS_Glyph_Names + * + * @description: + * Return true if a given face provides reliable PostScript glyph + * names. This is similar to using the @FT_HAS_GLYPH_NAMES macro, + * except that certain fonts (mostly TrueType) contain incorrect + * glyph name tables. + * + * When this function returns true, the caller is sure that the glyph + * names returned by @FT_Get_Glyph_Name are reliable. + * + * @input: + * face :: + * face handle + * + * @return: + * Boolean. True if glyph names are reliable. + * + */ + FT_EXPORT( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ); +/************************************************************************ + * + * @function: + * FT_Get_PS_Font_Info + * + * @description: + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_info :: + * Output font info structure pointer. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The string pointers within the font info structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not PostScript-based, this function will + * return the `FT_Err_Invalid_Argument' error code. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfo afont_info ); +/************************************************************************ + * + * @function: + * FT_Get_PS_Font_Private + * + * @description: + * Retrieve the @PS_PrivateRec structure corresponding to a given + * PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * @output: + * afont_private :: + * Output private dictionary structure pointer. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The string pointers within the @PS_PrivateRec structure are owned by + * the face and don't need to be freed by the caller. + * + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument' error code. + * + */ + FT_EXPORT( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_Private afont_private ); +/*************************************************************************/ +/* */ +/* <Enum> */ +/* T1_EncodingType */ +/* */ +/* <Description> */ +/* An enumeration describing the `Encoding' entry in a Type 1 */ +/* dictionary. */ +/* */ + typedef enum T1_EncodingType_ + { + T1_ENCODING_TYPE_NONE = 0, + T1_ENCODING_TYPE_ARRAY, + T1_ENCODING_TYPE_STANDARD, + T1_ENCODING_TYPE_ISOLATIN1, + T1_ENCODING_TYPE_EXPERT + } T1_EncodingType; +/*************************************************************************/ +/* */ +/* <Enum> */ +/* PS_Dict_Keys */ +/* */ +/* <Description> */ +/* An enumeration used in calls to @FT_Get_PS_Font_Value to identify */ +/* the Type~1 dictionary entry to retrieve. */ +/* */ + typedef enum PS_Dict_Keys_ + { +/* conventionally in the font dictionary */ +/* FT_Byte */ + PS_DICT_FONT_TYPE, +/* FT_Fixed */ + PS_DICT_FONT_MATRIX, +/* FT_Fixed */ + PS_DICT_FONT_BBOX, +/* FT_Byte */ + PS_DICT_PAINT_TYPE, +/* FT_String* */ + PS_DICT_FONT_NAME, +/* FT_Int */ + PS_DICT_UNIQUE_ID, +/* FT_Int */ + PS_DICT_NUM_CHAR_STRINGS, +/* FT_String* */ + PS_DICT_CHAR_STRING_KEY, +/* FT_String* */ + PS_DICT_CHAR_STRING, +/* T1_EncodingType */ + PS_DICT_ENCODING_TYPE, +/* FT_String* */ + PS_DICT_ENCODING_ENTRY, +/* conventionally in the font Private dictionary */ +/* FT_Int */ + PS_DICT_NUM_SUBRS, +/* FT_String* */ + PS_DICT_SUBR, +/* FT_UShort */ + PS_DICT_STD_HW, +/* FT_UShort */ + PS_DICT_STD_VW, +/* FT_Byte */ + PS_DICT_NUM_BLUE_VALUES, +/* FT_Short */ + PS_DICT_BLUE_VALUE, +/* FT_Int */ + PS_DICT_BLUE_FUZZ, +/* FT_Byte */ + PS_DICT_NUM_OTHER_BLUES, +/* FT_Short */ + PS_DICT_OTHER_BLUE, +/* FT_Byte */ + PS_DICT_NUM_FAMILY_BLUES, +/* FT_Short */ + PS_DICT_FAMILY_BLUE, +/* FT_Byte */ + PS_DICT_NUM_FAMILY_OTHER_BLUES, +/* FT_Short */ + PS_DICT_FAMILY_OTHER_BLUE, +/* FT_Fixed */ + PS_DICT_BLUE_SCALE, +/* FT_Int */ + PS_DICT_BLUE_SHIFT, +/* FT_Byte */ + PS_DICT_NUM_STEM_SNAP_H, +/* FT_Short */ + PS_DICT_STEM_SNAP_H, +/* FT_Byte */ + PS_DICT_NUM_STEM_SNAP_V, +/* FT_Short */ + PS_DICT_STEM_SNAP_V, +/* FT_Bool */ + PS_DICT_FORCE_BOLD, +/* FT_Bool */ + PS_DICT_RND_STEM_UP, +/* FT_Short */ + PS_DICT_MIN_FEATURE, +/* FT_Int */ + PS_DICT_LEN_IV, +/* FT_Long */ + PS_DICT_PASSWORD, +/* FT_Long */ + PS_DICT_LANGUAGE_GROUP, +/* conventionally in the font FontInfo dictionary */ +/* FT_String* */ + PS_DICT_VERSION, +/* FT_String* */ + PS_DICT_NOTICE, +/* FT_String* */ + PS_DICT_FULL_NAME, +/* FT_String* */ + PS_DICT_FAMILY_NAME, +/* FT_String* */ + PS_DICT_WEIGHT, +/* FT_Bool */ + PS_DICT_IS_FIXED_PITCH, +/* FT_Short */ + PS_DICT_UNDERLINE_POSITION, +/* FT_UShort */ + PS_DICT_UNDERLINE_THICKNESS, +/* FT_UShort */ + PS_DICT_FS_TYPE, +/* FT_Long */ + PS_DICT_ITALIC_ANGLE, + PS_DICT_MAX = PS_DICT_ITALIC_ANGLE + } PS_Dict_Keys; +/************************************************************************ + * + * @function: + * FT_Get_PS_Font_Value + * + * @description: + * Retrieve the value for the supplied key from a PostScript font. + * + * @input: + * face :: + * PostScript face handle. + * + * key :: + * An enumeration value representing the dictionary key to retrieve. + * + * idx :: + * For array values, this specifies the index to be returned. + * + * value :: + * A pointer to memory into which to write the value. + * + * valen_len :: + * The size, in bytes, of the memory supplied for the value. + * + * @output: + * value :: + * The value matching the above key, if it exists. + * + * @return: + * The amount of memory (in bytes) required to hold the requested + * value (if it exists, -1 otherwise). + * + * @note: + * The values returned are not pointers into the internal structures of + * the face, but are `fresh' copies, so that the memory containing them + * belongs to the calling application. This also enforces the + * `read-only' nature of these values, i.e., this function cannot be + * used to manipulate the face. + * + * `value' is a void pointer because the values returned can be of + * various types. + * + * If either `value' is NULL or `value_len' is too small, just the + * required memory size for the requested entry is returned. + * + * The `idx' parameter is used, not only to retrieve elements of, for + * example, the FontMatrix or FontBBox, but also to retrieve name keys + * from the CharStrings dictionary, and the charstrings themselves. It + * is ignored for atomic values. + * + * PS_DICT_BLUE_SCALE returns a value that is scaled up by 1000. To + * get the value as in the font stream, you need to divide by + * 65536000.0 (to remove the FT_Fixed scale, and the x1000 scale). + * + * IMPORTANT: Only key/value pairs read by the FreeType interpreter can + * be retrieved. So, for example, PostScript procedures such as NP, + * ND, and RD are not available. Arbitrary keys are, obviously, not be + * available either. + * + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument' error code. + * + */ + FT_EXPORT( FT_Long ) + FT_Get_PS_Font_Value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* multiple_masters */ +/* */ +/* <Title> */ +/* Multiple Masters */ +/* */ +/* <Abstract> */ +/* How to manage Multiple Masters fonts. */ +/* */ +/* <Description> */ +/* The following types and functions are used to manage Multiple */ +/* Master fonts, i.e., the selection of specific design instances by */ +/* setting design axis coordinates. */ +/* */ +/* George Williams has extended this interface to make it work with */ +/* both Type~1 Multiple Masters fonts and GX distortable (var) */ +/* fonts. Some of these routines only work with MM fonts, others */ +/* will work with both types. They are similar enough that a */ +/* consistent interface makes sense. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_MM_Axis */ +/* */ +/* <Description> */ +/* A simple structure used to model a given axis in design space for */ +/* Multiple Masters fonts. */ +/* */ +/* This structure can't be used for GX var fonts. */ +/* */ +/* <Fields> */ +/* name :: The axis's name. */ +/* */ +/* minimum :: The axis's minimum design coordinate. */ +/* */ +/* maximum :: The axis's maximum design coordinate. */ +/* */ + typedef struct FT_MM_Axis_ + { + FT_String* name; + FT_Long minimum; + FT_Long maximum; + } FT_MM_Axis; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Multi_Master */ +/* */ +/* <Description> */ +/* A structure used to model the axes and space of a Multiple Masters */ +/* font. */ +/* */ +/* This structure can't be used for GX var fonts. */ +/* */ +/* <Fields> */ +/* num_axis :: Number of axes. Cannot exceed~4. */ +/* */ +/* num_designs :: Number of designs; should be normally 2^num_axis */ +/* even though the Type~1 specification strangely */ +/* allows for intermediate designs to be present. This */ +/* number cannot exceed~16. */ +/* */ +/* axis :: A table of axis descriptors. */ +/* */ + typedef struct FT_Multi_Master_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_MM_Axis axis[T1_MAX_MM_AXIS]; + } FT_Multi_Master; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Var_Axis */ +/* */ +/* <Description> */ +/* A simple structure used to model a given axis in design space for */ +/* Multiple Masters and GX var fonts. */ +/* */ +/* <Fields> */ +/* name :: The axis's name. */ +/* Not always meaningful for GX. */ +/* */ +/* minimum :: The axis's minimum design coordinate. */ +/* */ +/* def :: The axis's default design coordinate. */ +/* FreeType computes meaningful default values for MM; it */ +/* is then an integer value, not in 16.16 format. */ +/* */ +/* maximum :: The axis's maximum design coordinate. */ +/* */ +/* tag :: The axis's tag (the GX equivalent to `name'). */ +/* FreeType provides default values for MM if possible. */ +/* */ +/* strid :: The entry in `name' table (another GX version of */ +/* `name'). */ +/* Not meaningful for MM. */ +/* */ + typedef struct FT_Var_Axis_ + { + FT_String* name; + FT_Fixed minimum; + FT_Fixed def; + FT_Fixed maximum; + FT_ULong tag; + FT_UInt strid; + } FT_Var_Axis; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_Var_Named_Style */ +/* */ +/* <Description> */ +/* A simple structure used to model a named style in a GX var font. */ +/* */ +/* This structure can't be used for MM fonts. */ +/* */ +/* <Fields> */ +/* coords :: The design coordinates for this style. */ +/* This is an array with one entry for each axis. */ +/* */ +/* strid :: The entry in `name' table identifying this style. */ +/* */ + typedef struct FT_Var_Named_Style_ + { + FT_Fixed* coords; + FT_UInt strid; + } FT_Var_Named_Style; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_MM_Var */ +/* */ +/* <Description> */ +/* A structure used to model the axes and space of a Multiple Masters */ +/* or GX var distortable font. */ +/* */ +/* Some fields are specific to one format and not to the other. */ +/* */ +/* <Fields> */ +/* num_axis :: The number of axes. The maximum value is~4 for */ +/* MM; no limit in GX. */ +/* */ +/* num_designs :: The number of designs; should be normally */ +/* 2^num_axis for MM fonts. Not meaningful for GX */ +/* (where every glyph could have a different */ +/* number of designs). */ +/* */ +/* num_namedstyles :: The number of named styles; only meaningful for */ +/* GX which allows certain design coordinates to */ +/* have a string ID (in the `name' table) */ +/* associated with them. The font can tell the */ +/* user that, for example, Weight=1.5 is `Bold'. */ +/* */ +/* axis :: A table of axis descriptors. */ +/* GX fonts contain slightly more data than MM. */ +/* */ +/* namedstyles :: A table of named styles. */ +/* Only meaningful with GX. */ +/* */ + typedef struct FT_MM_Var_ + { + FT_UInt num_axis; + FT_UInt num_designs; + FT_UInt num_namedstyles; + FT_Var_Axis* axis; + FT_Var_Named_Style* namedstyle; + } FT_MM_Var; +/* */ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Multi_Master */ +/* */ +/* <Description> */ +/* Retrieve the Multiple Master descriptor of a given font. */ +/* */ +/* This function can't be used with GX fonts. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face. */ +/* */ +/* <Output> */ +/* amaster :: The Multiple Masters descriptor. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_MM_Var */ +/* */ +/* <Description> */ +/* Retrieve the Multiple Master/GX var descriptor of a given font. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face. */ +/* */ +/* <Output> */ +/* amaster :: The Multiple Masters/GX var descriptor. */ +/* Allocates a data structure, which the user must free */ +/* (a single call to FT_FREE will do it). */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_MM_Design_Coordinates */ +/* */ +/* <Description> */ +/* For Multiple Masters fonts, choose an interpolated font design */ +/* through design coordinates. */ +/* */ +/* This function can't be used with GX fonts. */ +/* */ +/* <InOut> */ +/* face :: A handle to the source face. */ +/* */ +/* <Input> */ +/* num_coords :: The number of design coordinates (must be equal to */ +/* the number of axes in the font). */ +/* */ +/* coords :: An array of design coordinates. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Var_Design_Coordinates */ +/* */ +/* <Description> */ +/* For Multiple Master or GX Var fonts, choose an interpolated font */ +/* design through design coordinates. */ +/* */ +/* <InOut> */ +/* face :: A handle to the source face. */ +/* */ +/* <Input> */ +/* num_coords :: The number of design coordinates (must be equal to */ +/* the number of axes in the font). */ +/* */ +/* coords :: An array of design coordinates. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_MM_Blend_Coordinates */ +/* */ +/* <Description> */ +/* For Multiple Masters and GX var fonts, choose an interpolated font */ +/* design through normalized blend coordinates. */ +/* */ +/* <InOut> */ +/* face :: A handle to the source face. */ +/* */ +/* <Input> */ +/* num_coords :: The number of design coordinates (must be equal to */ +/* the number of axes in the font). */ +/* */ +/* coords :: The design coordinates array (each element must be */ +/* between 0 and 1.0). */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Set_Var_Blend_Coordinates */ +/* */ +/* <Description> */ +/* This is another name of @FT_Set_MM_Blend_Coordinates. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TTC_HeaderRec */ +/* */ +/* <Description> */ +/* TrueType collection header. This table contains the offsets of */ +/* the font headers of each distinct TrueType face in the file. */ +/* */ +/* <Fields> */ +/* tag :: Must be `ttc ' to indicate a TrueType collection. */ +/* */ +/* version :: The version number. */ +/* */ +/* count :: The number of faces in the collection. The */ +/* specification says this should be an unsigned long, but */ +/* we use a signed long since we need the value -1 for */ +/* specific purposes. */ +/* */ +/* offsets :: The offsets of the font headers, one per face. */ +/* */ + typedef struct TTC_HeaderRec_ + { + FT_ULong tag; + FT_Fixed version; + FT_Long count; + FT_ULong* offsets; + } TTC_HeaderRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* SFNT_HeaderRec */ +/* */ +/* <Description> */ +/* SFNT file format header. */ +/* */ +/* <Fields> */ +/* format_tag :: The font format tag. */ +/* */ +/* num_tables :: The number of tables in file. */ +/* */ +/* search_range :: Must be `16 * (max power of 2 <= num_tables)'. */ +/* */ +/* entry_selector :: Must be log2 of `search_range / 16'. */ +/* */ +/* range_shift :: Must be `num_tables * 16 - search_range'. */ +/* */ + typedef struct SFNT_HeaderRec_ + { + FT_ULong format_tag; + FT_UShort num_tables; + FT_UShort search_range; + FT_UShort entry_selector; + FT_UShort range_shift; +/* not in file */ + FT_ULong offset; + } SFNT_HeaderRec, *SFNT_Header; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_TableRec */ +/* */ +/* <Description> */ +/* This structure describes a given table of a TrueType font. */ +/* */ +/* <Fields> */ +/* Tag :: A four-bytes tag describing the table. */ +/* */ +/* CheckSum :: The table checksum. This value can be ignored. */ +/* */ +/* Offset :: The offset of the table from the start of the TrueType */ +/* font in its resource. */ +/* */ +/* Length :: The table length (in bytes). */ +/* */ + typedef struct TT_TableRec_ + { +/* table type */ + FT_ULong Tag; +/* table checksum */ + FT_ULong CheckSum; +/* table file offset */ + FT_ULong Offset; +/* table length */ + FT_ULong Length; + } TT_TableRec, *TT_Table; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_LongMetricsRec */ +/* */ +/* <Description> */ +/* A structure modeling the long metrics of the `hmtx' and `vmtx' */ +/* TrueType tables. The values are expressed in font units. */ +/* */ +/* <Fields> */ +/* advance :: The advance width or height for the glyph. */ +/* */ +/* bearing :: The left-side or top-side bearing for the glyph. */ +/* */ + typedef struct TT_LongMetricsRec_ + { + FT_UShort advance; + FT_Short bearing; + } TT_LongMetricsRec, *TT_LongMetrics; +/*************************************************************************/ +/* */ +/* <Type> */ +/* TT_ShortMetrics */ +/* */ +/* <Description> */ +/* A simple type to model the short metrics of the `hmtx' and `vmtx' */ +/* tables. */ +/* */ + typedef FT_Short TT_ShortMetrics; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_NameEntryRec */ +/* */ +/* <Description> */ +/* A structure modeling TrueType name records. Name records are used */ +/* to store important strings like family name, style name, */ +/* copyright, etc. in _localized_ versions (i.e., language, encoding, */ +/* etc). */ +/* */ +/* <Fields> */ +/* platformID :: The ID of the name's encoding platform. */ +/* */ +/* encodingID :: The platform-specific ID for the name's encoding. */ +/* */ +/* languageID :: The platform-specific ID for the name's language. */ +/* */ +/* nameID :: The ID specifying what kind of name this is. */ +/* */ +/* stringLength :: The length of the string in bytes. */ +/* */ +/* stringOffset :: The offset to the string in the `name' table. */ +/* */ +/* string :: A pointer to the string's bytes. Note that these */ +/* are usually UTF-16 encoded characters. */ +/* */ + typedef struct TT_NameEntryRec_ + { + FT_UShort platformID; + FT_UShort encodingID; + FT_UShort languageID; + FT_UShort nameID; + FT_UShort stringLength; + FT_ULong stringOffset; +/* this last field is not defined in the spec */ +/* but used by the FreeType engine */ + FT_Byte* string; + } TT_NameEntryRec, *TT_NameEntry; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_NameTableRec */ +/* */ +/* <Description> */ +/* A structure modeling the TrueType name table. */ +/* */ +/* <Fields> */ +/* format :: The format of the name table. */ +/* */ +/* numNameRecords :: The number of names in table. */ +/* */ +/* storageOffset :: The offset of the name table in the `name' */ +/* TrueType table. */ +/* */ +/* names :: An array of name records. */ +/* */ +/* stream :: the file's input stream. */ +/* */ + typedef struct TT_NameTableRec_ + { + FT_UShort format; + FT_UInt numNameRecords; + FT_UInt storageOffset; + TT_NameEntryRec* names; + FT_Stream stream; + } TT_NameTableRec, *TT_NameTable; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_GaspRangeRec */ +/* */ +/* <Description> */ +/* A tiny structure used to model a gasp range according to the */ +/* TrueType specification. */ +/* */ +/* <Fields> */ +/* maxPPEM :: The maximum ppem value to which `gaspFlag' applies. */ +/* */ +/* gaspFlag :: A flag describing the grid-fitting and anti-aliasing */ +/* modes to be used. */ +/* */ + typedef struct TT_GaspRangeRec_ + { + FT_UShort maxPPEM; + FT_UShort gaspFlag; + } TT_GaspRangeRec, *TT_GaspRange; +#define TT_GASP_GRIDFIT 0x01 +#define TT_GASP_DOGRAY 0x02 +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_GaspRec */ +/* */ +/* <Description> */ +/* A structure modeling the TrueType `gasp' table used to specify */ +/* grid-fitting and anti-aliasing behaviour. */ +/* */ +/* <Fields> */ +/* version :: The version number. */ +/* */ +/* numRanges :: The number of gasp ranges in table. */ +/* */ +/* gaspRanges :: An array of gasp ranges. */ +/* */ + typedef struct TT_Gasp_ + { + FT_UShort version; + FT_UShort numRanges; + TT_GaspRange gaspRanges; + } TT_GaspRec; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** EMBEDDED BITMAPS SUPPORT ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_MetricsRec */ +/* */ +/* <Description> */ +/* A structure used to hold the big metrics of a given glyph bitmap */ +/* in a TrueType or OpenType font. These are usually found in the */ +/* `EBDT' (Microsoft) or `bloc' (Apple) table. */ +/* */ +/* <Fields> */ +/* height :: The glyph height in pixels. */ +/* */ +/* width :: The glyph width in pixels. */ +/* */ +/* horiBearingX :: The horizontal left bearing. */ +/* */ +/* horiBearingY :: The horizontal top bearing. */ +/* */ +/* horiAdvance :: The horizontal advance. */ +/* */ +/* vertBearingX :: The vertical left bearing. */ +/* */ +/* vertBearingY :: The vertical top bearing. */ +/* */ +/* vertAdvance :: The vertical advance. */ +/* */ + typedef struct TT_SBit_MetricsRec_ + { + FT_Byte height; + FT_Byte width; + FT_Char horiBearingX; + FT_Char horiBearingY; + FT_Byte horiAdvance; + FT_Char vertBearingX; + FT_Char vertBearingY; + FT_Byte vertAdvance; + } TT_SBit_MetricsRec, *TT_SBit_Metrics; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_SmallMetricsRec */ +/* */ +/* <Description> */ +/* A structure used to hold the small metrics of a given glyph bitmap */ +/* in a TrueType or OpenType font. These are usually found in the */ +/* `EBDT' (Microsoft) or the `bdat' (Apple) table. */ +/* */ +/* <Fields> */ +/* height :: The glyph height in pixels. */ +/* */ +/* width :: The glyph width in pixels. */ +/* */ +/* bearingX :: The left-side bearing. */ +/* */ +/* bearingY :: The top-side bearing. */ +/* */ +/* advance :: The advance width or height. */ +/* */ + typedef struct TT_SBit_Small_Metrics_ + { + FT_Byte height; + FT_Byte width; + FT_Char bearingX; + FT_Char bearingY; + FT_Byte advance; + } TT_SBit_SmallMetricsRec, *TT_SBit_SmallMetrics; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_LineMetricsRec */ +/* */ +/* <Description> */ +/* A structure used to describe the text line metrics of a given */ +/* bitmap strike, for either a horizontal or vertical layout. */ +/* */ +/* <Fields> */ +/* ascender :: The ascender in pixels. */ +/* */ +/* descender :: The descender in pixels. */ +/* */ +/* max_width :: The maximum glyph width in pixels. */ +/* */ +/* caret_slope_enumerator :: Rise of the caret slope, typically set */ +/* to 1 for non-italic fonts. */ +/* */ +/* caret_slope_denominator :: Rise of the caret slope, typically set */ +/* to 0 for non-italic fonts. */ +/* */ +/* caret_offset :: Offset in pixels to move the caret for */ +/* proper positioning. */ +/* */ +/* min_origin_SB :: Minimum of horiBearingX (resp. */ +/* vertBearingY). */ +/* min_advance_SB :: Minimum of */ +/* */ +/* horizontal advance - */ +/* ( horiBearingX + width ) */ +/* */ +/* resp. */ +/* */ +/* vertical advance - */ +/* ( vertBearingY + height ) */ +/* */ +/* max_before_BL :: Maximum of horiBearingY (resp. */ +/* vertBearingY). */ +/* */ +/* min_after_BL :: Minimum of */ +/* */ +/* horiBearingY - height */ +/* */ +/* resp. */ +/* */ +/* vertBearingX - width */ +/* */ +/* pads :: Unused (to make the size of the record */ +/* a multiple of 32 bits. */ +/* */ + typedef struct TT_SBit_LineMetricsRec_ + { + FT_Char ascender; + FT_Char descender; + FT_Byte max_width; + FT_Char caret_slope_numerator; + FT_Char caret_slope_denominator; + FT_Char caret_offset; + FT_Char min_origin_SB; + FT_Char min_advance_SB; + FT_Char max_before_BL; + FT_Char min_after_BL; + FT_Char pads[2]; + } TT_SBit_LineMetricsRec, *TT_SBit_LineMetrics; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_RangeRec */ +/* */ +/* <Description> */ +/* A TrueType/OpenType subIndexTable as defined in the `EBLC' */ +/* (Microsoft) or `bloc' (Apple) tables. */ +/* */ +/* <Fields> */ +/* first_glyph :: The first glyph index in the range. */ +/* */ +/* last_glyph :: The last glyph index in the range. */ +/* */ +/* index_format :: The format of index table. Valid values are 1 */ +/* to 5. */ +/* */ +/* image_format :: The format of `EBDT' image data. */ +/* */ +/* image_offset :: The offset to image data in `EBDT'. */ +/* */ +/* image_size :: For index formats 2 and 5. This is the size in */ +/* bytes of each glyph bitmap. */ +/* */ +/* big_metrics :: For index formats 2 and 5. This is the big */ +/* metrics for each glyph bitmap. */ +/* */ +/* num_glyphs :: For index formats 4 and 5. This is the number of */ +/* glyphs in the code array. */ +/* */ +/* glyph_offsets :: For index formats 1 and 3. */ +/* */ +/* glyph_codes :: For index formats 4 and 5. */ +/* */ +/* table_offset :: The offset of the index table in the `EBLC' */ +/* table. Only used during strike loading. */ +/* */ + typedef struct TT_SBit_RangeRec_ + { + FT_UShort first_glyph; + FT_UShort last_glyph; + FT_UShort index_format; + FT_UShort image_format; + FT_ULong image_offset; + FT_ULong image_size; + TT_SBit_MetricsRec metrics; + FT_ULong num_glyphs; + FT_ULong* glyph_offsets; + FT_UShort* glyph_codes; + FT_ULong table_offset; + } TT_SBit_RangeRec, *TT_SBit_Range; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_StrikeRec */ +/* */ +/* <Description> */ +/* A structure used describe a given bitmap strike in the `EBLC' */ +/* (Microsoft) or `bloc' (Apple) tables. */ +/* */ +/* <Fields> */ +/* num_index_ranges :: The number of index ranges. */ +/* */ +/* index_ranges :: An array of glyph index ranges. */ +/* */ +/* color_ref :: Unused. `color_ref' is put in for future */ +/* enhancements, but these fields are already */ +/* in use by other platforms (e.g. Newton). */ +/* For details, please see */ +/* */ +/* http://fonts.apple.com/ */ +/* TTRefMan/RM06/Chap6bloc.html */ +/* */ +/* hori :: The line metrics for horizontal layouts. */ +/* */ +/* vert :: The line metrics for vertical layouts. */ +/* */ +/* start_glyph :: The lowest glyph index for this strike. */ +/* */ +/* end_glyph :: The highest glyph index for this strike. */ +/* */ +/* x_ppem :: The number of horizontal pixels per EM. */ +/* */ +/* y_ppem :: The number of vertical pixels per EM. */ +/* */ +/* bit_depth :: The bit depth. Valid values are 1, 2, 4, */ +/* and 8. */ +/* */ +/* flags :: Is this a vertical or horizontal strike? For */ +/* details, please see */ +/* */ +/* http://fonts.apple.com/ */ +/* TTRefMan/RM06/Chap6bloc.html */ +/* */ + typedef struct TT_SBit_StrikeRec_ + { + FT_Int num_ranges; + TT_SBit_Range sbit_ranges; + FT_ULong ranges_offset; + FT_ULong color_ref; + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + FT_UShort start_glyph; + FT_UShort end_glyph; + FT_Byte x_ppem; + FT_Byte y_ppem; + FT_Byte bit_depth; + FT_Char flags; + } TT_SBit_StrikeRec, *TT_SBit_Strike; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_ComponentRec */ +/* */ +/* <Description> */ +/* A simple structure to describe a compound sbit element. */ +/* */ +/* <Fields> */ +/* glyph_code :: The element's glyph index. */ +/* */ +/* x_offset :: The element's left bearing. */ +/* */ +/* y_offset :: The element's top bearing. */ +/* */ + typedef struct TT_SBit_ComponentRec_ + { + FT_UShort glyph_code; + FT_Char x_offset; + FT_Char y_offset; + } TT_SBit_ComponentRec, *TT_SBit_Component; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_SBit_ScaleRec */ +/* */ +/* <Description> */ +/* A structure used describe a given bitmap scaling table, as defined */ +/* in the `EBSC' table. */ +/* */ +/* <Fields> */ +/* hori :: The horizontal line metrics. */ +/* */ +/* vert :: The vertical line metrics. */ +/* */ +/* x_ppem :: The number of horizontal pixels per EM. */ +/* */ +/* y_ppem :: The number of vertical pixels per EM. */ +/* */ +/* x_ppem_substitute :: Substitution x_ppem value. */ +/* */ +/* y_ppem_substitute :: Substitution y_ppem value. */ +/* */ + typedef struct TT_SBit_ScaleRec_ + { + TT_SBit_LineMetricsRec hori; + TT_SBit_LineMetricsRec vert; + FT_Byte x_ppem; + FT_Byte y_ppem; + FT_Byte x_ppem_substitute; + FT_Byte y_ppem_substitute; + } TT_SBit_ScaleRec, *TT_SBit_Scale; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** POSTSCRIPT GLYPH NAMES SUPPORT ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_Post_20Rec */ +/* */ +/* <Description> */ +/* Postscript names sub-table, format 2.0. Stores the PS name of */ +/* each glyph in the font face. */ +/* */ +/* <Fields> */ +/* num_glyphs :: The number of named glyphs in the table. */ +/* */ +/* num_names :: The number of PS names stored in the table. */ +/* */ +/* glyph_indices :: The indices of the glyphs in the names arrays. */ +/* */ +/* glyph_names :: The PS names not in Mac Encoding. */ +/* */ + typedef struct TT_Post_20Rec_ + { + FT_UShort num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices; + FT_Char** glyph_names; + } TT_Post_20Rec, *TT_Post_20; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_Post_25Rec */ +/* */ +/* <Description> */ +/* Postscript names sub-table, format 2.5. Stores the PS name of */ +/* each glyph in the font face. */ +/* */ +/* <Fields> */ +/* num_glyphs :: The number of glyphs in the table. */ +/* */ +/* offsets :: An array of signed offsets in a normal Mac */ +/* Postscript name encoding. */ +/* */ + typedef struct TT_Post_25_ + { + FT_UShort num_glyphs; + FT_Char* offsets; + } TT_Post_25Rec, *TT_Post_25; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_Post_NamesRec */ +/* */ +/* <Description> */ +/* Postscript names table, either format 2.0 or 2.5. */ +/* */ +/* <Fields> */ +/* loaded :: A flag to indicate whether the PS names are loaded. */ +/* */ +/* format_20 :: The sub-table used for format 2.0. */ +/* */ +/* format_25 :: The sub-table used for format 2.5. */ +/* */ + typedef struct TT_Post_NamesRec_ + { + FT_Bool loaded; + union + { + TT_Post_20Rec format_20; + TT_Post_25Rec format_25; + } names; + } TT_Post_NamesRec, *TT_Post_Names; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** GX VARIATION TABLE SUPPORT ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct GX_BlendRec_ *GX_Blend; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** EMBEDDED BDF PROPERTIES TABLE SUPPORT ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* + * These types are used to support a `BDF ' table that isn't part of the + * official TrueType specification. It is mainly used in SFNT-based + * bitmap fonts that were generated from a set of BDF fonts. + * + * The format of the table is as follows. + * + * USHORT version `BDF ' table version number, should be 0x0001. + * USHORT strikeCount Number of strikes (bitmap sizes) in this table. + * ULONG stringTable Offset (from start of BDF table) to string + * table. + * + * This is followed by an array of `strikeCount' descriptors, having the + * following format. + * + * USHORT ppem Vertical pixels per EM for this strike. + * USHORT numItems Number of items for this strike (properties and + * atoms). Maximum is 255. + * + * This array in turn is followed by `strikeCount' value sets. Each + * `value set' is an array of `numItems' items with the following format. + * + * ULONG item_name Offset in string table to item name. + * USHORT item_type The item type. Possible values are + * 0 => string (e.g., COMMENT) + * 1 => atom (e.g., FONT or even SIZE) + * 2 => int32 + * 3 => uint32 + * 0x10 => A flag to indicate a properties. This + * is ORed with the above values. + * ULONG item_value For strings => Offset into string table without + * the corresponding double quotes. + * For atoms => Offset into string table. + * For integers => Direct value. + * + * All strings in the string table consist of bytes and are + * zero-terminated. + * + */ + typedef struct TT_BDFRec_ + { + FT_Byte* table; + FT_Byte* table_end; + FT_Byte* strings; + FT_ULong strings_size; + FT_UInt num_strikes; + FT_Bool loaded; + } TT_BDFRec, *TT_BDF; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** ORIGINAL TT_FACE CLASS DEFINITION ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* This structure/class is defined here because it is common to the */ +/* following formats: TTF, OpenType-TT, and OpenType-CFF. */ +/* */ +/* Note, however, that the classes TT_Size and TT_GlyphSlot are not */ +/* shared between font drivers, and are thus defined in `ttobjs.h'. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* TT_Face */ +/* */ +/* <Description> */ +/* A handle to a TrueType face/font object. A TT_Face encapsulates */ +/* the resolution and scaling independent parts of a TrueType font */ +/* resource. */ +/* */ +/* <Note> */ +/* The TT_Face structure is also used as a `parent class' for the */ +/* OpenType-CFF class (T2_Face). */ +/* */ + typedef struct TT_FaceRec_* TT_Face; +/* a function type used for the truetype bytecode interpreter hooks */ + typedef FT_Error + (*TT_Interpreter)( void* exec_context ); +/* forward declaration */ + typedef struct TT_LoaderRec_* TT_Loader; +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Loader_GotoTableFunc */ +/* */ +/* <Description> */ +/* Seeks a stream to the start of a given TrueType table. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* tag :: A 4-byte tag used to name the table. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Output> */ +/* length :: The length of the table in bytes. Set to 0 if not */ +/* needed. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* The stream cursor must be at the font file's origin. */ +/* */ + typedef FT_Error + (*TT_Loader_GotoTableFunc)( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Loader_StartGlyphFunc */ +/* */ +/* <Description> */ +/* Seeks a stream to the start of a given glyph element, and opens a */ +/* frame for it. */ +/* */ +/* <Input> */ +/* loader :: The current TrueType glyph loader object. */ +/* */ +/* glyph index :: The index of the glyph to access. */ +/* */ +/* offset :: The offset of the glyph according to the */ +/* `locations' table. */ +/* */ +/* byte_count :: The size of the frame in bytes. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* This function is normally equivalent to FT_STREAM_SEEK(offset) */ +/* followed by FT_FRAME_ENTER(byte_count) with the loader's stream, */ +/* but alternative formats (e.g. compressed ones) might use something */ +/* different. */ +/* */ + typedef FT_Error + (*TT_Loader_StartGlyphFunc)( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Loader_ReadGlyphFunc */ +/* */ +/* <Description> */ +/* Reads one glyph element (its header, a simple glyph, or a */ +/* composite) from the loader's current stream frame. */ +/* */ +/* <Input> */ +/* loader :: The current TrueType glyph loader object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + typedef FT_Error + (*TT_Loader_ReadGlyphFunc)( TT_Loader loader ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Loader_EndGlyphFunc */ +/* */ +/* <Description> */ +/* Closes the current loader stream frame for the glyph. */ +/* */ +/* <Input> */ +/* loader :: The current TrueType glyph loader object. */ +/* */ + typedef void + (*TT_Loader_EndGlyphFunc)( TT_Loader loader ); +/*************************************************************************/ +/* */ +/* TrueType Face Type */ +/* */ +/* <Struct> */ +/* TT_Face */ +/* */ +/* <Description> */ +/* The TrueType face class. These objects model the resolution and */ +/* point-size independent data found in a TrueType font file. */ +/* */ +/* <Fields> */ +/* root :: The base FT_Face structure, managed by the */ +/* base layer. */ +/* */ +/* ttc_header :: The TrueType collection header, used when */ +/* the file is a `ttc' rather than a `ttf'. */ +/* For ordinary font files, the field */ +/* `ttc_header.count' is set to 0. */ +/* */ +/* format_tag :: The font format tag. */ +/* */ +/* num_tables :: The number of TrueType tables in this font */ +/* file. */ +/* */ +/* dir_tables :: The directory of TrueType tables for this */ +/* font file. */ +/* */ +/* header :: The font's font header (`head' table). */ +/* Read on font opening. */ +/* */ +/* horizontal :: The font's horizontal header (`hhea' */ +/* table). This field also contains the */ +/* associated horizontal metrics table */ +/* (`hmtx'). */ +/* */ +/* max_profile :: The font's maximum profile table. Read on */ +/* font opening. Note that some maximum */ +/* values cannot be taken directly from this */ +/* table. We thus define additional fields */ +/* below to hold the computed maxima. */ +/* */ +/* vertical_info :: A boolean which is set when the font file */ +/* contains vertical metrics. If not, the */ +/* value of the `vertical' field is */ +/* undefined. */ +/* */ +/* vertical :: The font's vertical header (`vhea' table). */ +/* This field also contains the associated */ +/* vertical metrics table (`vmtx'), if found. */ +/* IMPORTANT: The contents of this field is */ +/* undefined if the `verticalInfo' field is */ +/* unset. */ +/* */ +/* num_names :: The number of name records within this */ +/* TrueType font. */ +/* */ +/* name_table :: The table of name records (`name'). */ +/* */ +/* os2 :: The font's OS/2 table (`OS/2'). */ +/* */ +/* postscript :: The font's PostScript table (`post' */ +/* table). The PostScript glyph names are */ +/* not loaded by the driver on face opening. */ +/* See the `ttpost' module for more details. */ +/* */ +/* cmap_table :: Address of the face's `cmap' SFNT table */ +/* in memory (it's an extracted frame). */ +/* */ +/* cmap_size :: The size in bytes of the `cmap_table' */ +/* described above. */ +/* */ +/* goto_table :: A function called by each TrueType table */ +/* loader to position a stream's cursor to */ +/* the start of a given table according to */ +/* its tag. It defaults to TT_Goto_Face but */ +/* can be different for strange formats (e.g. */ +/* Type 42). */ +/* */ +/* access_glyph_frame :: A function used to access the frame of a */ +/* given glyph within the face's font file. */ +/* */ +/* forget_glyph_frame :: A function used to forget the frame of a */ +/* given glyph when all data has been loaded. */ +/* */ +/* read_glyph_header :: A function used to read a glyph header. */ +/* It must be called between an `access' and */ +/* `forget'. */ +/* */ +/* read_simple_glyph :: A function used to read a simple glyph. */ +/* It must be called after the header was */ +/* read, and before the `forget'. */ +/* */ +/* read_composite_glyph :: A function used to read a composite glyph. */ +/* It must be called after the header was */ +/* read, and before the `forget'. */ +/* */ +/* sfnt :: A pointer to the SFNT service. */ +/* */ +/* psnames :: A pointer to the PostScript names service. */ +/* */ +/* hdmx :: The face's horizontal device metrics */ +/* (`hdmx' table). This table is optional in */ +/* TrueType/OpenType fonts. */ +/* */ +/* gasp :: The grid-fitting and scaling properties */ +/* table (`gasp'). This table is optional in */ +/* TrueType/OpenType fonts. */ +/* */ +/* pclt :: The `pclt' SFNT table. */ +/* */ +/* num_sbit_strikes :: The number of sbit strikes, i.e., bitmap */ +/* sizes, embedded in this font. */ +/* */ +/* sbit_strikes :: An array of sbit strikes embedded in this */ +/* font. This table is optional in a */ +/* TrueType/OpenType font. */ +/* */ +/* num_sbit_scales :: The number of sbit scales for this font. */ +/* */ +/* sbit_scales :: Array of sbit scales embedded in this */ +/* font. This table is optional in a */ +/* TrueType/OpenType font. */ +/* */ +/* postscript_names :: A table used to store the Postscript names */ +/* of the glyphs for this font. See the */ +/* file `ttconfig.h' for comments on the */ +/* TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. */ +/* */ +/* num_locations :: The number of glyph locations in this */ +/* TrueType file. This should be */ +/* identical to the number of glyphs. */ +/* Ignored for Type 2 fonts. */ +/* */ +/* glyph_locations :: An array of longs. These are offsets to */ +/* glyph data within the `glyf' table. */ +/* Ignored for Type 2 font faces. */ +/* */ +/* glyf_len :: The length of the `glyf' table. Needed */ +/* for malformed `loca' tables. */ +/* */ +/* font_program_size :: Size in bytecodes of the face's font */ +/* program. 0 if none defined. Ignored for */ +/* Type 2 fonts. */ +/* */ +/* font_program :: The face's font program (bytecode stream) */ +/* executed at load time, also used during */ +/* glyph rendering. Comes from the `fpgm' */ +/* table. Ignored for Type 2 font fonts. */ +/* */ +/* cvt_program_size :: The size in bytecodes of the face's cvt */ +/* program. Ignored for Type 2 fonts. */ +/* */ +/* cvt_program :: The face's cvt program (bytecode stream) */ +/* executed each time an instance/size is */ +/* changed/reset. Comes from the `prep' */ +/* table. Ignored for Type 2 fonts. */ +/* */ +/* cvt_size :: Size of the control value table (in */ +/* entries). Ignored for Type 2 fonts. */ +/* */ +/* cvt :: The face's original control value table. */ +/* Coordinates are expressed in unscaled font */ +/* units. Comes from the `cvt ' table. */ +/* Ignored for Type 2 fonts. */ +/* */ +/* num_kern_pairs :: The number of kerning pairs present in the */ +/* font file. The engine only loads the */ +/* first horizontal format 0 kern table it */ +/* finds in the font file. Ignored for */ +/* Type 2 fonts. */ +/* */ +/* kern_table_index :: The index of the kerning table in the font */ +/* kerning directory. Ignored for Type 2 */ +/* fonts. */ +/* */ +/* interpreter :: A pointer to the TrueType bytecode */ +/* interpreters field is also used to hook */ +/* the debugger in `ttdebug'. */ +/* */ +/* unpatented_hinting :: If true, use only unpatented methods in */ +/* the bytecode interpreter. */ +/* */ +/* doblend :: A boolean which is set if the font should */ +/* be blended (this is for GX var). */ +/* */ +/* blend :: Contains the data needed to control GX */ +/* variation tables (rather like Multiple */ +/* Master data). */ +/* */ +/* extra :: Reserved for third-party font drivers. */ +/* */ +/* postscript_name :: The PS name of the font. Used by the */ +/* postscript name service. */ +/* */ + typedef struct TT_FaceRec_ + { + FT_FaceRec root; + TTC_HeaderRec ttc_header; + FT_ULong format_tag; + FT_UShort num_tables; + TT_Table dir_tables; +/* TrueType header table */ + TT_Header header; +/* TrueType horizontal header */ + TT_HoriHeader horizontal; + TT_MaxProfile max_profile; + FT_Bool vertical_info; +/* TT Vertical header, if present */ + TT_VertHeader vertical; +/* number of name records */ + FT_UShort num_names; +/* name table */ + TT_NameTableRec name_table; +/* TrueType OS/2 table */ + TT_OS2 os2; +/* TrueType Postscript table */ + TT_Postscript postscript; +/* extracted `cmap' table */ + FT_Byte* cmap_table; + FT_ULong cmap_size; + TT_Loader_GotoTableFunc goto_table; + TT_Loader_StartGlyphFunc access_glyph_frame; + TT_Loader_EndGlyphFunc forget_glyph_frame; + TT_Loader_ReadGlyphFunc read_glyph_header; + TT_Loader_ReadGlyphFunc read_simple_glyph; + TT_Loader_ReadGlyphFunc read_composite_glyph; +/* a typeless pointer to the SFNT_Interface table used to load */ +/* the basic TrueType tables in the face object */ + void* sfnt; +/* a typeless pointer to the FT_Service_PsCMapsRec table used to */ +/* handle glyph names <-> unicode & Mac values */ + void* psnames; +/***********************************************************************/ +/* */ +/* Optional TrueType/OpenType tables */ +/* */ +/***********************************************************************/ +/* horizontal device metrics */ +/* grid-fitting and scaling table */ +/* the `gasp' table */ + TT_GaspRec gasp; +/* PCL 5 table */ + TT_PCLT pclt; +/* embedded bitmaps support */ + FT_ULong num_sbit_scales; + TT_SBit_Scale sbit_scales; +/* postscript names table */ + TT_Post_NamesRec postscript_names; +/***********************************************************************/ +/* */ +/* TrueType-specific fields (ignored by the OTF-Type2 driver) */ +/* */ +/***********************************************************************/ +/* the glyph locations */ +/* the font program, if any */ + FT_ULong font_program_size; + FT_Byte* font_program; +/* the cvt program, if any */ + FT_ULong cvt_program_size; + FT_Byte* cvt_program; +/* the original, unscaled, control value table */ + FT_ULong cvt_size; + FT_Short* cvt; +/* A pointer to the bytecode interpreter to use. This is also */ +/* used to hook the debugger for the `ttdebug' utility. */ + TT_Interpreter interpreter; +/***********************************************************************/ +/* */ +/* Other tables or fields. This is used by derivative formats like */ +/* OpenType. */ +/* */ +/***********************************************************************/ + FT_Generic extra; + const char* postscript_name; +/* since version 2.1.8, but was originally placed after */ +/* `glyph_locations_stub' */ + FT_ULong glyf_len; +/* since version 2.1.8, but was originally placed before `extra' */ + FT_Bool doblend; + GX_Blend blend; +/* since version 2.2 */ + FT_Byte* horz_metrics; + FT_ULong horz_metrics_size; + FT_Byte* vert_metrics; + FT_ULong vert_metrics_size; +/* in broken TTF, gid > 0xFFFF */ + FT_ULong num_locations; + FT_Byte* glyph_locations; + FT_Byte* hdmx_table; + FT_ULong hdmx_table_size; + FT_UInt hdmx_record_count; + FT_ULong hdmx_record_size; + FT_Byte* hdmx_record_sizes; + FT_Byte* sbit_table; + FT_ULong sbit_table_size; + FT_UInt sbit_num_strikes; + FT_Byte* kern_table; + FT_ULong kern_table_size; + FT_UInt num_kern_tables; + FT_UInt32 kern_avail_bits; + FT_UInt32 kern_order_bits; + TT_BDFRec bdf; +/* since 2.3.0 */ + FT_ULong horz_metrics_offset; + FT_ULong vert_metrics_offset; + } TT_FaceRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_GlyphZoneRec */ +/* */ +/* <Description> */ +/* A glyph zone is used to load, scale and hint glyph outline */ +/* coordinates. */ +/* */ +/* <Fields> */ +/* memory :: A handle to the memory manager. */ +/* */ +/* max_points :: The maximum size in points of the zone. */ +/* */ +/* max_contours :: Max size in links contours of the zone. */ +/* */ +/* n_points :: The current number of points in the zone. */ +/* */ +/* n_contours :: The current number of contours in the zone. */ +/* */ +/* org :: The original glyph coordinates (font */ +/* units/scaled). */ +/* */ +/* cur :: The current glyph coordinates (scaled/hinted). */ +/* */ +/* tags :: The point control tags. */ +/* */ +/* contours :: The contours end points. */ +/* */ +/* first_point :: Offset of the current subglyph's first point. */ +/* */ + typedef struct TT_GlyphZoneRec_ + { + FT_Memory memory; + FT_UShort max_points; + FT_UShort max_contours; +/* number of points in zone */ + FT_UShort n_points; +/* number of contours */ + FT_Short n_contours; +/* original point coordinates */ + FT_Vector* org; +/* current point coordinates */ + FT_Vector* cur; +/* original (unscaled) point coordinates */ + FT_Vector* orus; +/* current touch flags */ + FT_Byte* tags; +/* contour end points */ + FT_UShort* contours; +/* offset of first (#0) point */ + FT_UShort first_point; + } TT_GlyphZoneRec, *TT_GlyphZone; +/* handle to execution context */ + typedef struct TT_ExecContextRec_* TT_ExecContext; +/* glyph loader structure */ + typedef struct TT_LoaderRec_ + { + FT_Face face; + FT_Size size; + FT_GlyphSlot glyph; + FT_GlyphLoader gloader; + FT_ULong load_flags; + FT_UInt glyph_index; + FT_Stream stream; + FT_Int byte_len; + FT_Short n_contours; + FT_BBox bbox; + FT_Int left_bearing; + FT_Int advance; + FT_Int linear; + FT_Bool linear_def; + FT_Bool preserve_pps; + FT_Vector pp1; + FT_Vector pp2; + FT_ULong glyf_offset; +/* the zone where we load our glyphs */ + TT_GlyphZoneRec base; + TT_GlyphZoneRec zone; + TT_ExecContext exec; + FT_Byte* instructions; + FT_ULong ins_pos; +/* for possible extensibility in other formats */ + void* other; +/* since version 2.1.8 */ + FT_Int top_bearing; + FT_Int vadvance; + FT_Vector pp3; + FT_Vector pp4; +/* since version 2.2.1 */ + FT_Byte* cursor; + FT_Byte* limit; + } TT_LoaderRec; +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Init_Face_Func */ +/* */ +/* <Description> */ +/* First part of the SFNT face object initialization. This finds */ +/* the face in a SFNT file or collection, and load its format tag in */ +/* face->format_tag. */ +/* */ +/* <Input> */ +/* stream :: The input stream. */ +/* */ +/* face :: A handle to the target face object. */ +/* */ +/* face_index :: The index of the TrueType font, if we are opening a */ +/* collection. */ +/* */ +/* num_params :: The number of additional parameters. */ +/* */ +/* params :: Optional additional parameters. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* The stream cursor must be at the font file's origin. */ +/* */ +/* This function recognizes fonts embedded in a `TrueType */ +/* collection'. */ +/* */ +/* Once the format tag has been validated by the font driver, it */ +/* should then call the TT_Load_Face_Func() callback to read the rest */ +/* of the SFNT tables in the object. */ +/* */ + typedef FT_Error + (*TT_Init_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_Face_Func */ +/* */ +/* <Description> */ +/* Second part of the SFNT face object initialization. This loads */ +/* the common SFNT tables (head, OS/2, maxp, metrics, etc.) in the */ +/* face object. */ +/* */ +/* <Input> */ +/* stream :: The input stream. */ +/* */ +/* face :: A handle to the target face object. */ +/* */ +/* face_index :: The index of the TrueType font, if we are opening a */ +/* collection. */ +/* */ +/* num_params :: The number of additional parameters. */ +/* */ +/* params :: Optional additional parameters. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* This function must be called after TT_Init_Face_Func(). */ +/* */ + typedef FT_Error + (*TT_Load_Face_Func)( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Done_Face_Func */ +/* */ +/* <Description> */ +/* A callback used to delete the common SFNT data from a face. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Note> */ +/* This function does NOT destroy the face object. */ +/* */ + typedef void + (*TT_Done_Face_Func)( TT_Face face ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_Any_Func */ +/* */ +/* <Description> */ +/* Load any font table into client memory. */ +/* */ +/* <Input> */ +/* face :: The face object to look for. */ +/* */ +/* tag :: The tag of table to load. Use the value 0 if you want */ +/* to access the whole font file, else set this parameter */ +/* to a valid TrueType table tag that you can forge with */ +/* the MAKE_TT_TAG macro. */ +/* */ +/* offset :: The starting offset in the table (or the file if */ +/* tag == 0). */ +/* */ +/* length :: The address of the decision variable: */ +/* */ +/* If length == NULL: */ +/* Loads the whole table. Returns an error if */ +/* `offset' == 0! */ +/* */ +/* If *length == 0: */ +/* Exits immediately; returning the length of the given */ +/* table or of the font file, depending on the value of */ +/* `tag'. */ +/* */ +/* If *length != 0: */ +/* Loads the next `length' bytes of table or font, */ +/* starting at offset `offset' (in table or font too). */ +/* */ +/* <Output> */ +/* buffer :: The address of target buffer. */ +/* */ +/* <Return> */ +/* TrueType error code. 0 means success. */ +/* */ + typedef FT_Error + (*TT_Load_Any_Func)( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte *buffer, + FT_ULong* length ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Find_SBit_Image_Func */ +/* */ +/* <Description> */ +/* Check whether an embedded bitmap (an `sbit') exists for a given */ +/* glyph, at a given strike. */ +/* */ +/* <Input> */ +/* face :: The target face object. */ +/* */ +/* glyph_index :: The glyph index. */ +/* */ +/* strike_index :: The current strike index. */ +/* */ +/* <Output> */ +/* arange :: The SBit range containing the glyph index. */ +/* */ +/* astrike :: The SBit strike containing the glyph index. */ +/* */ +/* aglyph_offset :: The offset of the glyph data in `EBDT' table. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. Returns */ +/* SFNT_Err_Invalid_Argument if no sbit exists for the requested */ +/* glyph. */ +/* */ + typedef FT_Error + (*TT_Find_SBit_Image_Func)( TT_Face face, + FT_UInt glyph_index, + FT_ULong strike_index, + TT_SBit_Range *arange, + TT_SBit_Strike *astrike, + FT_ULong *aglyph_offset ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_SBit_Metrics_Func */ +/* */ +/* <Description> */ +/* Get the big metrics for a given embedded bitmap. */ +/* */ +/* <Input> */ +/* stream :: The input stream. */ +/* */ +/* range :: The SBit range containing the glyph. */ +/* */ +/* <Output> */ +/* big_metrics :: A big SBit metrics structure for the glyph. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* The stream cursor must be positioned at the glyph's offset within */ +/* the `EBDT' table before the call. */ +/* */ +/* If the image format uses variable metrics, the stream cursor is */ +/* positioned just after the metrics header in the `EBDT' table on */ +/* function exit. */ +/* */ + typedef FT_Error + (*TT_Load_SBit_Metrics_Func)( FT_Stream stream, + TT_SBit_Range range, + TT_SBit_Metrics metrics ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_SBit_Image_Func */ +/* */ +/* <Description> */ +/* Load a given glyph sbit image from the font resource. This also */ +/* returns its metrics. */ +/* */ +/* <Input> */ +/* face :: */ +/* The target face object. */ +/* */ +/* strike_index :: */ +/* The strike index. */ +/* */ +/* glyph_index :: */ +/* The current glyph index. */ +/* */ +/* load_flags :: */ +/* The current load flags. */ +/* */ +/* stream :: */ +/* The input stream. */ +/* */ +/* <Output> */ +/* amap :: */ +/* The target pixmap. */ +/* */ +/* ametrics :: */ +/* A big sbit metrics structure for the glyph image. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. Returns an error if no */ +/* glyph sbit exists for the index. */ +/* */ +/* <Note> */ +/* The `map.buffer' field is always freed before the glyph is loaded. */ +/* */ + typedef FT_Error + (*TT_Load_SBit_Image_Func)( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *amap, + TT_SBit_MetricsRec *ametrics ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Set_SBit_Strike_Func */ +/* */ +/* <Description> */ +/* Select an sbit strike for a given size request. */ +/* */ +/* <Input> */ +/* face :: The target face object. */ +/* */ +/* req :: The size request. */ +/* */ +/* <Output> */ +/* astrike_index :: The index of the sbit strike. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. Returns an error if no */ +/* sbit strike exists for the selected ppem values. */ +/* */ + typedef FT_Error + (*TT_Set_SBit_Strike_Func)( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_Strike_Metrics_Func */ +/* */ +/* <Description> */ +/* Load the metrics of a given strike. */ +/* */ +/* <Input> */ +/* face :: The target face object. */ +/* */ +/* strike_index :: The strike index. */ +/* */ +/* <Output> */ +/* metrics :: the metrics of the strike. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. Returns an error if no */ +/* such sbit strike exists. */ +/* */ + typedef FT_Error + (*TT_Load_Strike_Metrics_Func)( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Get_PS_Name_Func */ +/* */ +/* <Description> */ +/* Get the PostScript glyph name of a glyph. */ +/* */ +/* <Input> */ +/* idx :: The glyph index. */ +/* */ +/* PSname :: The address of a string pointer. Will be NULL in case */ +/* of error, otherwise it is a pointer to the glyph name. */ +/* */ +/* You must not modify the returned string! */ +/* */ +/* <Output> */ +/* FreeType error code. 0 means success. */ +/* */ + typedef FT_Error + (*TT_Get_PS_Name_Func)( TT_Face face, + FT_UInt idx, + FT_String** PSname ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_Metrics_Func */ +/* */ +/* <Description> */ +/* Load a metrics table, which is a table with a horizontal and a */ +/* vertical version. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* vertical :: A boolean flag. If set, load the vertical one. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + typedef FT_Error + (*TT_Load_Metrics_Func)( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Get_Metrics_Func */ +/* */ +/* <Description> */ +/* Load the horizontal or vertical header in a face object. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* vertical :: A boolean flag. If set, load vertical metrics. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + typedef FT_Error + (*TT_Get_Metrics_Func)( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Load_Table_Func */ +/* */ +/* <Description> */ +/* Load a given TrueType table. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* The function uses `face->goto_table' to seek the stream to the */ +/* start of the table, except while loading the font directory. */ +/* */ + typedef FT_Error + (*TT_Load_Table_Func)( TT_Face face, + FT_Stream stream ); +/*************************************************************************/ +/* */ +/* <FuncType> */ +/* TT_Free_Table_Func */ +/* */ +/* <Description> */ +/* Free a given TrueType table. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ + typedef void + (*TT_Free_Table_Func)( TT_Face face ); +/* + * @functype: + * TT_Face_GetKerningFunc + * + * @description: + * Return the horizontal kerning value between two glyphs. + * + * @input: + * face :: A handle to the source face object. + * left_glyph :: The left glyph index. + * right_glyph :: The right glyph index. + * + * @return: + * The kerning value in font units. + */ + typedef FT_Int + (*TT_Face_GetKerningFunc)( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); +/*************************************************************************/ +/* */ +/* <Struct> */ +/* SFNT_Interface */ +/* */ +/* <Description> */ +/* This structure holds pointers to the functions used to load and */ +/* free the basic tables that are required in a `sfnt' font file. */ +/* */ +/* <Fields> */ +/* Check the various xxx_Func() descriptions for details. */ +/* */ + typedef struct SFNT_Interface_ + { + TT_Loader_GotoTableFunc goto_table; + TT_Init_Face_Func init_face; + TT_Load_Face_Func load_face; + TT_Done_Face_Func done_face; + FT_Module_Requester get_interface; + TT_Load_Any_Func load_any; +/* these functions are called by `load_face' but they can also */ +/* be called from external modules, if there is a need to do so */ + TT_Load_Table_Func load_head; + TT_Load_Metrics_Func load_hhea; + TT_Load_Table_Func load_cmap; + TT_Load_Table_Func load_maxp; + TT_Load_Table_Func load_os2; + TT_Load_Table_Func load_post; + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; +/* optional tables */ +/* this field was called `load_kerning' up to version 2.1.10 */ + TT_Load_Table_Func load_kern; + TT_Load_Table_Func load_gasp; + TT_Load_Table_Func load_pclt; +/* see `ttload.h'; this field was called `load_bitmap_header' up to */ +/* version 2.1.10 */ + TT_Load_Table_Func load_bhed; + TT_Load_SBit_Image_Func load_sbit_image; +/* see `ttpost.h' */ + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; +/* starting here, the structure differs from version 2.1.7 */ +/* this field was introduced in version 2.1.8, named `get_psname' */ + TT_Face_GetKerningFunc get_kerning; +/* new elements introduced after version 2.1.10 */ +/* load the font directory, i.e., the offset table and */ +/* the table directory */ + TT_Load_Table_Func load_font_dir; + TT_Load_Metrics_Func load_hmtx; + TT_Load_Table_Func load_eblc; + TT_Free_Table_Func free_eblc; + TT_Set_SBit_Strike_Func set_sbit_strike; + TT_Load_Strike_Metrics_Func load_strike_metrics; + TT_Get_Metrics_Func get_metrics; + } SFNT_Interface; +/* transitional */ + typedef SFNT_Interface* SFNT_Service; +/* empty */ +#define FT_DEFINE_DRIVERS_OLD_INTERNAL( a ) +#define FT_INTERNAL( a ) \ + a, +#define FT_DEFINE_SFNT_INTERFACE( \ + class_, \ + goto_table_, \ + init_face_, \ + load_face_, \ + done_face_, \ + get_interface_, \ + load_any_, \ + load_sfnt_header_, \ + load_directory_, \ + load_head_, \ + load_hhea_, \ + load_cmap_, \ + load_maxp_, \ + load_os2_, \ + load_post_, \ + load_name_, \ + free_name_, \ + load_hdmx_stub_, \ + free_hdmx_stub_, \ + load_kern_, \ + load_gasp_, \ + load_pclt_, \ + load_bhed_, \ + set_sbit_strike_stub_, \ + load_sbits_stub_, \ + find_sbit_image_, \ + load_sbit_metrics_, \ + load_sbit_image_, \ + free_sbits_stub_, \ + get_psname_, \ + free_psnames_, \ + load_charmap_stub_, \ + free_charmap_stub_, \ + get_kerning_, \ + load_font_dir_, \ + load_hmtx_, \ + load_eblc_, \ + free_eblc_, \ + set_sbit_strike_, \ + load_strike_metrics_, \ + get_metrics_ ) \ + static const SFNT_Interface class_ = \ + { \ + FT_INTERNAL( goto_table_ ) \ + FT_INTERNAL( init_face_ ) \ + FT_INTERNAL( load_face_ ) \ + FT_INTERNAL( done_face_ ) \ + FT_INTERNAL( get_interface_ ) \ + FT_INTERNAL( load_any_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( load_sfnt_header_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( load_directory_ ) \ + FT_INTERNAL( load_head_ ) \ + FT_INTERNAL( load_hhea_ ) \ + FT_INTERNAL( load_cmap_ ) \ + FT_INTERNAL( load_maxp_ ) \ + FT_INTERNAL( load_os2_ ) \ + FT_INTERNAL( load_post_ ) \ + FT_INTERNAL( load_name_ ) \ + FT_INTERNAL( free_name_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( load_hdmx_stub_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( free_hdmx_stub_ ) \ + FT_INTERNAL( load_kern_ ) \ + FT_INTERNAL( load_gasp_ ) \ + FT_INTERNAL( load_pclt_ ) \ + FT_INTERNAL( load_bhed_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( set_sbit_strike_stub_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( load_sbits_stub_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( find_sbit_image_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( load_sbit_metrics_ ) \ + FT_INTERNAL( load_sbit_image_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( free_sbits_stub_ ) \ + FT_INTERNAL( get_psname_ ) \ + FT_INTERNAL( free_psnames_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( load_charmap_stub_ ) \ + FT_DEFINE_DRIVERS_OLD_INTERNAL( free_charmap_stub_ ) \ + FT_INTERNAL( get_kerning_ ) \ + FT_INTERNAL( load_font_dir_ ) \ + FT_INTERNAL( load_hmtx_ ) \ + FT_INTERNAL( load_eblc_ ) \ + FT_INTERNAL( free_eblc_ ) \ + FT_INTERNAL( set_sbit_strike_ ) \ + FT_INTERNAL( load_strike_metrics_ ) \ + FT_INTERNAL( get_metrics_ ) \ + }; +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* tttags.h */ +/* */ +/* Tags for TrueType and OpenType tables (specification only). */ +/* */ +/* Copyright 1996-2001, 2004, 2005, 2007, 2008 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 __TTAGS_H__ +#define __TTAGS_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 +FT_BEGIN_HEADER +#define TTAG_avar FT_MAKE_TAG( 'a', 'v', 'a', 'r' ) +#define TTAG_BASE FT_MAKE_TAG( 'B', 'A', 'S', 'E' ) +#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' ) +#define TTAG_BDF FT_MAKE_TAG( 'B', 'D', 'F', ' ' ) +#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' ) +#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' ) +#define TTAG_bsln FT_MAKE_TAG( 'b', 's', 'l', 'n' ) +#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' ) +#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' ) +#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' ) +#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) +#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) +#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) +#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) +#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' ) +#define TTAG_feat FT_MAKE_TAG( 'f', 'e', 'a', 't' ) +#define TTAG_FOND FT_MAKE_TAG( 'F', 'O', 'N', 'D' ) +#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' ) +#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' ) +#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) +#define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) +#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) +#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) +#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) +#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) +#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) +#define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) +#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) +#define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) +#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) +#define TTAG_LWFN FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) +#define TTAG_MATH FT_MAKE_TAG( 'M', 'A', 'T', 'H' ) +#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) +#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) +#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) +#define TTAG_mort FT_MAKE_TAG( 'm', 'o', 'r', 't' ) +#define TTAG_morx FT_MAKE_TAG( 'm', 'o', 'r', 'x' ) +#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' ) +#define TTAG_opbd FT_MAKE_TAG( 'o', 'p', 'b', 'd' ) +#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' ) +#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' ) +#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' ) +#define TTAG_POST FT_MAKE_TAG( 'P', 'O', 'S', 'T' ) +#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' ) +#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' ) +#define TTAG_prop FT_MAKE_TAG( 'p', 'r', 'o', 'p' ) +#define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) +#define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_trak FT_MAKE_TAG( 't', 'r', 'a', 'k' ) +#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' ) +#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' ) +#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' ) +#define TTAG_TYP1 FT_MAKE_TAG( 'T', 'Y', 'P', '1' ) +#define TTAG_typ1 FT_MAKE_TAG( 't', 'y', 'p', '1' ) +#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) +#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) +FT_END_HEADER +/* __TTAGS_H__ */ +#endif +/* END */ +/***************************************************************************/ +/* */ +/* ttnameid.h */ +/* */ +/* TrueType name ID definitions (specification only). */ +/* */ +/* Copyright 1996-2004, 2006-2008, 2012 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. */ +/* */ +/***************************************************************************/ +#define __TTNAMEID_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* truetype_tables */ +/* */ +/*************************************************************************/ +/* */ +/* Possible values for the `platform' identifier code in the name */ +/* records of the TTF `name' table. */ +/* */ +/*************************************************************************/ +/*********************************************************************** + * + * @enum: + * TT_PLATFORM_XXX + * + * @description: + * A list of valid values for the `platform_id' identifier code in + * @FT_CharMapRec and @FT_SfntName structures. + * + * @values: + * TT_PLATFORM_APPLE_UNICODE :: + * Used by Apple to indicate a Unicode character map and/or name entry. + * See @TT_APPLE_ID_XXX for corresponding `encoding_id' values. Note + * that name entries in this format are coded as big-endian UCS-2 + * character codes _only_. + * + * TT_PLATFORM_MACINTOSH :: + * Used by Apple to indicate a MacOS-specific charmap and/or name entry. + * See @TT_MAC_ID_XXX for corresponding `encoding_id' values. Note that + * most TrueType fonts contain an Apple roman charmap to be usable on + * MacOS systems (even if they contain a Microsoft charmap as well). + * + * TT_PLATFORM_ISO :: + * This value was used to specify ISO/IEC 10646 charmaps. It is however + * now deprecated. See @TT_ISO_ID_XXX for a list of corresponding + * `encoding_id' values. + * + * TT_PLATFORM_MICROSOFT :: + * Used by Microsoft to indicate Windows-specific charmaps. See + * @TT_MS_ID_XXX for a list of corresponding `encoding_id' values. + * Note that most fonts contain a Unicode charmap using + * (TT_PLATFORM_MICROSOFT, @TT_MS_ID_UNICODE_CS). + * + * TT_PLATFORM_CUSTOM :: + * Used to indicate application-specific charmaps. + * + * TT_PLATFORM_ADOBE :: + * This value isn't part of any font format specification, but is used + * by FreeType to report Adobe-specific charmaps in an @FT_CharMapRec + * structure. See @TT_ADOBE_ID_XXX. + */ +#define TT_PLATFORM_APPLE_UNICODE 0 +#define TT_PLATFORM_MACINTOSH 1 +/* deprecated */ +#define TT_PLATFORM_ISO 2 +#define TT_PLATFORM_MICROSOFT 3 +#define TT_PLATFORM_CUSTOM 4 +/* artificial */ +#define TT_PLATFORM_ADOBE 7 +/*********************************************************************** + * + * @enum: + * TT_APPLE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_APPLE_UNICODE charmaps and name entries. + * + * @values: + * TT_APPLE_ID_DEFAULT :: + * Unicode version 1.0. + * + * TT_APPLE_ID_UNICODE_1_1 :: + * Unicode 1.1; specifies Hangul characters starting at U+34xx. + * + * TT_APPLE_ID_ISO_10646 :: + * Deprecated (identical to preceding). + * + * TT_APPLE_ID_UNICODE_2_0 :: + * Unicode 2.0 and beyond (UTF-16 BMP only). + * + * TT_APPLE_ID_UNICODE_32 :: + * Unicode 3.1 and beyond, using UTF-32. + * + * TT_APPLE_ID_VARIANT_SELECTOR :: + * From Adobe, not Apple. Not a normal cmap. Specifies variations + * on a real cmap. + */ +/* Unicode 1.0 */ +#define TT_APPLE_ID_DEFAULT 0 +/* specify Hangul at U+34xx */ +#define TT_APPLE_ID_UNICODE_1_1 1 +/* deprecated */ +#define TT_APPLE_ID_ISO_10646 2 +/* or later */ +#define TT_APPLE_ID_UNICODE_2_0 3 +/* 2.0 or later, full repertoire */ +#define TT_APPLE_ID_UNICODE_32 4 +/* variation selector data */ +#define TT_APPLE_ID_VARIANT_SELECTOR 5 +/*********************************************************************** + * + * @enum: + * TT_MAC_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MACINTOSH charmaps and name entries. + * + * @values: + * TT_MAC_ID_ROMAN :: + * TT_MAC_ID_JAPANESE :: + * TT_MAC_ID_TRADITIONAL_CHINESE :: + * TT_MAC_ID_KOREAN :: + * TT_MAC_ID_ARABIC :: + * TT_MAC_ID_HEBREW :: + * TT_MAC_ID_GREEK :: + * TT_MAC_ID_RUSSIAN :: + * TT_MAC_ID_RSYMBOL :: + * TT_MAC_ID_DEVANAGARI :: + * TT_MAC_ID_GURMUKHI :: + * TT_MAC_ID_GUJARATI :: + * TT_MAC_ID_ORIYA :: + * TT_MAC_ID_BENGALI :: + * TT_MAC_ID_TAMIL :: + * TT_MAC_ID_TELUGU :: + * TT_MAC_ID_KANNADA :: + * TT_MAC_ID_MALAYALAM :: + * TT_MAC_ID_SINHALESE :: + * TT_MAC_ID_BURMESE :: + * TT_MAC_ID_KHMER :: + * TT_MAC_ID_THAI :: + * TT_MAC_ID_LAOTIAN :: + * TT_MAC_ID_GEORGIAN :: + * TT_MAC_ID_ARMENIAN :: + * TT_MAC_ID_MALDIVIAN :: + * TT_MAC_ID_SIMPLIFIED_CHINESE :: + * TT_MAC_ID_TIBETAN :: + * TT_MAC_ID_MONGOLIAN :: + * TT_MAC_ID_GEEZ :: + * TT_MAC_ID_SLAVIC :: + * TT_MAC_ID_VIETNAMESE :: + * TT_MAC_ID_SINDHI :: + * TT_MAC_ID_UNINTERP :: + */ +#define TT_MAC_ID_ROMAN 0 +#define TT_MAC_ID_JAPANESE 1 +#define TT_MAC_ID_TRADITIONAL_CHINESE 2 +#define TT_MAC_ID_KOREAN 3 +#define TT_MAC_ID_ARABIC 4 +#define TT_MAC_ID_HEBREW 5 +#define TT_MAC_ID_GREEK 6 +#define TT_MAC_ID_RUSSIAN 7 +#define TT_MAC_ID_RSYMBOL 8 +#define TT_MAC_ID_DEVANAGARI 9 +#define TT_MAC_ID_GURMUKHI 10 +#define TT_MAC_ID_GUJARATI 11 +#define TT_MAC_ID_ORIYA 12 +#define TT_MAC_ID_BENGALI 13 +#define TT_MAC_ID_TAMIL 14 +#define TT_MAC_ID_TELUGU 15 +#define TT_MAC_ID_KANNADA 16 +#define TT_MAC_ID_MALAYALAM 17 +#define TT_MAC_ID_SINHALESE 18 +#define TT_MAC_ID_BURMESE 19 +#define TT_MAC_ID_KHMER 20 +#define TT_MAC_ID_THAI 21 +#define TT_MAC_ID_LAOTIAN 22 +#define TT_MAC_ID_GEORGIAN 23 +#define TT_MAC_ID_ARMENIAN 24 +#define TT_MAC_ID_MALDIVIAN 25 +#define TT_MAC_ID_SIMPLIFIED_CHINESE 25 +#define TT_MAC_ID_TIBETAN 26 +#define TT_MAC_ID_MONGOLIAN 27 +#define TT_MAC_ID_GEEZ 28 +#define TT_MAC_ID_SLAVIC 29 +#define TT_MAC_ID_VIETNAMESE 30 +#define TT_MAC_ID_SINDHI 31 +#define TT_MAC_ID_UNINTERP 32 +/*********************************************************************** + * + * @enum: + * TT_ISO_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ISO charmaps and name entries. + * + * Their use is now deprecated. + * + * @values: + * TT_ISO_ID_7BIT_ASCII :: + * ASCII. + * TT_ISO_ID_10646 :: + * ISO/10646. + * TT_ISO_ID_8859_1 :: + * Also known as Latin-1. + */ +#define TT_ISO_ID_7BIT_ASCII 0 +#define TT_ISO_ID_10646 1 +#define TT_ISO_ID_8859_1 2 +/*********************************************************************** + * + * @enum: + * TT_MS_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_MICROSOFT charmaps and name entries. + * + * @values: + * TT_MS_ID_SYMBOL_CS :: + * Corresponds to Microsoft symbol encoding. See + * @FT_ENCODING_MS_SYMBOL. + * + * TT_MS_ID_UNICODE_CS :: + * Corresponds to a Microsoft WGL4 charmap, matching Unicode. See + * @FT_ENCODING_UNICODE. + * + * TT_MS_ID_SJIS :: + * Corresponds to SJIS Japanese encoding. See @FT_ENCODING_SJIS. + * + * TT_MS_ID_GB2312 :: + * Corresponds to Simplified Chinese as used in Mainland China. See + * @FT_ENCODING_GB2312. + * + * TT_MS_ID_BIG_5 :: + * Corresponds to Traditional Chinese as used in Taiwan and Hong Kong. + * See @FT_ENCODING_BIG5. + * + * TT_MS_ID_WANSUNG :: + * Corresponds to Korean Wansung encoding. See @FT_ENCODING_WANSUNG. + * + * TT_MS_ID_JOHAB :: + * Corresponds to Johab encoding. See @FT_ENCODING_JOHAB. + * + * TT_MS_ID_UCS_4 :: + * Corresponds to UCS-4 or UTF-32 charmaps. This has been added to + * the OpenType specification version 1.4 (mid-2001.) + */ +#define TT_MS_ID_SYMBOL_CS 0 +#define TT_MS_ID_UNICODE_CS 1 +#define TT_MS_ID_SJIS 2 +#define TT_MS_ID_GB2312 3 +#define TT_MS_ID_BIG_5 4 +#define TT_MS_ID_WANSUNG 5 +#define TT_MS_ID_JOHAB 6 +#define TT_MS_ID_UCS_4 10 +/*********************************************************************** + * + * @enum: + * TT_ADOBE_ID_XXX + * + * @description: + * A list of valid values for the `encoding_id' for + * @TT_PLATFORM_ADOBE charmaps. This is a FreeType-specific extension! + * + * @values: + * TT_ADOBE_ID_STANDARD :: + * Adobe standard encoding. + * TT_ADOBE_ID_EXPERT :: + * Adobe expert encoding. + * TT_ADOBE_ID_CUSTOM :: + * Adobe custom encoding. + * TT_ADOBE_ID_LATIN_1 :: + * Adobe Latin~1 encoding. + */ +#define TT_ADOBE_ID_STANDARD 0 +#define TT_ADOBE_ID_EXPERT 1 +#define TT_ADOBE_ID_CUSTOM 2 +#define TT_ADOBE_ID_LATIN_1 3 +/*************************************************************************/ +/* */ +/* Possible values of the language identifier field in the name records */ +/* of the TTF `name' table if the `platform' identifier code is */ +/* TT_PLATFORM_MACINTOSH. These values are also used as return values */ +/* for function @FT_Get_CMap_Language_ID. */ +/* */ +/* The canonical source for the Apple assigned Language ID's is at */ +/* */ +/* https://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html */ +/* */ +#define TT_MAC_LANGID_ENGLISH 0 +#define TT_MAC_LANGID_FRENCH 1 +#define TT_MAC_LANGID_GERMAN 2 +#define TT_MAC_LANGID_ITALIAN 3 +#define TT_MAC_LANGID_DUTCH 4 +#define TT_MAC_LANGID_SWEDISH 5 +#define TT_MAC_LANGID_SPANISH 6 +#define TT_MAC_LANGID_DANISH 7 +#define TT_MAC_LANGID_PORTUGUESE 8 +#define TT_MAC_LANGID_NORWEGIAN 9 +#define TT_MAC_LANGID_HEBREW 10 +#define TT_MAC_LANGID_JAPANESE 11 +#define TT_MAC_LANGID_ARABIC 12 +#define TT_MAC_LANGID_FINNISH 13 +#define TT_MAC_LANGID_GREEK 14 +#define TT_MAC_LANGID_ICELANDIC 15 +#define TT_MAC_LANGID_MALTESE 16 +#define TT_MAC_LANGID_TURKISH 17 +#define TT_MAC_LANGID_CROATIAN 18 +#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19 +#define TT_MAC_LANGID_URDU 20 +#define TT_MAC_LANGID_HINDI 21 +#define TT_MAC_LANGID_THAI 22 +#define TT_MAC_LANGID_KOREAN 23 +#define TT_MAC_LANGID_LITHUANIAN 24 +#define TT_MAC_LANGID_POLISH 25 +#define TT_MAC_LANGID_HUNGARIAN 26 +#define TT_MAC_LANGID_ESTONIAN 27 +#define TT_MAC_LANGID_LETTISH 28 +#define TT_MAC_LANGID_SAAMISK 29 +#define TT_MAC_LANGID_FAEROESE 30 +#define TT_MAC_LANGID_FARSI 31 +#define TT_MAC_LANGID_RUSSIAN 32 +#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33 +#define TT_MAC_LANGID_FLEMISH 34 +#define TT_MAC_LANGID_IRISH 35 +#define TT_MAC_LANGID_ALBANIAN 36 +#define TT_MAC_LANGID_ROMANIAN 37 +#define TT_MAC_LANGID_CZECH 38 +#define TT_MAC_LANGID_SLOVAK 39 +#define TT_MAC_LANGID_SLOVENIAN 40 +#define TT_MAC_LANGID_YIDDISH 41 +#define TT_MAC_LANGID_SERBIAN 42 +#define TT_MAC_LANGID_MACEDONIAN 43 +#define TT_MAC_LANGID_BULGARIAN 44 +#define TT_MAC_LANGID_UKRAINIAN 45 +#define TT_MAC_LANGID_BYELORUSSIAN 46 +#define TT_MAC_LANGID_UZBEK 47 +#define TT_MAC_LANGID_KAZAKH 48 +#define TT_MAC_LANGID_AZERBAIJANI 49 +#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49 +#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50 +#define TT_MAC_LANGID_ARMENIAN 51 +#define TT_MAC_LANGID_GEORGIAN 52 +#define TT_MAC_LANGID_MOLDAVIAN 53 +#define TT_MAC_LANGID_KIRGHIZ 54 +#define TT_MAC_LANGID_TAJIKI 55 +#define TT_MAC_LANGID_TURKMEN 56 +#define TT_MAC_LANGID_MONGOLIAN 57 +#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57 +#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58 +#define TT_MAC_LANGID_PASHTO 59 +#define TT_MAC_LANGID_KURDISH 60 +#define TT_MAC_LANGID_KASHMIRI 61 +#define TT_MAC_LANGID_SINDHI 62 +#define TT_MAC_LANGID_TIBETAN 63 +#define TT_MAC_LANGID_NEPALI 64 +#define TT_MAC_LANGID_SANSKRIT 65 +#define TT_MAC_LANGID_MARATHI 66 +#define TT_MAC_LANGID_BENGALI 67 +#define TT_MAC_LANGID_ASSAMESE 68 +#define TT_MAC_LANGID_GUJARATI 69 +#define TT_MAC_LANGID_PUNJABI 70 +#define TT_MAC_LANGID_ORIYA 71 +#define TT_MAC_LANGID_MALAYALAM 72 +#define TT_MAC_LANGID_KANNADA 73 +#define TT_MAC_LANGID_TAMIL 74 +#define TT_MAC_LANGID_TELUGU 75 +#define TT_MAC_LANGID_SINHALESE 76 +#define TT_MAC_LANGID_BURMESE 77 +#define TT_MAC_LANGID_KHMER 78 +#define TT_MAC_LANGID_LAO 79 +#define TT_MAC_LANGID_VIETNAMESE 80 +#define TT_MAC_LANGID_INDONESIAN 81 +#define TT_MAC_LANGID_TAGALOG 82 +#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83 +#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84 +#define TT_MAC_LANGID_AMHARIC 85 +#define TT_MAC_LANGID_TIGRINYA 86 +#define TT_MAC_LANGID_GALLA 87 +#define TT_MAC_LANGID_SOMALI 88 +#define TT_MAC_LANGID_SWAHILI 89 +#define TT_MAC_LANGID_RUANDA 90 +#define TT_MAC_LANGID_RUNDI 91 +#define TT_MAC_LANGID_CHEWA 92 +#define TT_MAC_LANGID_MALAGASY 93 +#define TT_MAC_LANGID_ESPERANTO 94 +#define TT_MAC_LANGID_WELSH 128 +#define TT_MAC_LANGID_BASQUE 129 +#define TT_MAC_LANGID_CATALAN 130 +#define TT_MAC_LANGID_LATIN 131 +#define TT_MAC_LANGID_QUECHUA 132 +#define TT_MAC_LANGID_GUARANI 133 +#define TT_MAC_LANGID_AYMARA 134 +#define TT_MAC_LANGID_TATAR 135 +#define TT_MAC_LANGID_UIGHUR 136 +#define TT_MAC_LANGID_DZONGKHA 137 +#define TT_MAC_LANGID_JAVANESE 138 +#define TT_MAC_LANGID_SUNDANESE 139 +/* these seem to be errors that have been dropped */ +#if 0 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 140 +#define TT_MAC_LANGID_IRISH_GAELIC 141 +#endif +/* The following codes are new as of 2000-03-10 */ +#define TT_MAC_LANGID_GALICIAN 140 +#define TT_MAC_LANGID_AFRIKAANS 141 +#define TT_MAC_LANGID_BRETON 142 +#define TT_MAC_LANGID_INUKTITUT 143 +#define TT_MAC_LANGID_SCOTTISH_GAELIC 144 +#define TT_MAC_LANGID_MANX_GAELIC 145 +#define TT_MAC_LANGID_IRISH_GAELIC 146 +#define TT_MAC_LANGID_TONGAN 147 +#define TT_MAC_LANGID_GREEK_POLYTONIC 148 +#define TT_MAC_LANGID_GREELANDIC 149 +#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150 +/*************************************************************************/ +/* */ +/* Possible values of the language identifier field in the name records */ +/* of the TTF `name' table if the `platform' identifier code is */ +/* TT_PLATFORM_MICROSOFT. */ +/* */ +/* The canonical source for the MS assigned LCIDs is */ +/* */ +/* http://www.microsoft.com/globaldev/reference/lcid-all.mspx */ +/* */ +#define TT_MS_LANGID_ARABIC_GENERAL 0x0001 +#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401 +#define TT_MS_LANGID_ARABIC_IRAQ 0x0801 +#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01 +#define TT_MS_LANGID_ARABIC_LIBYA 0x1001 +#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401 +#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801 +#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01 +#define TT_MS_LANGID_ARABIC_OMAN 0x2001 +#define TT_MS_LANGID_ARABIC_YEMEN 0x2401 +#define TT_MS_LANGID_ARABIC_SYRIA 0x2801 +#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01 +#define TT_MS_LANGID_ARABIC_LEBANON 0x3001 +#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401 +#define TT_MS_LANGID_ARABIC_UAE 0x3801 +#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01 +#define TT_MS_LANGID_ARABIC_QATAR 0x4001 +#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402 +#define TT_MS_LANGID_CATALAN_SPAIN 0x0403 +#define TT_MS_LANGID_CHINESE_GENERAL 0x0004 +#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404 +#define TT_MS_LANGID_CHINESE_PRC 0x0804 +#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04 +#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004 +/* this looks like the correct value */ +#if 1 +#define TT_MS_LANGID_CHINESE_MACAU 0x1404 +/* but beware, Microsoft may change its mind... + the most recent Word reference has the following: */ +#else +#define TT_MS_LANGID_CHINESE_MACAU TT_MS_LANGID_CHINESE_HONG_KONG +#endif +/* used only with .NET `cultures'; commented out */ +#if 0 +#define TT_MS_LANGID_CHINESE_TRADITIONAL 0x7C04 +#endif +#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405 +#define TT_MS_LANGID_DANISH_DENMARK 0x0406 +#define TT_MS_LANGID_GERMAN_GERMANY 0x0407 +#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807 +#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07 +#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007 +#define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407 +#define TT_MS_LANGID_GREEK_GREECE 0x0408 +/* don't ask what this one means... It is commented out currently. */ +#if 0 +#define TT_MS_LANGID_GREEK_GREECE2 0x2008 +#endif +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009 +#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409 +#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809 +#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09 +#define TT_MS_LANGID_ENGLISH_CANADA 0x1009 +#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409 +#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809 +#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09 +#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009 +#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409 +#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809 +#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09 +#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009 +#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409 +#define TT_MS_LANGID_ENGLISH_INDONESIA 0x3809 +#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3c09 +#define TT_MS_LANGID_ENGLISH_INDIA 0x4009 +#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409 +#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809 +#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a +#define TT_MS_LANGID_SPANISH_MEXICO 0x080a +#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a +#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a +#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a +#define TT_MS_LANGID_SPANISH_PANAMA 0x180a +#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a +#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a +#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a +#define TT_MS_LANGID_SPANISH_PERU 0x280a +#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a +#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a +#define TT_MS_LANGID_SPANISH_CHILE 0x340a +#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a +#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a +#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a +#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a +#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a +#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a +#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a +#define TT_MS_LANGID_SPANISH_UNITED_STATES 0x540a +/* The following ID blatantly violate MS specs by using a */ +/* sublanguage > 0x1F. */ +#define TT_MS_LANGID_SPANISH_LATIN_AMERICA 0xE40aU +#define TT_MS_LANGID_FINNISH_FINLAND 0x040b +#define TT_MS_LANGID_FRENCH_FRANCE 0x040c +#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c +#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c +#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c +#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c +#define TT_MS_LANGID_FRENCH_MONACO 0x180c +#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1c0c +#define TT_MS_LANGID_FRENCH_REUNION 0x200c +#define TT_MS_LANGID_FRENCH_CONGO 0x240c +/* which was formerly: */ +#define TT_MS_LANGID_FRENCH_ZAIRE TT_MS_LANGID_FRENCH_CONGO +#define TT_MS_LANGID_FRENCH_SENEGAL 0x280c +#define TT_MS_LANGID_FRENCH_CAMEROON 0x2c0c +#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300c +#define TT_MS_LANGID_FRENCH_MALI 0x340c +#define TT_MS_LANGID_FRENCH_MOROCCO 0x380c +#define TT_MS_LANGID_FRENCH_HAITI 0x3c0c +/* and another violation of the spec (see 0xE40aU) */ +#define TT_MS_LANGID_FRENCH_NORTH_AFRICA 0xE40cU +#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d +#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e +#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f +#define TT_MS_LANGID_ITALIAN_ITALY 0x0410 +#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810 +#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411 +#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA 0x0412 +#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812 +#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413 +#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414 +#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814 +#define TT_MS_LANGID_POLISH_POLAND 0x0415 +#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416 +#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816 +#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND 0x0417 +#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418 +#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818 +#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419 +#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819 +#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a +#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a +#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a +/* this used to be this value, but it looks like we were wrong */ +#if 0 +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101a +/* current sources say */ +#else +#define TT_MS_LANGID_CROATIAN_BOSNIA_HERZEGOVINA 0x101a +#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x141a +/* and XPsp2 Platform SDK added (2004-07-26) */ +/* Names are shortened to be significant within 40 chars. */ +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_LATIN 0x181a +#define TT_MS_LANGID_SERBIAN_BOSNIA_HERZ_CYRILLIC 0x181a +#endif +#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b +#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c +#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d +#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d +#define TT_MS_LANGID_THAI_THAILAND 0x041e +#define TT_MS_LANGID_TURKISH_TURKEY 0x041f +#define TT_MS_LANGID_URDU_PAKISTAN 0x0420 +#define TT_MS_LANGID_URDU_INDIA 0x0820 +#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421 +#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422 +#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423 +#define TT_MS_LANGID_SLOVENE_SLOVENIA 0x0424 +#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425 +#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426 +#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427 +#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827 +#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428 +#define TT_MS_LANGID_FARSI_IRAN 0x0429 +#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a +#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b +#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c +#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c +#define TT_MS_LANGID_BASQUE_SPAIN 0x042d +#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e +#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f +#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430 +#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431 +#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432 +#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433 +#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA 0x0434 +#define TT_MS_LANGID_ZULU_SOUTH_AFRICA 0x0435 +#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436 +#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437 +#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438 +#define TT_MS_LANGID_HINDI_INDIA 0x0439 +#define TT_MS_LANGID_MALTESE_MALTA 0x043a +/* Added by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SAMI_NORTHERN_NORWAY 0x043b +#define TT_MS_LANGID_SAMI_NORTHERN_SWEDEN 0x083b +#define TT_MS_LANGID_SAMI_NORTHERN_FINLAND 0x0C3b +#define TT_MS_LANGID_SAMI_LULE_NORWAY 0x103b +#define TT_MS_LANGID_SAMI_LULE_SWEDEN 0x143b +#define TT_MS_LANGID_SAMI_SOUTHERN_NORWAY 0x183b +#define TT_MS_LANGID_SAMI_SOUTHERN_SWEDEN 0x1C3b +#define TT_MS_LANGID_SAMI_SKOLT_FINLAND 0x203b +#define TT_MS_LANGID_SAMI_INARI_FINLAND 0x243b +/* ... and we also keep our old identifier... */ +#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b +/* this seems to be a previous inversion */ +#if 0 +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#else +#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c +#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c +#endif +#define TT_MS_LANGID_YIDDISH_GERMANY 0x043d +#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e +#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e +#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f +/* Cyrillic*/#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN 0x0440 +/* alias declared in Windows 2000 */ +#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \ + TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN +#define TT_MS_LANGID_SWAHILI_KENYA 0x0441 +#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 +#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843 +#define TT_MS_LANGID_TATAR_TATARSTAN 0x0444 +#define TT_MS_LANGID_BENGALI_INDIA 0x0445 +#define TT_MS_LANGID_BENGALI_BANGLADESH 0x0845 +#define TT_MS_LANGID_PUNJABI_INDIA 0x0446 +#define TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN 0x0846 +#define TT_MS_LANGID_GUJARATI_INDIA 0x0447 +#define TT_MS_LANGID_ORIYA_INDIA 0x0448 +#define TT_MS_LANGID_TAMIL_INDIA 0x0449 +#define TT_MS_LANGID_TELUGU_INDIA 0x044a +#define TT_MS_LANGID_KANNADA_INDIA 0x044b +#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c +#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d +#define TT_MS_LANGID_MARATHI_INDIA 0x044e +#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f +/* Cyrillic */#define TT_MS_LANGID_MONGOLIAN_MONGOLIA 0x0450 +#define TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN 0x0850 +#define TT_MS_LANGID_TIBETAN_CHINA 0x0451 +/* Don't use the next constant! It has */ +/* (1) the wrong spelling (Dzonghka) */ +/* (2) Microsoft doesn't officially define it -- */ +/* at least it is not in the List of Local */ +/* ID Values. */ +/* (3) Dzongkha is not the same language as */ +/* Tibetan, so merging it is wrong anyway. */ +/* */ +/* TT_MS_LANGID_TIBETAN_BHUTAN is correct, BTW. */ +#define TT_MS_LANGID_DZONGHKA_BHUTAN 0x0851 +#if 0 +/* the following used to be defined */ +#define TT_MS_LANGID_TIBETAN_BHUTAN 0x0451 +/* ... but it was changed; */ +#else +/* So we will continue to #define it, but with the correct value */ +#define TT_MS_LANGID_TIBETAN_BHUTAN TT_MS_LANGID_DZONGHKA_BHUTAN +#endif +#define TT_MS_LANGID_WELSH_WALES 0x0452 +#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453 +#define TT_MS_LANGID_LAO_LAOS 0x0454 +#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455 +#define TT_MS_LANGID_GALICIAN_SPAIN 0x0456 +#define TT_MS_LANGID_KONKANI_INDIA 0x0457 +/* Bengali */#define TT_MS_LANGID_MANIPURI_INDIA 0x0458 +/* Arabic */#define TT_MS_LANGID_SINDHI_INDIA 0x0459 +#define TT_MS_LANGID_SINDHI_PAKISTAN 0x0859 +/* Missing a LCID for Sindhi in Devanagari script */ +#define TT_MS_LANGID_SYRIAC_SYRIA 0x045a +#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045b +#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045c +#define TT_MS_LANGID_INUKTITUT_CANADA 0x045d +#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045e +/* Arabic */#define TT_MS_LANGID_TAMAZIGHT_MOROCCO 0x045f +#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085f +/* Missing a LCID for Tifinagh script */ +/* Arabic */#define TT_MS_LANGID_KASHMIRI_PAKISTAN 0x0460 +/* Spelled this way by XPsp2 Platform SDK (2004-07-26) */ +/* script is yet unclear... might be Arabic, Nagari or Sharada */ +#define TT_MS_LANGID_KASHMIRI_SASIA 0x0860 +/* ... and aliased (by MS) for compatibility reasons. */ +#define TT_MS_LANGID_KASHMIRI_INDIA TT_MS_LANGID_KASHMIRI_SASIA +#define TT_MS_LANGID_NEPALI_NEPAL 0x0461 +#define TT_MS_LANGID_NEPALI_INDIA 0x0861 +#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462 +#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463 +#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464 +#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465 +/* alias declared in Windows 2000 */ +#define TT_MS_LANGID_DIVEHI_MALDIVES TT_MS_LANGID_DHIVEHI_MALDIVES +#define TT_MS_LANGID_EDO_NIGERIA 0x0466 +#define TT_MS_LANGID_FULFULDE_NIGERIA 0x0467 +#define TT_MS_LANGID_HAUSA_NIGERIA 0x0468 +#define TT_MS_LANGID_IBIBIO_NIGERIA 0x0469 +#define TT_MS_LANGID_YORUBA_NIGERIA 0x046a +#define TT_MS_LANGID_QUECHUA_BOLIVIA 0x046b +#define TT_MS_LANGID_QUECHUA_ECUADOR 0x086b +#define TT_MS_LANGID_QUECHUA_PERU 0x0c6b +#define TT_MS_LANGID_SEPEDI_SOUTH_AFRICA 0x046c +/* Also spelled by XPsp2 Platform SDK (2004-07-26) */ +#define TT_MS_LANGID_SOTHO_SOUTHERN_SOUTH_AFRICA \ + TT_MS_LANGID_SEPEDI_SOUTH_AFRICA +/* language codes 0x046d, 0x046e and 0x046f are (still) unknown. */ +#define TT_MS_LANGID_IGBO_NIGERIA 0x0470 +#define TT_MS_LANGID_KANURI_NIGERIA 0x0471 +#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472 +#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473 +#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873 +/* also spelled in the `Passport SDK' list as: */ +#define TT_MS_LANGID_TIGRIGNA_ERYTREA TT_MS_LANGID_TIGRIGNA_ERYTHREA +#define TT_MS_LANGID_GUARANI_PARAGUAY 0x0474 +#define TT_MS_LANGID_HAWAIIAN_UNITED_STATES 0x0475 +#define TT_MS_LANGID_LATIN 0x0476 +#define TT_MS_LANGID_SOMALI_SOMALIA 0x0477 +/* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */ +/* not written (but OTOH the peculiar writing system is worth */ +/* studying). */ +#define TT_MS_LANGID_YI_CHINA 0x0478 +#define TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES 0x0479 +/* language codes from 0x047a to 0x047f are (still) unknown. */ +#define TT_MS_LANGID_UIGHUR_CHINA 0x0480 +#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0481 +/* not deemed useful for fonts */ +#if 0 +#define TT_MS_LANGID_HUMAN_INTERFACE_DEVICE 0x04ff +#endif +/*************************************************************************/ +/* */ +/* Possible values of the `name' identifier field in the name records of */ +/* the TTF `name' table. These values are platform independent. */ +/* */ +#define TT_NAME_ID_COPYRIGHT 0 +#define TT_NAME_ID_FONT_FAMILY 1 +#define TT_NAME_ID_FONT_SUBFAMILY 2 +#define TT_NAME_ID_UNIQUE_ID 3 +#define TT_NAME_ID_FULL_NAME 4 +#define TT_NAME_ID_VERSION_STRING 5 +#define TT_NAME_ID_PS_NAME 6 +#define TT_NAME_ID_TRADEMARK 7 +/* the following values are from the OpenType spec */ +#define TT_NAME_ID_MANUFACTURER 8 +#define TT_NAME_ID_DESIGNER 9 +#define TT_NAME_ID_DESCRIPTION 10 +#define TT_NAME_ID_VENDOR_URL 11 +#define TT_NAME_ID_DESIGNER_URL 12 +#define TT_NAME_ID_LICENSE 13 +#define TT_NAME_ID_LICENSE_URL 14 +/* number 15 is reserved */ +#define TT_NAME_ID_PREFERRED_FAMILY 16 +#define TT_NAME_ID_PREFERRED_SUBFAMILY 17 +#define TT_NAME_ID_MAC_FULL_NAME 18 +/* The following code is new as of 2000-01-21 */ +#define TT_NAME_ID_SAMPLE_TEXT 19 +/* This is new in OpenType 1.3 */ +#define TT_NAME_ID_CID_FINDFONT_NAME 20 +/* This is new in OpenType 1.5 */ +#define TT_NAME_ID_WWS_FAMILY 21 +#define TT_NAME_ID_WWS_SUBFAMILY 22 +/*************************************************************************/ +/* */ +/* Bit mask values for the Unicode Ranges from the TTF `OS2 ' table. */ +/* */ +/* Updated 08-Nov-2008. */ +/* */ +/* Bit 0 Basic Latin */ +/* U+0020-U+007E */ +#define TT_UCR_BASIC_LATIN (1L << 0) +/* Bit 1 C1 Controls and Latin-1 Supplement */ +/* U+0080-U+00FF */ +#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) +/* Bit 2 Latin Extended-A */ +/* U+0100-U+017F */ +#define TT_UCR_LATIN_EXTENDED_A (1L << 2) +/* Bit 3 Latin Extended-B */ +/* U+0180-U+024F */ +#define TT_UCR_LATIN_EXTENDED_B (1L << 3) +/* Bit 4 IPA Extensions */ +/* Phonetic Extensions */ +/* Phonetic Extensions Supplement */ +/* U+0250-U+02AF */ +#define TT_UCR_IPA_EXTENSIONS (1L << 4) +/* U+1D00-U+1D7F */ +/* U+1D80-U+1DBF */ +/* Bit 5 Spacing Modifier Letters */ +/* Modifier Tone Letters */ +/* U+02B0-U+02FF */ +#define TT_UCR_SPACING_MODIFIER (1L << 5) +/* U+A700-U+A71F */ +/* Bit 6 Combining Diacritical Marks */ +/* Combining Diacritical Marks Supplement */ +/* U+0300-U+036F */ +#define TT_UCR_COMBINING_DIACRITICS (1L << 6) +/* U+1DC0-U+1DFF */ +/* Bit 7 Greek and Coptic */ +/* U+0370-U+03FF */ +#define TT_UCR_GREEK (1L << 7) +/* Bit 8 Coptic */ +/* U+2C80-U+2CFF */ +#define TT_UCR_COPTIC (1L << 8) +/* Bit 9 Cyrillic */ +/* Cyrillic Supplement */ +/* Cyrillic Extended-A */ +/* Cyrillic Extended-B */ +/* U+0400-U+04FF */ +#define TT_UCR_CYRILLIC (1L << 9) +/* U+0500-U+052F */ +/* U+2DE0-U+2DFF */ +/* U+A640-U+A69F */ +/* Bit 10 Armenian */ +/* U+0530-U+058F */ +#define TT_UCR_ARMENIAN (1L << 10) +/* Bit 11 Hebrew */ +/* U+0590-U+05FF */ +#define TT_UCR_HEBREW (1L << 11) +/* Bit 12 Vai */ +/* U+A500-U+A63F */ +#define TT_UCR_VAI (1L << 12) +/* Bit 13 Arabic */ +/* Arabic Supplement */ +/* U+0600-U+06FF */ +#define TT_UCR_ARABIC (1L << 13) +/* U+0750-U+077F */ +/* Bit 14 NKo */ +/* U+07C0-U+07FF */ +#define TT_UCR_NKO (1L << 14) +/* Bit 15 Devanagari */ +/* U+0900-U+097F */ +#define TT_UCR_DEVANAGARI (1L << 15) +/* Bit 16 Bengali */ +/* U+0980-U+09FF */ +#define TT_UCR_BENGALI (1L << 16) +/* Bit 17 Gurmukhi */ +/* U+0A00-U+0A7F */ +#define TT_UCR_GURMUKHI (1L << 17) +/* Bit 18 Gujarati */ +/* U+0A80-U+0AFF */ +#define TT_UCR_GUJARATI (1L << 18) +/* Bit 19 Oriya */ +/* U+0B00-U+0B7F */ +#define TT_UCR_ORIYA (1L << 19) +/* Bit 20 Tamil */ +/* U+0B80-U+0BFF */ +#define TT_UCR_TAMIL (1L << 20) +/* Bit 21 Telugu */ +/* U+0C00-U+0C7F */ +#define TT_UCR_TELUGU (1L << 21) +/* Bit 22 Kannada */ +/* U+0C80-U+0CFF */ +#define TT_UCR_KANNADA (1L << 22) +/* Bit 23 Malayalam */ +/* U+0D00-U+0D7F */ +#define TT_UCR_MALAYALAM (1L << 23) +/* Bit 24 Thai */ +/* U+0E00-U+0E7F */ +#define TT_UCR_THAI (1L << 24) +/* Bit 25 Lao */ +/* U+0E80-U+0EFF */ +#define TT_UCR_LAO (1L << 25) +/* Bit 26 Georgian */ +/* Georgian Supplement */ +/* U+10A0-U+10FF */ +#define TT_UCR_GEORGIAN (1L << 26) +/* U+2D00-U+2D2F */ +/* Bit 27 Balinese */ +/* U+1B00-U+1B7F */ +#define TT_UCR_BALINESE (1L << 27) +/* Bit 28 Hangul Jamo */ +/* U+1100-U+11FF */ +#define TT_UCR_HANGUL_JAMO (1L << 28) +/* Bit 29 Latin Extended Additional */ +/* Latin Extended-C */ +/* Latin Extended-D */ +/* U+1E00-U+1EFF */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) +/* U+2C60-U+2C7F */ +/* U+A720-U+A7FF */ +/* Bit 30 Greek Extended */ +/* U+1F00-U+1FFF */ +#define TT_UCR_GREEK_EXTENDED (1L << 30) +/* Bit 31 General Punctuation */ +/* Supplemental Punctuation */ +/* U+2000-U+206F */ +#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) +/* U+2E00-U+2E7F */ +/* Bit 32 Superscripts And Subscripts */ +/* U+2070-U+209F */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) +/* Bit 33 Currency Symbols */ +/* U+20A0-U+20CF */ +#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) +/* Bit 34 Combining Diacritical Marks For Symbols */ +/* U+20D0-U+20FF */ +#define TT_UCR_COMBINING_DIACRITICS_SYMB (1L << 2) +/* Bit 35 Letterlike Symbols */ +/* U+2100-U+214F */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) +/* Bit 36 Number Forms */ +/* U+2150-U+218F */ +#define TT_UCR_NUMBER_FORMS (1L << 4) +/* Bit 37 Arrows */ +/* Supplemental Arrows-A */ +/* Supplemental Arrows-B */ +/* Miscellaneous Symbols and Arrows */ +/* U+2190-U+21FF */ +#define TT_UCR_ARROWS (1L << 5) +/* U+27F0-U+27FF */ +/* U+2900-U+297F */ +/* U+2B00-U+2BFF */ +/* Bit 38 Mathematical Operators */ +/* Supplemental Mathematical Operators */ +/* Miscellaneous Mathematical Symbols-A */ +/* Miscellaneous Mathematical Symbols-B */ +/* U+2200-U+22FF */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) +/* U+2A00-U+2AFF */ +/* U+27C0-U+27EF */ +/* U+2980-U+29FF */ +/* Bit 39 Miscellaneous Technical */ +/* U+2300-U+23FF */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) +/* Bit 40 Control Pictures */ +/* U+2400-U+243F */ +#define TT_UCR_CONTROL_PICTURES (1L << 8) +/* Bit 41 Optical Character Recognition */ +/* U+2440-U+245F */ +#define TT_UCR_OCR (1L << 9) +/* Bit 42 Enclosed Alphanumerics */ +/* U+2460-U+24FF */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) +/* Bit 43 Box Drawing */ +/* U+2500-U+257F */ +#define TT_UCR_BOX_DRAWING (1L << 11) +/* Bit 44 Block Elements */ +/* U+2580-U+259F */ +#define TT_UCR_BLOCK_ELEMENTS (1L << 12) +/* Bit 45 Geometric Shapes */ +/* U+25A0-U+25FF */ +#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) +/* Bit 46 Miscellaneous Symbols */ +/* U+2600-U+26FF */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) +/* Bit 47 Dingbats */ +/* U+2700-U+27BF */ +#define TT_UCR_DINGBATS (1L << 15) +/* Bit 48 CJK Symbols and Punctuation */ +/* U+3000-U+303F */ +#define TT_UCR_CJK_SYMBOLS (1L << 16) +/* Bit 49 Hiragana */ +/* U+3040-U+309F */ +#define TT_UCR_HIRAGANA (1L << 17) +/* Bit 50 Katakana */ +/* Katakana Phonetic Extensions */ +/* U+30A0-U+30FF */ +#define TT_UCR_KATAKANA (1L << 18) +/* U+31F0-U+31FF */ +/* Bit 51 Bopomofo */ +/* Bopomofo Extended */ +/* U+3100-U+312F */ +#define TT_UCR_BOPOMOFO (1L << 19) +/* U+31A0-U+31BF */ +/* Bit 52 Hangul Compatibility Jamo */ +/* U+3130-U+318F */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) +/* Bit 53 Phags-Pa */ +/* U+A840-U+A87F */ +#define TT_UCR_CJK_MISC (1L << 21) +/* deprecated */ +#define TT_UCR_KANBUN TT_UCR_CJK_MISC +#define TT_UCR_PHAGSPA +/* Bit 54 Enclosed CJK Letters and Months */ +/* U+3200-U+32FF */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) +/* Bit 55 CJK Compatibility */ +/* U+3300-U+33FF */ +#define TT_UCR_CJK_COMPATIBILITY (1L << 23) +/* Bit 56 Hangul Syllables */ +/* U+AC00-U+D7A3 */ +#define TT_UCR_HANGUL (1L << 24) +/* Bit 57 High Surrogates */ +/* High Private Use Surrogates */ +/* Low Surrogates */ +/* */ +/* According to OpenType specs v.1.3+, */ +/* setting bit 57 implies that there is */ +/* at least one codepoint beyond the */ +/* Basic Multilingual Plane that is */ +/* supported by this font. So it really */ +/* means >= U+10000 */ +/* U+D800-U+DB7F */ +#define TT_UCR_SURROGATES (1L << 25) +/* U+DB80-U+DBFF */ +/* U+DC00-U+DFFF */ +#define TT_UCR_NON_PLANE_0 TT_UCR_SURROGATES +/* Bit 58 Phoenician */ +/*U+10900-U+1091F*/ +#define TT_UCR_PHOENICIAN (1L << 26) +/* Bit 59 CJK Unified Ideographs */ +/* CJK Radicals Supplement */ +/* Kangxi Radicals */ +/* Ideographic Description Characters */ +/* CJK Unified Ideographs Extension A */ +/* CJK Unified Ideographs Extension B */ +/* Kanbun */ +/* U+4E00-U+9FFF */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) +/* U+2E80-U+2EFF */ +/* U+2F00-U+2FDF */ +/* U+2FF0-U+2FFF */ +/* U+3400-U+4DB5 */ +/*U+20000-U+2A6DF*/ +/* U+3190-U+319F */ +/* Bit 60 Private Use */ +/* U+E000-U+F8FF */ +#define TT_UCR_PRIVATE_USE (1L << 28) +/* Bit 61 CJK Strokes */ +/* CJK Compatibility Ideographs */ +/* CJK Compatibility Ideographs Supplement */ +/* U+31C0-U+31EF */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) +/* U+F900-U+FAFF */ +/*U+2F800-U+2FA1F*/ +/* Bit 62 Alphabetic Presentation Forms */ +/* U+FB00-U+FB4F */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) +/* Bit 63 Arabic Presentation Forms-A */ +/* U+FB50-U+FDFF */ +#define TT_UCR_ARABIC_PRESENTATIONS_A (1L << 31) +/* Bit 64 Combining Half Marks */ +/* U+FE20-U+FE2F */ +#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) +/* Bit 65 Vertical forms */ +/* CJK Compatibility Forms */ +/* U+FE10-U+FE1F */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) +/* U+FE30-U+FE4F */ +/* Bit 66 Small Form Variants */ +/* U+FE50-U+FE6F */ +#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) +/* Bit 67 Arabic Presentation Forms-B */ +/* U+FE70-U+FEFE */ +#define TT_UCR_ARABIC_PRESENTATIONS_B (1L << 3) +/* Bit 68 Halfwidth and Fullwidth Forms */ +/* U+FF00-U+FFEF */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) +/* Bit 69 Specials */ +/* U+FFF0-U+FFFD */ +#define TT_UCR_SPECIALS (1L << 5) +/* Bit 70 Tibetan */ +/* U+0F00-U+0FFF */ +#define TT_UCR_TIBETAN (1L << 6) +/* Bit 71 Syriac */ +/* U+0700-U+074F */ +#define TT_UCR_SYRIAC (1L << 7) +/* Bit 72 Thaana */ +/* U+0780-U+07BF */ +#define TT_UCR_THAANA (1L << 8) +/* Bit 73 Sinhala */ +/* U+0D80-U+0DFF */ +#define TT_UCR_SINHALA (1L << 9) +/* Bit 74 Myanmar */ +/* U+1000-U+109F */ +#define TT_UCR_MYANMAR (1L << 10) +/* Bit 75 Ethiopic */ +/* Ethiopic Supplement */ +/* Ethiopic Extended */ +/* U+1200-U+137F */ +#define TT_UCR_ETHIOPIC (1L << 11) +/* U+1380-U+139F */ +/* U+2D80-U+2DDF */ +/* Bit 76 Cherokee */ +/* U+13A0-U+13FF */ +#define TT_UCR_CHEROKEE (1L << 12) +/* Bit 77 Unified Canadian Aboriginal Syllabics */ +/* U+1400-U+167F */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) +/* Bit 78 Ogham */ +/* U+1680-U+169F */ +#define TT_UCR_OGHAM (1L << 14) +/* Bit 79 Runic */ +/* U+16A0-U+16FF */ +#define TT_UCR_RUNIC (1L << 15) +/* Bit 80 Khmer */ +/* Khmer Symbols */ +/* U+1780-U+17FF */ +#define TT_UCR_KHMER (1L << 16) +/* U+19E0-U+19FF */ +/* Bit 81 Mongolian */ +/* U+1800-U+18AF */ +#define TT_UCR_MONGOLIAN (1L << 17) +/* Bit 82 Braille Patterns */ +/* U+2800-U+28FF */ +#define TT_UCR_BRAILLE (1L << 18) +/* Bit 83 Yi Syllables */ +/* Yi Radicals */ +/* U+A000-U+A48F */ +#define TT_UCR_YI (1L << 19) +/* U+A490-U+A4CF */ +/* Bit 84 Tagalog */ +/* Hanunoo */ +/* Buhid */ +/* Tagbanwa */ +/* U+1700-U+171F */ +#define TT_UCR_PHILIPPINE (1L << 20) +/* U+1720-U+173F */ +/* U+1740-U+175F */ +/* U+1760-U+177F */ +/* Bit 85 Old Italic */ +/*U+10300-U+1032F*/ +#define TT_UCR_OLD_ITALIC (1L << 21) +/* Bit 86 Gothic */ +/*U+10330-U+1034F*/ +#define TT_UCR_GOTHIC (1L << 22) +/* Bit 87 Deseret */ +/*U+10400-U+1044F*/ +#define TT_UCR_DESERET (1L << 23) +/* Bit 88 Byzantine Musical Symbols */ +/* Musical Symbols */ +/* Ancient Greek Musical Notation */ +/*U+1D000-U+1D0FF*/ +#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) +/*U+1D100-U+1D1FF*/ +/*U+1D200-U+1D24F*/ +/* Bit 89 Mathematical Alphanumeric Symbols */ +/*U+1D400-U+1D7FF*/ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) +/* Bit 90 Private Use (plane 15) */ +/* Private Use (plane 16) */ +/*U+F0000-U+FFFFD*/ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) +/*U+100000-U+10FFFD*/ +/* Bit 91 Variation Selectors */ +/* Variation Selectors Supplement */ +/* U+FE00-U+FE0F */ +#define TT_UCR_VARIATION_SELECTORS (1L << 27) +/*U+E0100-U+E01EF*/ +/* Bit 92 Tags */ +/*U+E0000-U+E007F*/ +#define TT_UCR_TAGS (1L << 28) +/* Bit 93 Limbu */ +/* U+1900-U+194F */ +#define TT_UCR_LIMBU (1L << 29) +/* Bit 94 Tai Le */ +/* U+1950-U+197F */ +#define TT_UCR_TAI_LE (1L << 30) +/* Bit 95 New Tai Lue */ +/* U+1980-U+19DF */ +#define TT_UCR_NEW_TAI_LUE (1L << 31) +/* Bit 96 Buginese */ +/* U+1A00-U+1A1F */ +#define TT_UCR_BUGINESE (1L << 0) +/* Bit 97 Glagolitic */ +/* U+2C00-U+2C5F */ +#define TT_UCR_GLAGOLITIC (1L << 1) +/* Bit 98 Tifinagh */ +/* U+2D30-U+2D7F */ +#define TT_UCR_TIFINAGH (1L << 2) +/* Bit 99 Yijing Hexagram Symbols */ +/* U+4DC0-U+4DFF */ +#define TT_UCR_YIJING (1L << 3) +/* Bit 100 Syloti Nagri */ +/* U+A800-U+A82F */ +#define TT_UCR_SYLOTI_NAGRI (1L << 4) +/* Bit 101 Linear B Syllabary */ +/* Linear B Ideograms */ +/* Aegean Numbers */ +/*U+10000-U+1007F*/ +#define TT_UCR_LINEAR_B (1L << 5) +/*U+10080-U+100FF*/ +/*U+10100-U+1013F*/ +/* Bit 102 Ancient Greek Numbers */ +/*U+10140-U+1018F*/ +#define TT_UCR_ANCIENT_GREEK_NUMBERS (1L << 6) +/* Bit 103 Ugaritic */ +/*U+10380-U+1039F*/ +#define TT_UCR_UGARITIC (1L << 7) +/* Bit 104 Old Persian */ +/*U+103A0-U+103DF*/ +#define TT_UCR_OLD_PERSIAN (1L << 8) +/* Bit 105 Shavian */ +/*U+10450-U+1047F*/ +#define TT_UCR_SHAVIAN (1L << 9) +/* Bit 106 Osmanya */ +/*U+10480-U+104AF*/ +#define TT_UCR_OSMANYA (1L << 10) +/* Bit 107 Cypriot Syllabary */ +/*U+10800-U+1083F*/ +#define TT_UCR_CYPRIOT_SYLLABARY (1L << 11) +/* Bit 108 Kharoshthi */ +/*U+10A00-U+10A5F*/ +#define TT_UCR_KHAROSHTHI (1L << 12) +/* Bit 109 Tai Xuan Jing Symbols */ +/*U+1D300-U+1D35F*/ +#define TT_UCR_TAI_XUAN_JING (1L << 13) +/* Bit 110 Cuneiform */ +/* Cuneiform Numbers and Punctuation */ +/*U+12000-U+123FF*/ +#define TT_UCR_CUNEIFORM (1L << 14) +/*U+12400-U+1247F*/ +/* Bit 111 Counting Rod Numerals */ +/*U+1D360-U+1D37F*/ +#define TT_UCR_COUNTING_ROD_NUMERALS (1L << 15) +/* Bit 112 Sundanese */ +/* U+1B80-U+1BBF */ +#define TT_UCR_SUNDANESE (1L << 16) +/* Bit 113 Lepcha */ +/* U+1C00-U+1C4F */ +#define TT_UCR_LEPCHA (1L << 17) +/* Bit 114 Ol Chiki */ +/* U+1C50-U+1C7F */ +#define TT_UCR_OL_CHIKI (1L << 18) +/* Bit 115 Saurashtra */ +/* U+A880-U+A8DF */ +#define TT_UCR_SAURASHTRA (1L << 19) +/* Bit 116 Kayah Li */ +/* U+A900-U+A92F */ +#define TT_UCR_KAYAH_LI (1L << 20) +/* Bit 117 Rejang */ +/* U+A930-U+A95F */ +#define TT_UCR_REJANG (1L << 21) +/* Bit 118 Cham */ +/* U+AA00-U+AA5F */ +#define TT_UCR_CHAM (1L << 22) +/* Bit 119 Ancient Symbols */ +/*U+10190-U+101CF*/ +#define TT_UCR_ANCIENT_SYMBOLS (1L << 23) +/* Bit 120 Phaistos Disc */ +/*U+101D0-U+101FF*/ +#define TT_UCR_PHAISTOS_DISC (1L << 24) +/* Bit 121 Carian */ +/* Lycian */ +/* Lydian */ +/*U+102A0-U+102DF*/ +#define TT_UCR_OLD_ANATOLIAN (1L << 25) +/*U+10280-U+1029F*/ +/*U+10920-U+1093F*/ +/* Bit 122 Domino Tiles */ +/* Mahjong Tiles */ +/*U+1F030-U+1F09F*/ +#define TT_UCR_GAME_TILES (1L << 26) +/*U+1F000-U+1F02F*/ +/* Bit 123-127 Reserved for process-internal usage */ +/*************************************************************************/ +/* */ +/* Some compilers have a very limited length of identifiers. */ +/* */ +#if defined( __TURBOC__ ) && __TURBOC__ < 0x0410 || defined( __PACIFIC__ ) +#define HAVE_LIMIT_ON_IDENTS +#endif +#ifndef HAVE_LIMIT_ON_IDENTS +/*************************************************************************/ +/* */ +/* Here some alias #defines in order to be clearer. */ +/* */ +/* These are not always #defined to stay within the 31~character limit */ +/* which some compilers have. */ +/* */ +/* Credits go to Dave Hoo <dhoo@flash.net> for pointing out that modern */ +/* Borland compilers (read: from BC++ 3.1 on) can increase this limit. */ +/* If you get a warning with such a compiler, use the -i40 switch. */ +/* */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A \ + TT_UCR_ARABIC_PRESENTATIONS_A +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B \ + TT_UCR_ARABIC_PRESENTATIONS_B +#define TT_UCR_COMBINING_DIACRITICAL_MARKS \ + TT_UCR_COMBINING_DIACRITICS +#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ + TT_UCR_COMBINING_DIACRITICS_SYMB +/* !HAVE_LIMIT_ON_IDENTS */ +#endif +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svprop.h */ +/* */ +/* The FreeType property service (specification). */ +/* */ +/* Copyright 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVPROP_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_PROPERTIES "properties" + typedef FT_Error + (*FT_Properties_SetFunc)( FT_Module module, + const char* property_name, + const void* value ); + typedef FT_Error + (*FT_Properties_GetFunc)( FT_Module module, + const char* property_name, + void* value ); + FT_DEFINE_SERVICE( Properties ) + { + FT_Properties_SetFunc set_property; + FT_Properties_GetFunc get_property; + }; +#define FT_DEFINE_SERVICE_PROPERTIESREC( class_, \ + set_property_, \ + get_property_ ) \ + static const FT_Service_PropertiesRec class_ = \ + { \ + set_property_, \ + get_property_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svsfnt.h */ +/* */ +/* The FreeType SFNT table loading service (specification). */ +/* */ +/* Copyright 2003, 2004, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVSFNT_H__ +FT_BEGIN_HEADER +/* + * SFNT table loading service. + */ +#define FT_SERVICE_ID_SFNT_TABLE "sfnt-table" +/* + * Used to implement FT_Load_Sfnt_Table(). + */ + typedef FT_Error + (*FT_SFNT_TableLoadFunc)( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); +/* + * Used to implement FT_Get_Sfnt_Table(). + */ + typedef void* + (*FT_SFNT_TableGetFunc)( FT_Face face, + FT_Sfnt_Tag tag ); +/* + * Used to implement FT_Sfnt_Table_Info(). + */ + typedef FT_Error + (*FT_SFNT_TableInfoFunc)( FT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ); + FT_DEFINE_SERVICE( SFNT_Table ) + { + FT_SFNT_TableLoadFunc load_table; + FT_SFNT_TableGetFunc get_table; + FT_SFNT_TableInfoFunc table_info; + }; +#define FT_DEFINE_SERVICE_SFNT_TABLEREC( class_, load_, get_, info_ ) \ + static const FT_Service_SFNT_TableRec class_ = \ + { \ + load_, get_, info_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svpostnm.h */ +/* */ +/* The FreeType PostScript name services (specification). */ +/* */ +/* Copyright 2003, 2007, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVPOSTNM_H__ +FT_BEGIN_HEADER +/* + * A trivial service used to retrieve the PostScript name of a given + * font when available. The `get_name' field should never be NULL. + * + * The corresponding function can return NULL to indicate that the + * PostScript name is not available. + * + * The name is owned by the face and will be destroyed with it. + */ +#define FT_SERVICE_ID_POSTSCRIPT_FONT_NAME "postscript-font-name" + typedef const char* + (*FT_PsName_GetFunc)( FT_Face face ); + FT_DEFINE_SERVICE( PsFontName ) + { + FT_PsName_GetFunc get_ps_font_name; + }; +#define FT_DEFINE_SERVICE_PSFONTNAMEREC( class_, get_ps_font_name_ ) \ + static const FT_Service_PsFontNameRec class_ = \ + { \ + get_ps_font_name_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svgldict.h */ +/* */ +/* The FreeType glyph dictionary services (specification). */ +/* */ +/* Copyright 2003, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVGLDICT_H__ +FT_BEGIN_HEADER +/* + * A service used to retrieve glyph names, as well as to find the + * index of a given glyph name in a font. + * + */ +#define FT_SERVICE_ID_GLYPH_DICT "glyph-dict" + typedef FT_Error + (*FT_GlyphDict_GetNameFunc)( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ); + typedef FT_UInt + (*FT_GlyphDict_NameIndexFunc)( FT_Face face, + FT_String* glyph_name ); + FT_DEFINE_SERVICE( GlyphDict ) + { + FT_GlyphDict_GetNameFunc get_name; +/* optional */ + FT_GlyphDict_NameIndexFunc name_index; + }; +#define FT_DEFINE_SERVICE_GLYPHDICTREC( class_, \ + get_name_, \ + name_index_) \ + static const FT_Service_GlyphDictRec class_ = \ + { \ + get_name_, name_index_ \ + }; +/* */ +FT_END_HEADER +/***************************************************************************/ +/* */ +/* svttcmap.h */ +/* */ +/* The FreeType TrueType/sfnt cmap extra information service. */ +/* */ +/* Copyright 2003 by */ +/* Masatake YAMATO, Redhat K.K. */ +/* */ +/* Copyright 2003, 2008, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +/* Development of this service is support of + Information-technology Promotion Agency, Japan. */ +#define __SVTTCMAP_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_TT_CMAP "tt-cmaps" +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_CMapInfo */ +/* */ +/* <Description> */ +/* A structure used to store TrueType/sfnt specific cmap information */ +/* which is not covered by the generic @FT_CharMap structure. This */ +/* structure can be accessed with the @FT_Get_TT_CMap_Info function. */ +/* */ +/* <Fields> */ +/* language :: */ +/* The language ID used in Mac fonts. Definitions of values are in */ +/* freetype/ttnameid.h. */ +/* */ +/* format :: */ +/* The cmap format. OpenType 1.5 defines the formats 0 (byte */ +/* encoding table), 2~(high-byte mapping through table), 4~(segment */ +/* mapping to delta values), 6~(trimmed table mapping), 8~(mixed */ +/* 16-bit and 32-bit coverage), 10~(trimmed array), 12~(segmented */ +/* coverage), and 14 (Unicode Variation Sequences). */ +/* */ + typedef struct TT_CMapInfo_ + { + FT_ULong language; + FT_Long format; + } TT_CMapInfo; + typedef FT_Error + (*TT_CMap_Info_GetFunc)( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + FT_DEFINE_SERVICE( TTCMaps ) + { + TT_CMap_Info_GetFunc get_cmap_info; + }; +#define FT_DEFINE_SERVICE_TTCMAPSREC( class_, get_cmap_info_ ) \ + static const FT_Service_TTCMapsRec class_ = \ + { \ + get_cmap_info_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svkern.h */ +/* */ +/* The FreeType Kerning service (specification). */ +/* */ +/* Copyright 2006 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. */ +/* */ +/***************************************************************************/ +#define __SVKERN_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_KERNING "kerning" + typedef FT_Error + (*FT_Kerning_TrackGetFunc)( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ); + FT_DEFINE_SERVICE( Kerning ) + { + FT_Kerning_TrackGetFunc get_track; + }; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svtteng.h */ +/* */ +/* The FreeType TrueType engine query service (specification). */ +/* */ +/* Copyright 2006 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. */ +/* */ +/***************************************************************************/ +#define __SVTTENG_H__ +FT_BEGIN_HEADER +/* + * SFNT table loading service. + */ +#define FT_SERVICE_ID_TRUETYPE_ENGINE "truetype-engine" +/* + * Used to implement FT_Get_TrueType_Engine_Type + */ + FT_DEFINE_SERVICE( TrueTypeEngine ) + { + FT_TrueTypeEngineType engine_type; + }; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftbase.h */ +/* */ +/* The FreeType private functions used in base module (specification). */ +/* */ +/* Copyright 2008, 2010 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. */ +/* */ +/***************************************************************************/ +#define __FTBASE_H__ +FT_BEGIN_HEADER +/* 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 +FT_END_HEADER +/* END */ +#define GRID_FIT_METRICS + FT_BASE_DEF( FT_Pointer ) + ft_service_list_lookup( FT_ServiceDesc service_descriptors, + const char* service_id ) + { + FT_Pointer result = NULL; + FT_ServiceDesc desc = service_descriptors; + if ( desc && service_id ) + { + for ( ; desc->serv_id != NULL; desc++ ) + { + if ( ft_strcmp( desc->serv_id, service_id ) == 0 ) + { + result = (FT_Pointer)desc->serv_data; + break; + } + } + } + return result; + } + FT_BASE_DEF( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ) + { + valid->base = base; + valid->limit = limit; + valid->level = level; + valid->error = FT_Err_Ok; + } + FT_BASE_DEF( FT_Int ) + ft_validator_run( FT_Validator valid ) + { +/* This function doesn't work! None should call it. */ + FT_UNUSED( valid ); + return -1; + } + FT_BASE_DEF( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ) + { +/* since the cast below also disables the compiler's */ +/* type check, we introduce a dummy variable, which */ +/* will be optimized away */ + volatile ft_jmp_buf* jump_buffer = &valid->jump_buffer; + valid->error = error; +/* throw away volatileness; use `jump_buffer' or the */ +/* compiler may warn about an unused local variable */ + ft_longjmp( *(ft_jmp_buf*) jump_buffer, 1 ); + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** S T R E A M ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* create a new input stream from an FT_Open_Args structure */ +/* */ + FT_BASE_DEF( FT_Error ) + FT_Stream_New( FT_Library library, + const FT_Open_Args* args, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream = NULL; + *astream = 0; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !args ) + return FT_Err_Invalid_Argument; + memory = library->memory; + if ( FT_NEW( stream ) ) + goto Exit; + stream->memory = memory; + if ( args->flags & FT_OPEN_MEMORY ) + { +/* create a memory-based stream */ + FT_Stream_OpenMemory( stream, + (const FT_Byte*)args->memory_base, + args->memory_size ); + } + else if ( args->flags & FT_OPEN_PATHNAME ) + { +/* create a normal system stream */ + error = FT_Stream_Open( stream, args->pathname ); + stream->pathname.pointer = args->pathname; + } + else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + { +/* use an existing, user-provided stream */ +/* in this case, we do not need to allocate a new stream object */ +/* since the caller is responsible for closing it himself */ + FT_FREE( stream ); + stream = args->stream; + } + else + error = FT_Err_Invalid_Argument; + if ( error ) + FT_FREE( stream ); + else +/* just to be certain */ + stream->memory = memory; + *astream = stream; + Exit: + return error; + } + FT_BASE_DEF( void ) + FT_Stream_Free( FT_Stream stream, + FT_Int external ) + { + if ( stream ) + { + FT_Memory memory = stream->memory; + FT_Stream_Close( stream ); + if ( !external ) + FT_FREE( stream ); + } + } +/*************************************************************************/ +/* */ +/* 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 trace_objs +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** FACE, SIZE & GLYPH SLOT OBJECTS ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + ft_glyphslot_init( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + FT_Error error = FT_Err_Ok; + FT_Slot_Internal internal = NULL; + slot->library = driver->root.library; + if ( FT_NEW( internal ) ) + goto Exit; + slot->internal = internal; + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + error = FT_GlyphLoader_New( memory, &internal->loader ); + if ( !error && clazz->init_slot ) + error = clazz->init_slot( slot ); + Exit: + return error; + } + FT_BASE_DEF( void ) + ft_glyphslot_free_bitmap( FT_GlyphSlot slot ) + { + if ( slot->internal && ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_FREE( slot->bitmap.buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { +/* assume that the bitmap buffer was stolen or not */ +/* allocated from the heap */ + slot->bitmap.buffer = NULL; + } + } + FT_BASE_DEF( void ) + ft_glyphslot_set_bitmap( FT_GlyphSlot slot, + FT_Byte* buffer ) + { + ft_glyphslot_free_bitmap( slot ); + slot->bitmap.buffer = buffer; + FT_ASSERT( (slot->internal->flags & FT_GLYPH_OWN_BITMAP) == 0 ); + } + FT_BASE_DEF( FT_Error ) + ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot, + FT_ULong size ) + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Error error; + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + (void)FT_ALLOC( slot->bitmap.buffer, size ); + return error; + } + static void + ft_glyphslot_clear( FT_GlyphSlot slot ) + { +/* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); +/* clear all public fields in the glyph slot */ + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + slot->bitmap.width = 0; + slot->bitmap.rows = 0; + slot->bitmap.pitch = 0; + slot->bitmap.pixel_mode = 0; +/* `slot->bitmap.buffer' has been handled by ft_glyphslot_free_bitmap */ + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = 0; + slot->control_data = 0; + slot->control_len = 0; + slot->other = 0; + slot->format = FT_GLYPH_FORMAT_NONE; + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + slot->lsb_delta = 0; + slot->rsb_delta = 0; + } + static void + ft_glyphslot_done( FT_GlyphSlot slot ) + { + FT_Driver driver = slot->face->driver; + FT_Driver_Class clazz = driver->clazz; + FT_Memory memory = driver->root.memory; + if ( clazz->done_slot ) + clazz->done_slot( slot ); +/* free bitmap buffer if needed */ + ft_glyphslot_free_bitmap( slot ); +/* slot->internal might be NULL in out-of-memory situations */ + if ( slot->internal ) + { +/* free glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + FT_GlyphLoader_Done( slot->internal->loader ); + slot->internal->loader = 0; + } + FT_FREE( slot->internal ); + } + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( FT_Error ) + FT_New_GlyphSlot( FT_Face face, + FT_GlyphSlot *aslot ) + { + FT_Error error; + FT_Driver driver; + FT_Driver_Class clazz; + FT_Memory memory; + FT_GlyphSlot slot = NULL; + if ( !face || !face->driver ) + return FT_Err_Invalid_Argument; + driver = face->driver; + clazz = driver->clazz; + memory = driver->root.memory; + FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" )); + if ( !FT_ALLOC( slot, clazz->slot_object_size ) ) + { + slot->face = face; + error = ft_glyphslot_init( slot ); + if ( error ) + { + ft_glyphslot_done( slot ); + FT_FREE( slot ); + goto Exit; + } + slot->next = face->glyph; + face->glyph = slot; + if ( aslot ) + *aslot = slot; + } + else if ( aslot ) + *aslot = 0; + Exit: + FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error )); + return error; + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( void ) + FT_Done_GlyphSlot( FT_GlyphSlot slot ) + { + if ( slot ) + { + FT_Driver driver = slot->face->driver; + FT_Memory memory = driver->root.memory; + FT_GlyphSlot prev; + FT_GlyphSlot cur; +/* Remove slot from its parent face's list */ + prev = NULL; + cur = slot->face->glyph; + while ( cur ) + { + if ( cur == slot ) + { + if ( !prev ) + slot->face->glyph = cur->next; + else + prev->next = cur->next; +/* finalize client-specific data */ + if ( slot->generic.finalizer ) + slot->generic.finalizer( slot ); + ft_glyphslot_done( slot ); + FT_FREE( slot ); + break; + } + prev = cur; + cur = cur->next; + } + } + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( void ) + FT_Set_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + if ( !face ) + return; + internal = face->internal; + internal->transform_flags = 0; + if ( !matrix ) + { + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + matrix = &internal->transform_matrix; + } + else + internal->transform_matrix = *matrix; +/* set transform_flags bit flag 0 if `matrix' isn't the identity */ + if ( ( matrix->xy | matrix->yx ) || + matrix->xx != 0x10000L || + matrix->yy != 0x10000L ) + internal->transform_flags |= 1; + if ( !delta ) + { + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + delta = &internal->transform_delta; + } + else + internal->transform_delta = *delta; +/* set transform_flags bit flag 1 if `delta' isn't the null vector */ + if ( delta->x | delta->y ) + internal->transform_flags |= 2; + } + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ); +#ifdef GRID_FIT_METRICS + static void + ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, + FT_Bool vertical ) + { + FT_Glyph_Metrics* metrics = &slot->metrics; + FT_Pos right, bottom; + if ( vertical ) + { + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); + right = FT_PIX_CEIL( metrics->vertBearingX + metrics->width ); + bottom = FT_PIX_CEIL( metrics->vertBearingY + metrics->height ); + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + metrics->width = right - metrics->vertBearingX; + metrics->height = bottom - metrics->vertBearingY; + } + else + { + metrics->vertBearingX = FT_PIX_FLOOR( metrics->vertBearingX ); + metrics->vertBearingY = FT_PIX_FLOOR( metrics->vertBearingY ); + right = FT_PIX_CEIL ( metrics->horiBearingX + metrics->width ); + bottom = FT_PIX_FLOOR( metrics->horiBearingY - metrics->height ); + metrics->horiBearingX = FT_PIX_FLOOR( metrics->horiBearingX ); + metrics->horiBearingY = FT_PIX_CEIL ( metrics->horiBearingY ); + metrics->width = right - metrics->horiBearingX; + metrics->height = metrics->horiBearingY - bottom; + } + metrics->horiAdvance = FT_PIX_ROUND( metrics->horiAdvance ); + metrics->vertAdvance = FT_PIX_ROUND( metrics->vertAdvance ); + } +/* GRID_FIT_METRICS */ +#endif +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Load_Glyph( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + FT_Driver driver; + FT_GlyphSlot slot; + FT_Library library; + FT_Bool autohint = FALSE; + FT_Module hinter; + TT_Face ttface = (TT_Face)face; + if ( !face || !face->size || !face->glyph ) + return FT_Err_Invalid_Face_Handle; +/* The validity test for `glyph_index' is performed by the */ +/* font drivers. */ + slot = face->glyph; + ft_glyphslot_clear( slot ); + driver = face->driver; + library = driver->root.library; + hinter = library->auto_hinter; +/* resolve load flags dependencies */ + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_IGNORE_TRANSFORM; + if ( load_flags & FT_LOAD_NO_SCALE ) + { + load_flags |= FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + load_flags &= ~FT_LOAD_RENDER; + } +/* + * Determine whether we need to auto-hint or not. + * The general rules are: + * + * - Do only auto-hinting if we have a hinter module, a scalable font + * format dealing with outlines, and no transforms except simple + * slants and/or rotations by integer multiples of 90 degrees. + * + * - Then, auto-hint if FT_LOAD_FORCE_AUTOHINT is set or if we don't + * have a native font hinter. + * + * - Otherwise, auto-hint for LIGHT hinting mode or if there isn't + * any hinting bytecode in the TrueType/OpenType font. + * + * - Exception: The font is `tricky' and requires the native hinter to + * load properly. + */ + if ( hinter && + !( load_flags & FT_LOAD_NO_HINTING ) && + !( load_flags & FT_LOAD_NO_AUTOHINT ) && + FT_DRIVER_IS_SCALABLE( driver ) && + FT_DRIVER_USES_OUTLINES( driver ) && + !FT_IS_TRICKY( face ) && + ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) || + ( face->internal->transform_matrix.yx == 0 && + face->internal->transform_matrix.xx != 0 ) || + ( face->internal->transform_matrix.xx == 0 && + face->internal->transform_matrix.yx != 0 ) ) ) + { + if ( ( load_flags & FT_LOAD_FORCE_AUTOHINT ) || + !FT_DRIVER_HAS_HINTER( driver ) ) + autohint = TRUE; + else + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); +/* the check for `num_locations' assures that we actually */ +/* test for instructions in a TTF and not in a CFF-based OTF */ + if ( mode == FT_RENDER_MODE_LIGHT || + face->internal->ignore_unpatented_hinter || + ( FT_IS_SFNT( face ) && + ttface->num_locations && + ttface->max_profile.maxSizeOfInstructions == 0 ) ) + autohint = TRUE; + } + } + if ( autohint ) + { + FT_AutoHinter_Interface hinting; +/* try to load embedded bitmaps first if available */ +/* */ +/* XXX: This is really a temporary hack that should disappear */ +/* promptly with FreeType 2.1! */ +/* */ + if ( FT_HAS_FIXED_SIZES( face ) && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SBITS_ONLY ); + if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP ) + goto Load_Ok; + } + { + FT_Face_Internal internal = face->internal; + FT_Int transform_flags = internal->transform_flags; +/* since the auto-hinter calls FT_Load_Glyph by itself, */ +/* make sure that glyphs aren't transformed */ + internal->transform_flags = 0; +/* load auto-hinted outline */ + hinting = (FT_AutoHinter_Interface)hinter->clazz->module_interface; + error = hinting->load_glyph( (FT_AutoHinter)hinter, + slot, face->size, + glyph_index, load_flags ); + internal->transform_flags = transform_flags; + } + } + else + { + error = driver->clazz->load_glyph( slot, + face->size, + glyph_index, + load_flags ); + if ( error ) + goto Exit; + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { +/* check that the loaded outline is correct */ + error = FT_Outline_Check( &slot->outline ); + if ( error ) + goto Exit; +#ifdef GRID_FIT_METRICS + if ( !( load_flags & FT_LOAD_NO_HINTING ) ) + ft_glyphslot_grid_fit_metrics( slot, + FT_BOOL( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ); +#endif + } + } + Load_Ok: +/* compute the advance */ + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + slot->advance.x = 0; + slot->advance.y = slot->metrics.vertAdvance; + } + else + { + slot->advance.x = slot->metrics.horiAdvance; + slot->advance.y = 0; + } +/* compute the linear advance in 16.16 pixels */ + if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 && + ( FT_IS_SCALABLE( face ) ) ) + { + FT_Size_Metrics* metrics = &face->size->metrics; +/* it's tricky! */ + slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance, + metrics->x_scale, 64 ); + slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance, + metrics->y_scale, 64 ); + } + if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 ) + { + FT_Face_Internal internal = face->internal; +/* now, transform the glyph image if needed */ + if ( internal->transform_flags ) + { +/* get renderer */ + FT_Renderer renderer = ft_lookup_glyph_renderer( slot ); + if ( renderer ) + error = renderer->clazz->transform_glyph( + renderer, slot, + &internal->transform_matrix, + &internal->transform_delta ); + else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { +/* apply `standard' transformation if no renderer is available */ + if ( internal->transform_flags & 1 ) + FT_Outline_Transform( &slot->outline, + &internal->transform_matrix ); + if ( internal->transform_flags & 2 ) + FT_Outline_Translate( &slot->outline, + internal->transform_delta.x, + internal->transform_delta.y ); + } +/* transform advance */ + FT_Vector_Transform( &slot->advance, &internal->transform_matrix ); + } + } + FT_TRACE5(( " x advance: %d\n" , slot->advance.x )); + FT_TRACE5(( " y advance: %d\n" , slot->advance.y )); + FT_TRACE5(( " linear x advance: %d\n" , slot->linearHoriAdvance )); + FT_TRACE5(( " linear y advance: %d\n" , slot->linearVertAdvance )); +/* do we need to render the image now? */ + if ( !error && + slot->format != FT_GLYPH_FORMAT_BITMAP && + slot->format != FT_GLYPH_FORMAT_COMPOSITE && + load_flags & FT_LOAD_RENDER ) + { + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + if ( mode == FT_RENDER_MODE_NORMAL && + (load_flags & FT_LOAD_MONOCHROME ) ) + mode = FT_RENDER_MODE_MONO; + error = FT_Render_Glyph( slot, mode ); + } + Exit: + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Load_Char( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ) + { + FT_UInt glyph_index; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + glyph_index = (FT_UInt)char_code; + if ( face->charmap ) + glyph_index = FT_Get_Char_Index( face, char_code ); + return FT_Load_Glyph( face, glyph_index, load_flags ); + } +/* destructor for sizes list */ + static void + destroy_size( FT_Memory memory, + FT_Size size, + FT_Driver driver ) + { +/* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); +/* finalize format-specific stuff */ + if ( driver->clazz->done_size ) + driver->clazz->done_size( size ); + FT_FREE( size->internal ); + FT_FREE( size ); + } + static void + ft_cmap_done_internal( FT_CMap cmap ); + static void + destroy_charmaps( FT_Face face, + FT_Memory memory ) + { + FT_Int n; + if ( !face ) + return; + for ( n = 0; n < face->num_charmaps; n++ ) + { + FT_CMap cmap = FT_CMAP( face->charmaps[n] ); + ft_cmap_done_internal( cmap ); + face->charmaps[n] = NULL; + } + FT_FREE( face->charmaps ); + face->num_charmaps = 0; + } +/* destructor for faces list */ + static void + destroy_face( FT_Memory memory, + FT_Face face, + FT_Driver driver ) + { + FT_Driver_Class clazz = driver->clazz; +/* discard auto-hinting data */ + if ( face->autohint.finalizer ) + face->autohint.finalizer( face->autohint.data ); +/* Discard glyph slots for this face. */ +/* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */ + while ( face->glyph ) + FT_Done_GlyphSlot( face->glyph ); +/* discard all sizes for this face */ + FT_List_Finalize( &face->sizes_list, + (FT_List_Destructor)destroy_size, + memory, + driver ); + face->size = 0; +/* now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); +/* discard charmaps */ + destroy_charmaps( face, memory ); +/* finalize format-specific stuff */ + if ( clazz->done_face ) + clazz->done_face( face ); +/* close the stream for this face if needed */ + FT_Stream_Free( + face->stream, + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + face->stream = 0; +/* get rid of it */ + if ( face->internal ) + { + FT_FREE( face->internal ); + } + FT_FREE( face ); + } + static void + Destroy_Driver( FT_Driver driver ) + { + FT_List_Finalize( &driver->faces_list, + (FT_List_Destructor)destroy_face, + driver->root.memory, + driver ); +/* check whether we need to drop the driver's glyph loader */ + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + FT_GlyphLoader_Done( driver->glyph_loader ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* find_unicode_charmap */ +/* */ +/* <Description> */ +/* This function finds a Unicode charmap, if there is one. */ +/* And if there is more than one, it tries to favour the more */ +/* extensive one, i.e., one that supports UCS-4 against those which */ +/* are limited to the BMP (said UCS-2 encoding.) */ +/* */ +/* This function is called from open_face() (just below), and also */ +/* from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). */ +/* */ + static FT_Error + find_unicode_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* cur; +/* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + first = face->charmaps; + if ( !first ) + return FT_Err_Invalid_CharMap_Handle; +/* + * The original TrueType specification(s) only specified charmap + * formats that are capable of mapping 8 or 16 bit character codes to + * glyph indices. + * + * However, recent updates to the Apple and OpenType specifications + * introduced new formats that are capable of mapping 32-bit character + * codes as well. And these are already used on some fonts, mainly to + * map non-BMP Asian ideographs as defined in Unicode. + * + * For compatibility purposes, these fonts generally come with + * *several* Unicode charmaps: + * + * - One of them in the "old" 16-bit format, that cannot access + * all glyphs in the font. + * + * - Another one in the "new" 32-bit format, that can access all + * the glyphs. + * + * This function has been written to always favor a 32-bit charmap + * when found. Otherwise, a 16-bit one is returned when found. + */ +/* Since the `interesting' table, with IDs (3,10), is normally the */ +/* last one, we loop backwards. This loses with type1 fonts with */ +/* non-BMP characters (<.0001%), this wins with .ttf with non-BMP */ +/* chars (.01% ?), and this is the same about 99.99% of the time! */ +/* points after the last one */ + cur = first + face->num_charmaps; + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { +/* XXX If some new encodings to represent UCS-4 are added, */ +/* they should be added here. */ + if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && + cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || + ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) + { +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "find_unicode_charmap: UCS-4 cmap is found " + "at too late position (%d)\n", cur - first )); + continue; + } +#endif + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + } +/* We do not have any UCS-4 charmap. */ +/* Do the loop again and search for UCS-2 charmaps. */ + cur = first + face->num_charmaps; + for ( ; --cur >= first; ) + { + if ( cur[0]->encoding == FT_ENCODING_UNICODE ) + { +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "find_unicode_charmap: UCS-2 cmap is found " + "at too late position (%d)\n", cur - first )); + continue; + } +#endif + face->charmap = cur[0]; + return FT_Err_Ok; + } + } + return FT_Err_Invalid_CharMap_Handle; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* find_variant_selector_charmap */ +/* */ +/* <Description> */ +/* This function finds the variant selector charmap, if there is one. */ +/* There can only be one (platform=0, specific=5, format=14). */ +/* */ + static FT_CharMap + find_variant_selector_charmap( FT_Face face ) + { + FT_CharMap* first; + FT_CharMap* end; + FT_CharMap* cur; +/* caller should have already checked that `face' is valid */ + FT_ASSERT( face ); + first = face->charmaps; + if ( !first ) + return NULL; +/* points after the last one */ + end = first + face->num_charmaps; + for ( cur = first; cur < end; ++cur ) + { + if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && + cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && + FT_Get_CMap_Format( cur[0] ) == 14 ) + { +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( cur - first > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "find_unicode_charmap: UVS cmap is found " + "at too late position (%d)\n", cur - first )); + continue; + } +#endif + return cur[0]; + } + } + return NULL; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* open_face */ +/* */ +/* <Description> */ +/* This function does some work for FT_Open_Face(). */ +/* */ + static FT_Error + open_face( FT_Driver driver, + FT_Stream stream, + FT_Long face_index, + FT_Int num_params, + FT_Parameter* params, + FT_Face *aface ) + { + FT_Memory memory; + FT_Driver_Class clazz; + FT_Face face = 0; + FT_Error error, error2; + FT_Face_Internal internal = NULL; + clazz = driver->clazz; + memory = driver->root.memory; +/* allocate the face object and perform basic initialization */ + if ( FT_ALLOC( face, clazz->face_object_size ) ) + goto Fail; + if ( FT_NEW( internal ) ) + goto Fail; + face->internal = internal; + face->driver = driver; + face->memory = memory; + face->stream = stream; + { + int i; + face->internal->incremental_interface = 0; + for ( i = 0; i < num_params && !face->internal->incremental_interface; + i++ ) + if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL ) + face->internal->incremental_interface = + (FT_Incremental_Interface)params[i].data; + } + if ( clazz->init_face ) + error = clazz->init_face( stream, + face, + (FT_Int)face_index, + num_params, + params ); + if ( error ) + goto Fail; +/* select Unicode charmap by default */ + error2 = find_unicode_charmap( face ); +/* if no Unicode charmap can be found, FT_Err_Invalid_CharMap_Handle */ +/* is returned. */ +/* no error should happen, but we want to play safe */ + if ( error2 && error2 != FT_Err_Invalid_CharMap_Handle ) + { + error = error2; + goto Fail; + } + *aface = face; + Fail: + if ( error ) + { + destroy_charmaps( face, memory ); + if ( clazz->done_face ) + clazz->done_face( face ); + FT_FREE( internal ); + FT_FREE( face ); + *aface = 0; + } + return error; + } +/* there's a Mac-specific extended implementation of FT_New_Face() */ +/* in src/base/ftmac.c */ +#ifndef FT_MACINTOSH +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; +/* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_Err_Invalid_Argument; + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + args.stream = NULL; + return FT_Open_Face( library, &args, face_index, aface ); + } +#endif +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Memory_Face( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ) + { + FT_Open_Args args; +/* test for valid `library' and `face' delayed to FT_Open_Face() */ + if ( !file_base ) + return FT_Err_Invalid_Argument; + args.flags = FT_OPEN_MEMORY; + args.memory_base = file_base; + args.memory_size = file_size; + args.stream = NULL; + return FT_Open_Face( library, &args, face_index, aface ); + } +/* The behavior here is very similar to that in base/ftmac.c, but it */ +/* is designed to work on non-mac systems, so no mac specific calls. */ +/* */ +/* We look at the file and determine if it is a mac dfont file or a mac */ +/* resource file, or a macbinary file containing a mac resource file. */ +/* */ +/* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */ +/* the point, especially since there may be multiple `FOND' resources. */ +/* Instead I'll just look for `sfnt' and `POST' resources, ordered as */ +/* they occur in the file. */ +/* */ +/* Note that multiple `POST' resources do not mean multiple postscript */ +/* fonts; they all get jammed together to make what is essentially a */ +/* pfb file. */ +/* */ +/* We aren't interested in `NFNT' or `FONT' bitmap resources. */ +/* */ +/* As soon as we get an `sfnt' load it into memory and pass it off to */ +/* FT_Open_Face. */ +/* */ +/* If we have a (set of) `POST' resources, massage them into a (memory) */ +/* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */ +/* going to try to save the kerning info. After all that lives in the */ +/* `FOND' which isn't in the file containing the `POST' resources so */ +/* we don't really have access to it. */ +/* Finalizer for a memory stream; gets called by FT_Done_Face(). */ +/* It frees the memory it uses. */ +/* From ftmac.c. */ + static void + memory_stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + FT_FREE( stream->base ); + stream->size = 0; + stream->base = 0; + stream->close = 0; + } +/* Create a new memory stream from a buffer and a size. */ +/* From ftmac.c. */ + static FT_Error + new_memory_stream( FT_Library library, + FT_Byte* base, + FT_ULong size, + FT_Stream_CloseFunc close, + FT_Stream *astream ) + { + FT_Error error; + FT_Memory memory; + FT_Stream stream = NULL; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !base ) + return FT_Err_Invalid_Argument; + *astream = 0; + memory = library->memory; + if ( FT_NEW( stream ) ) + goto Exit; + FT_Stream_OpenMemory( stream, base, size ); + stream->close = close; + *astream = stream; + Exit: + return error; + } +/* Create a new FT_Face given a buffer and a driver name. */ +/* from ftmac.c */ + FT_LOCAL_DEF( 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 ) + { + FT_Open_Args args; + FT_Error error; + FT_Stream stream = NULL; + FT_Memory memory = library->memory; + error = new_memory_stream( library, + base, + size, + memory_stream_close, + &stream ); + if ( error ) + { + FT_FREE( base ); + return error; + } + args.flags = FT_OPEN_STREAM; + args.stream = stream; + if ( driver_name ) + { + args.flags = args.flags | FT_OPEN_DRIVER; + args.driver = FT_Get_Module( library, driver_name ); + } +#ifdef FT_MACINTOSH +/* At this point, face_index has served its purpose; */ +/* whoever calls this function has already used it to */ +/* locate the correct font data. We should not propagate */ +/* this index to FT_Open_Face() (unless it is negative). */ + if ( face_index > 0 ) + face_index = 0; +#endif + error = FT_Open_Face( library, &args, face_index, aface ); + if ( error == FT_Err_Ok ) + (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + else +#ifdef FT_MACINTOSH + FT_Stream_Free( stream, 0 ); +#else + { + FT_Stream_Close( stream ); + FT_FREE( stream ); + } +#endif + return error; + } +/* Look up `TYP1' or `CID ' table from sfnt table directory. */ +/* `offset' and `length' must exclude the binary header in tables. */ +/* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */ +/* format too. Here, since we can't expect that the TrueType font */ +/* driver is loaded unconditially, we must parse the font by */ +/* ourselves. We are only interested in the name of the table and */ +/* the offset. */ + static FT_Error + ft_lookup_PS_in_sfnt_stream( FT_Stream stream, + FT_Long face_index, + FT_ULong* offset, + FT_ULong* length, + FT_Bool* is_sfnt_cid ) + { + FT_Error error; + FT_UShort numTables; + FT_Long pstable_index; + FT_ULong tag; + int i; + *offset = 0; + *length = 0; + *is_sfnt_cid = FALSE; +/* TODO: support for sfnt-wrapped PS/CID in TTC format */ +/* version check for 'typ1' (should be ignored?) */ + if ( FT_READ_ULONG( tag ) ) + return error; + if ( tag != TTAG_typ1 ) + return FT_Err_Unknown_File_Format; + if ( FT_READ_USHORT( numTables ) ) + return error; +/* skip binary search header */ + if ( FT_STREAM_SKIP( 2 * 3 ) ) + return error; + pstable_index = -1; + *is_sfnt_cid = FALSE; + for ( i = 0; i < numTables; i++ ) + { + if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) || + FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) ) + return error; + if ( tag == TTAG_CID ) + { + pstable_index++; + *offset += 22; + *length -= 22; + *is_sfnt_cid = TRUE; + if ( face_index < 0 ) + return FT_Err_Ok; + } + else if ( tag == TTAG_TYP1 ) + { + pstable_index++; + *offset += 24; + *length -= 24; + *is_sfnt_cid = FALSE; + if ( face_index < 0 ) + return FT_Err_Ok; + } + if ( face_index >= 0 && pstable_index == face_index ) + return FT_Err_Ok; + } + return FT_Err_Table_Missing; + } + FT_LOCAL_DEF( 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 ) + { + FT_Error error; + FT_Memory memory = library->memory; + FT_ULong offset, length; + FT_Long pos; + FT_Bool is_sfnt_cid; + FT_Byte* sfnt_ps = NULL; + FT_UNUSED( num_params ); + FT_UNUSED( params ); + pos = FT_Stream_Pos( stream ); + error = ft_lookup_PS_in_sfnt_stream( stream, + face_index, + &offset, + &length, + &is_sfnt_cid ); + if ( error ) + goto Exit; + if ( FT_Stream_Seek( stream, pos + offset ) ) + goto Exit; + if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) ) + goto Exit; + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); + if ( error ) + goto Exit; + error = open_face_from_buffer( library, + sfnt_ps, + length, + face_index < 0 ? face_index : 0, + is_sfnt_cid ? "cid" : "type1", + aface ); + Exit: + { + FT_Error error1; + if ( error == FT_Err_Unknown_File_Format ) + { + error1 = FT_Stream_Seek( stream, pos ); + if ( error1 ) + return error1; + } + return error; + } + } +#ifndef FT_MACINTOSH +/* The resource header says we've got resource_cnt `POST' (type1) */ +/* resources in this file. They all need to be coalesced into */ +/* one lump which gets passed on to the type1 driver. */ +/* Here can be only one PostScript font in a file so face_index */ +/* must be 0 (or -1). */ +/* */ + static FT_Error + Mac_Read_POST_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Error error = FT_Err_Cannot_Open_Resource; + FT_Memory memory = library->memory; + FT_Byte* pfb_data = NULL; + int i, type, flags; + FT_Long len; + FT_Long pfb_len, pfb_pos, pfb_lenpos; + FT_Long rlen, temp; + if ( face_index == -1 ) + face_index = 0; + if ( face_index != 0 ) + return error; +/* Find the length of all the POST resources, concatenated. Assume */ +/* worst case (each resource in its own section). */ + pfb_len = 0; + for ( i = 0; i < resource_cnt; ++i ) + { + error = FT_Stream_Seek( stream, offsets[i] ); + if ( error ) + goto Exit; + if ( FT_READ_LONG( temp ) ) + goto Exit; + pfb_len += temp + 6; + } + if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) + goto Exit; + pfb_data[0] = 0x80; +/* Ascii section */ + pfb_data[1] = 1; +/* 4-byte length, fill in later */ + pfb_data[2] = 0; + pfb_data[3] = 0; + pfb_data[4] = 0; + pfb_data[5] = 0; + pfb_pos = 6; + pfb_lenpos = 2; + len = 0; + type = 1; + for ( i = 0; i < resource_cnt; ++i ) + { + error = FT_Stream_Seek( stream, offsets[i] ); + if ( error ) + goto Exit2; + if ( FT_READ_LONG( rlen ) ) + goto Exit; + if ( FT_READ_USHORT( flags ) ) + goto Exit; + FT_TRACE3(( "POST fragment[%d]: offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n", + i, offsets[i], rlen, flags )); +/* postpone the check of rlen longer than buffer until FT_Stream_Read() */ +/* Comment, should not be loaded */ + if ( ( flags >> 8 ) == 0 ) + continue; +/* the flags are part of the resource, so rlen >= 2. */ +/* but some fonts declare rlen = 0 for empty fragment */ + if ( rlen > 2 ) + rlen -= 2; + else + rlen = 0; + if ( ( flags >> 8 ) == type ) + len += rlen; + else + { + if ( pfb_lenpos + 3 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); +/* End of font mark */ + if ( ( flags >> 8 ) == 5 ) + break; + if ( pfb_pos + 6 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_pos++] = 0x80; + type = flags >> 8; + len = rlen; + pfb_data[pfb_pos++] = (FT_Byte)type; + pfb_lenpos = pfb_pos; +/* 4-byte length, fill in later */ + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + pfb_data[pfb_pos++] = 0; + } + error = FT_Err_Cannot_Open_Resource; + if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) + goto Exit2; + error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); + if ( error ) + goto Exit2; + pfb_pos += rlen; + } + if ( pfb_pos + 2 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_pos++] = 0x80; + pfb_data[pfb_pos++] = 3; + if ( pfb_lenpos + 3 > pfb_len + 2 ) + goto Exit2; + pfb_data[pfb_lenpos ] = (FT_Byte)( len ); + pfb_data[pfb_lenpos + 1] = (FT_Byte)( len >> 8 ); + pfb_data[pfb_lenpos + 2] = (FT_Byte)( len >> 16 ); + pfb_data[pfb_lenpos + 3] = (FT_Byte)( len >> 24 ); + return open_face_from_buffer( library, + pfb_data, + pfb_pos, + face_index, + "type1", + aface ); + Exit2: + FT_FREE( pfb_data ); + Exit: + return error; + } +/* The resource header says we've got resource_cnt `sfnt' */ +/* (TrueType/OpenType) resources in this file. Look through */ +/* them for the one indicated by face_index, load it into mem, */ +/* pass it on the the truetype driver and return it. */ +/* */ + static FT_Error + Mac_Read_sfnt_Resource( FT_Library library, + FT_Stream stream, + FT_Long *offsets, + FT_Long resource_cnt, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Byte* sfnt_data = NULL; + FT_Error error; + FT_Long flag_offset; + FT_Long rlen; + int is_cff; + FT_Long face_index_in_resource = 0; + if ( face_index == -1 ) + face_index = 0; + if ( face_index >= resource_cnt ) + return FT_Err_Cannot_Open_Resource; + flag_offset = offsets[face_index]; + error = FT_Stream_Seek( stream, flag_offset ); + if ( error ) + goto Exit; + if ( FT_READ_LONG( rlen ) ) + goto Exit; + if ( rlen == -1 ) + return FT_Err_Cannot_Open_Resource; + error = open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ); + if ( !error ) + goto Exit; +/* rewind sfnt stream before open_face_PS_from_sfnt_stream() */ + if ( FT_Stream_Seek( stream, flag_offset + 4 ) ) + goto Exit; + if ( FT_ALLOC( sfnt_data, (FT_Long)rlen ) ) + return error; + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); + if ( error ) + goto Exit; + is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + error = open_face_from_buffer( library, + sfnt_data, + rlen, + face_index_in_resource, + is_cff ? "cff" : "truetype", + aface ); + Exit: + return error; + } +/* Check for a valid resource fork header, or a valid dfont */ +/* header. In a resource fork the first 16 bytes are repeated */ +/* at the location specified by bytes 4-7. In a dfont bytes */ +/* 4-7 point to 16 bytes of zeroes instead. */ +/* */ + static FT_Error + IsMacResource( FT_Library library, + FT_Stream stream, + FT_Long resource_offset, + FT_Long face_index, + FT_Face *aface ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Long map_offset, rdara_pos; + FT_Long *data_offsets; + FT_Long count; + error = FT_Raccess_Get_HeaderInfo( library, stream, resource_offset, + &map_offset, &rdara_pos ); + if ( error ) + return error; + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdara_pos, + TTAG_POST, + &data_offsets, &count ); + if ( !error ) + { + error = Mac_Read_POST_Resource( library, stream, data_offsets, count, + face_index, aface ); + FT_FREE( data_offsets ); +/* POST exists in an LWFN providing a single face */ + if ( !error ) + (*aface)->num_faces = 1; + return error; + } + error = FT_Raccess_Get_DataOffsets( library, stream, + map_offset, rdara_pos, + TTAG_sfnt, + &data_offsets, &count ); + if ( !error ) + { + FT_Long face_index_internal = face_index % count; + error = Mac_Read_sfnt_Resource( library, stream, data_offsets, count, + face_index_internal, aface ); + FT_FREE( data_offsets ); + if ( !error ) + (*aface)->num_faces = count; + } + return error; + } +/* Check for a valid macbinary header, and if we find one */ +/* check that the (flattened) resource fork in it is valid. */ +/* */ + static FT_Error + IsMacBinary( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface ) + { + unsigned char header[128]; + FT_Error error; + FT_Long dlen, offset; + if ( NULL == stream ) + return FT_Err_Invalid_Stream_Operation; + error = FT_Stream_Seek( stream, 0 ); + if ( error ) + goto Exit; + error = FT_Stream_Read( stream, (FT_Byte*)header, 128 ); + if ( error ) + goto Exit; + if ( header[ 0] != 0 || + header[74] != 0 || + header[82] != 0 || + header[ 1] == 0 || + header[ 1] > 33 || + header[63] != 0 || + header[2 + header[1]] != 0 ) + return FT_Err_Unknown_File_Format; + dlen = ( header[0x53] << 24 ) | + ( header[0x54] << 16 ) | + ( header[0x55] << 8 ) | + header[0x56]; +#if 0 + rlen = ( header[0x57] << 24 ) | + ( header[0x58] << 16 ) | + ( header[0x59] << 8 ) | + header[0x5a]; +/* 0 */ +#endif + offset = 128 + ( ( dlen + 127 ) & ~127 ); + return IsMacResource( library, stream, offset, face_index, aface ); + Exit: + return error; + } + static FT_Error + load_face_in_embedded_rfork( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { +#undef FT_COMPONENT +#define FT_COMPONENT trace_raccess + FT_Memory memory = library->memory; + FT_Error error = FT_Err_Unknown_File_Format; + int i; + char * file_names[FT_RACCESS_N_RULES]; + FT_Long offsets[FT_RACCESS_N_RULES]; + FT_Error errors[FT_RACCESS_N_RULES]; +/* not tested */ + FT_Bool is_darwin_vfs, vfs_rfork_has_no_font = FALSE; + FT_Open_Args args2; + FT_Stream stream2 = 0; + FT_Raccess_Guess( library, stream, + args->pathname, file_names, offsets, errors ); + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); + if ( is_darwin_vfs && vfs_rfork_has_no_font ) + { + FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" + " is already checked and" + " no font is found\n", i )); + continue; + } + if ( errors[i] ) + { + FT_TRACE3(( "Error[%d] has occurred in rule %d\n", errors[i], i )); + continue; + } + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_names[i] ? file_names[i] : args->pathname; + FT_TRACE3(( "Try rule %d: %s (offset=%d) ...", + i, args2.pathname, offsets[i] )); + error = FT_Stream_New( library, &args2, &stream2 ); + if ( is_darwin_vfs && error == FT_Err_Cannot_Open_Stream ) + vfs_rfork_has_no_font = TRUE; + if ( error ) + { + FT_TRACE3(( "failed\n" )); + continue; + } + error = IsMacResource( library, stream2, offsets[i], + face_index, aface ); + FT_Stream_Free( stream2, 0 ); + FT_TRACE3(( "%s\n", error ? "failed": "successful" )); + if ( !error ) + break; + else if ( is_darwin_vfs ) + vfs_rfork_has_no_font = TRUE; + } + for (i = 0; i < FT_RACCESS_N_RULES; i++) + { + if ( file_names[i] ) + FT_FREE( file_names[i] ); + } +/* Caller (load_mac_face) requires FT_Err_Unknown_File_Format. */ + if ( error ) + error = FT_Err_Unknown_File_Format; + return error; +#undef FT_COMPONENT +#define FT_COMPONENT trace_objs + } +/* Check for some macintosh formats without Carbon framework. */ +/* Is this a macbinary file? If so look at the resource fork. */ +/* Is this a mac dfont file? */ +/* Is this an old style resource fork? (in data) */ +/* Else call load_face_in_embedded_rfork to try extra rules */ +/* (defined in `ftrfork.c'). */ +/* */ + static FT_Error + load_mac_face( FT_Library library, + FT_Stream stream, + FT_Long face_index, + FT_Face *aface, + const FT_Open_Args *args ) + { + FT_Error error; + FT_UNUSED( args ); + error = IsMacBinary( library, stream, face_index, aface ); + if ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format ) + { +#undef FT_COMPONENT +#define FT_COMPONENT trace_raccess + FT_TRACE3(( "Try as dfont: %s ...", args->pathname )); + error = IsMacResource( library, stream, 0, face_index, aface ); + FT_TRACE3(( "%s\n", error ? "failed" : "successful" )); +#undef FT_COMPONENT +#define FT_COMPONENT trace_objs + } + if ( ( FT_ERROR_BASE( error ) == FT_Err_Unknown_File_Format || + FT_ERROR_BASE( error ) == FT_Err_Invalid_Stream_Operation ) && + ( args->flags & FT_OPEN_PATHNAME ) ) + error = load_face_in_embedded_rfork( library, stream, + face_index, aface, args ); + return error; + } +#endif +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Open_Face( FT_Library library, + const FT_Open_Args* args, + FT_Long face_index, + FT_Face *aface ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Stream stream = NULL; + FT_Face face = NULL; + FT_ListNode node = NULL; + FT_Bool external_stream; + FT_Module* cur; + FT_Module* limit; +/* test for valid `library' delayed to */ +/* FT_Stream_New() */ + if ( ( !aface && face_index >= 0 ) || !args ) + return FT_Err_Invalid_Argument; + external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && + args->stream ); +/* create input stream */ + error = FT_Stream_New( library, args, &stream ); + if ( error ) + goto Fail3; + memory = library->memory; +/* If the font driver is specified in the `args' structure, use */ +/* it. Otherwise, we scan the list of registered drivers. */ + if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver ) + { + driver = FT_DRIVER( args->driver ); +/* not all modules are drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( driver ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = 0; + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + error = open_face( driver, stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + } + else + error = FT_Err_Invalid_Handle; + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + else + { + error = FT_Err_Missing_Module; +/* check each font driver for an appropriate format */ + cur = library->modules; + limit = cur + library->num_modules; + for ( ; cur < limit; cur++ ) + { +/* not all modules are font drivers, so check... */ + if ( FT_MODULE_IS_DRIVER( cur[0] ) ) + { + FT_Int num_params = 0; + FT_Parameter* params = 0; + driver = FT_DRIVER( cur[0] ); + if ( args->flags & FT_OPEN_PARAMS ) + { + num_params = args->num_params; + params = args->params; + } + error = open_face( driver, stream, face_index, + num_params, params, &face ); + if ( !error ) + goto Success; + if ( ft_strcmp( cur[0]->clazz->module_name, "truetype" ) == 0 && + FT_ERROR_BASE( error ) == FT_Err_Table_Missing ) + { +/* TrueType but essential tables are missing */ + if ( FT_Stream_Seek( stream, 0 ) ) + break; + error = open_face_PS_from_sfnt_stream( library, + stream, + face_index, + num_params, + params, + aface ); + if ( !error ) + { + FT_Stream_Free( stream, external_stream ); + return error; + } + } + if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format ) + goto Fail3; + } + } + Fail3: +/* If we are on the mac, and we get an */ +/* FT_Err_Invalid_Stream_Operation it may be because we have an */ +/* empty data fork, so we need to check the resource fork. */ + if ( FT_ERROR_BASE( error ) != FT_Err_Cannot_Open_Stream && + FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format && + FT_ERROR_BASE( error ) != FT_Err_Invalid_Stream_Operation ) + goto Fail2; +#if !defined( FT_MACINTOSH ) && defined( FT_CONFIG_OPTION_MAC_FONTS ) + error = load_mac_face( library, stream, face_index, aface, args ); + if ( !error ) + { +/* We don't want to go to Success here. We've already done that. */ +/* On the other hand, if we succeeded we still need to close this */ +/* stream (we opened a different stream which extracted the */ +/* interesting information out of this stream here. That stream */ +/* will still be open and the face will point to it). */ + FT_Stream_Free( stream, external_stream ); + return error; + } + if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format ) + goto Fail2; +/* !FT_MACINTOSH && FT_CONFIG_OPTION_MAC_FONTS */ +#endif +/* no driver is able to handle this format */ + error = FT_Err_Unknown_File_Format; + Fail2: + FT_Stream_Free( stream, external_stream ); + goto Fail; + } + Success: + FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); +/* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ + if ( external_stream ) + face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; +/* add the face object to its driver's list */ + if ( FT_NEW( node ) ) + goto Fail; + node->data = face; +/* don't assume driver is the same as face->driver, so use */ +/* face->driver instead. */ + FT_List_Add( &face->driver->faces_list, node ); +/* now allocate a glyph slot object for the face */ + FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" )); + if ( face_index >= 0 ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( error ) + goto Fail; +/* finally, allocate a size object for the face */ + { + FT_Size size; + FT_TRACE4(( "FT_Open_Face: Creating size object\n" )); + error = FT_New_Size( face, &size ); + if ( error ) + goto Fail; + face->size = size; + } + } +/* some checks */ + if ( FT_IS_SCALABLE( face ) ) + { + if ( face->height < 0 ) + face->height = (FT_Short)-face->height; + if ( !FT_HAS_VERTICAL( face ) ) + face->max_advance_height = (FT_Short)face->height; + } + if ( FT_HAS_FIXED_SIZES( face ) ) + { + FT_Int i; + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + if ( bsize->height < 0 ) + bsize->height = (FT_Short)-bsize->height; + if ( bsize->x_ppem < 0 ) + bsize->x_ppem = (FT_Short)-bsize->x_ppem; + if ( bsize->y_ppem < 0 ) + bsize->y_ppem = -bsize->y_ppem; + } + } +/* initialize internal face data */ + { + FT_Face_Internal internal = face->internal; + internal->transform_matrix.xx = 0x10000L; + internal->transform_matrix.xy = 0; + internal->transform_matrix.yx = 0; + internal->transform_matrix.yy = 0x10000L; + internal->transform_delta.x = 0; + internal->transform_delta.y = 0; + internal->refcount = 1; + } + if ( aface ) + *aface = face; + else + FT_Done_Face( face ); + goto Exit; + Fail: + FT_Done_Face( face ); + Exit: + FT_TRACE4(( "FT_Open_Face: Return %d\n", error )); + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Attach_File( FT_Face face, + const char* filepathname ) + { + FT_Open_Args open; +/* test for valid `face' delayed to FT_Attach_Stream() */ + if ( !filepathname ) + return FT_Err_Invalid_Argument; + open.stream = NULL; + open.flags = FT_OPEN_PATHNAME; + open.pathname = (char*)filepathname; + return FT_Attach_Stream( face, &open ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Attach_Stream( FT_Face face, + FT_Open_Args* parameters ) + { + FT_Stream stream; + FT_Error error; + FT_Driver driver; + FT_Driver_Class clazz; +/* test for valid `parameters' delayed to FT_Stream_New() */ + if ( !face ) + return FT_Err_Invalid_Face_Handle; + driver = face->driver; + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + error = FT_Stream_New( driver->root.library, parameters, &stream ); + if ( error ) + goto Exit; +/* we implement FT_Attach_Stream in each driver through the */ +/* `attach_file' interface */ + error = FT_Err_Unimplemented_Feature; + clazz = driver->clazz; + if ( clazz->attach_file ) + error = clazz->attach_file( face, stream ); +/* close the attached stream */ + FT_Stream_Free( stream, + (FT_Bool)( parameters->stream && + ( parameters->flags & FT_OPEN_STREAM ) ) ); + Exit: + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Reference_Face( FT_Face face ) + { + face->internal->refcount++; + return FT_Err_Ok; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Done_Face( FT_Face face ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_ListNode node; + error = FT_Err_Invalid_Face_Handle; + if ( face && face->driver ) + { + face->internal->refcount--; + if ( face->internal->refcount > 0 ) + error = FT_Err_Ok; + else + { + driver = face->driver; + memory = driver->root.memory; +/* find face in driver's list */ + node = FT_List_Find( &driver->faces_list, face ); + if ( node ) + { +/* remove face object from the driver's list */ + FT_List_Remove( &driver->faces_list, node ); + FT_FREE( node ); +/* now destroy the object proper */ + destroy_face( memory, face, driver ); + error = FT_Err_Ok; + } + } + } + return error; + } +/* documentation is in ftobjs.h */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Size( FT_Face face, + FT_Size *asize ) + { + FT_Error error; + FT_Memory memory; + FT_Driver driver; + FT_Driver_Class clazz; + FT_Size size = 0; + FT_ListNode node = 0; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + if ( !asize ) + return FT_Err_Invalid_Size_Handle; + if ( !face->driver ) + return FT_Err_Invalid_Driver_Handle; + *asize = 0; + driver = face->driver; + clazz = driver->clazz; + memory = face->memory; +/* Allocate new size object and perform basic initialisation */ + if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) + goto Exit; + size->face = face; +/* for now, do not use any internal fields in size objects */ + size->internal = 0; + if ( clazz->init_size ) + error = clazz->init_size( size ); +/* in case of success, add to the face's list */ + if ( !error ) + { + *asize = size; + node->data = size; + FT_List_Add( &face->sizes_list, node ); + } + Exit: + if ( error ) + { + FT_FREE( node ); + FT_FREE( size ); + } + return error; + } +/* documentation is in ftobjs.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Done_Size( FT_Size size ) + { + FT_Error error; + FT_Driver driver; + FT_Memory memory; + FT_Face face; + FT_ListNode node; + if ( !size ) + return FT_Err_Invalid_Size_Handle; + face = size->face; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + driver = face->driver; + if ( !driver ) + return FT_Err_Invalid_Driver_Handle; + memory = driver->root.memory; + error = FT_Err_Ok; + node = FT_List_Find( &face->sizes_list, size ); + if ( node ) + { + FT_List_Remove( &face->sizes_list, node ); + FT_FREE( node ); + if ( face->size == size ) + { + face->size = 0; + if ( face->sizes_list.head ) + face->size = (FT_Size)(face->sizes_list.head->data); + } + destroy_size( memory, size, driver ); + } + else + error = FT_Err_Invalid_Size_Handle; + return error; + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( FT_Error ) + FT_Match_Size( FT_Face face, + FT_Size_Request req, + FT_Bool ignore_width, + FT_ULong* size_index ) + { + FT_Int i; + FT_Long w, h; + if ( !FT_HAS_FIXED_SIZES( face ) ) + return FT_Err_Invalid_Face_Handle; +/* FT_Bitmap_Size doesn't provide enough info... */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + return FT_Err_Unimplemented_Feature; + w = FT_REQUEST_WIDTH ( req ); + h = FT_REQUEST_HEIGHT( req ); + if ( req->width && !req->height ) + h = w; + else if ( !req->width && req->height ) + w = h; + w = FT_PIX_ROUND( w ); + h = FT_PIX_ROUND( h ); + for ( i = 0; i < face->num_fixed_sizes; i++ ) + { + FT_Bitmap_Size* bsize = face->available_sizes + i; + if ( h != FT_PIX_ROUND( bsize->y_ppem ) ) + continue; + if ( w == FT_PIX_ROUND( bsize->x_ppem ) || ignore_width ) + { + if ( size_index ) + *size_index = (FT_ULong)i; + return FT_Err_Ok; + } + } + return FT_Err_Invalid_Pixel_Size; + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( void ) + ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics, + FT_Pos advance ) + { + FT_Pos height = metrics->height; +/* compensate for glyph with bbox above/below the baseline */ + if ( metrics->horiBearingY < 0 ) + { + if ( height < metrics->horiBearingY ) + height = metrics->horiBearingY; + } + else if ( metrics->horiBearingY > 0 ) + height -= metrics->horiBearingY; +/* the factor 1.2 is a heuristical value */ + if ( !advance ) + advance = height * 12 / 10; + metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; + metrics->vertBearingY = ( advance - height ) / 2; + metrics->vertAdvance = advance; + } + static void + ft_recompute_scaled_metrics( FT_Face face, + FT_Size_Metrics* metrics ) + { +/* Compute root ascender, descender, test height, and max_advance */ +#ifdef GRID_FIT_METRICS + metrics->ascender = FT_PIX_CEIL( FT_MulFix( face->ascender, + metrics->y_scale ) ); + metrics->descender = FT_PIX_FLOOR( FT_MulFix( face->descender, + metrics->y_scale ) ); + metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, + metrics->y_scale ) ); + metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, + metrics->x_scale ) ); +/* !GRID_FIT_METRICS */ +#else + metrics->ascender = FT_MulFix( face->ascender, + metrics->y_scale ); + metrics->descender = FT_MulFix( face->descender, + metrics->y_scale ); + metrics->height = FT_MulFix( face->height, + metrics->y_scale ); + metrics->max_advance = FT_MulFix( face->max_advance_width, + metrics->x_scale ); +/* !GRID_FIT_METRICS */ +#endif + } + FT_BASE_DEF( void ) + FT_Select_Metrics( FT_Face face, + FT_ULong strike_index ) + { + FT_Size_Metrics* metrics; + FT_Bitmap_Size* bsize; + metrics = &face->size->metrics; + bsize = face->available_sizes + strike_index; + metrics->x_ppem = (FT_UShort)( ( bsize->x_ppem + 32 ) >> 6 ); + metrics->y_ppem = (FT_UShort)( ( bsize->y_ppem + 32 ) >> 6 ); + if ( FT_IS_SCALABLE( face ) ) + { + metrics->x_scale = FT_DivFix( bsize->x_ppem, + face->units_per_EM ); + metrics->y_scale = FT_DivFix( bsize->y_ppem, + face->units_per_EM ); + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + metrics->x_scale = 1L << 16; + metrics->y_scale = 1L << 16; + metrics->ascender = bsize->y_ppem; + metrics->descender = 0; + metrics->height = bsize->height << 6; + metrics->max_advance = bsize->x_ppem; + } + FT_TRACE5(( "FT_Select_Metrics:\n" )); + FT_TRACE5(( " x scale: %d (%f)\n", + metrics->x_scale, metrics->x_scale / 65536.0 )); + FT_TRACE5(( " y scale: %d (%f)\n", + metrics->y_scale, metrics->y_scale / 65536.0 )); + FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); + FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); + FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); + FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + } + FT_BASE_DEF( void ) + FT_Request_Metrics( FT_Face face, + FT_Size_Request req ) + { + FT_Size_Metrics* metrics; + metrics = &face->size->metrics; + if ( FT_IS_SCALABLE( face ) ) + { + FT_Long w = 0, h = 0, scaled_w = 0, scaled_h = 0; + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + w = h = face->units_per_EM; + break; + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + w = h = face->ascender - face->descender; + break; + case FT_SIZE_REQUEST_TYPE_BBOX: + w = face->bbox.xMax - face->bbox.xMin; + h = face->bbox.yMax - face->bbox.yMin; + break; + case FT_SIZE_REQUEST_TYPE_CELL: + w = face->max_advance_width; + h = face->ascender - face->descender; + break; + case FT_SIZE_REQUEST_TYPE_SCALES: + metrics->x_scale = (FT_Fixed)req->width; + metrics->y_scale = (FT_Fixed)req->height; + if ( !metrics->x_scale ) + metrics->x_scale = metrics->y_scale; + else if ( !metrics->y_scale ) + metrics->y_scale = metrics->x_scale; + goto Calculate_Ppem; + case FT_SIZE_REQUEST_TYPE_MAX: + break; + } +/* to be on the safe side */ + if ( w < 0 ) + w = -w; + if ( h < 0 ) + h = -h; + scaled_w = FT_REQUEST_WIDTH ( req ); + scaled_h = FT_REQUEST_HEIGHT( req ); +/* determine scales */ + if ( req->width ) + { + metrics->x_scale = FT_DivFix( scaled_w, w ); + if ( req->height ) + { + metrics->y_scale = FT_DivFix( scaled_h, h ); + if ( req->type == FT_SIZE_REQUEST_TYPE_CELL ) + { + if ( metrics->y_scale > metrics->x_scale ) + metrics->y_scale = metrics->x_scale; + else + metrics->x_scale = metrics->y_scale; + } + } + else + { + metrics->y_scale = metrics->x_scale; + scaled_h = FT_MulDiv( scaled_w, h, w ); + } + } + else + { + metrics->x_scale = metrics->y_scale = FT_DivFix( scaled_h, h ); + scaled_w = FT_MulDiv( scaled_h, w, h ); + } + Calculate_Ppem: +/* calculate the ppems */ + if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) + { + scaled_w = FT_MulFix( face->units_per_EM, metrics->x_scale ); + scaled_h = FT_MulFix( face->units_per_EM, metrics->y_scale ); + } + metrics->x_ppem = (FT_UShort)( ( scaled_w + 32 ) >> 6 ); + metrics->y_ppem = (FT_UShort)( ( scaled_h + 32 ) >> 6 ); + ft_recompute_scaled_metrics( face, metrics ); + } + else + { + FT_ZERO( metrics ); + metrics->x_scale = 1L << 16; + metrics->y_scale = 1L << 16; + } + FT_TRACE5(( "FT_Request_Metrics:\n" )); + FT_TRACE5(( " x scale: %d (%f)\n", + metrics->x_scale, metrics->x_scale / 65536.0 )); + FT_TRACE5(( " y scale: %d (%f)\n", + metrics->y_scale, metrics->y_scale / 65536.0 )); + FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); + FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); + FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); + FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Select_Size( FT_Face face, + FT_Int strike_index ) + { + FT_Driver_Class clazz; + if ( !face || !FT_HAS_FIXED_SIZES( face ) ) + return FT_Err_Invalid_Face_Handle; + if ( strike_index < 0 || strike_index >= face->num_fixed_sizes ) + return FT_Err_Invalid_Argument; + clazz = face->driver->clazz; + if ( clazz->select_size ) + { + FT_Error error; + error = clazz->select_size( face->size, (FT_ULong)strike_index ); + return error; + } + FT_Select_Metrics( face, (FT_ULong)strike_index ); + return FT_Err_Ok; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Request_Size( FT_Face face, + FT_Size_Request req ) + { + FT_Driver_Class clazz; + FT_ULong strike_index; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + if ( !req || req->width < 0 || req->height < 0 || + req->type >= FT_SIZE_REQUEST_TYPE_MAX ) + return FT_Err_Invalid_Argument; + clazz = face->driver->clazz; + if ( clazz->request_size ) + { + FT_Error error; + error = clazz->request_size( face->size, req ); + return error; + } +/* + * The reason that a driver doesn't have `request_size' defined is + * either that the scaling here suffices or that the supported formats + * are bitmap-only and size matching is not implemented. + * + * In the latter case, a simple size matching is done. + */ + if ( !FT_IS_SCALABLE( face ) && FT_HAS_FIXED_SIZES( face ) ) + { + FT_Error error; + error = FT_Match_Size( face, req, 0, &strike_index ); + if ( error ) + return error; + FT_TRACE3(( "FT_Request_Size: bitmap strike %lu matched\n", + strike_index )); + return FT_Select_Size( face, (FT_Int)strike_index ); + } + FT_Request_Metrics( face, req ); + return FT_Err_Ok; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_Char_Size( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ) + { + FT_Size_RequestRec req; + if ( !char_width ) + char_width = char_height; + else if ( !char_height ) + char_height = char_width; + if ( !horz_resolution ) + horz_resolution = vert_resolution; + else if ( !vert_resolution ) + vert_resolution = horz_resolution; + if ( char_width < 1 * 64 ) + char_width = 1 * 64; + if ( char_height < 1 * 64 ) + char_height = 1 * 64; + if ( !horz_resolution ) + horz_resolution = vert_resolution = 72; + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = char_width; + req.height = char_height; + req.horiResolution = horz_resolution; + req.vertResolution = vert_resolution; + return FT_Request_Size( face, &req ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_Pixel_Sizes( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ) + { + FT_Size_RequestRec req; + if ( pixel_width == 0 ) + pixel_width = pixel_height; + else if ( pixel_height == 0 ) + pixel_height = pixel_width; + if ( pixel_width < 1 ) + pixel_width = 1; + if ( pixel_height < 1 ) + pixel_height = 1; +/* use `>=' to avoid potential compiler warning on 16bit platforms */ + if ( pixel_width >= 0xFFFFU ) + pixel_width = 0xFFFFU; + if ( pixel_height >= 0xFFFFU ) + pixel_height = 0xFFFFU; + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = pixel_width << 6; + req.height = pixel_height << 6; + req.horiResolution = 0; + req.vertResolution = 0; + return FT_Request_Size( face, &req ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_Kerning( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ) + { + FT_Error error = FT_Err_Ok; + FT_Driver driver; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + if ( !akerning ) + return FT_Err_Invalid_Argument; + driver = face->driver; + akerning->x = 0; + akerning->y = 0; + if ( driver->clazz->get_kerning ) + { + error = driver->clazz->get_kerning( face, + left_glyph, + right_glyph, + akerning ); + if ( !error ) + { + if ( kern_mode != FT_KERNING_UNSCALED ) + { + akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale ); + akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale ); + if ( kern_mode != FT_KERNING_UNFITTED ) + { +/* we scale down kerning values for small ppem values */ +/* to avoid that rounding makes them too big. */ +/* `25' has been determined heuristically. */ + if ( face->size->metrics.x_ppem < 25 ) + akerning->x = FT_MulDiv( akerning->x, + face->size->metrics.x_ppem, 25 ); + if ( face->size->metrics.y_ppem < 25 ) + akerning->y = FT_MulDiv( akerning->y, + face->size->metrics.y_ppem, 25 ); + akerning->x = FT_PIX_ROUND( akerning->x ); + akerning->y = FT_PIX_ROUND( akerning->y ); + } + } + } + } + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_Track_Kerning( FT_Face face, + FT_Fixed point_size, + FT_Int degree, + FT_Fixed* akerning ) + { + FT_Service_Kerning service; + FT_Error error = FT_Err_Ok; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + if ( !akerning ) + return FT_Err_Invalid_Argument; + FT_FACE_FIND_SERVICE( face, service, KERNING ); + if ( !service ) + return FT_Err_Unimplemented_Feature; + error = service->get_track( face, + point_size, + degree, + akerning ); + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Select_Charmap( FT_Face face, + FT_Encoding encoding ) + { + FT_CharMap* cur; + FT_CharMap* limit; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + if ( encoding == FT_ENCODING_NONE ) + return FT_Err_Invalid_Argument; +/* FT_ENCODING_UNICODE is special. We try to find the `best' Unicode */ +/* charmap available, i.e., one with UCS-4 characters, if possible. */ +/* */ +/* This is done by find_unicode_charmap() above, to share code. */ + if ( encoding == FT_ENCODING_UNICODE ) + return find_unicode_charmap( face ); + cur = face->charmaps; + if ( !cur ) + return FT_Err_Invalid_CharMap_Handle; + limit = cur + face->num_charmaps; + for ( ; cur < limit; cur++ ) + { + if ( cur[0]->encoding == encoding ) + { +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "FT_Select_Charmap: requested charmap is found (%d), " + "but in too late position to cache\n", + cur - face->charmaps )); + continue; + } +#endif + face->charmap = cur[0]; + return 0; + } + } + return FT_Err_Invalid_Argument; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_Charmap( FT_Face face, + FT_CharMap charmap ) + { + FT_CharMap* cur; + FT_CharMap* limit; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + cur = face->charmaps; + if ( !cur ) + return FT_Err_Invalid_CharMap_Handle; + if ( FT_Get_CMap_Format( charmap ) == 14 ) + return FT_Err_Invalid_Argument; + limit = cur + face->num_charmaps; + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == charmap ) + { +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( cur - face->charmaps > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "FT_Set_Charmap: requested charmap is found (%d), " + "but in too late position to cache\n", + cur - face->charmaps )); + continue; + } +#endif + face->charmap = cur[0]; + return 0; + } + } + return FT_Err_Invalid_Argument; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Int ) + FT_Get_Charmap_Index( FT_CharMap charmap ) + { + FT_Int i; + if ( !charmap || !charmap->face ) + return -1; + for ( i = 0; i < charmap->face->num_charmaps; i++ ) + if ( charmap->face->charmaps[i] == charmap ) + break; + FT_ASSERT( i < charmap->face->num_charmaps ); +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( i > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "FT_Get_Charmap_Index: requested charmap is found (%d), " + "but in too late position to cache\n", + i )); + return -i; + } +#endif + return i; + } + static void + ft_cmap_done_internal( FT_CMap cmap ) + { + FT_CMap_Class clazz = cmap->clazz; + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY(face); + if ( clazz->done ) + clazz->done( cmap ); + FT_FREE( cmap ); + } + FT_BASE_DEF( void ) + FT_CMap_Done( FT_CMap cmap ) + { + if ( cmap ) + { + FT_Face face = cmap->charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error; + FT_Int i, j; + for ( i = 0; i < face->num_charmaps; i++ ) + { + if ( (FT_CMap)face->charmaps[i] == cmap ) + { + FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; + if ( FT_RENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps - 1 ) ) + return; +/* remove it from our list of charmaps */ + for ( j = i + 1; j < face->num_charmaps; j++ ) + { + if ( j == face->num_charmaps - 1 ) + face->charmaps[j - 1] = last_charmap; + else + face->charmaps[j - 1] = face->charmaps[j]; + } + face->num_charmaps--; + if ( (FT_CMap)face->charmap == cmap ) + face->charmap = NULL; + ft_cmap_done_internal( cmap ); + break; + } + } + } + } + FT_BASE_DEF( FT_Error ) + FT_CMap_New( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ) + { + FT_Error error = FT_Err_Ok; + FT_Face face; + FT_Memory memory; + FT_CMap cmap = NULL; + if ( clazz == NULL || charmap == NULL || charmap->face == NULL ) + return FT_Err_Invalid_Argument; + face = charmap->face; + memory = FT_FACE_MEMORY( face ); + if ( !FT_ALLOC( cmap, clazz->size ) ) + { + cmap->charmap = *charmap; + cmap->clazz = clazz; + if ( clazz->init ) + { + error = clazz->init( cmap, init_data ); + if ( error ) + goto Fail; + } +/* add it to our list of charmaps */ + if ( FT_RENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps + 1 ) ) + goto Fail; + face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; + } + Exit: + if ( acmap ) + *acmap = cmap; + return error; + Fail: + ft_cmap_done_internal( cmap ); + cmap = NULL; + goto Exit; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Char_Index( FT_Face face, + FT_ULong charcode ) + { + FT_UInt result = 0; + if ( face && face->charmap ) + { + FT_CMap cmap = FT_CMAP( face->charmap ); + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); + FT_TRACE1(( " 0x%x is truncated\n", charcode )); + } + result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode ); + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_ULong ) + FT_Get_First_Char( FT_Face face, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + if ( face && face->charmap && face->num_glyphs ) + { + gindex = FT_Get_Char_Index( face, 0 ); + if ( gindex == 0 || gindex >= (FT_UInt)face->num_glyphs ) + result = FT_Get_Next_Char( face, 0, &gindex ); + } + if ( agindex ) + *agindex = gindex; + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_ULong ) + FT_Get_Next_Char( FT_Face face, + FT_ULong charcode, + FT_UInt *agindex ) + { + FT_ULong result = 0; + FT_UInt gindex = 0; + if ( face && face->charmap && face->num_glyphs ) + { + FT_UInt32 code = (FT_UInt32)charcode; + FT_CMap cmap = FT_CMAP( face->charmap ); + do { + gindex = cmap->clazz->char_next( cmap, &code ); + } while ( gindex >= (FT_UInt)face->num_glyphs ); + result = ( gindex == 0 ) ? 0 : code; + } + if ( agindex ) + *agindex = gindex; + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UInt ) + FT_Face_GetCharVariantIndex( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ) + { + FT_UInt result = 0; + if ( face && face->charmap && + face->charmap->encoding == FT_ENCODING_UNICODE ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + FT_CMap ucmap = FT_CMAP( face->charmap ); + if ( charmap != NULL ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); + FT_TRACE1(( " 0x%x is truncated\n", charcode )); + } + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); + FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); + } + result = vcmap->clazz->char_var_index( vcmap, ucmap, + (FT_UInt32)charcode, + (FT_UInt32)variantSelector ); + } + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Int ) + FT_Face_GetCharVariantIsDefault( FT_Face face, + FT_ULong charcode, + FT_ULong variantSelector ) + { + FT_Int result = -1; + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + if ( charmap != NULL ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); + FT_TRACE1(( " 0x%x is truncated\n", charcode )); + } + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); + FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); + } + result = vcmap->clazz->char_var_default( vcmap, + (FT_UInt32)charcode, + (FT_UInt32)variantSelector ); + } + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetVariantSelectors( FT_Face face ) + { + FT_UInt32 *result = NULL; + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + if ( charmap != NULL ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + result = vcmap->clazz->variant_list( vcmap, memory ); + } + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetVariantsOfChar( FT_Face face, + FT_ULong charcode ) + { + FT_UInt32 *result = NULL; + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + if ( charmap != NULL ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); + FT_TRACE1(( " 0x%x is truncated\n", charcode )); + } + result = vcmap->clazz->charvariant_list( vcmap, memory, + (FT_UInt32)charcode ); + } + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UInt32* ) + FT_Face_GetCharsOfVariant( FT_Face face, + FT_ULong variantSelector ) + { + FT_UInt32 *result = NULL; + if ( face ) + { + FT_CharMap charmap = find_variant_selector_charmap( face ); + if ( charmap != NULL ) + { + FT_CMap vcmap = FT_CMAP( charmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + if ( variantSelector > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); + FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); + } + result = vcmap->clazz->variantchar_list( vcmap, memory, + (FT_UInt32)variantSelector ); + } + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Name_Index( FT_Face face, + FT_String* glyph_name ) + { + FT_UInt result = 0; + if ( face && FT_HAS_GLYPH_NAMES( face ) ) + { + FT_Service_GlyphDict service; + FT_FACE_LOOKUP_SERVICE( face, + service, + GLYPH_DICT ); + if ( service && service->name_index ) + result = service->name_index( face, glyph_name ); + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph_Name( FT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_Error error = FT_Err_Invalid_Argument; +/* clean up buffer */ + if ( buffer && buffer_max > 0 ) + ((FT_Byte*)buffer)[0] = 0; + if ( face && + (FT_Long)glyph_index <= face->num_glyphs && + FT_HAS_GLYPH_NAMES( face ) ) + { + FT_Service_GlyphDict service; + FT_FACE_LOOKUP_SERVICE( face, + service, + GLYPH_DICT ); + if ( service && service->get_name ) + error = service->get_name( face, glyph_index, buffer, buffer_max ); + } + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( const char* ) + FT_Get_Postscript_Name( FT_Face face ) + { + const char* result = NULL; + if ( !face ) + goto Exit; + if ( !result ) + { + FT_Service_PsFontName service; + FT_FACE_LOOKUP_SERVICE( face, + service, + POSTSCRIPT_FONT_NAME ); + if ( service && service->get_ps_font_name ) + result = service->get_ps_font_name( face ); + } + Exit: + return result; + } +/* documentation is in tttables.h */ + FT_EXPORT_DEF( void* ) + FT_Get_Sfnt_Table( FT_Face face, + FT_Sfnt_Tag tag ) + { + void* table = 0; + FT_Service_SFNT_Table service; + if ( face && FT_IS_SFNT( face ) ) + { + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service != NULL ) + table = service->get_table( face, tag ); + } + return table; + } +/* documentation is in tttables.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Load_Sfnt_Table( FT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Service_SFNT_Table service; + if ( !face || !FT_IS_SFNT( face ) ) + return FT_Err_Invalid_Face_Handle; + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service == NULL ) + return FT_Err_Unimplemented_Feature; + return service->load_table( face, tag, offset, buffer, length ); + } +/* documentation is in tttables.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Sfnt_Table_Info( FT_Face face, + FT_UInt table_index, + FT_ULong *tag, + FT_ULong *length ) + { + FT_Service_SFNT_Table service; + FT_ULong offset; + if ( !face || !FT_IS_SFNT( face ) ) + return FT_Err_Invalid_Face_Handle; + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service == NULL ) + return FT_Err_Unimplemented_Feature; + return service->table_info( face, table_index, tag, &offset, length ); + } +/* documentation is in tttables.h */ + FT_EXPORT_DEF( FT_ULong ) + FT_Get_CMap_Language_ID( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + if ( !charmap || !charmap->face ) + return 0; + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( service == NULL ) + return 0; + if ( service->get_cmap_info( charmap, &cmap_info )) + return 0; + return cmap_info.language; + } +/* documentation is in tttables.h */ + FT_EXPORT_DEF( FT_Long ) + FT_Get_CMap_Format( FT_CharMap charmap ) + { + FT_Service_TTCMaps service; + FT_Face face; + TT_CMapInfo cmap_info; + if ( !charmap || !charmap->face ) + return -1; + face = charmap->face; + FT_FACE_FIND_SERVICE( face, service, TT_CMAP ); + if ( service == NULL ) + return -1; + if ( service->get_cmap_info( charmap, &cmap_info )) + return -1; + return cmap_info.format; + } +/* documentation is in ftsizes.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Activate_Size( FT_Size size ) + { + FT_Face face; + if ( size == NULL ) + return FT_Err_Invalid_Argument; + face = size->face; + if ( face == NULL || face->driver == NULL ) + return FT_Err_Invalid_Argument; +/* we don't need anything more complex than that; all size objects */ +/* are already listed by the face */ + face->size = size; + return FT_Err_Ok; + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** R E N D E R E R S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* lookup a renderer by glyph format in the library's list */ + FT_BASE_DEF( FT_Renderer ) + FT_Lookup_Renderer( FT_Library library, + FT_Glyph_Format format, + FT_ListNode* node ) + { + FT_ListNode cur; + FT_Renderer result = 0; + if ( !library ) + goto Exit; + cur = library->renderers.head; + if ( node ) + { + if ( *node ) + cur = (*node)->next; + *node = 0; + } + while ( cur ) + { + FT_Renderer renderer = FT_RENDERER( cur->data ); + if ( renderer->glyph_format == format ) + { + if ( node ) + *node = cur; + result = renderer; + break; + } + cur = cur->next; + } + Exit: + return result; + } + static FT_Renderer + ft_lookup_glyph_renderer( FT_GlyphSlot slot ) + { + FT_Face face = slot->face; + FT_Library library = FT_FACE_LIBRARY( face ); + FT_Renderer result = library->cur_renderer; + if ( !result || result->glyph_format != slot->format ) + result = FT_Lookup_Renderer( library, slot->format, 0 ); + return result; + } + static void + ft_set_current_renderer( FT_Library library ) + { + FT_Renderer renderer; + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 ); + library->cur_renderer = renderer; + } + static FT_Error + ft_add_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_Error error; + FT_ListNode node = NULL; + if ( FT_NEW( node ) ) + goto Exit; + { + FT_Renderer render = FT_RENDERER( module ); + FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz; + render->clazz = clazz; + render->glyph_format = clazz->glyph_format; +/* allocate raster object if needed */ + if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && + clazz->raster_class->raster_new ) + { + error = clazz->raster_class->raster_new( memory, &render->raster ); + if ( error ) + goto Fail; + render->raster_render = clazz->raster_class->raster_render; + render->render = clazz->render_glyph; + } +/* add to list */ + node->data = module; + FT_List_Add( &library->renderers, node ); + ft_set_current_renderer( library ); + } + Fail: + if ( error ) + FT_FREE( node ); + Exit: + return error; + } + static void + ft_remove_renderer( FT_Module module ) + { + FT_Library library = module->library; + FT_Memory memory = library->memory; + FT_ListNode node; + node = FT_List_Find( &library->renderers, module ); + if ( node ) + { + FT_Renderer render = FT_RENDERER( module ); +/* release raster object, if any */ + if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && + render->raster ) + render->clazz->raster_class->raster_done( render->raster ); +/* remove from list */ + FT_List_Remove( &library->renderers, node ); + FT_FREE( node ); + ft_set_current_renderer( library ); + } + } +/* documentation is in ftrender.h */ + FT_EXPORT_DEF( FT_Renderer ) + FT_Get_Renderer( FT_Library library, + FT_Glyph_Format format ) + { +/* test for valid `library' delayed to FT_Lookup_Renderer() */ + return FT_Lookup_Renderer( library, format, 0 ); + } +/* documentation is in ftrender.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_Renderer( FT_Library library, + FT_Renderer renderer, + FT_UInt num_params, + FT_Parameter* parameters ) + { + FT_ListNode node; + FT_Error error = FT_Err_Ok; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !renderer ) + return FT_Err_Invalid_Argument; + node = FT_List_Find( &library->renderers, renderer ); + if ( !node ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + FT_List_Up( &library->renderers, node ); + if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE ) + library->cur_renderer = renderer; + if ( num_params > 0 ) + { + FT_Renderer_SetModeFunc set_mode = renderer->clazz->set_mode; + for ( ; num_params > 0; num_params-- ) + { + error = set_mode( renderer, parameters->tag, parameters->data ); + if ( error ) + break; + parameters++; + } + } + Exit: + return error; + } + FT_BASE_DEF( FT_Error ) + FT_Render_Glyph_Internal( FT_Library library, + FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Error error = FT_Err_Ok; + FT_Renderer renderer; +/* if it is already a bitmap, no need to do anything */ + switch ( slot->format ) + { +/* already a bitmap, don't do anything */ + case FT_GLYPH_FORMAT_BITMAP: + break; + default: + { + FT_ListNode node = 0; + FT_Bool update = 0; +/* small shortcut for the very common case */ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + renderer = library->cur_renderer; + node = library->renderers.head; + } + else + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + error = FT_Err_Unimplemented_Feature; + while ( renderer ) + { + error = renderer->render( renderer, slot, render_mode, NULL ); + if ( !error || + FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph ) + break; +/* FT_Err_Cannot_Render_Glyph is returned if the render mode */ +/* is unsupported by the current renderer for this glyph image */ +/* format. */ +/* now, look for another renderer that supports the same */ +/* format. */ + renderer = FT_Lookup_Renderer( library, slot->format, &node ); + update = 1; + } +/* if we changed the current renderer for the glyph image format */ +/* we need to select it as the next current one */ + if ( !error && update && renderer ) + FT_Set_Renderer( library, renderer, 0, 0 ); + } + } + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Render_Glyph( FT_GlyphSlot slot, + FT_Render_Mode render_mode ) + { + FT_Library library; + if ( !slot || !slot->face ) + return FT_Err_Invalid_Argument; + library = FT_FACE_LIBRARY( slot->face ); + return FT_Render_Glyph_Internal( library, slot, render_mode ); + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** M O D U L E S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* Destroy_Module */ +/* */ +/* <Description> */ +/* Destroys a given module object. For drivers, this also destroys */ +/* all child faces. */ +/* */ +/* <InOut> */ +/* module :: A handle to the target driver object. */ +/* */ +/* <Note> */ +/* The driver _must_ be LOCKED! */ +/* */ + static void + Destroy_Module( FT_Module module ) + { + FT_Memory memory = module->memory; + FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + if ( library && library->auto_hinter == module ) + library->auto_hinter = 0; +/* if the module is a renderer */ + if ( FT_MODULE_IS_RENDERER( module ) ) + ft_remove_renderer( module ); +/* if the module is a font driver, add some steps */ + if ( FT_MODULE_IS_DRIVER( module ) ) + Destroy_Driver( FT_DRIVER( module ) ); +/* finalize the module object */ + if ( clazz->module_done ) + clazz->module_done( module ); +/* discard it */ + FT_FREE( module ); + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Add_Module( FT_Library library, + const FT_Module_Class* clazz ) + { + FT_Error error; + FT_Memory memory; + FT_Module module; + FT_UInt nn; +#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \ + FREETYPE_MINOR ) + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !clazz ) + return FT_Err_Invalid_Argument; +/* check freetype version */ + if ( clazz->module_requires > FREETYPE_VER_FIXED ) + return FT_Err_Invalid_Version; +/* look for a module with the same name in the library's table */ + for ( nn = 0; nn < library->num_modules; nn++ ) + { + module = library->modules[nn]; + if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 ) + { +/* this installed module has the same name, compare their versions */ + if ( clazz->module_version <= module->clazz->module_version ) + return FT_Err_Lower_Module_Version; +/* remove the module from our list, then exit the loop to replace */ +/* it by our new version.. */ + FT_Remove_Module( library, module ); + break; + } + } + memory = library->memory; + error = FT_Err_Ok; + if ( library->num_modules >= FT_MAX_MODULES ) + { + error = FT_Err_Too_Many_Drivers; + goto Exit; + } +/* allocate module object */ + if ( FT_ALLOC( module, clazz->module_size ) ) + goto Exit; +/* base initialization */ + module->library = library; + module->memory = memory; + module->clazz = (FT_Module_Class*)clazz; +/* check whether the module is a renderer - this must be performed */ +/* before the normal module initialization */ + if ( FT_MODULE_IS_RENDERER( module ) ) + { +/* add to the renderers list */ + error = ft_add_renderer( module ); + if ( error ) + goto Fail; + } +/* is the module a auto-hinter? */ + if ( FT_MODULE_IS_HINTER( module ) ) + library->auto_hinter = module; +/* if the module is a font driver */ + if ( FT_MODULE_IS_DRIVER( module ) ) + { +/* allocate glyph loader if needed */ + FT_Driver driver = FT_DRIVER( module ); + driver->clazz = (FT_Driver_Class)module->clazz; + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + { + error = FT_GlyphLoader_New( memory, &driver->glyph_loader ); + if ( error ) + goto Fail; + } + } + if ( clazz->module_init ) + { + error = clazz->module_init( module ); + if ( error ) + goto Fail; + } +/* add module to the library's table */ + library->modules[library->num_modules++] = module; + Exit: + return error; + Fail: + if ( FT_MODULE_IS_DRIVER( module ) ) + { + FT_Driver driver = FT_DRIVER( module ); + if ( FT_DRIVER_USES_OUTLINES( driver ) ) + FT_GlyphLoader_Done( driver->glyph_loader ); + } + if ( FT_MODULE_IS_RENDERER( module ) ) + { + FT_Renderer renderer = FT_RENDERER( module ); + if ( renderer->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && + renderer->raster ) + renderer->clazz->raster_class->raster_done( renderer->raster ); + } + FT_FREE( module ); + goto Exit; + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_Module ) + FT_Get_Module( FT_Library library, + const char* module_name ) + { + FT_Module result = 0; + FT_Module* cur; + FT_Module* limit; + if ( !library || !module_name ) + return result; + cur = library->modules; + limit = cur + library->num_modules; + for ( ; cur < limit; cur++ ) + if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 ) + { + result = cur[0]; + break; + } + return result; + } +/* documentation is in ftobjs.h */ + FT_BASE_DEF( const void* ) + FT_Get_Module_Interface( FT_Library library, + const char* mod_name ) + { + FT_Module module; +/* test for valid `library' delayed to FT_Get_Module() */ + module = FT_Get_Module( library, mod_name ); + return module ? module->clazz->module_interface : 0; + } + FT_BASE_DEF( FT_Pointer ) + ft_module_get_service( FT_Module module, + const char* service_id ) + { + FT_Pointer result = NULL; + if ( module ) + { + FT_ASSERT( module->clazz && module->clazz->get_interface ); +/* first, look for the service in the module */ + if ( module->clazz->get_interface ) + result = module->clazz->get_interface( module, service_id ); + if ( result == NULL ) + { +/* we didn't find it, look in all other modules then */ + FT_Library library = module->library; + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + for ( ; cur < limit; cur++ ) + { + if ( cur[0] != module ) + { + FT_ASSERT( cur[0]->clazz ); + if ( cur[0]->clazz->get_interface ) + { + result = cur[0]->clazz->get_interface( cur[0], service_id ); + if ( result != NULL ) + break; + } + } + } + } + } + return result; + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Remove_Module( FT_Library library, + FT_Module module ) + { +/* try to find the module from the table, then remove it from there */ + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( module ) + { + FT_Module* cur = library->modules; + FT_Module* limit = cur + library->num_modules; + for ( ; cur < limit; cur++ ) + { + if ( cur[0] == module ) + { +/* remove it from the table */ + library->num_modules--; + limit--; + while ( cur < limit ) + { + cur[0] = cur[1]; + cur++; + } + limit[0] = 0; +/* destroy the module */ + Destroy_Module( module ); + return FT_Err_Ok; + } + } + } + return FT_Err_Invalid_Driver_Handle; + } + FT_Error + ft_property_do( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value, + FT_Bool set ) + { + FT_Module* cur; + FT_Module* limit; + FT_Module_Interface interface; + FT_Service_Properties service; + FT_Bool missing_func; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !module_name || !property_name || !value ) + return FT_Err_Invalid_Argument; + cur = library->modules; + limit = cur + library->num_modules; +/* search module */ + for ( ; cur < limit; cur++ ) + if ( !ft_strcmp( cur[0]->clazz->module_name, module_name ) ) + break; + if ( cur == limit ) + { + FT_ERROR(( "%s: can't find module `%s'\n", + func_name, module_name )); + return FT_Err_Missing_Module; + } +/* check whether we have a service interface */ + if ( !cur[0]->clazz->get_interface ) + { + FT_ERROR(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); + return FT_Err_Unimplemented_Feature; + } +/* search property service */ + interface = cur[0]->clazz->get_interface( cur[0], + FT_SERVICE_ID_PROPERTIES ); + if ( !interface ) + { + FT_ERROR(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); + return FT_Err_Unimplemented_Feature; + } + service = (FT_Service_Properties)interface; + if ( set ) + missing_func = !service->set_property; + else + missing_func = !service->get_property; + if ( missing_func ) + { + FT_ERROR(( "%s: property service of module `%s' is broken\n", + func_name, module_name )); + return FT_Err_Unimplemented_Feature; + } + return set ? service->set_property( cur[0], property_name, value ) + : service->get_property( cur[0], property_name, value ); + } +/* documentation is in ftmodapi.h */ + FT_Error + FT_Property_Set( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ) + { + return ft_property_do( library, + module_name, + property_name, + (void*)value, + TRUE ); + } +/* documentation is in ftmodapi.h */ + FT_Error + FT_Property_Get( FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + void* value ) + { + return ft_property_do( library, + module_name, + property_name, + value, + FALSE ); + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** L I B R A R Y ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Reference_Library( FT_Library library ) + { + library->refcount++; + return FT_Err_Ok; + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Library( FT_Memory memory, + FT_Library *alibrary ) + { + FT_Library library = NULL; + FT_Error error; + if ( !memory ) + return FT_Err_Invalid_Argument; +/* first of all, allocate the library object */ + if ( FT_NEW( library ) ) + return error; + library->memory = memory; +/* allocate the render pool */ + library->raster_pool_size = FT_RENDER_POOL_SIZE; +#if FT_RENDER_POOL_SIZE > 0 + if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) ) + goto Fail; +#endif + library->version_major = FREETYPE_MAJOR; + library->version_minor = FREETYPE_MINOR; + library->version_patch = FREETYPE_PATCH; + library->refcount = 1; +/* That's ok now */ + *alibrary = library; + return FT_Err_Ok; + Fail: + FT_FREE( library ); + return error; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( void ) + FT_Library_Version( FT_Library library, + FT_Int *amajor, + FT_Int *aminor, + FT_Int *apatch ) + { + FT_Int major = 0; + FT_Int minor = 0; + FT_Int patch = 0; + if ( library ) + { + major = library->version_major; + minor = library->version_minor; + patch = library->version_patch; + } + if ( amajor ) + *amajor = major; + if ( aminor ) + *aminor = minor; + if ( apatch ) + *apatch = patch; + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Done_Library( FT_Library library ) + { + FT_Memory memory; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + library->refcount--; + if ( library->refcount > 0 ) + goto Exit; + memory = library->memory; +/* + * Close all faces in the library. If we don't do this, we can have + * some subtle memory leaks. + * + * Example: + * + * - the cff font driver uses the pshinter module in cff_size_done + * - if the pshinter module is destroyed before the cff font driver, + * opened FT_Face objects managed by the driver are not properly + * destroyed, resulting in a memory leak + * + * Some faces are dependent on other faces, like Type42 faces that + * depend on TrueType faces synthesized internally. + * + * The order of drivers should be specified in driver_name[]. + */ + { + FT_UInt m, n; + const char* driver_name[] = { "type42", NULL }; + for ( m = 0; + m < sizeof ( driver_name ) / sizeof ( driver_name[0] ); + m++ ) + { + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + const char* module_name = module->clazz->module_name; + FT_List faces; + if ( driver_name[m] && + ft_strcmp( module_name, driver_name[m] ) != 0 ) + continue; + if ( ( module->clazz->module_flags & FT_MODULE_FONT_DRIVER ) == 0 ) + continue; + FT_TRACE7(( "FT_Done_Library: close faces for %s\n", module_name )); + faces = &FT_DRIVER( module )->faces_list; + while ( faces->head ) + { + FT_Done_Face( FT_FACE( faces->head->data ) ); + if ( faces->head ) + FT_TRACE0(( "FT_Done_Library: failed to free some faces\n" )); + } + } + } + } +/* Close all other modules in the library */ +#if 1 +/* XXX Modules are removed in the reversed order so that */ +/* type42 module is removed before truetype module. This */ +/* avoids double free in some occasions. It is a hack. */ + while ( library->num_modules > 0 ) + FT_Remove_Module( library, + library->modules[library->num_modules - 1] ); +#else + { + FT_UInt n; + for ( n = 0; n < library->num_modules; n++ ) + { + FT_Module module = library->modules[n]; + if ( module ) + { + Destroy_Module( module ); + library->modules[n] = 0; + } + } + } +#endif +/* Destroy raster objects */ + FT_FREE( library->raster_pool ); + library->raster_pool_size = 0; + FT_FREE( library ); + Exit: + return FT_Err_Ok; + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( void ) + FT_Set_Debug_Hook( FT_Library library, + FT_UInt hook_index, + FT_DebugHook_Func debug_hook ) + { + if ( library && debug_hook && + hook_index < + ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) ) + library->debug_hooks[hook_index] = debug_hook; + } +/* documentation is in ftmodapi.h */ + FT_EXPORT_DEF( FT_TrueTypeEngineType ) + FT_Get_TrueType_Engine_Type( FT_Library library ) + { + FT_TrueTypeEngineType result = FT_TRUETYPE_ENGINE_TYPE_NONE; + if ( library ) + { + FT_Module module = FT_Get_Module( library, "truetype" ); + if ( module ) + { + FT_Service_TrueTypeEngine service; + service = (FT_Service_TrueTypeEngine) + ft_module_get_service( module, + FT_SERVICE_ID_TRUETYPE_ENGINE ); + if ( service ) + result = service->engine_type; + } + } + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_SubGlyph_Info( FT_GlyphSlot glyph, + FT_UInt sub_index, + FT_Int *p_index, + FT_UInt *p_flags, + FT_Int *p_arg1, + FT_Int *p_arg2, + FT_Matrix *p_transform ) + { + FT_Error error = FT_Err_Invalid_Argument; + if ( glyph && + glyph->subglyphs && + glyph->format == FT_GLYPH_FORMAT_COMPOSITE && + sub_index < glyph->num_subglyphs ) + { + FT_SubGlyph subg = glyph->subglyphs + sub_index; + *p_index = subg->index; + *p_flags = subg->flags; + *p_arg1 = subg->arg1; + *p_arg2 = subg->arg2; + *p_transform = subg->transform; + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftoutln.c */ +/* */ +/* FreeType outline management (body). */ +/* */ +/* Copyright 1996-2008, 2010, 2012 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* All functions are declared in freetype.h. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* fttrigon.h */ +/* */ +/* FreeType trigonometric functions (specification). */ +/* */ +/* Copyright 2001, 2003, 2005, 2007 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. */ +/* */ +/***************************************************************************/ +#define __FTTRIGON_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* computations */ +/* */ +/*************************************************************************/ +/************************************************************************* + * + * @type: + * FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed float value expressed in degrees. + * + */ + typedef FT_Fixed FT_Angle; +/************************************************************************* + * + * @macro: + * FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI ( 180L << 16 ) +/************************************************************************* + * + * @macro: + * FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_2PI ( FT_ANGLE_PI * 2 ) +/************************************************************************* + * + * @macro: + * FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI2 ( FT_ANGLE_PI / 2 ) +/************************************************************************* + * + * @macro: + * FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @FT_Angle units. + * + */ +#define FT_ANGLE_PI4 ( FT_ANGLE_PI / 4 ) +/************************************************************************* + * + * @function: + * FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Sin( FT_Angle angle ); +/************************************************************************* + * + * @function: + * FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @FT_Vector_Unit. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Cos( FT_Angle angle ); +/************************************************************************* + * + * @function: + * FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Tan( FT_Angle angle ); +/************************************************************************* + * + * @function: + * FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in + * the 2d plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ + FT_EXPORT( FT_Angle ) + FT_Atan2( FT_Fixed x, + FT_Fixed y ); +/************************************************************************* + * + * @function: + * FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `value2-value1'. + * + */ + FT_EXPORT( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ); +/************************************************************************* + * + * @function: + * FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x' will be `sin(angle)', and the value of + * `vec.y' will be `cos(angle)'. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ); +/************************************************************************* + * + * @function: + * FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The address of angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ); +/************************************************************************* + * + * @function: + * FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ + FT_EXPORT( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ); +/************************************************************************* + * + * @function: + * FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ); +/************************************************************************* + * + * @function: + * FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ + FT_EXPORT( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ); +/* */ +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_outline + static + const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 }; +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Decompose( FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ( (x) << shift ) - delta ) + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + FT_Vector* point; + FT_Vector* limit; + char* tags; + FT_Error error; +/* index of contour in outline */ + FT_Int n; +/* index of first point in contour */ + FT_UInt first; +/* current point's state */ + FT_Int tag; + FT_Int shift; + FT_Pos delta; + if ( !outline || !func_interface ) + return FT_Err_Invalid_Argument; + shift = func_interface->shift; + delta = func_interface->delta; + first = 0; + for ( n = 0; n < outline->n_contours; n++ ) + { +/* index of last point in contour */ + FT_Int last; + FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); + last = outline->contours[n]; + if ( last < 0 ) + goto Invalid_Outline; + limit = outline->points + last; + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + v_control = v_start; + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); +/* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; +/* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { +/* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { +/* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { +/* if both first and last points are conic, */ +/* start at their middle and record its position */ +/* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + v_last = v_start; + } + point--; + tags--; + } + FT_TRACE5(( " move to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + while ( point < limit ) + { + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { +/* emit a single line_to */ + case FT_CURVE_TAG_ON: + { + FT_Vector vec; + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + FT_TRACE5(( " line to (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } +/* consume conic arcs */ + case FT_CURVE_TAG_CONIC: + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + if ( tag == FT_CURVE_TAG_ON ) + { + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_middle.x / 64.0, v_middle.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + v_control = vec; + goto Do_Conic; + } + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; +/* FT_CURVE_TAG_CUBIC */ + default: + { + FT_Vector vec1, vec2; + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + point += 2; + tags += 2; + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + if ( point <= limit ) + { + FT_Vector vec; + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } +/* close the contour with a line segment */ + FT_TRACE5(( " line to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->line_to( &v_start, user ); + Close: + if ( error ) + goto Exit; + first = last + 1; + } + FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); + return FT_Err_Ok; + Exit: + FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error )); + return error; + Invalid_Outline: + return FT_Err_Invalid_Outline; + } + FT_EXPORT_DEF( FT_Error ) + FT_Outline_New_Internal( FT_Memory memory, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ) + { + FT_Error error; + if ( !anoutline || !memory ) + return FT_Err_Invalid_Argument; + *anoutline = null_outline; + if ( FT_NEW_ARRAY( anoutline->points, numPoints ) || + FT_NEW_ARRAY( anoutline->tags, numPoints ) || + FT_NEW_ARRAY( anoutline->contours, numContours ) ) + goto Fail; + anoutline->n_points = (FT_UShort)numPoints; + anoutline->n_contours = (FT_Short)numContours; + anoutline->flags |= FT_OUTLINE_OWNER; + return FT_Err_Ok; + Fail: + anoutline->flags |= FT_OUTLINE_OWNER; + FT_Outline_Done_Internal( memory, anoutline ); + return error; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_New( FT_Library library, + FT_UInt numPoints, + FT_Int numContours, + FT_Outline *anoutline ) + { + if ( !library ) + return FT_Err_Invalid_Library_Handle; + return FT_Outline_New_Internal( library->memory, numPoints, + numContours, anoutline ); + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Check( FT_Outline* outline ) + { + if ( outline ) + { + FT_Int n_points = outline->n_points; + FT_Int n_contours = outline->n_contours; + FT_Int end0, end; + FT_Int n; +/* empty glyph? */ + if ( n_points == 0 && n_contours == 0 ) + return 0; +/* check point and contour counts */ + if ( n_points <= 0 || n_contours <= 0 ) + goto Bad; + end0 = end = -1; + for ( n = 0; n < n_contours; n++ ) + { + end = outline->contours[n]; +/* note that we don't accept empty contours */ + if ( end <= end0 || end >= n_points ) + goto Bad; + end0 = end; + } + if ( end != n_points - 1 ) + goto Bad; +/* XXX: check the tags array */ + return 0; + } + Bad: + return FT_Err_Invalid_Argument; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Copy( const FT_Outline* source, + FT_Outline *target ) + { + FT_Int is_owner; + if ( !source || !target || + source->n_points != target->n_points || + source->n_contours != target->n_contours ) + return FT_Err_Invalid_Argument; + if ( source == target ) + return FT_Err_Ok; + FT_ARRAY_COPY( target->points, source->points, source->n_points ); + FT_ARRAY_COPY( target->tags, source->tags, source->n_points ); + FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); +/* copy all flags, except the `FT_OUTLINE_OWNER' one */ + is_owner = target->flags & FT_OUTLINE_OWNER; + target->flags = source->flags; + target->flags &= ~FT_OUTLINE_OWNER; + target->flags |= is_owner; + return FT_Err_Ok; + } + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Done_Internal( FT_Memory memory, + FT_Outline* outline ) + { + if ( memory && outline ) + { + if ( outline->flags & FT_OUTLINE_OWNER ) + { + FT_FREE( outline->points ); + FT_FREE( outline->tags ); + FT_FREE( outline->contours ); + } + *outline = null_outline; + return FT_Err_Ok; + } + else + return FT_Err_Invalid_Argument; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Done( FT_Library library, + FT_Outline* outline ) + { +/* check for valid `outline' in FT_Outline_Done_Internal() */ + if ( !library ) + return FT_Err_Invalid_Library_Handle; + return FT_Outline_Done_Internal( library->memory, outline ); + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( void ) + FT_Outline_Get_CBox( const FT_Outline* outline, + FT_BBox *acbox ) + { + FT_Pos xMin, yMin, xMax, yMax; + if ( outline && acbox ) + { + if ( outline->n_points == 0 ) + { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } + else + { + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + for ( ; vec < limit; vec++ ) + { + FT_Pos x, y; + x = vec->x; + if ( x < xMin ) xMin = x; + if ( x > xMax ) xMax = x; + y = vec->y; + if ( y < yMin ) yMin = y; + if ( y > yMax ) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( void ) + FT_Outline_Translate( const FT_Outline* outline, + FT_Pos xOffset, + FT_Pos yOffset ) + { + FT_UShort n; + FT_Vector* vec; + if ( !outline ) + return; + vec = outline->points; + for ( n = 0; n < outline->n_points; n++ ) + { + vec->x += xOffset; + vec->y += yOffset; + vec++; + } + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( void ) + FT_Outline_Reverse( FT_Outline* outline ) + { + FT_UShort n; + FT_Int first, last; + if ( !outline ) + return; + first = 0; + for ( n = 0; n < outline->n_contours; n++ ) + { + last = outline->contours[n]; +/* reverse point table */ + { + FT_Vector* p = outline->points + first; + FT_Vector* q = outline->points + last; + FT_Vector swap; + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } +/* reverse tags table */ + { + char* p = outline->tags + first; + char* q = outline->tags + last; + char swap; + while ( p < q ) + { + swap = *p; + *p = *q; + *q = swap; + p++; + q--; + } + } + first = last + 1; + } + outline->flags ^= FT_OUTLINE_REVERSE_FILL; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Render( FT_Library library, + FT_Outline* outline, + FT_Raster_Params* params ) + { + FT_Error error; + FT_Bool update = FALSE; + FT_Renderer renderer; + FT_ListNode node; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !outline || !params ) + return FT_Err_Invalid_Argument; + renderer = library->cur_renderer; + node = library->renderers.head; + params->source = (void*)outline; + error = FT_Err_Cannot_Render_Glyph; + while ( renderer ) + { + error = renderer->raster_render( renderer->raster, params ); + if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph ) + break; +/* FT_Err_Cannot_Render_Glyph is returned if the render mode */ +/* is unsupported by the current renderer for this glyph image */ +/* format */ +/* now, look for another renderer that supports the same */ +/* format */ + renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, + &node ); + update = TRUE; + } +/* if we changed the current renderer for the glyph image format */ +/* we need to select it as the next current one */ + if ( !error && update && renderer ) + FT_Set_Renderer( library, renderer, 0, 0 ); + return error; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_Bitmap( FT_Library library, + FT_Outline* outline, + const FT_Bitmap *abitmap ) + { + FT_Raster_Params params; + if ( !abitmap ) + return FT_Err_Invalid_Argument; +/* other checks are delayed to FT_Outline_Render() */ + params.target = abitmap; + params.flags = 0; + if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD || + abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) + params.flags |= FT_RASTER_FLAG_AA; + return FT_Outline_Render( library, outline, ¶ms ); + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( void ) + FT_Vector_Transform( FT_Vector* vector, + const FT_Matrix* matrix ) + { + FT_Pos xz, yz; + if ( !vector || !matrix ) + return; + xz = FT_MulFix( vector->x, matrix->xx ) + + FT_MulFix( vector->y, matrix->xy ); + yz = FT_MulFix( vector->x, matrix->yx ) + + FT_MulFix( vector->y, matrix->yy ); + vector->x = xz; + vector->y = yz; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( void ) + FT_Outline_Transform( const FT_Outline* outline, + const FT_Matrix* matrix ) + { + FT_Vector* vec; + FT_Vector* limit; + if ( !outline || !matrix ) + return; + vec = outline->points; + limit = vec + outline->n_points; + for ( ; vec < limit; vec++ ) + FT_Vector_Transform( vec, matrix ); + } +#if 0 +#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \ + do { \ + (first) = ( c > 0 ) ? (outline)->points + \ + (outline)->contours[c - 1] + 1 \ + : (outline)->points; \ + (last) = (outline)->points + (outline)->contours[c]; \ + } while ( 0 ) +/* Is a point in some contour? */ +/* */ +/* We treat every point of the contour as if it */ +/* it were ON. That is, we allow false positives, */ +/* but disallow false negatives. (XXX really?) */ + static FT_Bool + ft_contour_has( FT_Outline* outline, + FT_Short c, + FT_Vector* point ) + { + FT_Vector* first; + FT_Vector* last; + FT_Vector* a; + FT_Vector* b; + FT_UInt n = 0; + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + for ( a = first; a <= last; a++ ) + { + FT_Pos x; + FT_Int intersect; + b = ( a == last ) ? first : a + 1; + intersect = ( a->y - point->y ) ^ ( b->y - point->y ); +/* a and b are on the same side */ + if ( intersect >= 0 ) + { + if ( intersect == 0 && a->y == point->y ) + { + if ( ( a->x <= point->x && b->x >= point->x ) || + ( a->x >= point->x && b->x <= point->x ) ) + return 1; + } + continue; + } + x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y ); + if ( x < point->x ) + n++; + else if ( x == point->x ) + return 1; + } + return n & 1; + } + static FT_Bool + ft_contour_enclosed( FT_Outline* outline, + FT_UShort c ) + { + FT_Vector* first; + FT_Vector* last; + FT_Short i; + FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); + for ( i = 0; i < outline->n_contours; i++ ) + { + if ( i != c && ft_contour_has( outline, i, first ) ) + { + FT_Vector* pt; + for ( pt = first + 1; pt <= last; pt++ ) + if ( !ft_contour_has( outline, i, pt ) ) + return 0; + return 1; + } + } + return 0; + } +/* This version differs from the public one in that each */ +/* part (contour not enclosed in another contour) of the */ +/* outline is checked for orientation. This is */ +/* necessary for some buggy CJK fonts. */ + static FT_Orientation + ft_outline_get_orientation( FT_Outline* outline ) + { + FT_Short i; + FT_Vector* first; + FT_Vector* last; + FT_Orientation orient = FT_ORIENTATION_NONE; + first = outline->points; + for ( i = 0; i < outline->n_contours; i++, first = last + 1 ) + { + FT_Vector* point; + FT_Vector* xmin_point; + FT_Pos xmin; + last = outline->points + outline->contours[i]; +/* skip degenerate contours */ + if ( last < first + 2 ) + continue; + if ( ft_contour_enclosed( outline, i ) ) + continue; + xmin = first->x; + xmin_point = first; + for ( point = first + 1; point <= last; point++ ) + { + if ( point->x < xmin ) + { + xmin = point->x; + xmin_point = point; + } + } +/* check the orientation of the contour */ + { + FT_Vector* prev; + FT_Vector* next; + FT_Orientation o; + prev = ( xmin_point == first ) ? last : xmin_point - 1; + next = ( xmin_point == last ) ? first : xmin_point + 1; + if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) > + FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) ) + o = FT_ORIENTATION_POSTSCRIPT; + else + o = FT_ORIENTATION_TRUETYPE; + if ( orient == FT_ORIENTATION_NONE ) + orient = o; + else if ( orient != o ) + return FT_ORIENTATION_NONE; + } + } + return orient; + } +/* 0 */ +#endif +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Embolden( FT_Outline* outline, + FT_Pos strength ) + { + return FT_Outline_EmboldenXY( outline, strength, strength ); + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_EmboldenXY( FT_Outline* outline, + FT_Pos xstrength, + FT_Pos ystrength ) + { + FT_Vector* points; + FT_Vector v_prev, v_first, v_next, v_cur; + FT_Int c, n, first; + FT_Int orientation; + if ( !outline ) + return FT_Err_Invalid_Argument; + xstrength /= 2; + ystrength /= 2; + if ( xstrength == 0 && ystrength == 0 ) + return FT_Err_Ok; + orientation = FT_Outline_Get_Orientation( outline ); + if ( orientation == FT_ORIENTATION_NONE ) + { + if ( outline->n_contours ) + return FT_Err_Invalid_Argument; + else + return FT_Err_Ok; + } + points = outline->points; + first = 0; + for ( c = 0; c < outline->n_contours; c++ ) + { + FT_Vector in, out, shift; + FT_Fixed l_in, l_out, l, q, d; + int last = outline->contours[c]; + v_first = points[first]; + v_prev = points[last]; + v_cur = v_first; +/* compute the incoming vector and its length */ + in.x = v_cur.x - v_prev.x; + in.y = v_cur.y - v_prev.y; + l_in = FT_Vector_Length( &in ); + for ( n = first; n <= last; n++ ) + { + if ( n < last ) + v_next = points[n + 1]; + else + v_next = v_first; +/* compute the outgoing vector and its length */ + out.x = v_next.x - v_cur.x; + out.y = v_next.y - v_cur.y; + l_out = FT_Vector_Length( &out ); + d = l_in * l_out + in.x * out.x + in.y * out.y; +/* shift only if turn is less then ~160 degrees */ + if ( 16 * d > l_in * l_out ) + { +/* shift components are aligned along bisector */ +/* and directed according to the outline orientation. */ + shift.x = l_out * in.y + l_in * out.y; + shift.y = l_out * in.x + l_in * out.x; + if ( orientation == FT_ORIENTATION_TRUETYPE ) + shift.x = -shift.x; + else + shift.y = -shift.y; +/* threshold strength to better handle collapsing segments */ + l = FT_MIN( l_in, l_out ); + q = out.x * in.y - out.y * in.x; + if ( orientation == FT_ORIENTATION_TRUETYPE ) + q = -q; + if ( FT_MulDiv( xstrength, q, l ) < d ) + shift.x = FT_MulDiv( shift.x, xstrength, d ); + else + shift.x = FT_MulDiv( shift.x, l, q ); + if ( FT_MulDiv( ystrength, q, l ) < d ) + shift.y = FT_MulDiv( shift.y, ystrength, d ); + else + shift.y = FT_MulDiv( shift.y, l, q ); + } + else + shift.x = shift.y = 0; + outline->points[n].x = v_cur.x + xstrength + shift.x; + outline->points[n].y = v_cur.y + ystrength + shift.y; + in = out; + l_in = l_out; + v_cur = v_next; + } + first = last + 1; + } + return FT_Err_Ok; + } +/* documentation is in ftoutln.h */ + FT_EXPORT_DEF( FT_Orientation ) + FT_Outline_Get_Orientation( FT_Outline* outline ) + { + FT_Vector* points; + FT_Vector v_prev, v_cur; + FT_Int c, n, first; + FT_Pos area = 0; + if ( !outline || outline->n_points <= 0 ) + return FT_ORIENTATION_TRUETYPE; +/* We use the nonzero winding rule to find the orientation. */ +/* Since glyph outlines behave much more `regular' than arbitrary */ +/* cubic or quadratic curves, this test deals with the polygon */ +/* only which is spanned up by the control points. */ + points = outline->points; + first = 0; + for ( c = 0; c < outline->n_contours; c++ ) + { + FT_Int last = outline->contours[c]; + v_prev = points[last]; + for ( n = first; n <= last; n++ ) + { + v_cur = points[n]; + area += ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x ); + v_prev = v_cur; + } + first = last + 1; + } + if ( area > 0 ) + return FT_ORIENTATION_POSTSCRIPT; + else if ( area < 0 ) + return FT_ORIENTATION_TRUETYPE; + else + return FT_ORIENTATION_NONE; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftrfork.c */ +/* */ +/* Embedded resource forks accessor (body). */ +/* */ +/* Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */ +/* Masatake YAMATO and Redhat K.K. */ +/* */ +/* FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are */ +/* derived from ftobjs.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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* Development of the code in this file is support of */ +/* Information-technology Promotion Agency, Japan. */ +/***************************************************************************/ +#undef FT_COMPONENT +#define FT_COMPONENT trace_raccess +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** Resource fork directory access ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_HeaderInfo( FT_Library library, + FT_Stream stream, + FT_Long rfork_offset, + FT_Long *map_offset, + FT_Long *rdata_pos ) + { + FT_Error error; + unsigned char head[16], head2[16]; + FT_Long map_pos, rdata_len; + int allzeros, allmatch, i; + FT_Long type_list; + FT_UNUSED( library ); + error = FT_Stream_Seek( stream, rfork_offset ); + if ( error ) + return error; + error = FT_Stream_Read( stream, (FT_Byte *)head, 16 ); + if ( error ) + return error; + *rdata_pos = rfork_offset + ( ( head[0] << 24 ) | + ( head[1] << 16 ) | + ( head[2] << 8 ) | + head[3] ); + map_pos = rfork_offset + ( ( head[4] << 24 ) | + ( head[5] << 16 ) | + ( head[6] << 8 ) | + head[7] ); + rdata_len = ( head[ 8] << 24 ) | + ( head[ 9] << 16 ) | + ( head[10] << 8 ) | + head[11]; +/* map_len = head[12] .. head[15] */ + if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset ) + return FT_Err_Unknown_File_Format; + error = FT_Stream_Seek( stream, map_pos ); + if ( error ) + return error; +/* make it be different */ + head2[15] = (FT_Byte)( head[15] + 1 ); + error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); + if ( error ) + return error; + allzeros = 1; + allmatch = 1; + for ( i = 0; i < 16; ++i ) + { + if ( head2[i] != 0 ) + allzeros = 0; + if ( head2[i] != head[i] ) + allmatch = 0; + } + if ( !allzeros && !allmatch ) + return FT_Err_Unknown_File_Format; +/* If we have reached this point then it is probably a mac resource */ +/* file. Now, does it contain any interesting resources? */ +/* Skip handle to next resource map, the file resource number, and */ +/* attributes. */ +/* skip handle to next resource map */ + (void)FT_STREAM_SKIP( 4 +/* skip file resource number */ + + 2 +/* skip attributes */ + + 2 ); + if ( FT_READ_USHORT( type_list ) ) + return error; + if ( type_list == -1 ) + return FT_Err_Unknown_File_Format; + error = FT_Stream_Seek( stream, map_pos + type_list ); + if ( error ) + return error; + *map_offset = map_pos + type_list; + return FT_Err_Ok; + } + static int + ft_raccess_sort_ref_by_id( FT_RFork_Ref* a, + FT_RFork_Ref* b ) + { + if ( a->res_id < b->res_id ) + return -1; + else if ( a->res_id > b->res_id ) + return 1; + else + return 0; + } + FT_BASE_DEF( FT_Error ) + FT_Raccess_Get_DataOffsets( FT_Library library, + FT_Stream stream, + FT_Long map_offset, + FT_Long rdata_pos, + FT_Long tag, + FT_Long **offsets, + FT_Long *count ) + { + FT_Error error; + int i, j, cnt, subcnt; + FT_Long tag_internal, rpos; + FT_Memory memory = library->memory; + FT_Long temp; + FT_Long *offsets_internal = NULL; + FT_RFork_Ref *ref = NULL; + error = FT_Stream_Seek( stream, map_offset ); + if ( error ) + return error; + if ( FT_READ_USHORT( cnt ) ) + return error; + cnt++; + for ( i = 0; i < cnt; ++i ) + { + if ( FT_READ_LONG( tag_internal ) || + FT_READ_USHORT( subcnt ) || + FT_READ_USHORT( rpos ) ) + return error; + FT_TRACE2(( "Resource tags: %c%c%c%c\n", + (char)( 0xff & ( tag_internal >> 24 ) ), + (char)( 0xff & ( tag_internal >> 16 ) ), + (char)( 0xff & ( tag_internal >> 8 ) ), + (char)( 0xff & ( tag_internal >> 0 ) ) )); + if ( tag_internal == tag ) + { + *count = subcnt + 1; + rpos += map_offset; + error = FT_Stream_Seek( stream, rpos ); + if ( error ) + return error; + if ( FT_NEW_ARRAY( ref, *count ) ) + return error; + for ( j = 0; j < *count; ++j ) + { + if ( FT_READ_USHORT( ref[j].res_id ) ) + goto Exit; +/* resource name */ + if ( FT_STREAM_SKIP( 2 ) ) + goto Exit; + if ( FT_READ_LONG( temp ) ) + goto Exit; +/* mbz */ + if ( FT_STREAM_SKIP( 4 ) ) + goto Exit; + ref[j].offset = temp & 0xFFFFFFL; + } + ft_qsort( ref, *count, sizeof ( FT_RFork_Ref ), + ( int(*)(const void*, const void*) ) + ft_raccess_sort_ref_by_id ); + if ( FT_NEW_ARRAY( offsets_internal, *count ) ) + goto Exit; +/* XXX: duplicated reference ID, + * gap between reference IDs are acceptable? + * further investigation on Apple implementation is needed. + */ + for ( j = 0; j < *count; ++j ) + offsets_internal[j] = rdata_pos + ref[j].offset; + *offsets = offsets_internal; + error = FT_Err_Ok; + Exit: + FT_FREE( ref ); + return error; + } + } + return FT_Err_Cannot_Open_Resource; + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** Guessing functions ****/ +/**** ****/ +/**** When you add a new guessing function, ****/ +/**** update FT_RACCESS_N_RULES in ftrfork.h. ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_darwin_newvfs( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ); + CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table, + ft_raccess_guess_rec) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double, apple_double) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single, apple_single) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export, darwin_ufs_export) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs, darwin_newvfs) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus, darwin_hfsplus) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat, vfat) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap, linux_cap) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double, linux_double) + CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk, linux_netatalk) + CONST_FT_RFORK_RULE_ARRAY_END +/*************************************************************************/ +/**** ****/ +/**** Helper functions ****/ +/**** ****/ +/*************************************************************************/ + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char *base_file_name, + FT_Int32 magic, + FT_Long *result_offset ); + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char * file_name, + FT_Long *result_offset ); + static char * + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ); + FT_BASE_DEF( void ) + FT_Raccess_Guess( FT_Library library, + FT_Stream stream, + char* base_name, + char **new_names, + FT_Long *offsets, + FT_Error *errors ) + { + FT_Int i; + for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) + { + new_names[i] = NULL; + if ( NULL != stream ) + errors[i] = FT_Stream_Seek( stream, 0 ); + else + errors[i] = FT_Err_Ok; + if ( errors[i] ) + continue ; + errors[i] = (FT_RACCESS_GUESS_TABLE_GET[i].func)( library, + stream, base_name, + &(new_names[i]), + &(offsets[i]) ); + } + return; + } +#ifndef FT_MACINTOSH + static FT_RFork_Rule + raccess_get_rule_type_from_rule_index( FT_Library library, + FT_UInt rule_index ) + { + FT_UNUSED( library ); + if ( rule_index >= FT_RACCESS_N_RULES ) + return FT_RFork_Rule_invalid; + return FT_RACCESS_GUESS_TABLE_GET[rule_index].type; + } +/* + * For this function, refer ftbase.h. + */ + FT_LOCAL_DEF( FT_Bool ) + ft_raccess_rule_by_darwin_vfs( FT_Library library, + FT_UInt rule_index ) + { + switch( raccess_get_rule_type_from_rule_index( library, rule_index ) ) + { + case FT_RFork_Rule_darwin_newvfs: + case FT_RFork_Rule_darwin_hfsplus: + return TRUE; + default: + return FALSE; + } + } +#endif + static FT_Error + raccess_guess_apple_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 ) | + ( 0x05 << 16 ) | + ( 0x16 << 8 ) | + 0x07; + *result_file_name = NULL; + if ( NULL == stream ) + return FT_Err_Cannot_Open_Stream; + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + static FT_Error + raccess_guess_apple_single( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + FT_Int32 magic = ( 0x00 << 24 ) | + ( 0x05 << 16 ) | + ( 0x16 << 8 ) | + 0x00; + *result_file_name = NULL; + if ( NULL == stream ) + return FT_Err_Cannot_Open_Stream; + return raccess_guess_apple_generic( library, stream, base_file_name, + magic, result_offset ); + } + static FT_Error + raccess_guess_darwin_ufs_export( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + FT_UNUSED( stream ); + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, "._" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + return error; + } + static FT_Error + raccess_guess_darwin_hfsplus( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { +/* + Only meaningful on systems with hfs+ drivers (or Macs). + */ + FT_Error error; + char* newpath = NULL; + FT_Memory memory; + FT_Long base_file_len = ft_strlen( base_file_name ); + FT_UNUSED( stream ); + memory = library->memory; + if ( base_file_len + 6 > FT_INT_MAX ) + return FT_Err_Array_Too_Large; + if ( FT_ALLOC( newpath, base_file_len + 6 ) ) + return error; + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); + *result_file_name = newpath; + *result_offset = 0; + return FT_Err_Ok; + } + static FT_Error + raccess_guess_darwin_newvfs( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { +/* + Only meaningful on systems with Mac OS X (> 10.1). + */ + FT_Error error; + char* newpath = NULL; + FT_Memory memory; + FT_Long base_file_len = ft_strlen( base_file_name ); + FT_UNUSED( stream ); + memory = library->memory; + if ( base_file_len + 18 > FT_INT_MAX ) + return FT_Err_Array_Too_Large; + if ( FT_ALLOC( newpath, base_file_len + 18 ) ) + return error; + FT_MEM_COPY( newpath, base_file_name, base_file_len ); + FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 ); + *result_file_name = newpath; + *result_offset = 0; + return FT_Err_Ok; + } + static FT_Error + raccess_guess_vfat( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + FT_UNUSED( stream ); + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, + "resource.frk/" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + *result_file_name = newpath; + *result_offset = 0; + return FT_Err_Ok; + } + static FT_Error + raccess_guess_linux_cap( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Memory memory; + FT_UNUSED( stream ); + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + *result_file_name = newpath; + *result_offset = 0; + return FT_Err_Ok; + } + static FT_Error + raccess_guess_linux_double( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + FT_UNUSED( stream ); + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, "%" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + return error; + } + static FT_Error + raccess_guess_linux_netatalk( FT_Library library, + FT_Stream stream, + char *base_file_name, + char **result_file_name, + FT_Long *result_offset ) + { + char* newpath; + FT_Error error; + FT_Memory memory; + FT_UNUSED( stream ); + memory = library->memory; + newpath = raccess_make_file_name( memory, base_file_name, + ".AppleDouble/" ); + if ( !newpath ) + return FT_Err_Out_Of_Memory; + error = raccess_guess_linux_double_from_file_name( library, newpath, + result_offset ); + if ( !error ) + *result_file_name = newpath; + else + FT_FREE( newpath ); + return error; + } + static FT_Error + raccess_guess_apple_generic( FT_Library library, + FT_Stream stream, + char *base_file_name, + FT_Int32 magic, + FT_Long *result_offset ) + { + FT_Int32 magic_from_stream; + FT_Error error; + FT_Int32 version_number = 0; + FT_UShort n_of_entries; + int i; + FT_UInt32 entry_id, entry_offset, entry_length = 0; + const FT_UInt32 resource_fork_entry_id = 0x2; + FT_UNUSED( library ); + FT_UNUSED( base_file_name ); + FT_UNUSED( version_number ); + FT_UNUSED( entry_length ); + if ( FT_READ_LONG( magic_from_stream ) ) + return error; + if ( magic_from_stream != magic ) + return FT_Err_Unknown_File_Format; + if ( FT_READ_LONG( version_number ) ) + return error; +/* filler */ + error = FT_Stream_Skip( stream, 16 ); + if ( error ) + return error; + if ( FT_READ_USHORT( n_of_entries ) ) + return error; + if ( n_of_entries == 0 ) + return FT_Err_Unknown_File_Format; + for ( i = 0; i < n_of_entries; i++ ) + { + if ( FT_READ_LONG( entry_id ) ) + return error; + if ( entry_id == resource_fork_entry_id ) + { + if ( FT_READ_LONG( entry_offset ) || + FT_READ_LONG( entry_length ) ) + continue; + *result_offset = entry_offset; + return FT_Err_Ok; + } + else + { +/* offset + length */ + error = FT_Stream_Skip( stream, 4 + 4 ); + if ( error ) + return error; + } + } + return FT_Err_Unknown_File_Format; + } + static FT_Error + raccess_guess_linux_double_from_file_name( FT_Library library, + char *file_name, + FT_Long *result_offset ) + { + FT_Open_Args args2; + FT_Stream stream2; + char * nouse = NULL; + FT_Error error; + args2.flags = FT_OPEN_PATHNAME; + args2.pathname = file_name; + error = FT_Stream_New( library, &args2, &stream2 ); + if ( error ) + return error; + error = raccess_guess_apple_double( library, stream2, file_name, + &nouse, result_offset ); + FT_Stream_Free( stream2, 0 ); + return error; + } + static char* + raccess_make_file_name( FT_Memory memory, + const char *original_name, + const char *insertion ) + { + char* new_name = NULL; + const char* tmp; + const char* slash; + size_t new_length; + FT_Error error = FT_Err_Ok; + FT_UNUSED( error ); + new_length = ft_strlen( original_name ) + ft_strlen( insertion ); + if ( FT_ALLOC( new_name, new_length + 1 ) ) + return NULL; + tmp = ft_strrchr( original_name, '/' ); + if ( tmp ) + { + ft_strncpy( new_name, original_name, tmp - original_name + 1 ); + new_name[tmp - original_name + 1] = '\0'; + slash = tmp + 1; + } + else + { + slash = original_name; + new_name[0] = '\0'; + } + ft_strcat( new_name, insertion ); + ft_strcat( new_name, slash ); + return new_name; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftsnames.c */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.) (body). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2001, 2002, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftsnames.h */ +/* */ +/* Simple interface to access SFNT name tables (which are used */ +/* to hold font names, copyright info, notices, etc.) (specification). */ +/* */ +/* This is _not_ used to retrieve glyph names! */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2009, 2010 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 __FT_SFNT_NAMES_H__ +#define __FT_SFNT_NAMES_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* sfnt_names */ +/* */ +/* <Title> */ +/* SFNT Names */ +/* */ +/* <Abstract> */ +/* Access the names embedded in TrueType and OpenType files. */ +/* */ +/* <Description> */ +/* The TrueType and OpenType specifications allow the inclusion of */ +/* a special `names table' in font files. This table contains */ +/* textual (and internationalized) information regarding the font, */ +/* like family name, copyright, version, etc. */ +/* */ +/* The definitions below are used to access them if available. */ +/* */ +/* Note that this has nothing to do with glyph names! */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_SfntName */ +/* */ +/* <Description> */ +/* A structure used to model an SFNT `name' table entry. */ +/* */ +/* <Fields> */ +/* platform_id :: The platform ID for `string'. */ +/* */ +/* encoding_id :: The encoding ID for `string'. */ +/* */ +/* language_id :: The language ID for `string'. */ +/* */ +/* name_id :: An identifier for `string'. */ +/* */ +/* string :: The `name' string. Note that its format differs */ +/* depending on the (platform,encoding) pair. It can */ +/* be a Pascal String, a UTF-16 one, etc. */ +/* */ +/* Generally speaking, the string is not */ +/* zero-terminated. Please refer to the TrueType */ +/* specification for details. */ +/* */ +/* string_len :: The length of `string' in bytes. */ +/* */ +/* <Note> */ +/* Possible values for `platform_id', `encoding_id', `language_id', */ +/* and `name_id' are given in the file `ttnameid.h'. For details */ +/* please refer to the TrueType or OpenType specification. */ +/* */ +/* See also @TT_PLATFORM_XXX, @TT_APPLE_ID_XXX, @TT_MAC_ID_XXX, */ +/* @TT_ISO_ID_XXX, and @TT_MS_ID_XXX. */ +/* */ + typedef struct FT_SfntName_ + { + FT_UShort platform_id; + FT_UShort encoding_id; + FT_UShort language_id; + FT_UShort name_id; +/* this string is *not* null-terminated! */ + FT_Byte* string; +/* in bytes */ + FT_UInt string_len; + } FT_SfntName; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Sfnt_Name_Count */ +/* */ +/* <Description> */ +/* Retrieve the number of name strings in the SFNT `name' table. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face. */ +/* */ +/* <Return> */ +/* The number of strings in the `name' table. */ +/* */ + FT_EXPORT( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_Sfnt_Name */ +/* */ +/* <Description> */ +/* Retrieve a string of the SFNT `name' table for a given index. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face. */ +/* */ +/* idx :: The index of the `name' string. */ +/* */ +/* <Output> */ +/* aname :: The indexed @FT_SfntName structure. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The `string' array returned in the `aname' structure is not */ +/* null-terminated. The application should deallocate it if it is no */ +/* longer in use. */ +/* */ +/* Use @FT_Get_Sfnt_Name_Count to get the total number of available */ +/* `name' table entries, then do a loop until you get the right */ +/* platform, encoding, and name ID. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ); +/*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY + * + * @description: + * A constant used as the tag of @FT_Parameter structures to make + * FT_Open_Face() ignore preferred family subfamily names in `name' + * table since OpenType version 1.4. For backwards compatibility with + * legacy systems which has 4-face-per-family restriction. + * + */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY FT_MAKE_TAG( 'i', 'g', 'p', 'f' ) +/*************************************************************************** + * + * @constant: + * FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY + * + * @description: + * A constant used as the tag of @FT_Parameter structures to make + * FT_Open_Face() ignore preferred subfamily names in `name' table since + * OpenType version 1.4. For backwards compatibility with legacy + * systems which has 4-face-per-family restriction. + * + */ +#define FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY FT_MAKE_TAG( 'i', 'g', 'p', 's' ) +/* */ +FT_END_HEADER +/* __FT_SFNT_NAMES_H__ */ +#endif +/* END */ +/* documentation is in ftsnames.h */ + FT_EXPORT_DEF( FT_UInt ) + FT_Get_Sfnt_Name_Count( FT_Face face ) + { + return ( face && FT_IS_SFNT( face ) ) ? ((TT_Face)face)->num_names : 0; + } +/* documentation is in ftsnames.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_Sfnt_Name( FT_Face face, + FT_UInt idx, + FT_SfntName *aname ) + { + FT_Error error = FT_Err_Invalid_Argument; + if ( aname && face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + if ( idx < (FT_UInt)ttface->num_names ) + { + TT_NameEntryRec* entry = ttface->name_table.names + idx; +/* load name on demand */ + if ( entry->stringLength > 0 && entry->string == NULL ) + { + FT_Memory memory = face->memory; + FT_Stream stream = face->stream; + if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) || + FT_STREAM_SEEK( entry->stringOffset ) || + FT_STREAM_READ( entry->string, entry->stringLength ) ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } + } + aname->platform_id = entry->platformID; + aname->encoding_id = entry->encodingID; + aname->language_id = entry->languageID; + aname->name_id = entry->nameID; + aname->string = (FT_Byte*)entry->string; + aname->string_len = entry->stringLength; + error = FT_Err_Ok; + } + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftstream.c */ +/* */ +/* I/O stream support (body). */ +/* */ +/* Copyright 2000-2002, 2004-2006, 2008-2011 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 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 trace_stream + FT_BASE_DEF( void ) + FT_Stream_OpenMemory( FT_Stream stream, + const FT_Byte* base, + FT_ULong size ) + { + stream->base = (FT_Byte*) base; + stream->size = size; + stream->pos = 0; + stream->cursor = 0; + stream->read = 0; + stream->close = 0; + } + FT_BASE_DEF( void ) + FT_Stream_Close( FT_Stream stream ) + { + if ( stream && stream->close ) + stream->close( stream ); + } + FT_BASE_DEF( FT_Error ) + FT_Stream_Seek( FT_Stream stream, + FT_ULong pos ) + { + FT_Error error = FT_Err_Ok; + if ( stream->read ) + { + if ( stream->read( stream, pos, 0, 0 ) ) + { + FT_ERROR(( "FT_Stream_Seek:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + error = FT_Err_Invalid_Stream_Operation; + } + } +/* note that seeking to the first position after the file is valid */ + else if ( pos > stream->size ) + { + FT_ERROR(( "FT_Stream_Seek:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + error = FT_Err_Invalid_Stream_Operation; + } + if ( !error ) + stream->pos = pos; + return error; + } + FT_BASE_DEF( FT_Error ) + FT_Stream_Skip( FT_Stream stream, + FT_Long distance ) + { + if ( distance < 0 ) + return FT_Err_Invalid_Stream_Operation; + return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) ); + } + FT_BASE_DEF( FT_Long ) + FT_Stream_Pos( FT_Stream stream ) + { + return stream->pos; + } + FT_BASE_DEF( FT_Error ) + FT_Stream_Read( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + return FT_Stream_ReadAt( stream, stream->pos, buffer, count ); + } + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadAt( FT_Stream stream, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; + if ( pos >= stream->size ) + { + FT_ERROR(( "FT_Stream_ReadAt:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + pos, stream->size )); + return FT_Err_Invalid_Stream_Operation; + } + if ( stream->read ) + read_bytes = stream->read( stream, pos, buffer, count ); + else + { + read_bytes = stream->size - pos; + if ( read_bytes > count ) + read_bytes = count; + FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); + } + stream->pos = pos + read_bytes; + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_ReadAt:" + " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + error = FT_Err_Invalid_Stream_Operation; + } + return error; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_TryRead( FT_Stream stream, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong read_bytes = 0; + if ( stream->pos >= stream->size ) + goto Exit; + if ( stream->read ) + read_bytes = stream->read( stream, stream->pos, buffer, count ); + else + { + read_bytes = stream->size - stream->pos; + if ( read_bytes > count ) + read_bytes = count; + FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); + } + stream->pos += read_bytes; + Exit: + return read_bytes; + } + FT_BASE_DEF( FT_Error ) + FT_Stream_ExtractFrame( FT_Stream stream, + FT_ULong count, + FT_Byte** pbytes ) + { + FT_Error error; + error = FT_Stream_EnterFrame( stream, count ); + if ( !error ) + { + *pbytes = (FT_Byte*)stream->cursor; +/* equivalent to FT_Stream_ExitFrame(), with no memory block release */ + stream->cursor = 0; + stream->limit = 0; + } + return error; + } + FT_BASE_DEF( void ) + FT_Stream_ReleaseFrame( FT_Stream stream, + FT_Byte** pbytes ) + { + if ( stream && stream->read ) + { + FT_Memory memory = stream->memory; + FT_FREE( *pbytes ); + } + *pbytes = 0; + } + FT_BASE_DEF( FT_Error ) + FT_Stream_EnterFrame( FT_Stream stream, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + FT_ULong read_bytes; +/* check for nested frame access */ + FT_ASSERT( stream && stream->cursor == 0 ); + if ( stream->read ) + { +/* allocate the frame in memory */ + FT_Memory memory = stream->memory; +/* simple sanity check */ + if ( count > stream->size ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " frame size (%lu) larger than stream size (%lu)\n", + count, stream->size )); + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + if ( FT_QALLOC( stream->base, count ) ) + goto Exit; +/* read it */ + read_bytes = stream->read( stream, stream->pos, + stream->base, count ); + if ( read_bytes < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " invalid read; expected %lu bytes, got %lu\n", + count, read_bytes )); + FT_FREE( stream->base ); + error = FT_Err_Invalid_Stream_Operation; + } + stream->cursor = stream->base; + stream->limit = stream->cursor + count; + stream->pos += read_bytes; + } + else + { +/* check current and new position */ + if ( stream->pos >= stream->size || + stream->size - stream->pos < count ) + { + FT_ERROR(( "FT_Stream_EnterFrame:" + " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", + stream->pos, count, stream->size )); + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } +/* set cursor */ + stream->cursor = stream->base + stream->pos; + stream->limit = stream->cursor + count; + stream->pos += count; + } + Exit: + return error; + } + FT_BASE_DEF( void ) + FT_Stream_ExitFrame( FT_Stream stream ) + { +/* IMPORTANT: The assertion stream->cursor != 0 was removed, given */ +/* that it is possible to access a frame of length 0 in */ +/* some weird fonts (usually, when accessing an array of */ +/* 0 records, like in some strange kern tables). */ +/* */ +/* In this case, the loader code handles the 0-length table */ +/* gracefully; however, stream.cursor is really set to 0 by the */ +/* FT_Stream_EnterFrame() call, and this is not an error. */ +/* */ + FT_ASSERT( stream ); + if ( stream->read ) + { + FT_Memory memory = stream->memory; + FT_FREE( stream->base ); + } + stream->cursor = 0; + stream->limit = 0; + } + FT_BASE_DEF( FT_Char ) + FT_Stream_GetChar( FT_Stream stream ) + { + FT_Char result; + FT_ASSERT( stream && stream->cursor ); + result = 0; + if ( stream->cursor < stream->limit ) + result = *stream->cursor++; + return result; + } + FT_BASE_DEF( FT_UShort ) + FT_Stream_GetUShort( FT_Stream stream ) + { + FT_Byte* p; + FT_Short result; + FT_ASSERT( stream && stream->cursor ); + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_USHORT( p ); + stream->cursor = p; + return result; + } + FT_BASE_DEF( FT_UShort ) + FT_Stream_GetUShortLE( FT_Stream stream ) + { + FT_Byte* p; + FT_Short result; + FT_ASSERT( stream && stream->cursor ); + result = 0; + p = stream->cursor; + if ( p + 1 < stream->limit ) + result = FT_NEXT_USHORT_LE( p ); + stream->cursor = p; + return result; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_GetUOffset( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + FT_ASSERT( stream && stream->cursor ); + result = 0; + p = stream->cursor; + if ( p + 2 < stream->limit ) + result = FT_NEXT_UOFF3( p ); + stream->cursor = p; + return result; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_GetULong( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + FT_ASSERT( stream && stream->cursor ); + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_ULONG( p ); + stream->cursor = p; + return result; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_GetULongLE( FT_Stream stream ) + { + FT_Byte* p; + FT_Long result; + FT_ASSERT( stream && stream->cursor ); + result = 0; + p = stream->cursor; + if ( p + 3 < stream->limit ) + result = FT_NEXT_ULONG_LE( p ); + stream->cursor = p; + return result; + } + FT_BASE_DEF( FT_Char ) + FT_Stream_ReadChar( FT_Stream stream, + FT_Error* error ) + { + FT_Byte result = 0; + FT_ASSERT( stream ); + *error = FT_Err_Ok; + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } + else + { + if ( stream->pos < stream->size ) + result = stream->base[stream->pos]; + else + goto Fail; + } + stream->pos++; + return result; + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadChar:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + return 0; + } + FT_BASE_DEF( FT_UShort ) + FT_Stream_ReadUShort( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p = 0; + FT_Short result = 0; + FT_ASSERT( stream ); + *error = FT_Err_Ok; + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + p = reads; + } + else + { + p = stream->base + stream->pos; + } + if ( p ) + result = FT_NEXT_USHORT( p ); + } + else + goto Fail; + stream->pos += 2; + return result; + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadUShort:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + return 0; + } + FT_BASE_DEF( FT_UShort ) + FT_Stream_ReadUShortLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[2]; + FT_Byte* p = 0; + FT_Short result = 0; + FT_ASSERT( stream ); + *error = FT_Err_Ok; + if ( stream->pos + 1 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 2L ) != 2L ) + goto Fail; + p = reads; + } + else + { + p = stream->base + stream->pos; + } + if ( p ) + result = FT_NEXT_USHORT_LE( p ); + } + else + goto Fail; + stream->pos += 2; + return result; + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadUShortLE:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + return 0; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_ReadUOffset( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[3]; + FT_Byte* p = 0; + FT_Long result = 0; + FT_ASSERT( stream ); + *error = FT_Err_Ok; + if ( stream->pos + 2 < stream->size ) + { + if ( stream->read ) + { + if (stream->read( stream, stream->pos, reads, 3L ) != 3L ) + goto Fail; + p = reads; + } + else + { + p = stream->base + stream->pos; + } + if ( p ) + result = FT_NEXT_UOFF3( p ); + } + else + goto Fail; + stream->pos += 3; + return result; + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadUOffset:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + return 0; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_ReadULong( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p = 0; + FT_Long result = 0; + FT_ASSERT( stream ); + *error = FT_Err_Ok; + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + p = reads; + } + else + { + p = stream->base + stream->pos; + } + if ( p ) + result = FT_NEXT_ULONG( p ); + } + else + goto Fail; + stream->pos += 4; + return result; + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadULong:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + return 0; + } + FT_BASE_DEF( FT_ULong ) + FT_Stream_ReadULongLE( FT_Stream stream, + FT_Error* error ) + { + FT_Byte reads[4]; + FT_Byte* p = 0; + FT_Long result = 0; + FT_ASSERT( stream ); + *error = FT_Err_Ok; + if ( stream->pos + 3 < stream->size ) + { + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, reads, 4L ) != 4L ) + goto Fail; + p = reads; + } + else + { + p = stream->base + stream->pos; + } + if ( p ) + result = FT_NEXT_ULONG_LE( p ); + } + else + goto Fail; + stream->pos += 4; + return result; + Fail: + *error = FT_Err_Invalid_Stream_Operation; + FT_ERROR(( "FT_Stream_ReadULongLE:" + " invalid i/o; pos = 0x%lx, size = 0x%lx\n", + stream->pos, stream->size )); + return 0; + } + FT_BASE_DEF( FT_Error ) + FT_Stream_ReadFields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ) + { + FT_Error error; + FT_Bool frame_accessed = 0; + FT_Byte* cursor; + if ( !fields || !stream ) + return FT_Err_Invalid_Argument; + cursor = stream->cursor; + error = FT_Err_Ok; + do + { + FT_ULong value; + FT_Int sign_shift; + FT_Byte* p; + switch ( fields->value ) + { +/* access a new frame */ + case ft_frame_start: + error = FT_Stream_EnterFrame( stream, fields->offset ); + if ( error ) + goto Exit; + frame_accessed = 1; + cursor = stream->cursor; + fields++; +/* loop! */ + continue; +/* read a byte sequence */ + case ft_frame_bytes: +/* skip some bytes */ + case ft_frame_skip: + { + FT_UInt len = fields->size; + if ( cursor + len > stream->limit ) + { + error = FT_Err_Invalid_Stream_Operation; + goto Exit; + } + if ( fields->value == ft_frame_bytes ) + { + p = (FT_Byte*)structure + fields->offset; + FT_MEM_COPY( p, cursor, len ); + } + cursor += len; + fields++; + continue; + } + case ft_frame_byte: +/* read a single byte */ + case ft_frame_schar: + value = FT_NEXT_BYTE(cursor); + sign_shift = 24; + break; + case ft_frame_short_be: +/* read a 2-byte big-endian short */ + case ft_frame_ushort_be: + value = FT_NEXT_USHORT(cursor); + sign_shift = 16; + break; + case ft_frame_short_le: +/* read a 2-byte little-endian short */ + case ft_frame_ushort_le: + value = FT_NEXT_USHORT_LE(cursor); + sign_shift = 16; + break; + case ft_frame_long_be: +/* read a 4-byte big-endian long */ + case ft_frame_ulong_be: + value = FT_NEXT_ULONG(cursor); + sign_shift = 0; + break; + case ft_frame_long_le: +/* read a 4-byte little-endian long */ + case ft_frame_ulong_le: + value = FT_NEXT_ULONG_LE(cursor); + sign_shift = 0; + break; + case ft_frame_off3_be: +/* read a 3-byte big-endian long */ + case ft_frame_uoff3_be: + value = FT_NEXT_UOFF3(cursor); + sign_shift = 8; + break; + case ft_frame_off3_le: +/* read a 3-byte little-endian long */ + case ft_frame_uoff3_le: + value = FT_NEXT_UOFF3_LE(cursor); + sign_shift = 8; + break; + default: +/* otherwise, exit the loop */ + stream->cursor = cursor; + goto Exit; + } +/* now, compute the signed value is necessary */ + if ( fields->value & FT_FRAME_OP_SIGNED ) + value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); +/* finally, store the value in the object */ + p = (FT_Byte*)structure + fields->offset; + switch ( fields->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)p = (FT_Byte)value; + break; + case (16 / FT_CHAR_BIT): + *(FT_UShort*)p = (FT_UShort)value; + break; + case (32 / FT_CHAR_BIT): + *(FT_UInt32*)p = (FT_UInt32)value; + break; +/* for 64-bit systems */ + default: + *(FT_ULong*)p = (FT_ULong)value; + } +/* go to next field */ + fields++; + } + while ( 1 ); + Exit: +/* close the frame if it was opened by this read */ + if ( frame_accessed ) + FT_Stream_ExitFrame( stream ); + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* fttrigon.c */ +/* */ +/* FreeType trigonometric functions (body). */ +/* */ +/* Copyright 2001-2005, 2012 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. */ +/* */ +/***************************************************************************/ +#ifdef FT_LONG64 + typedef FT_INT64 FT_Int64; +#endif +/* the Cordic shrink factor 0.607252935008887 * 2^32 */ +#define FT_TRIG_SCALE 0x9B74EDA8UL +/* the following is 0.607252935008887 * 2^30 */ +#define FT_TRIG_COSCALE 0x26DD3B6AUL +/* this table was generated for FT_PI = 180L << 16, i.e. degrees */ +#define FT_TRIG_MAX_ITERS 23 + static const FT_Fixed + ft_trig_arctan_table[23] = + { + 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, + 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, + 57L, 29L, 14L, 7L, 4L, 2L, 1L + }; +#ifdef FT_LONG64 +/* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Fixed s; + FT_Int64 v; + s = val; + val = ( val >= 0 ) ? val : -val; + v = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL; + val = (FT_Fixed)( v >> 32 ); + return ( s >= 0 ) ? val : -val; + } +/* !FT_LONG64 */ +#else +/* multiply a given value by the CORDIC shrink factor */ + static FT_Fixed + ft_trig_downscale( FT_Fixed val ) + { + FT_Fixed s; + FT_UInt32 v1, v2, k1, k2, hi, lo1, lo2, lo3; + s = val; + val = ( val >= 0 ) ? val : -val; + v1 = (FT_UInt32)val >> 16; + v2 = (FT_UInt32)( val & 0xFFFFL ); +/* constant */ + k1 = (FT_UInt32)FT_TRIG_SCALE >> 16; +/* constant */ + k2 = (FT_UInt32)( FT_TRIG_SCALE & 0xFFFFL ); + hi = k1 * v1; +/* can't overflow */ + lo1 = k1 * v2 + k2 * v1; + lo2 = ( k2 * v2 ) >> 16; + lo3 = ( lo1 >= lo2 ) ? lo1 : lo2; + lo1 += lo2; + hi += lo1 >> 16; + if ( lo1 < lo3 ) + hi += (FT_UInt32)0x10000UL; + val = (FT_Fixed)hi; + return ( s >= 0 ) ? val : -val; + } +/* !FT_LONG64 */ +#endif + static FT_Int + ft_trig_prenorm( FT_Vector* vec ) + { + FT_Fixed x, y, z; + FT_Int shift; + x = vec->x; + y = vec->y; + z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y ); + shift = 0; +#if 1 +/* determine msb bit index in `shift' */ + if ( z >= ( 1L << 16 ) ) + { + z >>= 16; + shift += 16; + } + if ( z >= ( 1L << 8 ) ) + { + z >>= 8; + shift += 8; + } + if ( z >= ( 1L << 4 ) ) + { + z >>= 4; + shift += 4; + } + if ( z >= ( 1L << 2 ) ) + { + z >>= 2; + shift += 2; + } + if ( z >= ( 1L << 1 ) ) + { + z >>= 1; + shift += 1; + } + if ( shift <= 27 ) + { + shift = 27 - shift; + vec->x = x << shift; + vec->y = y << shift; + } + else + { + shift -= 27; + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } +/* 0 */ +#else + if ( z < ( 1L << 27 ) ) + { + do + { + shift++; + z <<= 1; + } while ( z < ( 1L << 27 ) ); + vec->x = x << shift; + vec->y = y << shift; + } + else if ( z > ( 1L << 28 ) ) + { + do + { + shift++; + z >>= 1; + } while ( z > ( 1L << 28 ) ); + vec->x = x >> shift; + vec->y = y >> shift; + shift = -shift; + } +/* 0 */ +#endif + return shift; + } + static void + ft_trig_pseudo_rotate( FT_Vector* vec, + FT_Angle theta ) + { + FT_Int i; + FT_Fixed x, y, xtemp; + const FT_Fixed *arctanptr; + x = vec->x; + y = vec->y; +/* Get angle between -90 and 90 degrees */ + while ( theta <= -FT_ANGLE_PI2 ) + { + x = -x; + y = -y; + theta += FT_ANGLE_PI; + } + while ( theta > FT_ANGLE_PI2 ) + { + x = -x; + y = -y; + theta -= FT_ANGLE_PI; + } + arctanptr = ft_trig_arctan_table; +/* Pseudorotations, with right shifts */ + i = 0; + do + { + if ( theta < 0 ) + { + xtemp = x + ( y >> i ); + y = y - ( x >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( y >> i ); + y = y + ( x >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } while ( ++i < FT_TRIG_MAX_ITERS ); + vec->x = x; + vec->y = y; + } + static void + ft_trig_pseudo_polarize( FT_Vector* vec ) + { + FT_Angle theta; + FT_Int i; + FT_Fixed x, y, xtemp; + const FT_Fixed *arctanptr; + x = vec->x; + y = vec->y; +/* Get the vector into the right half plane */ + theta = 0; + if ( x < 0 ) + { + x = -x; + y = -y; + theta = 2 * FT_ANGLE_PI2; + } + if ( y > 0 ) + theta = - theta; + arctanptr = ft_trig_arctan_table; +/* Pseudorotations, with right shifts */ + i = 0; + do + { + if ( y > 0 ) + { + xtemp = x + ( y >> i ); + y = y - ( x >> i ); + x = xtemp; + theta += *arctanptr++; + } + else + { + xtemp = x - ( y >> i ); + y = y + ( x >> i ); + x = xtemp; + theta -= *arctanptr++; + } + } while ( ++i < FT_TRIG_MAX_ITERS ); +/* round theta */ + if ( theta >= 0 ) + theta = FT_PAD_ROUND( theta, 32 ); + else + theta = -FT_PAD_ROUND( -theta, 32 ); + vec->x = x; + vec->y = theta; + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_Cos( FT_Angle angle ) + { + FT_Vector v; + v.x = FT_TRIG_COSCALE >> 2; + v.y = 0; + ft_trig_pseudo_rotate( &v, angle ); + return v.x / ( 1 << 12 ); + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_Sin( FT_Angle angle ) + { + return FT_Cos( FT_ANGLE_PI2 - angle ); + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_Tan( FT_Angle angle ) + { + FT_Vector v; + v.x = FT_TRIG_COSCALE >> 2; + v.y = 0; + ft_trig_pseudo_rotate( &v, angle ); + return FT_DivFix( v.y, v.x ); + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( FT_Angle ) + FT_Atan2( FT_Fixed dx, + FT_Fixed dy ) + { + FT_Vector v; + if ( dx == 0 && dy == 0 ) + return 0; + v.x = dx; + v.y = dy; + ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + return v.y; + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( void ) + FT_Vector_Unit( FT_Vector* vec, + FT_Angle angle ) + { + vec->x = FT_TRIG_COSCALE >> 2; + vec->y = 0; + ft_trig_pseudo_rotate( vec, angle ); + vec->x >>= 12; + vec->y >>= 12; + } +/* these macros return 0 for positive numbers, + and -1 for negative ones */ +#define FT_SIGN_LONG( x ) ( (x) >> ( FT_SIZEOF_LONG * 8 - 1 ) ) +#define FT_SIGN_INT( x ) ( (x) >> ( FT_SIZEOF_INT * 8 - 1 ) ) +#define FT_SIGN_INT32( x ) ( (x) >> 31 ) +#define FT_SIGN_INT16( x ) ( (x) >> 15 ) +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( void ) + FT_Vector_Rotate( FT_Vector* vec, + FT_Angle angle ) + { + FT_Int shift; + FT_Vector v; + v.x = vec->x; + v.y = vec->y; + if ( angle && ( v.x != 0 || v.y != 0 ) ) + { + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_rotate( &v, angle ); + v.x = ft_trig_downscale( v.x ); + v.y = ft_trig_downscale( v.y ); + if ( shift > 0 ) + { + FT_Int32 half = (FT_Int32)1L << ( shift - 1 ); + vec->x = ( v.x + half + FT_SIGN_LONG( v.x ) ) >> shift; + vec->y = ( v.y + half + FT_SIGN_LONG( v.y ) ) >> shift; + } + else + { + shift = -shift; + vec->x = v.x << shift; + vec->y = v.y << shift; + } + } + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( FT_Fixed ) + FT_Vector_Length( FT_Vector* vec ) + { + FT_Int shift; + FT_Vector v; + v = *vec; +/* handle trivial cases */ + if ( v.x == 0 ) + { + return ( v.y >= 0 ) ? v.y : -v.y; + } + else if ( v.y == 0 ) + { + return ( v.x >= 0 ) ? v.x : -v.x; + } +/* general case */ + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + v.x = ft_trig_downscale( v.x ); + if ( shift > 0 ) + return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift; + return v.x << -shift; + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( void ) + FT_Vector_Polarize( FT_Vector* vec, + FT_Fixed *length, + FT_Angle *angle ) + { + FT_Int shift; + FT_Vector v; + v = *vec; + if ( v.x == 0 && v.y == 0 ) + return; + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_polarize( &v ); + v.x = ft_trig_downscale( v.x ); + *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift ); + *angle = v.y; + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( void ) + FT_Vector_From_Polar( FT_Vector* vec, + FT_Fixed length, + FT_Angle angle ) + { + vec->x = length; + vec->y = 0; + FT_Vector_Rotate( vec, angle ); + } +/* documentation is in fttrigon.h */ + FT_EXPORT_DEF( FT_Angle ) + FT_Angle_Diff( FT_Angle angle1, + FT_Angle angle2 ) + { + FT_Angle delta = angle2 - angle1; + delta %= FT_ANGLE_2PI; + if ( delta < 0 ) + delta += FT_ANGLE_2PI; + if ( delta > FT_ANGLE_PI ) + delta -= FT_ANGLE_2PI; + return delta; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftutil.c */ +/* */ +/* FreeType utility file for memory and list management (body). */ +/* */ +/* Copyright 2002, 2004, 2005, 2006, 2007 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 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 trace_memory +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** *****/ +/***** M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + FT_BASE_DEF( FT_Pointer ) + ft_mem_alloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer block = ft_mem_qalloc( memory, size, &error ); + if ( !error && size > 0 ) + FT_MEM_ZERO( block, size ); + *p_error = error; + return block; + } + FT_BASE_DEF( FT_Pointer ) + ft_mem_qalloc( FT_Memory memory, + FT_Long size, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + FT_Pointer block = NULL; + if ( size > 0 ) + { + block = memory->alloc( memory, size ); + if ( block == NULL ) + error = FT_Err_Out_Of_Memory; + } + else if ( size < 0 ) + { +/* may help catch/prevent security issues */ + error = FT_Err_Invalid_Argument; + } + *p_error = error; + return block; + } + FT_BASE_DEF( FT_Pointer ) + ft_mem_realloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; + block = ft_mem_qrealloc( memory, item_size, + cur_count, new_count, block, &error ); + if ( !error && new_count > cur_count ) + FT_MEM_ZERO( (char*)block + cur_count * item_size, + ( new_count - cur_count ) * item_size ); + *p_error = error; + return block; + } + FT_BASE_DEF( FT_Pointer ) + ft_mem_qrealloc( FT_Memory memory, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, + void* block, + FT_Error *p_error ) + { + FT_Error error = FT_Err_Ok; +/* Note that we now accept `item_size == 0' as a valid parameter, in + * order to cover very weird cases where an ALLOC_MULT macro would be + * called. + */ + if ( cur_count < 0 || new_count < 0 || item_size < 0 ) + { +/* may help catch/prevent nasty security issues */ + error = FT_Err_Invalid_Argument; + } + else if ( new_count == 0 || item_size == 0 ) + { + ft_mem_free( memory, block ); + block = NULL; + } + else if ( new_count > FT_INT_MAX/item_size ) + { + error = FT_Err_Array_Too_Large; + } + else if ( cur_count == 0 ) + { + FT_ASSERT( block == NULL ); + block = ft_mem_alloc( memory, new_count*item_size, &error ); + } + else + { + FT_Pointer block2; + FT_Long cur_size = cur_count*item_size; + FT_Long new_size = new_count*item_size; + block2 = memory->realloc( memory, cur_size, new_size, block ); + if ( block2 == NULL ) + error = FT_Err_Out_Of_Memory; + else + block = block2; + } + *p_error = error; + return block; + } + FT_BASE_DEF( void ) + ft_mem_free( FT_Memory memory, + const void *P ) + { + if ( P ) + memory->free( memory, (void*)P ); + } + FT_BASE_DEF( FT_Pointer ) + ft_mem_dup( FT_Memory memory, + const void* address, + FT_ULong size, + FT_Error *p_error ) + { + FT_Error error; + FT_Pointer p = ft_mem_qalloc( memory, size, &error ); + if ( !error && address ) + ft_memcpy( p, address, size ); + *p_error = error; + return p; + } + FT_BASE_DEF( FT_Pointer ) + ft_mem_strdup( FT_Memory memory, + const char* str, + FT_Error *p_error ) + { + FT_ULong len = str ? (FT_ULong)ft_strlen( str ) + 1 + : 0; + return ft_mem_dup( memory, str, len, p_error ); + } + FT_BASE_DEF( FT_Int ) + ft_mem_strcpyn( char* dst, + const char* src, + FT_ULong size ) + { + while ( size > 1 && *src != 0 ) + { + *dst++ = *src++; + size--; + } +/* always zero-terminate */ + *dst = 0; + return *src != 0; + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** *****/ +/***** D O U B L Y L I N K E D L I S T S *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +#undef FT_COMPONENT +#define FT_COMPONENT trace_list +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( FT_ListNode ) + FT_List_Find( FT_List list, + void* data ) + { + FT_ListNode cur; + cur = list->head; + while ( cur ) + { + if ( cur->data == data ) + return cur; + cur = cur->next; + } + return (FT_ListNode)0; + } +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( void ) + FT_List_Add( FT_List list, + FT_ListNode node ) + { + FT_ListNode before = list->tail; + node->next = 0; + node->prev = before; + if ( before ) + before->next = node; + else + list->head = node; + list->tail = node; + } +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( void ) + FT_List_Insert( FT_List list, + FT_ListNode node ) + { + FT_ListNode after = list->head; + node->next = after; + node->prev = 0; + if ( !after ) + list->tail = node; + else + after->prev = node; + list->head = node; + } +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( void ) + FT_List_Remove( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + before = node->prev; + after = node->next; + if ( before ) + before->next = after; + else + list->head = after; + if ( after ) + after->prev = before; + else + list->tail = before; + } +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( void ) + FT_List_Up( FT_List list, + FT_ListNode node ) + { + FT_ListNode before, after; + before = node->prev; + after = node->next; +/* check whether we are already on top of the list */ + if ( !before ) + return; + before->next = after; + if ( after ) + after->prev = before; + else + list->tail = before; + node->prev = 0; + node->next = list->head; + list->head->prev = node; + list->head = node; + } +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( FT_Error ) + FT_List_Iterate( FT_List list, + FT_List_Iterator iterator, + void* user ) + { + FT_ListNode cur = list->head; + FT_Error error = FT_Err_Ok; + while ( cur ) + { + FT_ListNode next = cur->next; + error = iterator( cur, user ); + if ( error ) + break; + cur = next; + } + return error; + } +/* documentation is in ftlist.h */ + FT_EXPORT_DEF( void ) + FT_List_Finalize( FT_List list, + FT_List_Destructor destroy, + FT_Memory memory, + void* user ) + { + FT_ListNode cur; + cur = list->head; + while ( cur ) + { + FT_ListNode next = cur->next; + void* data = cur->data; + if ( destroy ) + destroy( memory, data, user ); + FT_FREE( cur ); + cur = next; + } + list->head = 0; + list->tail = 0; + } + FT_BASE_DEF( FT_UInt32 ) + ft_highpow2( FT_UInt32 value ) + { + FT_UInt32 value2; +/* + * We simply clear the lowest bit in each iteration. When + * we reach 0, we know that the previous value was our result. + */ + for ( ;; ) + { +/* clear lowest bit */ + value2 = value & (value - 1); + if ( value2 == 0 ) + break; + value = value2; + } + return value; + } +/* END */ +#ifdef FT_MACINTOSH +/***************************************************************************/ +/* */ +/* ftmac.c */ +/* */ +/* Mac FOND support. Written by just@letterror.com. */ +/* Heavily modified by mpsuzuki, George Williams, and Sean McBride. */ +/* */ +/* This file is for Mac OS X only; see builds/mac/ftoldmac.c for */ +/* classic platforms built by MPW. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, */ +/* 2009 by */ +/* Just van Rossum, 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. */ +/* */ +/***************************************************************************/ +/* + Notes + + Mac suitcase files can (and often do!) contain multiple fonts. To + support this I use the face_index argument of FT_(Open|New)_Face() + functions, and pretend the suitcase file is a collection. + + Warning: fbit and NFNT bitmap resources are not supported yet. In old + sfnt fonts, bitmap glyph data for each size is stored in each `NFNT' + resources instead of the `bdat' table in the sfnt resource. Therefore, + face->num_fixed_sizes is set to 0, because bitmap data in `NFNT' + resource is unavailable at present. + + The Mac FOND support works roughly like this: + + - Check whether the offered stream points to a Mac suitcase file. This + is done by checking the file type: it has to be 'FFIL' or 'tfil'. The + stream that gets passed to our init_face() routine is a stdio stream, + which isn't usable for us, since the FOND resources live in the + resource fork. So we just grab the stream->pathname field. + + - Read the FOND resource into memory, then check whether there is a + TrueType font and/or(!) a Type 1 font available. + + - If there is a Type 1 font available (as a separate `LWFN' file), read + its data into memory, massage it slightly so it becomes PFB data, wrap + it into a memory stream, load the Type 1 driver and delegate the rest + of the work to it by calling FT_Open_Face(). (XXX TODO: after this + has been done, the kerning data from the FOND resource should be + appended to the face: On the Mac there are usually no AFM files + available. However, this is tricky since we need to map Mac char + codes to ps glyph names to glyph ID's...) + + - If there is a TrueType font (an `sfnt' resource), read it into memory, + wrap it into a memory stream, load the TrueType driver and delegate + the rest of the work to it, by calling FT_Open_Face(). + + - Some suitcase fonts (notably Onyx) might point the `LWFN' file to + itself, even though it doesn't contains `POST' resources. To handle + this special case without opening the file an extra time, we just + ignore errors from the `LWFN' and fallback to the `sfnt' if both are + available. + */ +/* This is for Mac OS X. Without redefinition, OS_INLINE */ +/* expands to `static inline' which doesn't survive the */ +/* -ansi compilation flag of GCC. */ +#if !HAVE_ANSI_OS_INLINE +#undef OS_INLINE +#define OS_INLINE static __inline__ +#endif +/* `configure' checks the availability of `ResourceIndex' strictly */ +/* and sets HAVE_TYPE_RESOURCE_INDEX 1 or 0 always. If it is */ +/* not set (e.g., a build without `configure'), the availability */ +/* is guessed from the SDK version. */ +#ifndef HAVE_TYPE_RESOURCE_INDEX +#if !defined( MAC_OS_X_VERSION_10_5 ) || \ + ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 ) +#define HAVE_TYPE_RESOURCE_INDEX 0 +#else +#define HAVE_TYPE_RESOURCE_INDEX 1 +#endif +/* !HAVE_TYPE_RESOURCE_INDEX */ +#endif +#if ( HAVE_TYPE_RESOURCE_INDEX == 0 ) + typedef short ResourceIndex; +#endif +#include <CoreServices/CoreServices.h> +#include <ApplicationServices/ApplicationServices.h> +/* PATH_MAX */ +#include <sys/syslimits.h> +/* Don't want warnings about our own use of deprecated functions. */ +#define FT_DEPRECATED_ATTRIBUTE +/***************************************************************************/ +/* */ +/* ftmac.h */ +/* */ +/* Additional Mac-specific API. */ +/* */ +/* Copyright 1996-2001, 2004, 2006, 2007 by */ +/* Just van Rossum, 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* NOTE: Include this file after <freetype/freetype.h> and after any */ +/* Mac-specific headers (because this header uses Mac types such as */ +/* Handle, FSSpec, FSRef, etc.) */ +/* */ +/***************************************************************************/ +#define __FTMAC_H__ +FT_BEGIN_HEADER +/* gcc-3.4.1 and later can warn about functions tagged as deprecated */ +#ifndef FT_DEPRECATED_ATTRIBUTE +#if defined(__GNUC__) && \ + ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) +#define FT_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#else +#define FT_DEPRECATED_ATTRIBUTE +#endif +#endif +/*************************************************************************/ +/* */ +/* <Section> */ +/* mac_specific */ +/* */ +/* <Title> */ +/* Mac Specific Interface */ +/* */ +/* <Abstract> */ +/* Only available on the Macintosh. */ +/* */ +/* <Description> */ +/* The following definitions are only available if FreeType is */ +/* compiled on a Macintosh. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face_From_FOND */ +/* */ +/* <Description> */ +/* Create a new face object from a FOND resource. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library resource. */ +/* */ +/* <Input> */ +/* fond :: A FOND resource. */ +/* */ +/* face_index :: Only supported for the -1 `sanity check' special */ +/* case. */ +/* */ +/* <Output> */ +/* aface :: A handle to a new face object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Notes> */ +/* This function can be used to create @FT_Face objects from fonts */ +/* that are installed in the system as follows. */ +/* */ +/* { */ +/* fond = GetResource( 'FOND', fontName ); */ +/* error = FT_New_Face_From_FOND( library, fond, 0, &face ); */ +/* } */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_GetFile_From_Mac_Name */ +/* */ +/* <Description> */ +/* Return an FSSpec for the disk file containing the named font. */ +/* */ +/* <Input> */ +/* fontName :: Mac OS name of the font (e.g., Times New Roman */ +/* Bold). */ +/* */ +/* <Output> */ +/* pathSpec :: FSSpec to the file. For passing to */ +/* @FT_New_Face_From_FSSpec. */ +/* */ +/* face_index :: Index of the face. For passing to */ +/* @FT_New_Face_From_FSSpec. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_GetFile_From_Mac_ATS_Name */ +/* */ +/* <Description> */ +/* Return an FSSpec for the disk file containing the named font. */ +/* */ +/* <Input> */ +/* fontName :: Mac OS name of the font in ATS framework. */ +/* */ +/* <Output> */ +/* pathSpec :: FSSpec to the file. For passing to */ +/* @FT_New_Face_From_FSSpec. */ +/* */ +/* face_index :: Index of the face. For passing to */ +/* @FT_New_Face_From_FSSpec. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_GetFilePath_From_Mac_ATS_Name */ +/* */ +/* <Description> */ +/* Return a pathname of the disk file and face index for given font */ +/* name which is handled by ATS framework. */ +/* */ +/* <Input> */ +/* fontName :: Mac OS name of the font in ATS framework. */ +/* */ +/* <Output> */ +/* path :: Buffer to store pathname of the file. For passing */ +/* to @FT_New_Face. The client must allocate this */ +/* buffer before calling this function. */ +/* */ +/* maxPathSize :: Lengths of the buffer `path' that client allocated. */ +/* */ +/* face_index :: Index of the face. For passing to @FT_New_Face. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + FT_DEPRECATED_ATTRIBUTE; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face_From_FSSpec */ +/* */ +/* <Description> */ +/* Create a new face object from a given resource and typeface index */ +/* using an FSSpec to the font file. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library resource. */ +/* */ +/* <Input> */ +/* spec :: FSSpec to the font file. */ +/* */ +/* face_index :: The index of the face within the resource. The */ +/* first face has index~0. */ +/* <Output> */ +/* aface :: A handle to a new face object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* @FT_New_Face_From_FSSpec is identical to @FT_New_Face except */ +/* it accepts an FSSpec instead of a path. */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec *spec, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face_From_FSRef */ +/* */ +/* <Description> */ +/* Create a new face object from a given resource and typeface index */ +/* using an FSRef to the font file. */ +/* */ +/* <InOut> */ +/* library :: A handle to the library resource. */ +/* */ +/* <Input> */ +/* spec :: FSRef to the font file. */ +/* */ +/* face_index :: The index of the face within the resource. The */ +/* first face has index~0. */ +/* <Output> */ +/* aface :: A handle to a new face object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* @FT_New_Face_From_FSRef is identical to @FT_New_Face except */ +/* it accepts an FSRef instead of a path. */ +/* */ + FT_EXPORT( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef *ref, + FT_Long face_index, + FT_Face *aface ) + FT_DEPRECATED_ATTRIBUTE; +/* */ +FT_END_HEADER +/* END */ +/* since Mac OS X 10.1 */ +#ifndef kATSOptionFlagsUnRestrictedScope +#define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault +#endif +/* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over + TrueType in case *both* are available (this is not common, + but it *is* possible). */ +#ifndef PREFER_LWFN +#define PREFER_LWFN 1 +#endif +#ifdef FT_MACINTOSH +/* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + return FT_Err_Unimplemented_Feature; + } +/* Private function. */ +/* The FSSpec type has been discouraged for a long time, */ +/* unfortunately an FSRef replacement API for */ +/* ATSFontGetFileSpecification() is only available in */ +/* Mac OS X 10.5 and later. */ + static OSStatus + FT_ATSFontGetFileReference( ATSFontRef ats_font_id, + FSRef* ats_font_ref ) + { +#if defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) + OSStatus err; + err = ATSFontGetFileReference( ats_font_id, ats_font_ref ); + return err; +/* No 64bit Carbon API on legacy platforms */ +#elif __LP64__ + FT_UNUSED( ats_font_id ); + FT_UNUSED( ats_font_ref ); + return fnfErr; +/* 32bit Carbon API on legacy platforms */ +#else + OSStatus err; + FSSpec spec; + err = ATSFontGetFileSpecification( ats_font_id, &spec ); + if ( noErr == err ) + err = FSpMakeFSRef( &spec, ats_font_ref ); + return err; +#endif + } + static FT_Error + FT_GetFileRef_From_Mac_ATS_Name( const char* fontName, + FSRef* ats_font_ref, + FT_Long* face_index ) + { + CFStringRef cf_fontName; + ATSFontRef ats_font_id; + *face_index = 0; + cf_fontName = CFStringCreateWithCString( NULL, fontName, + kCFStringEncodingMacRoman ); + ats_font_id = ATSFontFindFromName( cf_fontName, + kATSOptionFlagsUnRestrictedScope ); + CFRelease( cf_fontName ); + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + return FT_Err_Unknown_File_Format; + if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) ) + return FT_Err_Unknown_File_Format; +/* face_index calculation by searching preceding fontIDs */ +/* with same FSRef */ + { + ATSFontRef id2 = ats_font_id - 1; + FSRef ref2; + while ( id2 > 0 ) + { + if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) ) + break; + if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) ) + break; + id2 --; + } + *face_index = ats_font_id - ( id2 + 1 ); + } + return FT_Err_Ok; + } + FT_EXPORT_DEF( FT_Error ) + FT_GetFilePath_From_Mac_ATS_Name( const char* fontName, + UInt8* path, + UInt32 maxPathSize, + FT_Long* face_index ) + { + FSRef ref; + FT_Error err; + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( FT_Err_Ok != err ) + return err; + if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) ) + return FT_Err_Unknown_File_Format; + return FT_Err_Ok; + } +/* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_GetFile_From_Mac_ATS_Name( const char* fontName, + FSSpec* pathSpec, + FT_Long* face_index ) + { +#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) + FT_UNUSED( fontName ); + FT_UNUSED( pathSpec ); + FT_UNUSED( face_index ); + return FT_Err_Unimplemented_Feature; +#else + FSRef ref; + FT_Error err; + err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index ); + if ( FT_Err_Ok != err ) + return err; + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, + pathSpec, NULL ) ) + return FT_Err_Unknown_File_Format; + return FT_Err_Ok; +#endif + } + static OSErr + FT_FSPathMakeRes( const UInt8* pathname, + ResFileRefNum* res ) + { + OSErr err; + FSRef ref; + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return FT_Err_Cannot_Open_Resource; +/* at present, no support for dfont format */ + err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res ); + if ( noErr == err ) + return err; +/* fallback to original resource-fork font */ + *res = FSOpenResFile( &ref, fsRdPerm ); + err = ResError(); + return err; + } +/* Return the file type for given pathname */ + static OSType + get_file_type_from_path( const UInt8* pathname ) + { + FSRef ref; + FSCatalogInfo info; + if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) ) + return ( OSType ) 0; + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info, + NULL, NULL, NULL ) ) + return ( OSType ) 0; + return ((FInfo *)(info.finderInfo))->fdType; + } +/* Given a PostScript font name, create the Macintosh LWFN file name. */ + static void + create_lwfn_name( char* ps_name, + Str255 lwfn_file_name ) + { + int max = 5, count = 0; + FT_Byte* p = lwfn_file_name; + FT_Byte* q = (FT_Byte*)ps_name; + lwfn_file_name[0] = 0; + while ( *q ) + { + if ( ft_isupper( *q ) ) + { + if ( count ) + max = 3; + count = 0; + } + if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) + { + *++p = *q; + lwfn_file_name[0]++; + count++; + } + q++; + } + } + static short + count_faces_sfnt( char* fond_data ) + { +/* The count is 1 greater than the value in the FOND. */ +/* Isn't that cute? :-) */ + return EndianS16_BtoN( *( (short*)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + } + static short + count_faces_scalable( char* fond_data ) + { + AsscEntry* assoc; + FamRec* fond; + short i, face, face_all; + fond = (FamRec*)fond_data; + face_all = EndianS16_BtoN( *( (short *)( fond_data + + sizeof ( FamRec ) ) ) ) + 1; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + face = 0; + for ( i = 0; i < face_all; i++ ) + { + if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) ) + face++; + } + return face; + } +/* Look inside the FOND data, answer whether there should be an SFNT + resource, and answer the name of a possible LWFN Type 1 file. + + Thanks to Paul Miller (paulm@profoundeffects.com) for the fix + to load a face OTHER than the first one in the FOND! + */ + static void + parse_fond( char* fond_data, + short* have_sfnt, + ResID* sfnt_id, + Str255 lwfn_file_name, + short face_index ) + { + AsscEntry* assoc; + AsscEntry* base_assoc; + FamRec* fond; + *sfnt_id = 0; + *have_sfnt = 0; + lwfn_file_name[0] = 0; + fond = (FamRec*)fond_data; + assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); + base_assoc = assoc; +/* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */ + if ( 47 < face_index ) + return; +/* Let's do a little range checking before we get too excited here */ + if ( face_index < count_faces_sfnt( fond_data ) ) + { +/* add on the face_index! */ + assoc += face_index; +/* if the face at this index is not scalable, + fall back to the first one (old behavior) */ + if ( EndianS16_BtoN( assoc->fontSize ) == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( assoc->fontID ); + } + else if ( base_assoc->fontSize == 0 ) + { + *have_sfnt = 1; + *sfnt_id = EndianS16_BtoN( base_assoc->fontID ); + } + } + if ( EndianS32_BtoN( fond->ffStylOff ) ) + { + unsigned char* p = (unsigned char*)fond_data; + StyleTable* style; + unsigned short string_count; + char ps_name[256]; + unsigned char* names[64]; + int i; + p += EndianS32_BtoN( fond->ffStylOff ); + style = (StyleTable*)p; + p += sizeof ( StyleTable ); + string_count = EndianS16_BtoN( *(short*)(p) ); + p += sizeof ( short ); + for ( i = 0; i < string_count && i < 64; i++ ) + { + names[i] = p; + p += names[i][0]; + p++; + } + { + size_t ps_name_len = (size_t)names[0][0]; + if ( ps_name_len != 0 ) + { + ft_memcpy(ps_name, names[0] + 1, ps_name_len); + ps_name[ps_name_len] = 0; + } + if ( style->indexes[face_index] > 1 && + style->indexes[face_index] <= FT_MIN( string_count, 64 ) ) + { + unsigned char* suffixes = names[style->indexes[face_index] - 1]; + for ( i = 1; i <= suffixes[0]; i++ ) + { + unsigned char* s; + size_t j = suffixes[i] - 1; + if ( j < string_count && ( s = names[j] ) != NULL ) + { + size_t s_len = (size_t)s[0]; + if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) + { + ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); + ps_name_len += s_len; + ps_name[ps_name_len] = 0; + } + } + } + } + } + create_lwfn_name( ps_name, lwfn_file_name ); + } + } + static FT_Error + lookup_lwfn_by_fond( const UInt8* path_fond, + ConstStr255Param base_lwfn, + UInt8* path_lwfn, + size_t path_size ) + { + FSRef ref, par_ref; + size_t dirname_len; +/* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */ +/* We should not extract parent directory by string manipulation. */ + if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) ) + return FT_Err_Invalid_Argument; + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, &par_ref ) ) + return FT_Err_Invalid_Argument; + if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) ) + return FT_Err_Invalid_Argument; + if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size ) + return FT_Err_Invalid_Argument; +/* now we have absolute dirname in path_lwfn */ + ft_strcat( (char *)path_lwfn, "/" ); + dirname_len = ft_strlen( (char *)path_lwfn ); + ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 ); + path_lwfn[dirname_len + base_lwfn[0]] = '\0'; + if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) ) + return FT_Err_Cannot_Open_Resource; + if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, + NULL, NULL, NULL, NULL ) ) + return FT_Err_Cannot_Open_Resource; + return FT_Err_Ok; + } + static short + count_faces( Handle fond, + const UInt8* pathname ) + { + ResID sfnt_id; + short have_sfnt, have_lwfn; + Str255 lwfn_file_name; + UInt8 buff[PATH_MAX]; + FT_Error err; + short num_faces; + have_sfnt = have_lwfn = 0; + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 ); + if ( lwfn_file_name[0] ) + { + err = lookup_lwfn_by_fond( pathname, lwfn_file_name, + buff, sizeof ( buff ) ); + if ( FT_Err_Ok == err ) + have_lwfn = 1; + } + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + num_faces = 1; + else + num_faces = count_faces_scalable( *fond ); + return num_faces; + } +/* Read Type 1 data from the POST resources inside the LWFN file, + return a PFB buffer. This is somewhat convoluted because the FT2 + PFB parser wants the ASCII header as one chunk, and the LWFN + chunks are often not organized that way, so we glue chunks + of the same type together. */ + static FT_Error + read_lwfn( FT_Memory memory, + ResFileRefNum res, + FT_Byte** pfb_data, + FT_ULong* size ) + { + FT_Error error = FT_Err_Ok; + ResID res_id; + unsigned char *buffer, *p, *size_p = NULL; + FT_ULong total_size = 0; + FT_ULong old_total_size = 0; + FT_ULong post_size, pfb_chunk_size; + Handle post_data; + char code, last_code; + UseResFile( res ); +/* First pass: load all POST resources, and determine the size of */ +/* the output buffer. */ + res_id = 501; + last_code = -1; + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( post_data == NULL ) +/* we are done */ + break; + code = (*post_data)[0]; + if ( code != last_code ) + { + if ( code == 5 ) +/* just the end code */ + total_size += 2; + else +/* code + 4 bytes chunk length */ + total_size += 6; + } + total_size += GetHandleSize( post_data ) - 2; + last_code = code; +/* detect integer overflows */ + if ( total_size < old_total_size ) + { + error = FT_Err_Array_Too_Large; + goto Error; + } + old_total_size = total_size; + } + if ( FT_ALLOC( buffer, (FT_Long)total_size ) ) + goto Error; +/* Second pass: append all POST data to the buffer, add PFB fields. */ +/* Glue all consecutive chunks of the same type together. */ + p = buffer; + res_id = 501; + last_code = -1; + pfb_chunk_size = 0; + for (;;) + { + post_data = Get1Resource( TTAG_POST, res_id++ ); + if ( post_data == NULL ) +/* we are done */ + break; + post_size = (FT_ULong)GetHandleSize( post_data ) - 2; + code = (*post_data)[0]; + if ( code != last_code ) + { + if ( last_code != -1 ) + { +/* we are done adding a chunk, fill in the size field */ + if ( size_p != NULL ) + { + *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); + *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); + } + pfb_chunk_size = 0; + } + *p++ = 0x80; + if ( code == 5 ) +/* the end */ + *p++ = 0x03; + else if ( code == 2 ) +/* binary segment */ + *p++ = 0x02; + else +/* ASCII segment */ + *p++ = 0x01; + if ( code != 5 ) + { +/* save for later */ + size_p = p; +/* make space for size field */ + p += 4; + } + } + ft_memcpy( p, *post_data + 2, post_size ); + pfb_chunk_size += post_size; + p += post_size; + last_code = code; + } + *pfb_data = buffer; + *size = total_size; + Error: + CloseResFile( res ); + return error; + } +/* Create a new FT_Face from a file path to an LWFN file. */ + static FT_Error + FT_New_Face_From_LWFN( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Byte* pfb_data; + FT_ULong pfb_size; + FT_Error error; + ResFileRefNum res; + if ( noErr != FT_FSPathMakeRes( pathname, &res ) ) + return FT_Err_Cannot_Open_Resource; + pfb_data = NULL; + pfb_size = 0; + error = read_lwfn( library->memory, res, &pfb_data, &pfb_size ); +/* PFB is already loaded, useless anymore */ + CloseResFile( res ); + if ( error ) + return error; + return open_face_from_buffer( library, + pfb_data, + pfb_size, + face_index, + "type1", + aface ); + } +/* Create a new FT_Face from an SFNT resource, specified by res ID. */ + static FT_Error + FT_New_Face_From_SFNT( FT_Library library, + ResID sfnt_id, + FT_Long face_index, + FT_Face* aface ) + { + Handle sfnt = NULL; + FT_Byte* sfnt_data; + size_t sfnt_size; + FT_Error error = FT_Err_Ok; + FT_Memory memory = library->memory; + int is_cff, is_sfnt_ps; + sfnt = GetResource( TTAG_sfnt, sfnt_id ); + if ( sfnt == NULL ) + return FT_Err_Invalid_Handle; + sfnt_size = (FT_ULong)GetHandleSize( sfnt ); + if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + { + ReleaseResource( sfnt ); + return error; + } + ft_memcpy( sfnt_data, *sfnt, sfnt_size ); + ReleaseResource( sfnt ); + is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); + is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); + if ( is_sfnt_ps ) + { + FT_Stream stream; + if ( FT_NEW( stream ) ) + goto Try_OpenType; + FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); + if ( !open_face_PS_from_sfnt_stream( library, + stream, + face_index, + 0, NULL, + aface ) ) + { + FT_Stream_Close( stream ); + FT_FREE( stream ); + FT_FREE( sfnt_data ); + goto Exit; + } + FT_FREE( stream ); + } + Try_OpenType: + error = open_face_from_buffer( library, + sfnt_data, + sfnt_size, + face_index, + is_cff ? "cff" : "truetype", + aface ); + Exit: + return error; + } +/* Create a new FT_Face from a file path to a suitcase file. */ + static FT_Error + FT_New_Face_From_Suitcase( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error = FT_Err_Cannot_Open_Resource; + ResFileRefNum res_ref; + ResourceIndex res_index; + Handle fond; + short num_faces_in_res, num_faces_in_fond; + if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) + return FT_Err_Cannot_Open_Resource; + UseResFile( res_ref ); + if ( ResError() ) + return FT_Err_Cannot_Open_Resource; + num_faces_in_res = 0; + for ( res_index = 1; ; ++res_index ) + { + fond = Get1IndResource( TTAG_FOND, res_index ); + if ( ResError() ) + break; + num_faces_in_fond = count_faces( fond, pathname ); + num_faces_in_res += num_faces_in_fond; + if ( 0 <= face_index && face_index < num_faces_in_fond && error ) + error = FT_New_Face_From_FOND( library, fond, face_index, aface ); + face_index -= num_faces_in_fond; + } + CloseResFile( res_ref ); + if ( FT_Err_Ok == error && NULL != aface && NULL != *aface ) + (*aface)->num_faces = num_faces_in_res; + return error; + } +/* documentation is in ftmac.h */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FOND( FT_Library library, + Handle fond, + FT_Long face_index, + FT_Face* aface ) + { + short have_sfnt, have_lwfn = 0; + ResID sfnt_id, fond_id; + OSType fond_type; + Str255 fond_name; + Str255 lwfn_file_name; + UInt8 path_lwfn[PATH_MAX]; + OSErr err; + FT_Error error = FT_Err_Ok; + GetResInfo( fond, &fond_id, &fond_type, fond_name ); + if ( ResError() != noErr || fond_type != TTAG_FOND ) + return FT_Err_Invalid_File_Format; + parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index ); + if ( lwfn_file_name[0] ) + { + ResFileRefNum res; + res = HomeResFile( fond ); + if ( noErr != ResError() ) + goto found_no_lwfn_file; + { + UInt8 path_fond[PATH_MAX]; + FSRef ref; + err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum, + NULL, NULL, NULL, &ref, NULL ); + if ( noErr != err ) + goto found_no_lwfn_file; + err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) ); + if ( noErr != err ) + goto found_no_lwfn_file; + error = lookup_lwfn_by_fond( path_fond, lwfn_file_name, + path_lwfn, sizeof ( path_lwfn ) ); + if ( FT_Err_Ok == error ) + have_lwfn = 1; + } + } + if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) ) + error = FT_New_Face_From_LWFN( library, + path_lwfn, + face_index, + aface ); + else + error = FT_Err_Unknown_File_Format; + found_no_lwfn_file: + if ( have_sfnt && FT_Err_Ok != error ) + error = FT_New_Face_From_SFNT( library, + sfnt_id, + face_index, + aface ); + return error; + } +/* Common function to load a new FT_Face from a resource file. */ + static FT_Error + FT_New_Face_From_Resource( FT_Library library, + const UInt8* pathname, + FT_Long face_index, + FT_Face* aface ) + { + OSType file_type; + FT_Error error; +/* LWFN is a (very) specific file format, check for it explicitly */ + file_type = get_file_type_from_path( pathname ); + if ( file_type == TTAG_LWFN ) + return FT_New_Face_From_LWFN( library, pathname, face_index, aface ); +/* Otherwise the file type doesn't matter (there are more than */ +/* `FFIL' and `tfil'). Just try opening it as a font suitcase; */ +/* if it works, fine. */ + error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface ); + if ( error == 0 ) + return error; +/* let it fall through to normal loader (.ttf, .otf, etc.); */ +/* we signal this by returning no error and no FT_Face */ + *aface = NULL; + return 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face */ +/* */ +/* <Description> */ +/* This is the Mac-specific implementation of FT_New_Face. In */ +/* addition to the standard FT_New_Face() functionality, it also */ +/* accepts pathnames to Mac suitcase files. For further */ +/* documentation see the original FT_New_Face() in freetype.h. */ +/* */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face( FT_Library library, + const char* pathname, + FT_Long face_index, + FT_Face* aface ) + { + FT_Open_Args args; + FT_Error error; +/* test for valid `library' and `aface' delayed to FT_Open_Face() */ + if ( !pathname ) + return FT_Err_Invalid_Argument; + error = FT_Err_Ok; + *aface = NULL; +/* try resourcefork based font: LWFN, FFIL */ + error = FT_New_Face_From_Resource( library, (UInt8 *)pathname, + face_index, aface ); + if ( error != 0 || *aface != NULL ) + return error; +/* let it fall through to normal loader (.ttf, .otf, etc.) */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face_From_FSRef */ +/* */ +/* <Description> */ +/* FT_New_Face_From_FSRef is identical to FT_New_Face except it */ +/* accepts an FSRef instead of a path. */ +/* */ +/* This function is deprecated because Carbon data types (FSRef) */ +/* are not cross-platform, and thus not suitable for the freetype API. */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSRef( FT_Library library, + const FSRef* ref, + FT_Long face_index, + FT_Face* aface ) + { + FT_Error error; + FT_Open_Args args; + OSErr err; + UInt8 pathname[PATH_MAX]; + if ( !ref ) + return FT_Err_Invalid_Argument; + err = FSRefMakePath( ref, pathname, sizeof ( pathname ) ); + if ( err ) + error = FT_Err_Cannot_Open_Resource; + error = FT_New_Face_From_Resource( library, pathname, face_index, aface ); + if ( error != 0 || *aface != NULL ) + return error; +/* fallback to datafork font */ + args.flags = FT_OPEN_PATHNAME; + args.pathname = (char*)pathname; + return FT_Open_Face( library, &args, face_index, aface ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_New_Face_From_FSSpec */ +/* */ +/* <Description> */ +/* FT_New_Face_From_FSSpec is identical to FT_New_Face except it */ +/* accepts an FSSpec instead of a path. */ +/* */ +/* This function is deprecated because FSSpec is deprecated in Mac OS X */ + FT_EXPORT_DEF( FT_Error ) + FT_New_Face_From_FSSpec( FT_Library library, + const FSSpec* spec, + FT_Long face_index, + FT_Face* aface ) + { +#if ( __LP64__ ) || ( defined( MAC_OS_X_VERSION_10_5 ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) ) + FT_UNUSED( library ); + FT_UNUSED( spec ); + FT_UNUSED( face_index ); + FT_UNUSED( aface ); + return FT_Err_Unimplemented_Feature; +#else + FSRef ref; + if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr ) + return FT_Err_Invalid_Argument; + else + return FT_New_Face_From_FSRef( library, &ref, face_index, aface ); +#endif + } +/* FT_MACINTOSH */ +#endif +/* END */ +#endif +/* END */ +/***************************************************************************/ +/* */ +/* ftbbox.c */ +/* */ +/* FreeType bbox computation (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006, 2010 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. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* ftbbox.h */ +/* */ +/* FreeType exact bbox computation (specification). */ +/* */ +/* Copyright 1996-2001, 2003, 2007, 2011 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. */ +/* */ +/* It is separated from the rest of the engine for various technical */ +/* reasons. It may well be integrated in `ftoutln' later. */ +/* */ +/*************************************************************************/ +#define __FTBBOX_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* outline_processing */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Get_BBox */ +/* */ +/* <Description> */ +/* Compute the exact bounding box of an outline. This is slower */ +/* than computing the control box. However, it uses an advanced */ +/* algorithm which returns _very_ quickly when the two boxes */ +/* coincide. Otherwise, the outline Bézier arcs are traversed to */ +/* extract their extrema. */ +/* */ +/* <Input> */ +/* outline :: A pointer to the source outline. */ +/* */ +/* <Output> */ +/* abbox :: The outline's exact bounding box. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* If the font is tricky and the glyph has been loaded with */ +/* @FT_LOAD_NO_SCALE, the resulting BBox is meaningless. To get */ +/* reasonable values for the BBox it is necessary to load the glyph */ +/* at a large ppem value (so that the hinting instructions can */ +/* properly shift and scale the subglyphs), then extracting the BBox */ +/* which can be eventually converted back to font units. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ); +/* */ +FT_END_HEADER +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ + typedef struct TBBox_Rec_ + { + FT_Vector last; + FT_BBox bbox; + } TBBox_Rec; +/*************************************************************************/ +/* */ +/* <Function> */ +/* BBox_Move_To */ +/* */ +/* <Description> */ +/* This function is used as a `move_to' and `line_to' emitter during */ +/* FT_Outline_Decompose(). It simply records the destination point */ +/* in `user->last'; no further computations are necessary since we */ +/* use the cbox as the starting bbox which must be refined. */ +/* */ +/* <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. */ +/* */ + static int + BBox_Move_To( FT_Vector* to, + TBBox_Rec* user ) + { + user->last = *to; + return 0; + } +#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_Conic_Check */ +/* */ +/* <Description> */ +/* Finds 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 ) + { +/* flat arc */ + if ( y1 <= y3 && y2 == y1 ) + goto Suite; + if ( y1 < y3 ) + { +/* ascending arc */ + if ( y2 >= y1 && y2 <= y3 ) + goto Suite; + } + else + { +/* descending arc */ + if ( y2 >= y3 && y2 <= y1 ) + { + y2 = y1; + y1 = y3; + y3 = y2; + goto Suite; + } + } + y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 ); + Suite: + if ( y1 < *min ) *min = y1; + if ( y3 > *max ) *max = y3; + } +/*************************************************************************/ +/* */ +/* <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. */ +/* */ + static int + BBox_Conic_To( FT_Vector* control, + FT_Vector* to, + TBBox_Rec* user ) + { +/* we don't need to check `to' since it is always an `on' point, thus */ +/* within the 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> */ +/* Finds the extrema of a 1-dimensional cubic Bezier curve and */ +/* updates a bounding range. This version uses splitting because we */ +/* don't want to use square roots and extra accuracy. */ +/* */ +/* <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. */ +/* */ +#if 0 + static void + BBox_Cubic_Check( FT_Pos p1, + FT_Pos p2, + FT_Pos p3, + FT_Pos p4, + FT_Pos* min, + FT_Pos* max ) + { + FT_Pos stack[32*3 + 1], *arc; + arc = stack; + arc[0] = p1; + arc[1] = p2; + arc[2] = p3; + arc[3] = p4; + do + { + FT_Pos y1 = arc[0]; + FT_Pos y2 = arc[1]; + FT_Pos y3 = arc[2]; + FT_Pos y4 = arc[3]; + if ( y1 == y4 ) + { +/* flat */ + if ( y1 == y2 && y1 == y3 ) + goto Test; + } + else if ( y1 < y4 ) + { +/* ascending */ + if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) + goto Test; + } + else + { +/* descending */ + if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) + { + y2 = y1; + y1 = y4; + y4 = y2; + goto Test; + } + } +/* unknown direction -- split the arc in two */ + arc[6] = y4; + arc[1] = y1 = ( y1 + y2 ) / 2; + arc[5] = y4 = ( y4 + y3 ) / 2; + y2 = ( y2 + y3 ) / 2; + arc[2] = y1 = ( y1 + y2 ) / 2; + arc[4] = y4 = ( y4 + y2 ) / 2; + arc[3] = ( y1 + y4 ) / 2; + arc += 3; + goto Suite; + Test: + if ( y1 < *min ) *min = y1; + if ( y4 > *max ) *max = y4; + arc -= 3; + Suite: + ; + } while ( arc >= stack ); + } +#else + static void + test_cubic_extrema( FT_Pos y1, + FT_Pos y2, + FT_Pos y3, + FT_Pos y4, + FT_Fixed u, + FT_Pos* min, + FT_Pos* max ) + { +/* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */ + FT_Pos b = y3 - 2*y2 + y1; + FT_Pos c = y2 - y1; + FT_Pos d = y1; + FT_Pos y; + FT_Fixed uu; + FT_UNUSED ( y4 ); +/* The polynomial is */ +/* */ +/* P(x) = a*x^3 + 3b*x^2 + 3c*x + d , */ +/* */ +/* dP/dx = 3a*x^2 + 6b*x + 3c . */ +/* */ +/* However, we also have */ +/* */ +/* dP/dx(u) = 0 , */ +/* */ +/* which implies by subtraction that */ +/* */ +/* P(u) = b*u^2 + 2c*u + d . */ + if ( u > 0 && u < 0x10000L ) + { + uu = FT_MulFix( u, u ); + y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu ); + if ( y < *min ) *min = y; + if ( y > *max ) *max = y; + } + } + static void + BBox_Cubic_Check( FT_Pos y1, + FT_Pos y2, + FT_Pos y3, + FT_Pos y4, + FT_Pos* min, + FT_Pos* max ) + { +/* always compare first and last points */ + if ( y1 < *min ) *min = y1; + else if ( y1 > *max ) *max = y1; + if ( y4 < *min ) *min = y4; + else if ( y4 > *max ) *max = y4; +/* now, try to see if there are split points here */ + if ( y1 <= y4 ) + { +/* flat or ascending arc test */ + if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 ) + return; + } +/* y1 > y4 */ + else + { +/* descending arc test */ + if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 ) + return; + } +/* There are some split points. Find them. */ + { + FT_Pos a = y4 - 3*y3 + 3*y2 - y1; + FT_Pos b = y3 - 2*y2 + y1; + FT_Pos c = y2 - y1; + FT_Pos d; + FT_Fixed t; +/* We need to solve `ax^2+2bx+c' here, without floating points! */ +/* The trick is to normalize to a different representation in order */ +/* to use our 16.16 fixed point routines. */ +/* */ +/* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */ +/* These values must fit into a single 16.16 value. */ +/* */ +/* We normalize a, b, and c to `8.16' fixed float values to ensure */ +/* that its product is held in a `16.16' value. */ + { + FT_ULong t1, t2; + int shift = 0; +/* The following computation is based on the fact that for */ +/* any value `y', if `n' is the position of the most */ +/* significant bit of `abs(y)' (starting from 0 for the */ +/* least significant bit), then `y' is in the range */ +/* */ +/* -2^n..2^n-1 */ +/* */ +/* We want to shift `a', `b', and `c' concurrently in order */ +/* to ensure that they all fit in 8.16 values, which maps */ +/* to the integer range `-2^23..2^23-1'. */ +/* */ +/* Necessarily, we need to shift `a', `b', and `c' so that */ +/* the most significant bit of its absolute values is at */ +/* _most_ at position 23. */ +/* */ +/* We begin by computing `t1' as the bitwise `OR' of the */ +/* absolute values of `a', `b', `c'. */ + t1 = (FT_ULong)( ( a >= 0 ) ? a : -a ); + t2 = (FT_ULong)( ( b >= 0 ) ? b : -b ); + t1 |= t2; + t2 = (FT_ULong)( ( c >= 0 ) ? c : -c ); + t1 |= t2; +/* Now we can be sure that the most significant bit of `t1' */ +/* is the most significant bit of either `a', `b', or `c', */ +/* depending on the greatest integer range of the particular */ +/* variable. */ +/* */ +/* Next, we compute the `shift', by shifting `t1' as many */ +/* times as necessary to move its MSB to position 23. This */ +/* corresponds to a value of `t1' that is in the range */ +/* 0x40_0000..0x7F_FFFF. */ +/* */ +/* Finally, we shift `a', `b', and `c' by the same amount. */ +/* This ensures that all values are now in the range */ +/* -2^23..2^23, i.e., they are now expressed as 8.16 */ +/* fixed-float numbers. This also means that we are using */ +/* 24 bits of precision to compute the zeros, independently */ +/* of the range of the original polynomial coefficients. */ +/* */ +/* This algorithm should ensure reasonably accurate values */ +/* for the zeros. Note that they are only expressed with */ +/* 16 bits when computing the extrema (the zeros need to */ +/* be in 0..1 exclusive to be considered part of the arc). */ +/* all coefficients are 0! */ + if ( t1 == 0 ) + return; + if ( t1 > 0x7FFFFFUL ) + { + do + { + shift++; + t1 >>= 1; + } while ( t1 > 0x7FFFFFUL ); +/* this loses some bits of precision, but we use 24 of them */ +/* for the computation anyway */ + a >>= shift; + b >>= shift; + c >>= shift; + } + else if ( t1 < 0x400000UL ) + { + do + { + shift++; + t1 <<= 1; + } while ( t1 < 0x400000UL ); + a <<= shift; + b <<= shift; + c <<= shift; + } + } +/* handle a == 0 */ + if ( a == 0 ) + { + if ( b != 0 ) + { + t = - FT_DivFix( c, b ) / 2; + test_cubic_extrema( y1, y2, y3, y4, t, min, max ); + } + } + else + { +/* solve the equation now */ + d = FT_MulFix( b, b ) - FT_MulFix( a, c ); + if ( d < 0 ) + return; + if ( d == 0 ) + { +/* there is a single split point at -b/a */ + t = - FT_DivFix( b, a ); + test_cubic_extrema( y1, y2, y3, y4, t, min, max ); + } + else + { +/* there are two solutions; we need to filter them */ + d = FT_SqrtFixed( (FT_Int32)d ); + t = - FT_DivFix( b - d, a ); + test_cubic_extrema( y1, y2, y3, y4, t, min, max ); + t = - FT_DivFix( b + d, a ); + test_cubic_extrema( y1, y2, y3, y4, t, min, max ); + } + } + } + } +#endif +/*************************************************************************/ +/* */ +/* <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. */ +/* */ + static int + BBox_Cubic_To( FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to, + TBBox_Rec* user ) + { +/* we don't need to check `to' since it is always an `on' point, thus */ +/* within the bbox */ + 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, + (FT_Outline_LineTo_Func) BBox_Move_To, + (FT_Outline_ConicTo_Func)BBox_Conic_To, + (FT_Outline_CubicTo_Func)BBox_Cubic_To, + 0, 0 + ) +/* documentation is in ftbbox.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Outline_Get_BBox( FT_Outline* outline, + FT_BBox *abbox ) + { + FT_BBox cbox; + FT_BBox bbox; + FT_Vector* vec; + FT_UShort n; + if ( !abbox ) + return FT_Err_Invalid_Argument; + if ( !outline ) + return FT_Err_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; + bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x; + bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y; + vec++; + for ( n = 1; n < outline->n_points; n++ ) + { + FT_Pos x = vec->x; + FT_Pos y = vec->y; +/* update control box */ + if ( x < cbox.xMin ) cbox.xMin = x; + if ( x > cbox.xMax ) cbox.xMax = x; + if ( y < cbox.yMin ) cbox.yMin = y; + if ( y > cbox.yMax ) cbox.yMax = y; + if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON ) + { +/* update bbox for `on' points only */ + if ( x < bbox.xMin ) bbox.xMin = x; + if ( x > bbox.xMax ) bbox.xMax = x; + if ( y < bbox.yMin ) bbox.yMin = y; + if ( y > bbox.yMax ) bbox.yMax = y; + } + 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 */ +/***************************************************************************/ +/* */ +/* ftglyph.c */ +/* */ +/* FreeType convenience functions to handle glyphs (body). */ +/* */ +/* Copyright 1996-2005, 2007, 2008, 2010, 2012 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 contains the definition of several convenience functions */ +/* that can be used by client applications to easily retrieve glyph */ +/* bitmaps and outlines from a given face. */ +/* */ +/* These functions should be optional if you are writing a font server */ +/* or text layout engine on top of FreeType. However, they are pretty */ +/* handy for many other simple uses of the library. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* ftbitmap.h */ +/* */ +/* FreeType utility functions for bitmaps (specification). */ +/* */ +/* Copyright 2004, 2005, 2006, 2008 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. */ +/* */ +/***************************************************************************/ +#define __FTBITMAP_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* bitmap_handling */ +/* */ +/* <Title> */ +/* Bitmap Handling */ +/* */ +/* <Abstract> */ +/* Handling FT_Bitmap objects. */ +/* */ +/* <Description> */ +/* This section contains functions for converting FT_Bitmap objects. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Bitmap_New */ +/* */ +/* <Description> */ +/* Initialize a pointer to an @FT_Bitmap structure. */ +/* */ +/* <InOut> */ +/* abitmap :: A pointer to the bitmap structure. */ +/* */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Bitmap_Copy */ +/* */ +/* <Description> */ +/* Copy a bitmap into another one. */ +/* */ +/* <Input> */ +/* library :: A handle to a library object. */ +/* */ +/* source :: A handle to the source bitmap. */ +/* */ +/* <Output> */ +/* target :: A handle to the target bitmap. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Bitmap_Embolden */ +/* */ +/* <Description> */ +/* Embolden a bitmap. The new bitmap will be about `xStrength' */ +/* pixels wider and `yStrength' pixels higher. The left and bottom */ +/* borders are kept unchanged. */ +/* */ +/* <Input> */ +/* library :: A handle to a library object. */ +/* */ +/* xStrength :: How strong the glyph is emboldened horizontally. */ +/* Expressed in 26.6 pixel format. */ +/* */ +/* yStrength :: How strong the glyph is emboldened vertically. */ +/* Expressed in 26.6 pixel format. */ +/* */ +/* <InOut> */ +/* bitmap :: A handle to the target bitmap. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The current implementation restricts `xStrength' to be less than */ +/* or equal to~8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. */ +/* */ +/* If you want to embolden the bitmap owned by a @FT_GlyphSlotRec, */ +/* you should call @FT_GlyphSlot_Own_Bitmap on the slot first. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Bitmap_Convert */ +/* */ +/* <Description> */ +/* Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, or 8bpp to a */ +/* bitmap object with depth 8bpp, making the number of used bytes per */ +/* line (a.k.a. the `pitch') a multiple of `alignment'. */ +/* */ +/* <Input> */ +/* library :: A handle to a library object. */ +/* */ +/* source :: The source bitmap. */ +/* */ +/* alignment :: The pitch of the bitmap is a multiple of this */ +/* parameter. Common values are 1, 2, or 4. */ +/* */ +/* <Output> */ +/* target :: The target bitmap. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* It is possible to call @FT_Bitmap_Convert multiple times without */ +/* calling @FT_Bitmap_Done (the memory is simply reallocated). */ +/* */ +/* Use @FT_Bitmap_Done to finally remove the bitmap object. */ +/* */ +/* The `library' argument is taken to have access to FreeType's */ +/* memory handling functions. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_GlyphSlot_Own_Bitmap */ +/* */ +/* <Description> */ +/* Make sure that a glyph slot owns `slot->bitmap'. */ +/* */ +/* <Input> */ +/* slot :: The glyph slot. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* This function is to be used in combination with */ +/* @FT_Bitmap_Embolden. */ +/* */ + FT_EXPORT( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Bitmap_Done */ +/* */ +/* <Description> */ +/* Destroy a bitmap object created with @FT_Bitmap_New. */ +/* */ +/* <Input> */ +/* library :: A handle to a library object. */ +/* */ +/* bitmap :: The bitmap object to be freed. */ +/* */ +/* <Return> */ +/* FreeType error code. 0~means success. */ +/* */ +/* <Note> */ +/* The `library' argument is taken to have access to FreeType's */ +/* memory handling functions. */ +/* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); +/* */ +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_glyph +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** FT_BitmapGlyph support ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_DEF( FT_Error ) + ft_bitmap_glyph_init( FT_Glyph bitmap_glyph, + FT_GlyphSlot slot ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH( glyph )->library; + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) + { + error = FT_Err_Invalid_Glyph_Format; + goto Exit; + } + glyph->left = slot->bitmap_left; + glyph->top = slot->bitmap_top; +/* do lazy copying whenever possible */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + glyph->bitmap = slot->bitmap; + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + FT_Bitmap_New( &glyph->bitmap ); + error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap ); + } + Exit: + return error; + } + FT_CALLBACK_DEF( FT_Error ) + ft_bitmap_glyph_copy( FT_Glyph bitmap_source, + FT_Glyph bitmap_target ) + { + FT_Library library = bitmap_source->library; + FT_BitmapGlyph source = (FT_BitmapGlyph)bitmap_source; + FT_BitmapGlyph target = (FT_BitmapGlyph)bitmap_target; + target->left = source->left; + target->top = source->top; + return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap ); + } + FT_CALLBACK_DEF( void ) + ft_bitmap_glyph_done( FT_Glyph bitmap_glyph ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + FT_Library library = FT_GLYPH( glyph )->library; + FT_Bitmap_Done( library, &glyph->bitmap ); + } + FT_CALLBACK_DEF( void ) + ft_bitmap_glyph_bbox( FT_Glyph bitmap_glyph, + FT_BBox* cbox ) + { + FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph; + cbox->xMin = glyph->left << 6; + cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 ); + cbox->yMax = glyph->top << 6; + cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 ); + } + FT_DEFINE_GLYPH(ft_bitmap_glyph_class, + sizeof ( FT_BitmapGlyphRec ), + FT_GLYPH_FORMAT_BITMAP, + ft_bitmap_glyph_init, + ft_bitmap_glyph_done, + ft_bitmap_glyph_copy, +/* FT_Glyph_TransformFunc */ + 0, + ft_bitmap_glyph_bbox, +/* FT_Glyph_PrepareFunc */ + 0 + ) +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** FT_OutlineGlyph support ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_init( FT_Glyph outline_glyph, + FT_GlyphSlot slot ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + FT_Error error = FT_Err_Ok; + FT_Library library = FT_GLYPH( glyph )->library; + FT_Outline* source = &slot->outline; + FT_Outline* target = &glyph->outline; +/* check format in glyph slot */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + { + error = FT_Err_Invalid_Glyph_Format; + goto Exit; + } +/* allocate new outline */ + error = FT_Outline_New( library, source->n_points, source->n_contours, + &glyph->outline ); + if ( error ) + goto Exit; + FT_Outline_Copy( source, target ); + Exit: + return error; + } + FT_CALLBACK_DEF( void ) + ft_outline_glyph_done( FT_Glyph outline_glyph ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline ); + } + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_copy( FT_Glyph outline_source, + FT_Glyph outline_target ) + { + FT_OutlineGlyph source = (FT_OutlineGlyph)outline_source; + FT_OutlineGlyph target = (FT_OutlineGlyph)outline_target; + FT_Error error; + FT_Library library = FT_GLYPH( source )->library; + error = FT_Outline_New( library, source->outline.n_points, + source->outline.n_contours, &target->outline ); + if ( !error ) + FT_Outline_Copy( &source->outline, &target->outline ); + return error; + } + FT_CALLBACK_DEF( void ) + ft_outline_glyph_transform( FT_Glyph outline_glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + if ( matrix ) + FT_Outline_Transform( &glyph->outline, matrix ); + if ( delta ) + FT_Outline_Translate( &glyph->outline, delta->x, delta->y ); + } + FT_CALLBACK_DEF( void ) + ft_outline_glyph_bbox( FT_Glyph outline_glyph, + FT_BBox* bbox ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + FT_Outline_Get_CBox( &glyph->outline, bbox ); + } + FT_CALLBACK_DEF( FT_Error ) + ft_outline_glyph_prepare( FT_Glyph outline_glyph, + FT_GlyphSlot slot ) + { + FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph; + slot->format = FT_GLYPH_FORMAT_OUTLINE; + slot->outline = glyph->outline; + slot->outline.flags &= ~FT_OUTLINE_OWNER; + return FT_Err_Ok; + } + FT_DEFINE_GLYPH( ft_outline_glyph_class, + sizeof ( FT_OutlineGlyphRec ), + FT_GLYPH_FORMAT_OUTLINE, + ft_outline_glyph_init, + ft_outline_glyph_done, + ft_outline_glyph_copy, + ft_outline_glyph_transform, + ft_outline_glyph_bbox, + ft_outline_glyph_prepare + ) +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** FT_Glyph class and API ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + ft_new_glyph( FT_Library library, + const FT_Glyph_Class* clazz, + FT_Glyph* aglyph ) + { + FT_Memory memory = library->memory; + FT_Error error; + FT_Glyph glyph = NULL; + *aglyph = 0; + if ( !FT_ALLOC( glyph, clazz->glyph_size ) ) + { + glyph->library = library; + glyph->clazz = clazz; + glyph->format = clazz->glyph_format; + *aglyph = glyph; + } + return error; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Copy( FT_Glyph source, + FT_Glyph *target ) + { + FT_Glyph copy; + FT_Error error; + const FT_Glyph_Class* clazz; +/* check arguments */ + if ( !target ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + *target = 0; + if ( !source || !source->clazz ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + clazz = source->clazz; + error = ft_new_glyph( source->library, clazz, © ); + if ( error ) + goto Exit; + copy->advance = source->advance; + copy->format = source->format; + if ( clazz->glyph_copy ) + error = clazz->glyph_copy( source, copy ); + if ( error ) + FT_Done_Glyph( copy ); + else + *target = copy; + Exit: + return error; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_Glyph( FT_GlyphSlot slot, + FT_Glyph *aglyph ) + { + FT_Library library; + FT_Error error; + FT_Glyph glyph; + const FT_Glyph_Class* clazz = 0; + if ( !slot ) + return FT_Err_Invalid_Slot_Handle; + library = slot->library; + if ( !aglyph ) + return FT_Err_Invalid_Argument; +/* if it is a bitmap, that's easy :-) */ + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + clazz = FT_BITMAP_GLYPH_CLASS_GET; +/* if it is an outline */ + else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + clazz = FT_OUTLINE_GLYPH_CLASS_GET; + else + { +/* try to find a renderer that supports the glyph image format */ + FT_Renderer render = FT_Lookup_Renderer( library, slot->format, 0 ); + if ( render ) + clazz = &render->glyph_class; + } + if ( !clazz ) + { + error = FT_Err_Invalid_Glyph_Format; + goto Exit; + } +/* create FT_Glyph object */ + error = ft_new_glyph( library, clazz, &glyph ); + if ( error ) + goto Exit; +/* copy advance while converting it to 16.16 format */ + glyph->advance.x = slot->advance.x << 10; + glyph->advance.y = slot->advance.y << 10; +/* now import the image from the glyph slot */ + error = clazz->glyph_init( glyph, slot ); +/* if an error occurred, destroy the glyph */ + if ( error ) + FT_Done_Glyph( glyph ); + else + *aglyph = glyph; + Exit: + return error; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Transform( FT_Glyph glyph, + FT_Matrix* matrix, + FT_Vector* delta ) + { + const FT_Glyph_Class* clazz; + FT_Error error = FT_Err_Ok; + if ( !glyph || !glyph->clazz ) + error = FT_Err_Invalid_Argument; + else + { + clazz = glyph->clazz; + if ( clazz->glyph_transform ) + { +/* transform glyph image */ + clazz->glyph_transform( glyph, matrix, delta ); +/* transform advance vector */ + if ( matrix ) + FT_Vector_Transform( &glyph->advance, matrix ); + } + else + error = FT_Err_Invalid_Glyph_Format; + } + return error; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( void ) + FT_Glyph_Get_CBox( FT_Glyph glyph, + FT_UInt bbox_mode, + FT_BBox *acbox ) + { + const FT_Glyph_Class* clazz; + if ( !acbox ) + return; + acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0; + if ( !glyph || !glyph->clazz ) + return; + else + { + clazz = glyph->clazz; + if ( !clazz->glyph_bbox ) + return; + else + { +/* retrieve bbox in 26.6 coordinates */ + clazz->glyph_bbox( glyph, acbox ); +/* perform grid fitting if needed */ + if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT || + bbox_mode == FT_GLYPH_BBOX_PIXELS ) + { + acbox->xMin = FT_PIX_FLOOR( acbox->xMin ); + acbox->yMin = FT_PIX_FLOOR( acbox->yMin ); + acbox->xMax = FT_PIX_CEIL( acbox->xMax ); + acbox->yMax = FT_PIX_CEIL( acbox->yMax ); + } +/* convert to integer pixels if needed */ + if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE || + bbox_mode == FT_GLYPH_BBOX_PIXELS ) + { + acbox->xMin >>= 6; + acbox->yMin >>= 6; + acbox->xMax >>= 6; + acbox->yMax >>= 6; + } + } + } + return; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + FT_Vector* origin, + FT_Bool destroy ) + { + FT_GlyphSlotRec dummy; + FT_GlyphSlot_InternalRec dummy_internal; + FT_Error error = FT_Err_Ok; + FT_Glyph b, glyph; + FT_BitmapGlyph bitmap = NULL; + const FT_Glyph_Class* clazz; +/* FT_BITMAP_GLYPH_CLASS_GET derefers `library' in PIC mode */ + FT_Library library; +/* check argument */ + if ( !the_glyph ) + goto Bad; + glyph = *the_glyph; + if ( !glyph ) + goto Bad; + clazz = glyph->clazz; + library = glyph->library; + if ( !library || !clazz ) + goto Bad; +/* when called with a bitmap glyph, do nothing and return successfully */ + if ( clazz == FT_BITMAP_GLYPH_CLASS_GET ) + goto Exit; + if ( !clazz->glyph_prepare ) + goto Bad; +/* we render the glyph into a glyph bitmap using a `dummy' glyph slot */ +/* then calling FT_Render_Glyph_Internal() */ + FT_MEM_ZERO( &dummy, sizeof ( dummy ) ); + FT_MEM_ZERO( &dummy_internal, sizeof ( dummy_internal ) ); + dummy.internal = &dummy_internal; + dummy.library = library; + dummy.format = clazz->glyph_format; +/* create result bitmap glyph */ + error = ft_new_glyph( library, FT_BITMAP_GLYPH_CLASS_GET, &b ); + if ( error ) + goto Exit; + bitmap = (FT_BitmapGlyph)b; +#if 1 +/* if `origin' is set, translate the glyph image */ + if ( origin ) + FT_Glyph_Transform( glyph, 0, origin ); +#else + FT_UNUSED( origin ); +#endif +/* prepare dummy slot for rendering */ + error = clazz->glyph_prepare( glyph, &dummy ); + if ( !error ) + error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); +#if 1 + if ( !destroy && origin ) + { + FT_Vector v; + v.x = -origin->x; + v.y = -origin->y; + FT_Glyph_Transform( glyph, 0, &v ); + } +#endif + if ( error ) + goto Exit; +/* in case of success, copy the bitmap to the glyph bitmap */ + error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); + if ( error ) + goto Exit; +/* copy advance */ + bitmap->root.advance = glyph->advance; + if ( destroy ) + FT_Done_Glyph( glyph ); + *the_glyph = FT_GLYPH( bitmap ); + Exit: + if ( error && bitmap ) + FT_Done_Glyph( FT_GLYPH( bitmap ) ); + return error; + Bad: + error = FT_Err_Invalid_Argument; + goto Exit; + } +/* documentation is in ftglyph.h */ + FT_EXPORT_DEF( void ) + FT_Done_Glyph( FT_Glyph glyph ) + { + if ( glyph ) + { + FT_Memory memory = glyph->library->memory; + const FT_Glyph_Class* clazz = glyph->clazz; + if ( clazz->glyph_done ) + clazz->glyph_done( glyph ); + FT_FREE( glyph ); + } + } +/* END */ +/***************************************************************************/ +/* */ +/* ftbitmap.c */ +/* */ +/* FreeType utility functions for bitmaps (body). */ +/* */ +/* Copyright 2004-2009, 2011 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. */ +/* */ +/***************************************************************************/ + static + const FT_Bitmap null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 }; +/* documentation is in ftbitmap.h */ + FT_EXPORT_DEF( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ) + { + *abitmap = null_bitmap; + } +/* documentation is in ftbitmap.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target) + { + FT_Memory memory = library->memory; + FT_Error error = FT_Err_Ok; + FT_Int pitch = source->pitch; + FT_ULong size; + if ( source == target ) + return FT_Err_Ok; + if ( source->buffer == NULL ) + { + *target = *source; + return FT_Err_Ok; + } + if ( pitch < 0 ) + pitch = -pitch; + size = (FT_ULong)( pitch * source->rows ); + if ( target->buffer ) + { + FT_Int target_pitch = target->pitch; + FT_ULong target_size; + if ( target_pitch < 0 ) + target_pitch = -target_pitch; + target_size = (FT_ULong)( target_pitch * target->rows ); + if ( target_size != size ) + (void)FT_QREALLOC( target->buffer, target_size, size ); + } + else + (void)FT_QALLOC( target->buffer, size ); + if ( !error ) + { + unsigned char *p; + p = target->buffer; + *target = *source; + target->buffer = p; + FT_MEM_COPY( target->buffer, source->buffer, size ); + } + return error; + } + static FT_Error + ft_bitmap_assure_buffer( FT_Memory memory, + FT_Bitmap* bitmap, + FT_UInt xpixels, + FT_UInt ypixels ) + { + FT_Error error; + int pitch; + int new_pitch; + FT_UInt bpp; + FT_Int i, width, height; + unsigned char* buffer = NULL; + width = bitmap->width; + height = bitmap->rows; + pitch = bitmap->pitch; + if ( pitch < 0 ) + pitch = -pitch; + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + bpp = 1; + new_pitch = ( width + xpixels + 7 ) >> 3; + break; + case FT_PIXEL_MODE_GRAY2: + bpp = 2; + new_pitch = ( width + xpixels + 3 ) >> 2; + break; + case FT_PIXEL_MODE_GRAY4: + bpp = 4; + new_pitch = ( width + xpixels + 1 ) >> 1; + break; + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + bpp = 8; + new_pitch = ( width + xpixels ); + break; + default: + return FT_Err_Invalid_Glyph_Format; + } +/* if no need to allocate memory */ + if ( ypixels == 0 && new_pitch <= pitch ) + { +/* zero the padding */ + FT_Int bit_width = pitch * 8; + FT_Int bit_last = ( width + xpixels ) * bpp; + if ( bit_last < bit_width ) + { + FT_Byte* line = bitmap->buffer + ( bit_last >> 3 ); + FT_Byte* end = bitmap->buffer + pitch; + FT_Int shift = bit_last & 7; + FT_UInt mask = 0xFF00U >> shift; + FT_Int count = height; + for ( ; count > 0; count--, line += pitch, end += pitch ) + { + FT_Byte* write = line; + if ( shift > 0 ) + { + write[0] = (FT_Byte)( write[0] & mask ); + write++; + } + if ( write < end ) + FT_MEM_ZERO( write, end-write ); + } + } + return FT_Err_Ok; + } + if ( FT_QALLOC_MULT( buffer, new_pitch, bitmap->rows + ypixels ) ) + return error; + if ( bitmap->pitch > 0 ) + { + FT_Int len = ( width * bpp + 7 ) >> 3; + for ( i = 0; i < bitmap->rows; i++ ) + FT_MEM_COPY( buffer + new_pitch * ( ypixels + i ), + bitmap->buffer + pitch * i, len ); + } + else + { + FT_Int len = ( width * bpp + 7 ) >> 3; + for ( i = 0; i < bitmap->rows; i++ ) + FT_MEM_COPY( buffer + new_pitch * i, + bitmap->buffer + pitch * i, len ); + } + FT_FREE( bitmap->buffer ); + bitmap->buffer = buffer; + if ( bitmap->pitch < 0 ) + new_pitch = -new_pitch; +/* set pitch only, width and height are left untouched */ + bitmap->pitch = new_pitch; + return FT_Err_Ok; + } +/* documentation is in ftbitmap.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ) + { + FT_Error error; + unsigned char* p; + FT_Int i, x, y, pitch; + FT_Int xstr, ystr; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !bitmap || !bitmap->buffer ) + return FT_Err_Invalid_Argument; + if ( ( ( FT_PIX_ROUND( xStrength ) >> 6 ) > FT_INT_MAX ) || + ( ( FT_PIX_ROUND( yStrength ) >> 6 ) > FT_INT_MAX ) ) + return FT_Err_Invalid_Argument; + xstr = (FT_Int)FT_PIX_ROUND( xStrength ) >> 6; + ystr = (FT_Int)FT_PIX_ROUND( yStrength ) >> 6; + if ( xstr == 0 && ystr == 0 ) + return FT_Err_Ok; + else if ( xstr < 0 || ystr < 0 ) + return FT_Err_Invalid_Argument; + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + { + FT_Bitmap tmp; + FT_Int align; + if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY2 ) + align = ( bitmap->width + xstr + 3 ) / 4; + else + align = ( bitmap->width + xstr + 1 ) / 2; + FT_Bitmap_New( &tmp ); + error = FT_Bitmap_Convert( library, bitmap, &tmp, align ); + if ( error ) + return error; + FT_Bitmap_Done( library, bitmap ); + *bitmap = tmp; + } + break; + case FT_PIXEL_MODE_MONO: + if ( xstr > 8 ) + xstr = 8; + break; + case FT_PIXEL_MODE_LCD: + xstr *= 3; + break; + case FT_PIXEL_MODE_LCD_V: + ystr *= 3; + break; + } + error = ft_bitmap_assure_buffer( library->memory, bitmap, xstr, ystr ); + if ( error ) + return error; + pitch = bitmap->pitch; + if ( pitch > 0 ) + p = bitmap->buffer + pitch * ystr; + else + { + pitch = -pitch; + p = bitmap->buffer + pitch * ( bitmap->rows - 1 ); + } +/* for each row */ + for ( y = 0; y < bitmap->rows ; y++ ) + { +/* + * Horizontally: + * + * From the last pixel on, make each pixel or'ed with the + * `xstr' pixels before it. + */ + for ( x = pitch - 1; x >= 0; x-- ) + { + unsigned char tmp; + tmp = p[x]; + for ( i = 1; i <= xstr; i++ ) + { + if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) + { + p[x] |= tmp >> i; +/* the maximum value of 8 for `xstr' comes from here */ + if ( x > 0 ) + p[x] |= p[x - 1] << ( 8 - i ); +#if 0 + if ( p[x] == 0xff ) + break; +#endif + } + else + { + if ( x - i >= 0 ) + { + if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) + { + p[x] = (unsigned char)(bitmap->num_grays - 1); + break; + } + else + { + p[x] = (unsigned char)(p[x] + p[x-i]); + if ( p[x] == bitmap->num_grays - 1 ) + break; + } + } + else + break; + } + } + } +/* + * Vertically: + * + * Make the above `ystr' rows or'ed with it. + */ + for ( x = 1; x <= ystr; x++ ) + { + unsigned char* q; + q = p - bitmap->pitch * x; + for ( i = 0; i < pitch; i++ ) + q[i] |= p[i]; + } + p += bitmap->pitch; + } + bitmap->width += xstr; + bitmap->rows += ystr; + return FT_Err_Ok; + } +/* documentation is in ftbitmap.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + memory = library->memory; + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + { + FT_Int pad; + FT_Long old_size; + old_size = target->rows * target->pitch; + if ( old_size < 0 ) + old_size = -old_size; + target->pixel_mode = FT_PIXEL_MODE_GRAY; + target->rows = source->rows; + target->width = source->width; + pad = 0; + if ( alignment > 0 ) + { + pad = source->width % alignment; + if ( pad != 0 ) + pad = alignment - pad; + } + target->pitch = source->width + pad; + if ( target->pitch > 0 && + (FT_ULong)target->rows > FT_ULONG_MAX / target->pitch ) + return FT_Err_Invalid_Argument; + if ( target->rows * target->pitch > old_size && + FT_QREALLOC( target->buffer, + old_size, target->rows * target->pitch ) ) + return error; + } + break; + default: + error = FT_Err_Invalid_Argument; + } + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int i; + target->num_grays = 2; + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_Int j; +/* get the full bytes */ + for ( j = source->width >> 3; j > 0; j-- ) + { +/* avoid a byte->int cast on each line */ + FT_Int val = ss[0]; + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); + tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); + tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); + tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); + tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); + tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); + tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); + tt[7] = (FT_Byte)( val & 0x01 ); + tt += 8; + ss += 1; + } +/* get remaining pixels (if any) */ + j = source->width & 7; + if ( j > 0 ) + { + FT_Int val = *ss; + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); + val <<= 1; + tt += 1; + } + } + s += source->pitch; + t += target->pitch; + } + } + break; + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + { + FT_Int width = source->width; + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int s_pitch = source->pitch; + FT_Int t_pitch = target->pitch; + FT_Int i; + target->num_grays = 256; + for ( i = source->rows; i > 0; i-- ) + { + FT_ARRAY_COPY( t, s, width ); + s += s_pitch; + t += t_pitch; + } + } + break; + case FT_PIXEL_MODE_GRAY2: + { + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int i; + target->num_grays = 4; + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_Int j; +/* get the full bytes */ + for ( j = source->width >> 2; j > 0; j-- ) + { + FT_Int val = ss[0]; + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); + tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); + tt[3] = (FT_Byte)( ( val & 0x03 ) ); + ss += 1; + tt += 4; + } + j = source->width & 3; + if ( j > 0 ) + { + FT_Int val = ss[0]; + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + val <<= 2; + tt += 1; + } + } + s += source->pitch; + t += target->pitch; + } + } + break; + case FT_PIXEL_MODE_GRAY4: + { + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int i; + target->num_grays = 16; + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_Int j; +/* get the full bytes */ + for ( j = source->width >> 1; j > 0; j-- ) + { + FT_Int val = ss[0]; + tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); + tt[1] = (FT_Byte)( ( val & 0x0F ) ); + ss += 1; + tt += 2; + } + if ( source->width & 1 ) + tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); + s += source->pitch; + t += target->pitch; + } + } + break; + default: + ; + } + return error; + } +/* documentation is in ftbitmap.h */ + FT_EXPORT_DEF( FT_Error ) + FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot ) + { + if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP && + !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_Bitmap bitmap; + FT_Error error; + FT_Bitmap_New( &bitmap ); + error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap ); + if ( error ) + return error; + slot->bitmap = bitmap; + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + return FT_Err_Ok; + } +/* documentation is in ftbitmap.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ) + { + FT_Memory memory; + if ( !library ) + return FT_Err_Invalid_Library_Handle; + if ( !bitmap ) + return FT_Err_Invalid_Argument; + memory = library->memory; + FT_FREE( bitmap->buffer ); + *bitmap = null_bitmap; + return FT_Err_Ok; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftbdf.c */ +/* */ +/* FreeType API for accessing BDF-specific strings (body). */ +/* */ +/* Copyright 2002, 2003, 2004 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svbdf.h */ +/* */ +/* The FreeType BDF services (specification). */ +/* */ +/* Copyright 2003, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVBDF_H__ +/***************************************************************************/ +/* */ +/* ftbdf.h */ +/* */ +/* FreeType API for accessing BDF-specific strings (specification). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2009 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. */ +/* */ +/***************************************************************************/ +#define __FTBDF_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* bdf_fonts */ +/* */ +/* <Title> */ +/* BDF and PCF Files */ +/* */ +/* <Abstract> */ +/* BDF and PCF specific API. */ +/* */ +/* <Description> */ +/* This section contains the declaration of functions specific to BDF */ +/* and PCF fonts. */ +/* */ +/*************************************************************************/ +/********************************************************************** + * + * @enum: + * FT_PropertyType + * + * @description: + * A list of BDF property types. + * + * @values: + * BDF_PROPERTY_TYPE_NONE :: + * Value~0 is used to indicate a missing property. + * + * BDF_PROPERTY_TYPE_ATOM :: + * Property is a string atom. + * + * BDF_PROPERTY_TYPE_INTEGER :: + * Property is a 32-bit signed integer. + * + * BDF_PROPERTY_TYPE_CARDINAL :: + * Property is a 32-bit unsigned integer. + */ + typedef enum BDF_PropertyType_ + { + BDF_PROPERTY_TYPE_NONE = 0, + BDF_PROPERTY_TYPE_ATOM = 1, + BDF_PROPERTY_TYPE_INTEGER = 2, + BDF_PROPERTY_TYPE_CARDINAL = 3 + } BDF_PropertyType; +/********************************************************************** + * + * @type: + * BDF_Property + * + * @description: + * A handle to a @BDF_PropertyRec structure to model a given + * BDF/PCF property. + */ + typedef struct BDF_PropertyRec_* BDF_Property; +/********************************************************************** + * + * @struct: + * BDF_PropertyRec + * + * @description: + * This structure models a given BDF/PCF property. + * + * @fields: + * type :: + * The property type. + * + * u.atom :: + * The atom string, if type is @BDF_PROPERTY_TYPE_ATOM. + * + * u.integer :: + * A signed integer, if type is @BDF_PROPERTY_TYPE_INTEGER. + * + * u.cardinal :: + * An unsigned integer, if type is @BDF_PROPERTY_TYPE_CARDINAL. + */ + typedef struct BDF_PropertyRec_ + { + BDF_PropertyType type; + union { + const char* atom; + FT_Int32 integer; + FT_UInt32 cardinal; + } u; + } BDF_PropertyRec; +/********************************************************************** + * + * @function: + * FT_Get_BDF_Charset_ID + * + * @description: + * Retrieve a BDF font character set identity, according to + * the BDF specification. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * acharset_encoding :: + * Charset encoding, as a C~string, owned by the face. + * + * acharset_registry :: + * Charset registry, as a C~string, owned by the face. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with BDF faces, returning an error otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Charset_ID( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); +/********************************************************************** + * + * @function: + * FT_Get_BDF_Property + * + * @description: + * Retrieve a BDF property from a BDF or PCF font file. + * + * @input: + * face :: A handle to the input face. + * + * name :: The property name. + * + * @output: + * aproperty :: The property. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function works with BDF _and_ PCF fonts. It returns an error + * otherwise. It also returns an error if the property is not in the + * font. + * + * A `property' is a either key-value pair within the STARTPROPERTIES + * ... ENDPROPERTIES block of a BDF font or a key-value pair from the + * `info->props' array within a `FontRec' structure of a PCF font. + * + * Integer properties are always stored as `signed' within PCF fonts; + * consequently, @BDF_PROPERTY_TYPE_CARDINAL is a possible return value + * for BDF fonts only. + * + * In case of error, `aproperty->type' is always set to + * @BDF_PROPERTY_TYPE_NONE. + */ + FT_EXPORT( FT_Error ) + FT_Get_BDF_Property( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_BDF "bdf" + typedef FT_Error + (*FT_BDF_GetCharsetIdFunc)( FT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ); + typedef FT_Error + (*FT_BDF_GetPropertyFunc)( FT_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ); + FT_DEFINE_SERVICE( BDF ) + { + FT_BDF_GetCharsetIdFunc get_charset_id; + FT_BDF_GetPropertyFunc get_property; + }; +#define FT_DEFINE_SERVICE_BDFRec( class_, \ + get_charset_id_, \ + get_property_ ) \ + static const FT_Service_BDFRec class_ = \ + { \ + get_charset_id_, get_property_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/* 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; + error = FT_Err_Invalid_Argument; + if ( face ) + { + FT_Service_BDF service; + FT_FACE_FIND_SERVICE( face, service, BDF ); + if ( service && service->get_charset_id ) + error = service->get_charset_id( face, &encoding, ®istry ); + } + 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; + error = FT_Err_Invalid_Argument; + aproperty->type = BDF_PROPERTY_TYPE_NONE; + if ( face ) + { + FT_Service_BDF service; + FT_FACE_FIND_SERVICE( face, service, BDF ); + if ( service && service->get_property ) + error = service->get_property( face, prop_name, aproperty ); + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftcid.c */ +/* */ +/* FreeType API for accessing CID font information. */ +/* */ +/* Copyright 2007, 2009 by Derek Clegg, 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftcid.h */ +/* */ +/* FreeType API for accessing CID font information (specification). */ +/* */ +/* Copyright 2007, 2009 by Dereg Clegg, 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. */ +/* */ +/***************************************************************************/ +#define __FTCID_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* cid_fonts */ +/* */ +/* <Title> */ +/* CID Fonts */ +/* */ +/* <Abstract> */ +/* CID-keyed font specific API. */ +/* */ +/* <Description> */ +/* This section contains the declaration of CID-keyed font specific */ +/* functions. */ +/* */ +/*************************************************************************/ +/********************************************************************** + * + * @function: + * FT_Get_CID_Registry_Ordering_Supplement + * + * @description: + * Retrieve the Registry/Ordering/Supplement triple (also known as the + * "R/O/S") from a CID-keyed font. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * registry :: + * The registry, as a C~string, owned by the face. + * + * ordering :: + * The ordering, as a C~string, owned by the face. + * + * supplement :: + * The supplement. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces, returning an error + * otherwise. + * + * @since: + * 2.3.6 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Registry_Ordering_Supplement( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement); +/********************************************************************** + * + * @function: + * FT_Get_CID_Is_Internally_CID_Keyed + * + * @description: + * Retrieve the type of the input face, CID keyed or not. In + * constrast to the @FT_IS_CID_KEYED macro this function returns + * successfully also for CID-keyed fonts in an SNFT wrapper. + * + * @input: + * face :: + * A handle to the input face. + * + * @output: + * is_cid :: + * The type of the face as an @FT_Bool. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, + * returning an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face, + FT_Bool *is_cid ); +/********************************************************************** + * + * @function: + * FT_Get_CID_From_Glyph_Index + * + * @description: + * Retrieve the CID of the input glyph index. + * + * @input: + * face :: + * A handle to the input face. + * + * glyph_index :: + * The input glyph index. + * + * @output: + * cid :: + * The CID as an @FT_UInt. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with CID faces and OpenType fonts, + * returning an error otherwise. + * + * @since: + * 2.3.9 + */ + FT_EXPORT( FT_Error ) + FT_Get_CID_From_Glyph_Index( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svcid.h */ +/* */ +/* The FreeType CID font services (specification). */ +/* */ +/* Copyright 2007, 2009, 2012 by Derek Clegg, 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. */ +/* */ +/***************************************************************************/ +#define __SVCID_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_CID "CID" + typedef FT_Error + (*FT_CID_GetRegistryOrderingSupplementFunc)( FT_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ); + typedef FT_Error + (*FT_CID_GetIsInternallyCIDKeyedFunc)( FT_Face face, + FT_Bool *is_cid ); + typedef FT_Error + (*FT_CID_GetCIDFromGlyphIndexFunc)( FT_Face face, + FT_UInt glyph_index, + FT_UInt *cid ); + FT_DEFINE_SERVICE( CID ) + { + FT_CID_GetRegistryOrderingSupplementFunc get_ros; + FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid; + FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index; + }; +#define FT_DEFINE_SERVICE_CIDREC( class_, \ + get_ros_, \ + get_is_cid_, \ + get_cid_from_glyph_index_ ) \ + static const FT_Service_CIDRec class_ = \ + { \ + get_ros_, get_is_cid_, get_cid_from_glyph_index_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/* 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 */ +/***************************************************************************/ +/* */ +/* ftfstype.c */ +/* */ +/* FreeType utility file to access FSType data (body). */ +/* */ +/* Copyright 2008, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svpsinfo.h */ +/* */ +/* The FreeType PostScript info service (specification). */ +/* */ +/* Copyright 2003, 2004, 2009, 2011, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVPSINFO_H__ +/***************************************************************************/ +/* */ +/* t1types.h */ +/* */ +/* Basic Type1/Type2 type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2004, 2006, 2008, 2009, 2011 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. */ +/* */ +/***************************************************************************/ +#define __T1TYPES_H__ +/***************************************************************************/ +/* */ +/* pshints.h */ +/* */ +/* Interface to Postscript-specific (Type 1 and Type 2) hints */ +/* recorders (specification only). These are used to support native */ +/* T1/T2 hints in the `type1', `cid', and `cff' font drivers. */ +/* */ +/* Copyright 2001-2003, 2005-2007, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __PSHINTS_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** INTERNAL REPRESENTATION OF GLOBALS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct PSH_GlobalsRec_* PSH_Globals; + typedef FT_Error + (*PSH_Globals_NewFunc)( FT_Memory memory, + T1_Private* private_dict, + PSH_Globals* aglobals ); + typedef FT_Error + (*PSH_Globals_SetScaleFunc)( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); + typedef void + (*PSH_Globals_DestroyFunc)( PSH_Globals globals ); + typedef struct PSH_Globals_FuncsRec_ + { + PSH_Globals_NewFunc create; + PSH_Globals_SetScaleFunc set_scale; + PSH_Globals_DestroyFunc destroy; + } PSH_Globals_FuncsRec, *PSH_Globals_Funcs; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PUBLIC TYPE 1 HINTS RECORDER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/************************************************************************* + * + * @type: + * T1_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 1 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T1_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the `open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method (`stem', `stem3', or `reset'). Note that these functions do + * not return an error code. + * + * - Close the recording session by calling the `close' method. It + * returns an error code if the hints were invalid or something + * strange happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * PostScript hinter. + * + */ + typedef struct T1_HintsRec_* T1_Hints; +/************************************************************************* + * + * @type: + * T1_Hints_Funcs + * + * @description: + * A pointer to the @T1_Hints_FuncsRec structure that defines the API of + * a given @T1_Hints object. + * + */ + typedef const struct T1_Hints_FuncsRec_* T1_Hints_Funcs; +/************************************************************************* + * + * @functype: + * T1_Hints_OpenFunc + * + * @description: + * A method of the @T1_Hints class used to prepare it for a new Type 1 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * @note: + * You should always call the @T1_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T1_Hints_OpenFunc)( T1_Hints hints ); +/************************************************************************* + * + * @functype: + * T1_Hints_SetStemFunc + * + * @description: + * A method of the @T1_Hints class used to record a new horizontal or + * vertical stem. This corresponds to the Type 1 `hstem' and `vstem' + * operators. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * coords :: + * Array of 2 coordinates in 16.16 format, used as (position,length) + * stem descriptor. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * `coords[0]' is the absolute stem position (lowest coordinate); + * `coords[1]' is the length. + * + * The length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a `ghost' stem, according to the Type 1 + * specification. + * + * If the length is -21 (corresponding to a bottom ghost stem), then + * the real stem position is `coords[0]+coords[1]'. + * + */ + typedef void + (*T1_Hints_SetStemFunc)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); +/************************************************************************* + * + * @functype: + * T1_Hints_SetStem3Func + * + * @description: + * A method of the @T1_Hints class used to record three + * counter-controlled horizontal or vertical stems at once. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * dimension :: + * 0 for horizontal stems, 1 for vertical ones. + * + * coords :: + * An array of 6 values in 16.16 format, holding 3 (position,length) + * pairs for the counter-controlled stems. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * The lengths cannot be negative (ghost stems are never + * counter-controlled). + * + */ + typedef void + (*T1_Hints_SetStem3Func)( T1_Hints hints, + FT_UInt dimension, + FT_Fixed* coords ); +/************************************************************************* + * + * @functype: + * T1_Hints_ResetFunc + * + * @description: + * A method of the @T1_Hints class used to reset the stems hints in a + * recording session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph in which the + * previously defined hints apply. + * + */ + typedef void + (*T1_Hints_ResetFunc)( T1_Hints hints, + FT_UInt end_point ); +/************************************************************************* + * + * @functype: + * T1_Hints_CloseFunc + * + * @description: + * A method of the @T1_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T1_Hints_CloseFunc)( T1_Hints hints, + FT_UInt end_point ); +/************************************************************************* + * + * @functype: + * T1_Hints_ApplyFunc + * + * @description: + * A method of the @T1_Hints class used to apply hints to the + * corresponding glyph outline. Must be called once all hints have been + * recorded. + * + * @input: + * hints :: + * A handle to the Type 1 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64th of pixels. + * + * The scaling transformation is taken from the `globals' object which + * must correspond to the same font as the glyph. + * + */ + typedef FT_Error + (*T1_Hints_ApplyFunc)( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); +/************************************************************************* + * + * @struct: + * T1_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T1_Hints objects. + * + * @fields: + * hints :: + * A handle to the T1 Hints recorder. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stem :: + * The function to set a simple stem. + * + * stem3 :: + * The function to set counter-controlled stems. + * + * reset :: + * The function to reset stem hints. + * + * apply :: + * The function to apply the hints to the corresponding glyph outline. + * + */ + typedef struct T1_Hints_FuncsRec_ + { + T1_Hints hints; + T1_Hints_OpenFunc open; + T1_Hints_CloseFunc close; + T1_Hints_SetStemFunc stem; + T1_Hints_SetStem3Func stem3; + T1_Hints_ResetFunc reset; + T1_Hints_ApplyFunc apply; + } T1_Hints_FuncsRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PUBLIC TYPE 2 HINTS RECORDER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/************************************************************************* + * + * @type: + * T2_Hints + * + * @description: + * This is a handle to an opaque structure used to record glyph hints + * from a Type 2 character glyph character string. + * + * The methods used to operate on this object are defined by the + * @T2_Hints_FuncsRec structure. Recording glyph hints is normally + * achieved through the following scheme: + * + * - Open a new hint recording session by calling the `open' method. + * This rewinds the recorder and prepare it for new input. + * + * - For each hint found in the glyph charstring, call the corresponding + * method (`stems', `hintmask', `counters'). Note that these + * functions do not return an error code. + * + * - Close the recording session by calling the `close' method. It + * returns an error code if the hints were invalid or something + * strange happened (e.g., memory shortage). + * + * The hints accumulated in the object can later be used by the + * Postscript hinter. + * + */ + typedef struct T2_HintsRec_* T2_Hints; +/************************************************************************* + * + * @type: + * T2_Hints_Funcs + * + * @description: + * A pointer to the @T2_Hints_FuncsRec structure that defines the API of + * a given @T2_Hints object. + * + */ + typedef const struct T2_Hints_FuncsRec_* T2_Hints_Funcs; +/************************************************************************* + * + * @functype: + * T2_Hints_OpenFunc + * + * @description: + * A method of the @T2_Hints class used to prepare it for a new Type 2 + * hints recording session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * @note: + * You should always call the @T2_Hints_CloseFunc method in order to + * close an opened recording session. + * + */ + typedef void + (*T2_Hints_OpenFunc)( T2_Hints hints ); +/************************************************************************* + * + * @functype: + * T2_Hints_StemsFunc + * + * @description: + * A method of the @T2_Hints class used to set the table of stems in + * either the vertical or horizontal dimension. Equivalent to the + * `hstem', `vstem', `hstemhm', and `vstemhm' Type 2 operators. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * dimension :: + * 0 for horizontal stems (hstem), 1 for vertical ones (vstem). + * + * count :: + * The number of stems. + * + * coords :: + * An array of `count' (position,length) pairs in 16.16 format. + * + * @note: + * Use vertical coordinates (y) for horizontal stems (dim=0). Use + * horizontal coordinates (x) for vertical stems (dim=1). + * + * There are `2*count' elements in the `coords' array. Each even + * element is an absolute position in font units, each odd element is a + * length in font units. + * + * A length can be negative, in which case it must be either -20 or + * -21. It is interpreted as a `ghost' stem, according to the Type 1 + * specification. + * + */ + typedef void + (*T2_Hints_StemsFunc)( T2_Hints hints, + FT_UInt dimension, + FT_UInt count, + FT_Fixed* coordinates ); +/************************************************************************* + * + * @functype: + * T2_Hints_MaskFunc + * + * @description: + * A method of the @T2_Hints class used to set a given hintmask (this + * corresponds to the `hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The glyph index of the last point to which the previously defined + * or activated hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point' should be 0. + * + * `bit_count' is the number of meaningful bits in the `bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The `bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_MaskFunc)( T2_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ); +/************************************************************************* + * + * @functype: + * T2_Hints_CounterFunc + * + * @description: + * A method of the @T2_Hints class used to set a given counter mask + * (this corresponds to the `hintmask' Type 2 operator). + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * A glyph index of the last point to which the previously defined or + * active hints apply. + * + * bit_count :: + * The number of bits in the hint mask. + * + * bytes :: + * An array of bytes modelling the hint mask. + * + * @note: + * If the hintmask starts the charstring (before any glyph point + * definition), the value of `end_point' should be 0. + * + * `bit_count' is the number of meaningful bits in the `bytes' array; it + * must be equal to the total number of hints defined so far (i.e., + * horizontal+verticals). + * + * The `bytes' array can come directly from the Type 2 charstring and + * respects the same format. + * + */ + typedef void + (*T2_Hints_CounterFunc)( T2_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ); +/************************************************************************* + * + * @functype: + * T2_Hints_CloseFunc + * + * @description: + * A method of the @T2_Hints class used to close a hint recording + * session. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * end_point :: + * The index of the last point in the input glyph. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * The error code is set to indicate that an error occurred during the + * recording session. + * + */ + typedef FT_Error + (*T2_Hints_CloseFunc)( T2_Hints hints, + FT_UInt end_point ); +/************************************************************************* + * + * @functype: + * T2_Hints_ApplyFunc + * + * @description: + * A method of the @T2_Hints class used to apply hints to the + * corresponding glyph outline. Must be called after the `close' + * method. + * + * @input: + * hints :: + * A handle to the Type 2 hints recorder. + * + * outline :: + * A pointer to the target outline descriptor. + * + * globals :: + * The hinter globals for this font. + * + * hint_mode :: + * Hinting information. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * On input, all points within the outline are in font coordinates. On + * output, they are in 1/64th of pixels. + * + * The scaling transformation is taken from the `globals' object which + * must correspond to the same font than the glyph. + * + */ + typedef FT_Error + (*T2_Hints_ApplyFunc)( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); +/************************************************************************* + * + * @struct: + * T2_Hints_FuncsRec + * + * @description: + * The structure used to provide the API to @T2_Hints objects. + * + * @fields: + * hints :: + * A handle to the T2 hints recorder object. + * + * open :: + * The function to open a recording session. + * + * close :: + * The function to close a recording session. + * + * stems :: + * The function to set the dimension's stems table. + * + * hintmask :: + * The function to set hint masks. + * + * counter :: + * The function to set counter masks. + * + * apply :: + * The function to apply the hints on the corresponding glyph outline. + * + */ + typedef struct T2_Hints_FuncsRec_ + { + T2_Hints hints; + T2_Hints_OpenFunc open; + T2_Hints_CloseFunc close; + T2_Hints_StemsFunc stems; + T2_Hints_MaskFunc hintmask; + T2_Hints_CounterFunc counter; + T2_Hints_ApplyFunc apply; + } T2_Hints_FuncsRec; +/* */ + typedef struct PSHinter_Interface_ + { + PSH_Globals_Funcs (*get_globals_funcs)( FT_Module module ); + T1_Hints_Funcs (*get_t1_funcs) ( FT_Module module ); + T2_Hints_Funcs (*get_t2_funcs) ( FT_Module module ); + } PSHinter_Interface; + typedef PSHinter_Interface* PSHinter_Service; +#define FT_DEFINE_PSHINTER_INTERFACE( \ + class_, \ + get_globals_funcs_, \ + get_t1_funcs_, \ + get_t2_funcs_ ) \ + static const PSHinter_Interface class_ = \ + { \ + get_globals_funcs_, \ + get_t1_funcs_, \ + get_t2_funcs_ \ + }; +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* svpscmap.h */ +/* */ +/* The FreeType PostScript charmap service (specification). */ +/* */ +/* Copyright 2003, 2006, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVPSCMAP_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_POSTSCRIPT_CMAPS "postscript-cmaps" +/* + * Adobe glyph name to unicode value. + */ + typedef FT_UInt32 + (*PS_Unicode_ValueFunc)( const char* glyph_name ); +/* + * Macintosh name id to glyph name. NULL if invalid index. + */ + typedef const char* + (*PS_Macintosh_NameFunc)( FT_UInt name_index ); +/* + * Adobe standard string ID to glyph name. NULL if invalid index. + */ + typedef const char* + (*PS_Adobe_Std_StringsFunc)( FT_UInt string_index ); +/* + * Simple unicode -> glyph index charmap built from font glyph names + * table. + */ + typedef struct PS_UniMap_ + { +/* bit 31 set: is glyph variant */ + FT_UInt32 unicode; + FT_UInt glyph_index; + } PS_UniMap; + typedef struct PS_UnicodesRec_* PS_Unicodes; + typedef struct PS_UnicodesRec_ + { + FT_CMapRec cmap; + FT_UInt num_maps; + PS_UniMap* maps; + } PS_UnicodesRec; +/* + * A function which returns a glyph name for a given index. Returns + * NULL if invalid index. + */ + typedef const char* + (*PS_GetGlyphNameFunc)( FT_Pointer data, + FT_UInt string_index ); +/* + * A function used to release the glyph name returned by + * PS_GetGlyphNameFunc, when needed + */ + typedef void + (*PS_FreeGlyphNameFunc)( FT_Pointer data, + const char* name ); + typedef FT_Error + (*PS_Unicodes_InitFunc)( FT_Memory memory, + PS_Unicodes unicodes, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ); + typedef FT_UInt + (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, + FT_UInt32 unicode ); + typedef FT_UInt32 + (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, + FT_UInt32 *unicode ); + FT_DEFINE_SERVICE( PsCMaps ) + { + PS_Unicode_ValueFunc unicode_value; + PS_Unicodes_InitFunc unicodes_init; + PS_Unicodes_CharIndexFunc unicodes_char_index; + PS_Unicodes_CharNextFunc unicodes_char_next; + PS_Macintosh_NameFunc macintosh_name; + PS_Adobe_Std_StringsFunc adobe_std_strings; + const unsigned short* adobe_std_encoding; + const unsigned short* adobe_expert_encoding; + }; +#define FT_DEFINE_SERVICE_PSCMAPSREC( class_, \ + unicode_value_, \ + unicodes_init_, \ + unicodes_char_index_, \ + unicodes_char_next_, \ + macintosh_name_, \ + adobe_std_strings_, \ + adobe_std_encoding_, \ + adobe_expert_encoding_ ) \ + static const FT_Service_PsCMapsRec class_ = \ + { \ + unicode_value_, unicodes_init_, \ + unicodes_char_index_, unicodes_char_next_, macintosh_name_, \ + adobe_std_strings_, adobe_std_encoding_, adobe_expert_encoding_ \ + }; +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Struct> */ +/* T1_EncodingRec */ +/* */ +/* <Description> */ +/* A structure modeling a custom encoding. */ +/* */ +/* <Fields> */ +/* num_chars :: The number of character codes in the encoding. */ +/* Usually 256. */ +/* */ +/* code_first :: The lowest valid character code in the encoding. */ +/* */ +/* code_last :: The highest valid character code in the encoding */ +/* + 1. When equal to code_first there are no valid */ +/* character codes. */ +/* */ +/* char_index :: An array of corresponding glyph indices. */ +/* */ +/* char_name :: An array of corresponding glyph names. */ +/* */ + typedef struct T1_EncodingRecRec_ + { + FT_Int num_chars; + FT_Int code_first; + FT_Int code_last; + FT_UShort* char_index; + FT_String** char_name; + } T1_EncodingRec, *T1_Encoding; +/* used to hold extra data of PS_FontInfoRec that + * cannot be stored in the publicly defined structure. + * + * Note these can't be blended with multiple-masters. + */ + typedef struct PS_FontExtraRec_ + { + FT_UShort fs_type; + } PS_FontExtraRec; + typedef struct T1_FontRec_ + { +/* font info dictionary */ + PS_FontInfoRec font_info; +/* font info extra fields */ + PS_FontExtraRec font_extra; +/* private dictionary */ + PS_PrivateRec private_dict; +/* top-level dictionary */ + FT_String* font_name; + T1_EncodingType encoding_type; + T1_EncodingRec encoding; + FT_Byte* subrs_block; + FT_Byte* charstrings_block; + FT_Byte* glyph_names_block; + FT_Int num_subrs; + FT_Byte** subrs; + FT_PtrDist* subrs_len; + FT_Int num_glyphs; +/* array of glyph names */ + FT_String** glyph_names; +/* array of glyph charstrings */ + FT_Byte** charstrings; + FT_PtrDist* charstrings_len; + FT_Byte paint_type; + FT_Byte font_type; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_BBox font_bbox; + FT_Long font_id; + FT_Fixed stroke_width; + } T1_FontRec, *T1_Font; + typedef struct CID_SubrsRec_ + { + FT_UInt num_subrs; + FT_Byte** code; + } CID_SubrsRec, *CID_Subrs; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** AFM FONT INFORMATION STRUCTURES ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct AFM_TrackKernRec_ + { + FT_Int degree; + FT_Fixed min_ptsize; + FT_Fixed min_kern; + FT_Fixed max_ptsize; + FT_Fixed max_kern; + } AFM_TrackKernRec, *AFM_TrackKern; + typedef struct AFM_KernPairRec_ + { + FT_Int index1; + FT_Int index2; + FT_Int x; + FT_Int y; + } AFM_KernPairRec, *AFM_KernPair; + typedef struct AFM_FontInfoRec_ + { + FT_Bool IsCIDFont; + FT_BBox FontBBox; + FT_Fixed Ascender; + FT_Fixed Descender; +/* free if non-NULL */ + AFM_TrackKern TrackKerns; + FT_Int NumTrackKern; +/* free if non-NULL */ + AFM_KernPair KernPairs; + FT_Int NumKernPair; + } AFM_FontInfoRec, *AFM_FontInfo; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** ***/ +/*** ORIGINAL T1_FACE CLASS DEFINITION ***/ +/*** ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct T1_FaceRec_* T1_Face; + typedef struct CID_FaceRec_* CID_Face; + typedef struct T1_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; +/* support for Multiple Masters fonts */ + PS_Blend blend; +/* undocumented, optional: indices of subroutines that express */ +/* the NormalizeDesignVector and the ConvertDesignVector procedure, */ +/* respectively, as Type 2 charstrings; -1 if keywords not present */ + FT_Int ndv_idx; + FT_Int cdv_idx; +/* undocumented, optional: has the same meaning as len_buildchar */ +/* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ + FT_UInt len_buildchar; + FT_Long* buildchar; +/* since version 2.1 - interface to PostScript hinter */ + const void* pshinter; + } T1_FaceRec; + typedef struct CID_FaceRec_ + { + FT_FaceRec root; + void* psnames; + void* psaux; + CID_FaceInfoRec cid; + PS_FontExtraRec font_extra; +#if 0 + void* afm_data; +#endif + CID_Subrs subrs; +/* since version 2.1 - interface to PostScript hinter */ + void* pshinter; +/* since version 2.1.8, but was originally positioned after `afm_data' */ +/* used if hex data has been converted */ + FT_Byte* binary_data; + FT_Stream cid_stream; + } CID_FaceRec; +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_POSTSCRIPT_INFO "postscript-info" + typedef FT_Error + (*PS_GetFontInfoFunc)( FT_Face face, + PS_FontInfoRec* afont_info ); + typedef FT_Error + (*PS_GetFontExtraFunc)( FT_Face face, + PS_FontExtraRec* afont_extra ); + typedef FT_Int + (*PS_HasGlyphNamesFunc)( FT_Face face ); + typedef FT_Error + (*PS_GetFontPrivateFunc)( FT_Face face, + PS_PrivateRec* afont_private ); + typedef FT_Long + (*PS_GetFontValueFunc)( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ); + FT_DEFINE_SERVICE( PsInfo ) + { + PS_GetFontInfoFunc ps_get_font_info; + PS_GetFontExtraFunc ps_get_font_extra; + PS_HasGlyphNamesFunc ps_has_glyph_names; + PS_GetFontPrivateFunc ps_get_font_private; + PS_GetFontValueFunc ps_get_font_value; + }; +#define FT_DEFINE_SERVICE_PSINFOREC( class_, \ + get_font_info_, \ + ps_get_font_extra_, \ + has_glyph_names_, \ + get_font_private_, \ + get_font_value_ ) \ + static const FT_Service_PsInfoRec class_ = \ + { \ + get_font_info_, ps_get_font_extra_, has_glyph_names_, \ + get_font_private_, get_font_value_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_UShort ) + FT_Get_FSType_Flags( FT_Face face ) + { + TT_OS2* os2; +/* first, try to get the fs_type directly from the font */ + if ( face ) + { + FT_Service_PsInfo service = NULL; + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + if ( service && service->ps_get_font_extra ) + { + PS_FontExtraRec extra; + if ( !service->ps_get_font_extra( face, &extra ) && + extra.fs_type != 0 ) + return extra.fs_type; + } + } +/* look at FSType before fsType for Type42 */ + if ( ( os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, ft_sfnt_os2 ) ) != NULL && + os2->version != 0xFFFFU ) + return os2->fsType; + return 0; + } +/* END */ +/***************************************************************************/ +/* */ +/* fttype1.c */ +/* */ +/* FreeType utility file for PS names support (body). */ +/* */ +/* Copyright 2002-2004, 2011 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. */ +/* */ +/***************************************************************************/ +/* documentation is in t1tables.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + FT_Error error = FT_Err_Invalid_Argument; + if ( face ) + { + FT_Service_PsInfo service = NULL; + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + if ( service && service->ps_get_font_info ) + error = service->ps_get_font_info( face, afont_info ); + } + return error; + } +/* documentation is in t1tables.h */ + FT_EXPORT_DEF( FT_Int ) + FT_Has_PS_Glyph_Names( FT_Face face ) + { + FT_Int result = 0; + FT_Service_PsInfo service = NULL; + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + if ( service && service->ps_has_glyph_names ) + result = service->ps_has_glyph_names( face ); + } + return result; + } +/* documentation is in t1tables.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_PS_Font_Private( FT_Face face, + PS_PrivateRec* afont_private ) + { + FT_Error error = FT_Err_Invalid_Argument; + if ( face ) + { + FT_Service_PsInfo service = NULL; + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + if ( service && service->ps_get_font_private ) + error = service->ps_get_font_private( face, afont_private ); + } + return error; + } +/* documentation is in t1tables.h */ + FT_EXPORT_DEF( FT_Long ) + FT_Get_PS_Font_Value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ) + { + FT_Int result = 0; + FT_Service_PsInfo service = NULL; + if ( face ) + { + FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO ); + if ( service && service->ps_get_font_value ) + result = service->ps_get_font_value( face, key, idx, + value, value_len ); + } + return result; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftgasp.c */ +/* */ +/* Access of TrueType's `gasp' table (body). */ +/* */ +/* Copyright 2007 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftgasp.h */ +/* */ +/* Access of TrueType's `gasp' table (specification). */ +/* */ +/* Copyright 2007, 2008, 2011 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 _FT_GASP_H_ +#define _FT_GASP_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 +/*************************************************************************** + * + * @section: + * gasp_table + * + * @title: + * Gasp Table + * + * @abstract: + * Retrieving TrueType `gasp' table entries. + * + * @description: + * The function @FT_Get_Gasp can be used to query a TrueType or OpenType + * font for specific entries in its `gasp' table, if any. This is + * mainly useful when implementing native TrueType hinting with the + * bytecode interpreter to duplicate the Windows text rendering results. + */ +/************************************************************************* + * + * @enum: + * FT_GASP_XXX + * + * @description: + * A list of values and/or bit-flags returned by the @FT_Get_Gasp + * function. + * + * @values: + * FT_GASP_NO_TABLE :: + * This special value means that there is no GASP table in this face. + * It is up to the client to decide what to do. + * + * FT_GASP_DO_GRIDFIT :: + * Grid-fitting and hinting should be performed at the specified ppem. + * This *really* means TrueType bytecode interpretation. If this bit + * is not set, no hinting gets applied. + * + * FT_GASP_DO_GRAY :: + * Anti-aliased rendering should be performed at the specified ppem. + * If not set, do monochrome rendering. + * + * FT_GASP_SYMMETRIC_SMOOTHING :: + * If set, smoothing along multiple axes must be used with ClearType. + * + * FT_GASP_SYMMETRIC_GRIDFIT :: + * Grid-fitting must be used with ClearType's symmetric smoothing. + * + * @note: + * The bit-flags `FT_GASP_DO_GRIDFIT' and `FT_GASP_DO_GRAY' are to be + * used for standard font rasterization only. Independently of that, + * `FT_GASP_SYMMETRIC_SMOOTHING' and `FT_GASP_SYMMETRIC_GRIDFIT' are to + * be used if ClearType is enabled (and `FT_GASP_DO_GRIDFIT' and + * `FT_GASP_DO_GRAY' are consequently ignored). + * + * `ClearType' is Microsoft's implementation of LCD rendering, partly + * protected by patents. + * + * @since: + * 2.3.0 + */ +#define FT_GASP_NO_TABLE -1 +#define FT_GASP_DO_GRIDFIT 0x01 +#define FT_GASP_DO_GRAY 0x02 +#define FT_GASP_SYMMETRIC_SMOOTHING 0x08 +#define FT_GASP_SYMMETRIC_GRIDFIT 0x10 +/************************************************************************* + * + * @func: + * FT_Get_Gasp + * + * @description: + * Read the `gasp' table from a TrueType or OpenType font file and + * return the entry corresponding to a given character pixel size. + * + * @input: + * face :: The source face handle. + * ppem :: The vertical character pixel size. + * + * @return: + * Bit flags (see @FT_GASP_XXX), or @FT_GASP_NO_TABLE if there is no + * `gasp' table in the face. + * + * @since: + * 2.3.0 + */ + FT_EXPORT( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ); +/* */ +/* _FT_GASP_H_ */ +#endif +/* END */ + FT_EXPORT_DEF( FT_Int ) + FT_Get_Gasp( FT_Face face, + FT_UInt ppem ) + { + FT_Int result = FT_GASP_NO_TABLE; + if ( face && FT_IS_SFNT( face ) ) + { + TT_Face ttface = (TT_Face)face; + if ( ttface->gasp.numRanges > 0 ) + { + TT_GaspRange range = ttface->gasp.gaspRanges; + TT_GaspRange range_end = range + ttface->gasp.numRanges; + while ( ppem > range->maxPPEM ) + { + range++; + if ( range >= range_end ) + goto Exit; + } + result = range->gaspFlag; +/* ensure that we don't have spurious bits */ + if ( ttface->gasp.version == 0 ) + result &= 3; + } + } + Exit: + return result; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftgxval.c */ +/* */ +/* FreeType API for validating TrueTyepGX/AAT tables (body). */ +/* */ +/* Copyright 2004, 2005, 2006, 2010 by */ +/* Masatake YAMATO, Redhat K.K, */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* gxvalid is derived from both gxlayout module and otvalid module. */ +/* Development of gxlayout is supported by the Information-technology */ +/* Promotion Agency(IPA), Japan. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* Copyright 2004, 2005 by */ +/* Masatake YAMATO, Red Hat K.K., */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* gxvalid is derived from both gxlayout module and otvalid module. */ +/* Development of gxlayout is supported by the Information-technology */ +/* Promotion Agency(IPA), Japan. */ +/* */ +/***************************************************************************/ +#define __SVGXVAL_H__ +/***************************************************************************/ +/* */ +/* ftgxval.h */ +/* */ +/* FreeType API for validating TrueTypeGX/AAT tables (specification). */ +/* */ +/* Copyright 2004, 2005, 2006 by */ +/* Masatake YAMATO, Redhat K.K, */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* gxvalid is derived from both gxlayout module and otvalid module. */ +/* Development of gxlayout is supported by the Information-technology */ +/* Promotion Agency(IPA), Japan. */ +/* */ +/***************************************************************************/ +#define __FTGXVAL_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* gx_validation */ +/* */ +/* <Title> */ +/* TrueTypeGX/AAT Validation */ +/* */ +/* <Abstract> */ +/* An API to validate TrueTypeGX/AAT tables. */ +/* */ +/* <Description> */ +/* This section contains the declaration of functions to validate */ +/* some TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd, */ +/* trak, prop, lcar). */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* */ +/* Warning: Use FT_VALIDATE_XXX to validate a table. */ +/* Following definitions are for gxvalid developers. */ +/* */ +/* */ +/*************************************************************************/ +#define FT_VALIDATE_feat_INDEX 0 +#define FT_VALIDATE_mort_INDEX 1 +#define FT_VALIDATE_morx_INDEX 2 +#define FT_VALIDATE_bsln_INDEX 3 +#define FT_VALIDATE_just_INDEX 4 +#define FT_VALIDATE_kern_INDEX 5 +#define FT_VALIDATE_opbd_INDEX 6 +#define FT_VALIDATE_trak_INDEX 7 +#define FT_VALIDATE_prop_INDEX 8 +#define FT_VALIDATE_lcar_INDEX 9 +#define FT_VALIDATE_GX_LAST_INDEX FT_VALIDATE_lcar_INDEX +/************************************************************************* + * + * @macro: + * FT_VALIDATE_GX_LENGTH + * + * @description: + * The number of tables checked in this module. Use it as a parameter + * for the `table-length' argument of function @FT_TrueTypeGX_Validate. + */ +#define FT_VALIDATE_GX_LENGTH (FT_VALIDATE_GX_LAST_INDEX + 1) +/* */ +/* Up to 0x1000 is used by otvalid. + Ox2xxx is reserved for feature OT extension. */ +#define FT_VALIDATE_GX_START 0x4000 +#define FT_VALIDATE_GX_BITFIELD( tag ) \ + ( FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX ) +/********************************************************************** + * + * @enum: + * FT_VALIDATE_GXXXX + * + * @description: + * A list of bit-field constants used with @FT_TrueTypeGX_Validate to + * indicate which TrueTypeGX/AAT Type tables should be validated. + * + * @values: + * FT_VALIDATE_feat :: + * Validate `feat' table. + * + * FT_VALIDATE_mort :: + * Validate `mort' table. + * + * FT_VALIDATE_morx :: + * Validate `morx' table. + * + * FT_VALIDATE_bsln :: + * Validate `bsln' table. + * + * FT_VALIDATE_just :: + * Validate `just' table. + * + * FT_VALIDATE_kern :: + * Validate `kern' table. + * + * FT_VALIDATE_opbd :: + * Validate `opbd' table. + * + * FT_VALIDATE_trak :: + * Validate `trak' table. + * + * FT_VALIDATE_prop :: + * Validate `prop' table. + * + * FT_VALIDATE_lcar :: + * Validate `lcar' table. + * + * FT_VALIDATE_GX :: + * Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern, + * opbd, trak, prop and lcar). + * + */ +#define FT_VALIDATE_feat FT_VALIDATE_GX_BITFIELD( feat ) +#define FT_VALIDATE_mort FT_VALIDATE_GX_BITFIELD( mort ) +#define FT_VALIDATE_morx FT_VALIDATE_GX_BITFIELD( morx ) +#define FT_VALIDATE_bsln FT_VALIDATE_GX_BITFIELD( bsln ) +#define FT_VALIDATE_just FT_VALIDATE_GX_BITFIELD( just ) +#define FT_VALIDATE_kern FT_VALIDATE_GX_BITFIELD( kern ) +#define FT_VALIDATE_opbd FT_VALIDATE_GX_BITFIELD( opbd ) +#define FT_VALIDATE_trak FT_VALIDATE_GX_BITFIELD( trak ) +#define FT_VALIDATE_prop FT_VALIDATE_GX_BITFIELD( prop ) +#define FT_VALIDATE_lcar FT_VALIDATE_GX_BITFIELD( lcar ) +#define FT_VALIDATE_GX ( FT_VALIDATE_feat | \ + FT_VALIDATE_mort | \ + FT_VALIDATE_morx | \ + FT_VALIDATE_bsln | \ + FT_VALIDATE_just | \ + FT_VALIDATE_kern | \ + FT_VALIDATE_opbd | \ + FT_VALIDATE_trak | \ + FT_VALIDATE_prop | \ + FT_VALIDATE_lcar ) +/* */ +/********************************************************************** + * + * @function: + * FT_TrueTypeGX_Validate + * + * @description: + * Validate various TrueTypeGX tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_GXXXX for possible values. + * + * table_length :: + * The size of the `tables' array. Normally, @FT_VALIDATE_GX_LENGTH + * should be passed. + * + * @output: + * tables :: + * The array where all validated sfnt tables are stored. + * The array itself must be allocated by a client. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with TrueTypeGX fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the buffers pointed to by + * each `tables' element, by calling @FT_TrueTypeGX_Free. A NULL value + * indicates that the table either doesn't exist in the font, the + * application hasn't asked for validation, or the validator doesn't have + * the ability to validate the sfnt table. + */ + FT_EXPORT( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); +/* */ +/********************************************************************** + * + * @function: + * FT_TrueTypeGX_Free + * + * @description: + * Free the buffer allocated by TrueTypeGX validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer allocated by + * @FT_TrueTypeGX_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_TrueTypeGX_Validate only. + */ + FT_EXPORT( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ); +/* */ +/********************************************************************** + * + * @enum: + * FT_VALIDATE_CKERNXXX + * + * @description: + * A list of bit-field constants used with @FT_ClassicKern_Validate + * to indicate the classic kern dialect or dialects. If the selected + * type doesn't fit, @FT_ClassicKern_Validate regards the table as + * invalid. + * + * @values: + * FT_VALIDATE_MS :: + * Handle the `kern' table as a classic Microsoft kern table. + * + * FT_VALIDATE_APPLE :: + * Handle the `kern' table as a classic Apple kern table. + * + * FT_VALIDATE_CKERN :: + * Handle the `kern' as either classic Apple or Microsoft kern table. + */ +#define FT_VALIDATE_MS ( FT_VALIDATE_GX_START << 0 ) +#define FT_VALIDATE_APPLE ( FT_VALIDATE_GX_START << 1 ) +#define FT_VALIDATE_CKERN ( FT_VALIDATE_MS | FT_VALIDATE_APPLE ) +/* */ +/********************************************************************** + * + * @function: + * FT_ClassicKern_Validate + * + * @description: + * Validate classic (16-bit format) kern table to assure that the offsets + * and indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without error + * checking (which can be quite time consuming). + * + * The `kern' table validator in @FT_TrueTypeGX_Validate deals with both + * the new 32-bit format and the classic 16-bit format, while + * FT_ClassicKern_Validate only supports the classic 16-bit format. + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the dialect to be validated. See + * @FT_VALIDATE_CKERNXXX for possible values. + * + * @output: + * ckern_table :: + * A pointer to the kern table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * After use, the application should deallocate the buffers pointed to by + * `ckern_table', by calling @FT_ClassicKern_Free. A NULL value + * indicates that the table doesn't exist in the font. + */ + FT_EXPORT( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ); +/* */ +/********************************************************************** + * + * @function: + * FT_ClassicKern_Free + * + * @description: + * Free the buffer allocated by classic Kern validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_ClassicKern_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_ClassicKern_Validate only. + */ + FT_EXPORT( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_GX_VALIDATE "truetypegx-validate" +#define FT_SERVICE_ID_CLASSICKERN_VALIDATE "classickern-validate" + typedef FT_Error + (*gxv_validate_func)( FT_Face face, + FT_UInt gx_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ); + typedef FT_Error + (*ckern_validate_func)( FT_Face face, + FT_UInt ckern_flags, + FT_Bytes *ckern_table ); + FT_DEFINE_SERVICE( GXvalidate ) + { + gxv_validate_func validate; + }; + FT_DEFINE_SERVICE( CKERNvalidate ) + { + ckern_validate_func validate; + }; +/* */ +FT_END_HEADER +/* END */ +/* documentation is in ftgxval.h */ + FT_EXPORT_DEF( FT_Error ) + FT_TrueTypeGX_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes tables[FT_VALIDATE_GX_LENGTH], + FT_UInt table_length ) + { + FT_Service_GXvalidate service; + FT_Error error; + if ( !face ) + { + error = FT_Err_Invalid_Face_Handle; + goto Exit; + } + if ( tables == NULL ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE ); + if ( service ) + error = service->validate( face, + validation_flags, + tables, + table_length ); + else + error = FT_Err_Unimplemented_Feature; + Exit: + return error; + } + FT_EXPORT_DEF( void ) + FT_TrueTypeGX_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + if ( !face ) + return; + memory = FT_FACE_MEMORY( face ); + FT_FREE( table ); + } + FT_EXPORT_DEF( FT_Error ) + FT_ClassicKern_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *ckern_table ) + { + FT_Service_CKERNvalidate service; + FT_Error error; + if ( !face ) + { + error = FT_Err_Invalid_Face_Handle; + goto Exit; + } + if ( ckern_table == NULL ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE ); + if ( service ) + error = service->validate( face, + validation_flags, + ckern_table ); + else + error = FT_Err_Unimplemented_Feature; + Exit: + return error; + } + FT_EXPORT_DEF( void ) + FT_ClassicKern_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + if ( !face ) + return; + memory = FT_FACE_MEMORY( face ); + FT_FREE( table ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ftlcdfil.c */ +/* */ +/* FreeType API for color filtering of subpixel bitmap glyphs (body). */ +/* */ +/* Copyright 2006, 2008, 2009, 2010 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. */ +/* */ +/***************************************************************************/ +/* define USE_LEGACY to implement the legacy filter */ +#define USE_LEGACY +/* FIR filter used by the default and light filters */ + static void + _ft_lcd_filter_fir( FT_Bitmap* bitmap, + FT_Render_Mode mode, + FT_Library library ) + { + FT_Byte* weights = library->lcd_weights; + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; +/* horizontal in-place FIR filter */ + if ( mode == FT_RENDER_MODE_LCD && width >= 4 ) + { + FT_Byte* line = bitmap->buffer; + for ( ; height > 0; height--, line += bitmap->pitch ) + { + FT_UInt fir[5]; + FT_UInt val1, xx; + val1 = line[0]; + fir[0] = weights[2] * val1; + fir[1] = weights[3] * val1; + fir[2] = weights[4] * val1; + fir[3] = 0; + fir[4] = 0; + val1 = line[1]; + fir[0] += weights[1] * val1; + fir[1] += weights[2] * val1; + fir[2] += weights[3] * val1; + fir[3] += weights[4] * val1; + for ( xx = 2; xx < width; xx++ ) + { + FT_UInt val, pix; + val = line[xx]; + pix = fir[0] + weights[0] * val; + fir[0] = fir[1] + weights[1] * val; + fir[1] = fir[2] + weights[2] * val; + fir[2] = fir[3] + weights[3] * val; + fir[3] = weights[4] * val; + pix >>= 8; + pix |= -( pix >> 8 ); + line[xx - 2] = (FT_Byte)pix; + } + { + FT_UInt pix; + pix = fir[0] >> 8; + pix |= -( pix >> 8 ); + line[xx - 2] = (FT_Byte)pix; + pix = fir[1] >> 8; + pix |= -( pix >> 8 ); + line[xx - 1] = (FT_Byte)pix; + } + } + } +/* vertical in-place FIR filter */ + else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 ) + { + FT_Byte* column = bitmap->buffer; + FT_Int pitch = bitmap->pitch; + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column; + FT_UInt fir[5]; + FT_UInt val1, yy; + val1 = col[0]; + fir[0] = weights[2] * val1; + fir[1] = weights[3] * val1; + fir[2] = weights[4] * val1; + fir[3] = 0; + fir[4] = 0; + col += pitch; + val1 = col[0]; + fir[0] += weights[1] * val1; + fir[1] += weights[2] * val1; + fir[2] += weights[3] * val1; + fir[3] += weights[4] * val1; + col += pitch; + for ( yy = 2; yy < height; yy++ ) + { + FT_UInt val, pix; + val = col[0]; + pix = fir[0] + weights[0] * val; + fir[0] = fir[1] + weights[1] * val; + fir[1] = fir[2] + weights[2] * val; + fir[2] = fir[3] + weights[3] * val; + fir[3] = weights[4] * val; + pix >>= 8; + pix |= -( pix >> 8 ); + col[-2 * pitch] = (FT_Byte)pix; + col += pitch; + } + { + FT_UInt pix; + pix = fir[0] >> 8; + pix |= -( pix >> 8 ); + col[-2 * pitch] = (FT_Byte)pix; + pix = fir[1] >> 8; + pix |= -( pix >> 8 ); + col[-pitch] = (FT_Byte)pix; + } + } + } + } +#ifdef USE_LEGACY +/* intra-pixel filter used by the legacy filter */ + static void + _ft_lcd_filter_legacy( FT_Bitmap* bitmap, + FT_Render_Mode mode, + FT_Library library ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + static const int filters[3][3] = + { + { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 }, + { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 }, + { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 } + }; + FT_UNUSED( library ); +/* horizontal in-place intra-pixel filter */ + if ( mode == FT_RENDER_MODE_LCD && width >= 3 ) + { + FT_Byte* line = bitmap->buffer; + for ( ; height > 0; height--, line += pitch ) + { + FT_UInt xx; + for ( xx = 0; xx < width; xx += 3 ) + { + FT_UInt r = 0; + FT_UInt g = 0; + FT_UInt b = 0; + FT_UInt p; + p = line[xx]; + r += filters[0][0] * p; + g += filters[0][1] * p; + b += filters[0][2] * p; + p = line[xx + 1]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + p = line[xx + 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + line[xx] = (FT_Byte)( r / 65536 ); + line[xx + 1] = (FT_Byte)( g / 65536 ); + line[xx + 2] = (FT_Byte)( b / 65536 ); + } + } + } + else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 ) + { + FT_Byte* column = bitmap->buffer; + for ( ; width > 0; width--, column++ ) + { + FT_Byte* col = column; + FT_Byte* col_end = col + height * pitch; + for ( ; col < col_end; col += 3 * pitch ) + { + FT_UInt r = 0; + FT_UInt g = 0; + FT_UInt b = 0; + FT_UInt p; + p = col[0]; + r += filters[0][0] * p; + g += filters[0][1] * p; + b += filters[0][2] * p; + p = col[pitch]; + r += filters[1][0] * p; + g += filters[1][1] * p; + b += filters[1][2] * p; + p = col[pitch * 2]; + r += filters[2][0] * p; + g += filters[2][1] * p; + b += filters[2][2] * p; + col[0] = (FT_Byte)( r / 65536 ); + col[pitch] = (FT_Byte)( g / 65536 ); + col[2 * pitch] = (FT_Byte)( b / 65536 ); + } + } + } + } +/* USE_LEGACY */ +#endif + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilterWeights( FT_Library library, + unsigned char *weights ) + { + if ( !library || !weights ) + return FT_Err_Invalid_Argument; + ft_memcpy( library->lcd_weights, weights, 5 ); + return FT_Err_Ok; + } + FT_EXPORT_DEF( FT_Error ) + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { + static const FT_Byte light_filter[5] = + { 0x00, 0x55, 0x56, 0x55, 0x00 }; +/* the values here sum up to a value larger than 256, */ +/* providing a cheap gamma correction */ + static const FT_Byte default_filter[5] = + { 0x10, 0x40, 0x70, 0x40, 0x10 }; + if ( !library ) + return FT_Err_Invalid_Argument; + switch ( filter ) + { + case FT_LCD_FILTER_NONE: + library->lcd_filter_func = NULL; + library->lcd_extra = 0; + break; + case FT_LCD_FILTER_DEFAULT: +#if defined( FT_FORCE_LEGACY_LCD_FILTER ) + library->lcd_filter_func = _ft_lcd_filter_legacy; + library->lcd_extra = 0; +#elif defined( FT_FORCE_LIGHT_LCD_FILTER ) + ft_memcpy( library->lcd_weights, light_filter, 5 ); + library->lcd_filter_func = _ft_lcd_filter_fir; + library->lcd_extra = 2; +#else + ft_memcpy( library->lcd_weights, default_filter, 5 ); + library->lcd_filter_func = _ft_lcd_filter_fir; + library->lcd_extra = 2; +#endif + break; + case FT_LCD_FILTER_LIGHT: + ft_memcpy( library->lcd_weights, light_filter, 5 ); + library->lcd_filter_func = _ft_lcd_filter_fir; + library->lcd_extra = 2; + break; +#ifdef USE_LEGACY + case FT_LCD_FILTER_LEGACY: + library->lcd_filter_func = _ft_lcd_filter_legacy; + library->lcd_extra = 0; + break; +#endif + default: + return FT_Err_Invalid_Argument; + } + library->lcd_filter = filter; + return FT_Err_Ok; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftmm.c */ +/* */ +/* Multiple Master font support (body). */ +/* */ +/* Copyright 1996-2001, 2003, 2004, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svmm.h */ +/* */ +/* The FreeType Multiple Masters and GX var services (specification). */ +/* */ +/* Copyright 2003, 2004, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __SVMM_H__ +FT_BEGIN_HEADER +/* + * A service used to manage multiple-masters data in a given face. + * + * See the related APIs in `ftmm.h' (FT_MULTIPLE_MASTERS_H). + * + */ +#define FT_SERVICE_ID_MULTI_MASTERS "multi-masters" + typedef FT_Error + (*FT_Get_MM_Func)( FT_Face face, + FT_Multi_Master* master ); + typedef FT_Error + (*FT_Get_MM_Var_Func)( FT_Face face, + FT_MM_Var* *master ); + typedef FT_Error + (*FT_Set_MM_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + typedef FT_Error + (*FT_Set_Var_Design_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + typedef FT_Error + (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ); + FT_DEFINE_SERVICE( MultiMasters ) + { + FT_Get_MM_Func get_mm; + FT_Set_MM_Design_Func set_mm_design; + FT_Set_MM_Blend_Func set_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + }; +#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_var_, \ + set_var_design_ ) \ + static const FT_Service_MultiMastersRec class_ = \ + { \ + get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_ \ + }; +/* */ +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_mm + static FT_Error + ft_face_get_mm_service( FT_Face face, + FT_Service_MultiMasters *aservice ) + { + FT_Error error; + *aservice = NULL; + if ( !face ) + return FT_Err_Invalid_Face_Handle; + error = FT_Err_Invalid_Argument; + if ( FT_HAS_MULTIPLE_MASTERS( face ) ) + { + FT_FACE_LOOKUP_SERVICE( face, + *aservice, + MULTI_MASTERS ); + if ( *aservice ) + error = FT_Err_Ok; + } + return error; + } +/* documentation is in ftmm.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_Multi_Master( FT_Face face, + FT_Multi_Master *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->get_mm ) + error = service->get_mm( face, amaster ); + } + return error; + } +/* documentation is in ftmm.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_Var( FT_Face face, + FT_MM_Var* *amaster ) + { + FT_Error error; + FT_Service_MultiMasters service; + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->get_mm_var ) + error = service->get_mm_var( face, amaster ); + } + return error; + } +/* documentation is in ftmm.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_mm_design ) + error = service->set_mm_design( face, num_coords, coords ); + } + return error; + } +/* documentation is in ftmm.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Design_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_var_design ) + error = service->set_var_design( face, num_coords, coords ); + } + return error; + } +/* documentation is in ftmm.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_mm_blend ) + error = service->set_mm_blend( face, num_coords, coords ); + } + return error; + } +/* documentation is in ftmm.h */ +/* This is exactly the same as the previous function. It exists for */ +/* orthogonality. */ + FT_EXPORT_DEF( FT_Error ) + FT_Set_Var_Blend_Coordinates( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error; + FT_Service_MultiMasters service; + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_Err_Invalid_Argument; + if ( service->set_mm_blend ) + error = service->set_mm_blend( face, num_coords, coords ); + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftotval.c */ +/* */ +/* FreeType API for validating OpenType tables (body). */ +/* */ +/* Copyright 2004, 2006, 2008, 2010 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svotval.h */ +/* */ +/* The FreeType OpenType validation service (specification). */ +/* */ +/* Copyright 2004, 2006 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. */ +/* */ +/***************************************************************************/ +#define __SVOTVAL_H__ +/***************************************************************************/ +/* */ +/* ftotval.h */ +/* */ +/* FreeType API for validating OpenType tables (specification). */ +/* */ +/* Copyright 2004, 2005, 2006, 2007 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* */ +/* Warning: This module might be moved to a different library in the */ +/* future to avoid a tight dependency between FreeType and the */ +/* OpenType specification. */ +/* */ +/* */ +/***************************************************************************/ +#define __FTOTVAL_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* ot_validation */ +/* */ +/* <Title> */ +/* OpenType Validation */ +/* */ +/* <Abstract> */ +/* An API to validate OpenType tables. */ +/* */ +/* <Description> */ +/* This section contains the declaration of functions to validate */ +/* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). */ +/* */ +/*************************************************************************/ +/********************************************************************** + * + * @enum: + * FT_VALIDATE_OTXXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_MATH :: + * Validate MATH table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF, MATH). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 +#define FT_VALIDATE_MATH 0x2000 +#define FT_VALIDATE_OT FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF | \ + FT_VALIDATE_MATH +/* */ +/********************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_OTXXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * @FT_OpenType_Free. A NULL value indicates that the table either + * doesn't exist in the font, or the application hasn't asked for + * validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); +/* */ +/********************************************************************** + * + * @function: + * FT_OpenType_Free + * + * @description: + * Free the buffer allocated by OpenType validator. + * + * @input: + * face :: + * A handle to the input face. + * + * table :: + * The pointer to the buffer that is allocated by + * @FT_OpenType_Validate. + * + * @note: + * This function must be used to free the buffer allocated by + * @FT_OpenType_Validate only. + */ + FT_EXPORT( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" + typedef FT_Error + (*otv_validate_func)( FT_Face volatile face, + FT_UInt ot_flags, + FT_Bytes *base, + FT_Bytes *gdef, + FT_Bytes *gpos, + FT_Bytes *gsub, + FT_Bytes *jstf ); + FT_DEFINE_SERVICE( OTvalidate ) + { + otv_validate_func validate; + }; +/* */ +FT_END_HEADER +/* END */ +/* documentation is in ftotval.h */ + FT_EXPORT_DEF( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ) + { + FT_Service_OTvalidate service; + FT_Error error; + if ( !face ) + { + error = FT_Err_Invalid_Face_Handle; + goto Exit; + } + if ( !( BASE_table && + GDEF_table && + GPOS_table && + GSUB_table && + JSTF_table ) ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE ); + if ( service ) + error = service->validate( face, + validation_flags, + BASE_table, + GDEF_table, + GPOS_table, + GSUB_table, + JSTF_table ); + else + error = FT_Err_Unimplemented_Feature; + Exit: + return error; + } + FT_EXPORT_DEF( void ) + FT_OpenType_Free( FT_Face face, + FT_Bytes table ) + { + FT_Memory memory; + if ( !face ) + return; + memory = FT_FACE_MEMORY( face ); + FT_FREE( table ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ftpatent.c */ +/* */ +/* FreeType API for checking patented TrueType bytecode instructions */ +/* (body). */ +/* */ +/* Copyright 2007, 2008, 2010 by David Turner. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svttglyf.h */ +/* */ +/* The FreeType TrueType glyph service. */ +/* */ +/* Copyright 2007, 2009, 2012 by David Turner. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __SVTTGLYF_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_TT_GLYF "tt-glyf" + typedef FT_ULong + (*TT_Glyf_GetLocationFunc)( FT_Face face, + FT_UInt gindex, + FT_ULong *psize ); + FT_DEFINE_SERVICE( TTGlyf ) + { + TT_Glyf_GetLocationFunc get_location; + }; +#define FT_DEFINE_SERVICE_TTGLYFREC( class_, get_location_ ) \ + static const FT_Service_TTGlyfRec class_ = \ + { \ + get_location_ \ + }; +/* */ +FT_END_HEADER +/* END */ + static FT_Bool + _tt_check_patents_in_range( FT_Stream stream, + FT_ULong size ) + { + FT_Bool result = FALSE; + FT_Error error; + FT_Bytes p, end; + if ( FT_FRAME_ENTER( size ) ) + return 0; + p = stream->cursor; + end = p + size; + while ( p < end ) + { + switch (p[0]) + { +/* SPvTL // */ + case 0x06: +/* SPvTL + */ + case 0x07: +/* SFvTL // */ + case 0x08: +/* SFvTL + */ + case 0x09: +/* SPvFS */ + case 0x0A: +/* SFvFS */ + case 0x0B: + result = TRUE; + goto Exit; + case 0x40: + if ( p + 1 >= end ) + goto Exit; + p += p[1] + 2; + break; + case 0x41: + if ( p + 1 >= end ) + goto Exit; + p += p[1] * 2 + 2; + break; +/* DELTAP2 */ + case 0x71: +/* DELTAP3 */ + case 0x72: +/* DELTAC0 */ + case 0x73: +/* DELTAC1 */ + case 0x74: +/* DELTAC2 */ + case 0x75: + result = TRUE; + goto Exit; + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + p += ( p[0] - 0xB0 ) + 2; + break; + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + p += ( p[0] - 0xB8 ) * 2 + 3; + break; + default: + p += 1; + break; + } + } + Exit: + FT_UNUSED( error ); + FT_FRAME_EXIT(); + return result; + } + static FT_Bool + _tt_check_patents_in_table( FT_Face face, + FT_ULong tag ) + { + FT_Stream stream = face->stream; + FT_Error error = FT_Err_Ok; + FT_Service_SFNT_Table service; + FT_Bool result = FALSE; + FT_FACE_FIND_SERVICE( face, service, SFNT_TABLE ); + if ( service ) + { + FT_UInt i = 0; + FT_ULong tag_i = 0, offset_i = 0, length_i = 0; + for ( i = 0; !error && tag_i != tag ; i++ ) + error = service->table_info( face, i, + &tag_i, &offset_i, &length_i ); + if ( error || + FT_STREAM_SEEK( offset_i ) ) + goto Exit; + result = _tt_check_patents_in_range( stream, length_i ); + } + Exit: + return result; + } + static FT_Bool + _tt_face_check_patents( FT_Face face ) + { + FT_Stream stream = face->stream; + FT_UInt gindex; + FT_Error error; + FT_Bool result; + FT_Service_TTGlyf service; + result = _tt_check_patents_in_table( face, TTAG_fpgm ); + if ( result ) + goto Exit; + result = _tt_check_patents_in_table( face, TTAG_prep ); + if ( result ) + goto Exit; + FT_FACE_FIND_SERVICE( face, service, TT_GLYF ); + if ( service == NULL ) + goto Exit; + for ( gindex = 0; gindex < (FT_UInt)face->num_glyphs; gindex++ ) + { + FT_ULong offset, num_ins, size; + FT_Int num_contours; + offset = service->get_location( face, gindex, &size ); + if ( size == 0 ) + continue; + if ( FT_STREAM_SEEK( offset ) || + FT_READ_SHORT( num_contours ) ) + continue; +/* simple glyph */ + if ( num_contours >= 0 ) + { + if ( FT_STREAM_SKIP( 8 + num_contours * 2 ) ) + continue; + } +/* compound glyph */ + else + { + FT_Bool has_instr = 0; + if ( FT_STREAM_SKIP( 8 ) ) + continue; +/* now read each component */ + for (;;) + { + FT_UInt flags, toskip; + if( FT_READ_USHORT( flags ) ) + break; + toskip = 2 + 1 + 1; +/* ARGS_ARE_WORDS */ + if ( ( flags & ( 1 << 0 ) ) != 0 ) + toskip += 2; +/* WE_HAVE_A_SCALE */ + if ( ( flags & ( 1 << 3 ) ) != 0 ) + toskip += 2; +/* WE_HAVE_X_Y_SCALE */ + else if ( ( flags & ( 1 << 6 ) ) != 0 ) + toskip += 4; +/* WE_HAVE_A_2x2 */ + else if ( ( flags & ( 1 << 7 ) ) != 0 ) + toskip += 8; +/* WE_HAVE_INSTRUCTIONS */ + if ( ( flags & ( 1 << 8 ) ) != 0 ) + has_instr = 1; + if ( FT_STREAM_SKIP( toskip ) ) + goto NextGlyph; +/* MORE_COMPONENTS */ + if ( ( flags & ( 1 << 5 ) ) == 0 ) + break; + } + if ( !has_instr ) + goto NextGlyph; + } + if ( FT_READ_USHORT( num_ins ) ) + continue; + result = _tt_check_patents_in_range( stream, num_ins ); + if ( result ) + goto Exit; + NextGlyph: + ; + } + Exit: + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Bool ) + FT_Face_CheckTrueTypePatents( FT_Face face ) + { + FT_Bool result = FALSE; + if ( face && FT_IS_SFNT( face ) ) + result = _tt_face_check_patents( face ); + return result; + } +/* documentation is in freetype.h */ + FT_EXPORT_DEF( FT_Bool ) + FT_Face_SetUnpatentedHinting( FT_Face face, + FT_Bool value ) + { + FT_Bool result = FALSE; +#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ + !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) + if ( face && FT_IS_SFNT( face ) ) + { + result = !face->internal->ignore_unpatented_hinter; + face->internal->ignore_unpatented_hinter = !value; + } +#else + FT_UNUSED( face ); + FT_UNUSED( value ); +#endif + return result; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftpfr.c */ +/* */ +/* FreeType API for accessing PFR-specific data (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2008, 2010 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* svpfr.h */ +/* */ +/* Internal PFR service functions (specification). */ +/* */ +/* Copyright 2003, 2006 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. */ +/* */ +/***************************************************************************/ +#define __SVPFR_H__ +/***************************************************************************/ +/* */ +/* ftpfr.h */ +/* */ +/* FreeType API for accessing PFR-specific data (specification only). */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2008, 2009 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. */ +/* */ +/***************************************************************************/ +#define __FTPFR_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* pfr_fonts */ +/* */ +/* <Title> */ +/* PFR Fonts */ +/* */ +/* <Abstract> */ +/* PFR/TrueDoc specific API. */ +/* */ +/* <Description> */ +/* This section contains the declaration of PFR-specific functions. */ +/* */ +/*************************************************************************/ +/********************************************************************** + * + * @function: + * FT_Get_PFR_Metrics + * + * @description: + * Return the outline and metrics resolutions of a given PFR face. + * + * @input: + * face :: Handle to the input face. It can be a non-PFR face. + * + * @output: + * aoutline_resolution :: + * Outline resolution. This is equivalent to `face->units_per_EM' + * for non-PFR fonts. Optional (parameter can be NULL). + * + * ametrics_resolution :: + * Metrics resolution. This is equivalent to `outline_resolution' + * for non-PFR fonts. Optional (parameter can be NULL). + * + * ametrics_x_scale :: + * A 16.16 fixed-point number used to scale distance expressed + * in metrics units to device sub-pixels. This is equivalent to + * `face->size->x_scale', but for metrics only. Optional (parameter + * can be NULL). + * + * ametrics_y_scale :: + * Same as `ametrics_x_scale' but for the vertical direction. + * optional (parameter can be NULL). + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If the input face is not a PFR, this function will return an error. + * However, in all cases, it will return valid values. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ); +/********************************************************************** + * + * @function: + * FT_Get_PFR_Kerning + * + * @description: + * Return the kerning pair corresponding to two glyphs in a PFR face. + * The distance is expressed in metrics units, unlike the result of + * @FT_Get_Kerning. + * + * @input: + * face :: A handle to the input face. + * + * left :: Index of the left glyph. + * + * right :: Index of the right glyph. + * + * @output: + * avector :: A kerning vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function always return distances in original PFR metrics + * units. This is unlike @FT_Get_Kerning with the @FT_KERNING_UNSCALED + * mode, which always returns distances converted to outline units. + * + * You can use the value of the `x_scale' and `y_scale' parameters + * returned by @FT_Get_PFR_Metrics to scale these to device sub-pixels. + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); +/********************************************************************** + * + * @function: + * FT_Get_PFR_Advance + * + * @description: + * Return a given glyph advance, expressed in original metrics units, + * from a PFR font. + * + * @input: + * face :: A handle to the input face. + * + * gindex :: The glyph index. + * + * @output: + * aadvance :: The glyph advance in metrics units. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You can use the `x_scale' or `y_scale' results of @FT_Get_PFR_Metrics + * to convert the advance to device sub-pixels (i.e., 1/64th of pixels). + */ + FT_EXPORT( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_PFR_METRICS "pfr-metrics" + typedef FT_Error + (*FT_PFR_GetMetricsFunc)( FT_Face face, + FT_UInt *aoutline, + FT_UInt *ametrics, + FT_Fixed *ax_scale, + FT_Fixed *ay_scale ); + typedef FT_Error + (*FT_PFR_GetKerningFunc)( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ); + typedef FT_Error + (*FT_PFR_GetAdvanceFunc)( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ); + FT_DEFINE_SERVICE( PfrMetrics ) + { + FT_PFR_GetMetricsFunc get_metrics; + FT_PFR_GetKerningFunc get_kerning; + FT_PFR_GetAdvanceFunc get_advance; + }; +/* */ +FT_END_HEADER +/* END */ +/* check the format */ + static FT_Service_PfrMetrics + ft_pfr_check( FT_Face face ) + { + FT_Service_PfrMetrics service = NULL; + if ( face ) + FT_FACE_LOOKUP_SERVICE( face, service, PFR_METRICS ); + return service; + } +/* documentation is in ftpfr.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Metrics( FT_Face face, + FT_UInt *aoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + FT_Error error = FT_Err_Ok; + FT_Service_PfrMetrics service; + if ( !face ) + return FT_Err_Invalid_Argument; + service = ft_pfr_check( face ); + if ( service ) + { + error = service->get_metrics( face, + aoutline_resolution, + ametrics_resolution, + ametrics_x_scale, + ametrics_y_scale ); + } + else + { + FT_Fixed x_scale, y_scale; +/* this is not a PFR font */ + if ( aoutline_resolution ) + *aoutline_resolution = face->units_per_EM; + if ( ametrics_resolution ) + *ametrics_resolution = face->units_per_EM; + x_scale = y_scale = 0x10000L; + if ( face->size ) + { + x_scale = face->size->metrics.x_scale; + y_scale = face->size->metrics.y_scale; + } + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + error = FT_Err_Unknown_File_Format; + } + return error; + } +/* documentation is in ftpfr.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Kerning( FT_Face face, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + FT_Error error; + FT_Service_PfrMetrics service; + if ( !face ) + return FT_Err_Invalid_Argument; + service = ft_pfr_check( face ); + if ( service ) + error = service->get_kerning( face, left, right, avector ); + else + error = FT_Get_Kerning( face, left, right, + FT_KERNING_UNSCALED, avector ); + return error; + } +/* documentation is in ftpfr.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_PFR_Advance( FT_Face face, + FT_UInt gindex, + FT_Pos *aadvance ) + { + FT_Error error; + FT_Service_PfrMetrics service; + service = ft_pfr_check( face ); + if ( service ) + { + error = service->get_advance( face, gindex, aadvance ); + } + else +/* XXX: TODO: PROVIDE ADVANCE-LOADING METHOD TO ALL FONT DRIVERS */ + error = FT_Err_Invalid_Argument; + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftstroke.c */ +/* */ +/* FreeType path stroker (body). */ +/* */ +/* Copyright 2002-2006, 2008-2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftstroke.h */ +/* */ +/* FreeType path stroker (specification). */ +/* */ +/* Copyright 2002-2006, 2008, 2009, 2011-2012 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 __FT_STROKE_H__ +#define __FT_STROKE_H__ +FT_BEGIN_HEADER +/************************************************************************ + * + * @section: + * glyph_stroker + * + * @title: + * Glyph Stroker + * + * @abstract: + * Generating bordered and stroked glyphs. + * + * @description: + * This component generates stroked outlines of a given vectorial + * glyph. It also allows you to retrieve the `outside' and/or the + * `inside' borders of the stroke. + * + * This can be useful to generate `bordered' glyph, i.e., glyphs + * displayed with a coloured (and anti-aliased) border around their + * shape. + */ +/************************************************************** + * + * @type: + * FT_Stroker + * + * @description: + * Opaque handler to a path stroker object. + */ + typedef struct FT_StrokerRec_* FT_Stroker; +/************************************************************** + * + * @enum: + * FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered + * in a stroker. + * + * @values: + * FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used + * to join two lines smoothly. + * + * FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins. The outer corner of + * the joined lines is filled by enclosing the triangular + * region of the corner with a straight line between the + * outer corners of each stroke. + * + * FT_STROKER_LINEJOIN_MITER_FIXED :: + * Used to render mitered line joins, with fixed bevels if the + * miter limit is exceeded. The outer edges of the strokes + * for the two segments are extended until they meet at an + * angle. If the segments meet at too sharp an angle (such + * that the miter would extend from the intersection of the + * segments a distance greater than the product of the miter + * limit value and the border radius), then a bevel join (see + * above) is used instead. This prevents long spikes being + * created. FT_STROKER_LINEJOIN_MITER_FIXED generates a miter + * line join as used in PostScript and PDF. + * + * FT_STROKER_LINEJOIN_MITER_VARIABLE :: + * FT_STROKER_LINEJOIN_MITER :: + * Used to render mitered line joins, with variable bevels if + * the miter limit is exceeded. The intersection of the + * strokes is clipped at a line perpendicular to the bisector + * of the angle between the strokes, at the distance from the + * intersection of the segments equal to the product of the + * miter limit value and the border radius. This prevents + * long spikes being created. + * FT_STROKER_LINEJOIN_MITER_VARIABLE generates a mitered line + * join as used in XPS. FT_STROKER_LINEJOIN_MITER is an alias + * for FT_STROKER_LINEJOIN_MITER_VARIABLE, retained for + * backwards compatibility. + */ + typedef enum FT_Stroker_LineJoin_ + { + FT_STROKER_LINEJOIN_ROUND = 0, + FT_STROKER_LINEJOIN_BEVEL = 1, + FT_STROKER_LINEJOIN_MITER_VARIABLE = 2, + FT_STROKER_LINEJOIN_MITER = FT_STROKER_LINEJOIN_MITER_VARIABLE, + FT_STROKER_LINEJOIN_MITER_FIXED = 3 + } FT_Stroker_LineJoin; +/************************************************************** + * + * @enum: + * FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are + * rendered in a stroke. + * + * @values: + * FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last + * point itself. + * + * FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the + * last point. + * + * FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the + * last point. + */ + typedef enum FT_Stroker_LineCap_ + { + FT_STROKER_LINECAP_BUTT = 0, + FT_STROKER_LINECAP_ROUND, + FT_STROKER_LINECAP_SQUARE + } FT_Stroker_LineCap; +/************************************************************** + * + * @enum: + * FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border + * in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder. + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the `inside' and `outside' + * borders. However, there is no direct mapping between these and the + * `left' and `right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum FT_StrokerBorder_ + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + } FT_StrokerBorder; +/************************************************************** + * + * @function: + * FT_Outline_GetInsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `inside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_RIGHT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); +/************************************************************** + * + * @function: + * FT_Outline_GetOutsideBorder + * + * @description: + * Retrieve the @FT_StrokerBorder value corresponding to the + * `outside' borders of a given outline. + * + * @input: + * outline :: + * The source outline handle. + * + * @return: + * The border index. @FT_STROKER_BORDER_LEFT for empty or invalid + * outlines. + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); +/************************************************************** + * + * @function: + * FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. NULL in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ); +/************************************************************** + * + * @function: + * FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The miter limit for the FT_STROKER_LINEJOIN_MITER_FIXED and + * FT_STROKER_LINEJOIN_MITER_VARIABLE line join styles, + * expressed as 16.16 fixed point value. + * + * @note: + * The radius is expressed in the same units as the outline + * coordinates. + */ + FT_EXPORT( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ); +/************************************************************** + * + * @function: + * FT_Stroker_Rewind + * + * @description: + * Reset a stroker object without changing its attributes. + * You should call this function before beginning a new + * series of calls to @FT_Stroker_BeginSubPath or + * @FT_Stroker_EndSubPath. + * + * @input: + * stroker :: + * The target stroker handle. + */ + FT_EXPORT( void ) + FT_Stroker_Rewind( FT_Stroker stroker ); +/************************************************************** + * + * @function: + * FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * opened :: + * A boolean. If~1, the outline is treated as an open path instead + * of a closed one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `opened' is~0 (the default), the outline is treated as a closed + * path, and the stroker generates two distinct `border' outlines. + * + * If `opened' is~1, the outline is processed as an open path, and the + * stroker generates a single `stroke' outline. + * + * This function calls @FT_Stroker_Rewind automatically. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ); +/************************************************************** + * + * @function: + * FT_Stroker_BeginSubPath + * + * @description: + * Start a new sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the start vector. + * + * open :: + * A boolean. If~1, the sub-path is treated as an open one. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function is useful when you need to stroke a path that is + * not stored as an @FT_Outline object. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ); +/************************************************************** + * + * @function: + * FT_Stroker_EndSubPath + * + * @description: + * Close the current sub-path in the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function after @FT_Stroker_BeginSubPath. + * If the subpath was not `opened', this function `draws' a + * single line segment to the start position when needed. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ); +/************************************************************** + * + * @function: + * FT_Stroker_LineTo + * + * @description: + * `Draw' a single line segment in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ); +/************************************************************** + * + * @function: + * FT_Stroker_ConicTo + * + * @description: + * `Draw' a single quadratic Bézier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control :: + * A pointer to a Bézier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ); +/************************************************************** + * + * @function: + * FT_Stroker_CubicTo + * + * @description: + * `Draw' a single cubic Bézier in the stroker's current sub-path, + * from the last position. + * + * @input: + * stroker :: + * The target stroker handle. + * + * control1 :: + * A pointer to the first Bézier control point. + * + * control2 :: + * A pointer to second Bézier control point. + * + * to :: + * A pointer to the destination point. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * You should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ); +/************************************************************** + * + * @function: + * FT_Stroker_GetBorderCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export one of the `border' or `stroke' + * outlines generated by the stroker. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right'. + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_GetCounts instead if you want to + * retrieve the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); +/************************************************************** + * + * @function: + * FT_Stroker_ExportBorder + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export the corresponding border to your own @FT_Outline + * structure. + * + * Note that this function appends the border points and + * contours to your outline, but does not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * border :: + * The border index. + * + * outline :: + * The target outline handle. + * + * @note: + * Always call this function after @FT_Stroker_GetBorderCounts to + * get sure that there is enough room in your @FT_Outline object to + * receive all new data. + * + * When an outline, or a sub-path, is `closed', the stroker generates + * two independent `border' outlines, named `left' and `right' + * + * When the outline, or a sub-path, is `opened', the stroker merges + * the `border' outlines with caps. The `left' border receives all + * points, while the `right' border becomes empty. + * + * Use the function @FT_Stroker_Export instead if you want to + * retrieve all borders at once. + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); +/************************************************************** + * + * @function: + * FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ); +/************************************************************** + * + * @function: + * FT_Stroker_Export + * + * @description: + * Call this function after @FT_Stroker_GetBorderCounts to + * export all borders to your own @FT_Outline structure. + * + * Note that this function appends the border points and + * contours to your outline, but does not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ + FT_EXPORT( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ); +/************************************************************** + * + * @function: + * FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be NULL. + */ + FT_EXPORT( void ) + FT_Stroker_Done( FT_Stroker stroker ); +/************************************************************** + * + * @function: + * FT_Glyph_Stroke + * + * @description: + * Stroke a given outline glyph object with a given stroker. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + * + * Adding stroke may yield a significantly wider and taller glyph + * depending on how large of a radius was used to stroke the glyph. You + * may need to manually adjust horizontal and vertical advance amounts + * to account for this added size. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ); +/************************************************************** + * + * @function: + * FT_Glyph_StrokeBorder + * + * @description: + * Stroke a given outline glyph object with a given stroker, but + * only return either its inside or outside border. + * + * @inout: + * pglyph :: + * Source glyph handle on input, new glyph handle on output. + * + * @input: + * stroker :: + * A stroker handle. + * + * inside :: + * A Boolean. If~1, return the inside border, otherwise + * the outside border. + * + * destroy :: + * A Boolean. If~1, the source glyph object is destroyed + * on success. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source glyph is untouched in case of error. + * + * Adding stroke may yield a significantly wider and taller glyph + * depending on how large of a radius was used to stroke the glyph. You + * may need to manually adjust horizontal and vertical advance amounts + * to account for this added size. + */ + FT_EXPORT( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ); +/* */ +FT_END_HEADER +/* __FT_STROKE_H__ */ +#endif +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT + : FT_STROKER_BORDER_LEFT; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ) + { + FT_Orientation o = FT_Outline_Get_Orientation( outline ); + return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT + : FT_STROKER_BORDER_RIGHT; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** BEZIER COMPUTATIONS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 ) +#define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 8 ) +#define FT_EPSILON 2 +#define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON ) + static FT_Pos + ft_pos_abs( FT_Pos x ) + { + return x >= 0 ? x : -x; + } + static void + ft_conic_split( FT_Vector* base ) + { + FT_Pos a, b; + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + static FT_Bool + ft_conic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_out ) + { + FT_Vector d1, d2; + FT_Angle theta; + FT_Int close1, close2; + d1.x = base[1].x - base[2].x; + d1.y = base[1].y - base[2].y; + d2.x = base[0].x - base[1].x; + d2.y = base[0].y - base[1].y; + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + if ( close1 ) + { + if ( close2 ) + { +/* basically a point; */ +/* do nothing to retain original direction */ + } + else + { + *angle_in = + *angle_out = FT_Atan2( d2.x, d2.y ); + } + } +/* !close1 */ + else + { + if ( close2 ) + { + *angle_in = + *angle_out = FT_Atan2( d1.x, d1.y ); + } + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d2.x, d2.y ); + } + } + theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) ); + return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD ); + } + static void + ft_cubic_split( FT_Vector* base ) + { + FT_Pos a, b, c, d; + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } +/* Return the average of `angle1' and `angle2'. */ +/* This gives correct result even if `angle1' and `angle2' */ +/* have opposite signs. */ + static FT_Angle + ft_angle_mean( FT_Angle angle1, + FT_Angle angle2 ) + { + return angle1 + FT_Angle_Diff( angle1, angle2 ) / 2; + } + static FT_Bool + ft_cubic_is_small_enough( FT_Vector* base, + FT_Angle *angle_in, + FT_Angle *angle_mid, + FT_Angle *angle_out ) + { + FT_Vector d1, d2, d3; + FT_Angle theta1, theta2; + FT_Int close1, close2, close3; + d1.x = base[2].x - base[3].x; + d1.y = base[2].y - base[3].y; + d2.x = base[1].x - base[2].x; + d2.y = base[1].y - base[2].y; + d3.x = base[0].x - base[1].x; + d3.y = base[0].y - base[1].y; + close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); + close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); + close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y ); + if ( close1 ) + { + if ( close2 ) + { + if ( close3 ) + { +/* basically a point; */ +/* do nothing to retain original direction */ + } +/* !close3 */ + else + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } +/* !close2 */ + else + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d2.x, d2.y ); + } +/* !close3 */ + else + { + *angle_in = + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + } +/* !close1 */ + else + { + if ( close2 ) + { + if ( close3 ) + { + *angle_in = + *angle_mid = + *angle_out = FT_Atan2( d1.x, d1.y ); + } +/* !close3 */ + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + *angle_mid = ft_angle_mean( *angle_in, *angle_out ); + } + } +/* !close2 */ + else + { + if ( close3 ) + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = + *angle_out = FT_Atan2( d2.x, d2.y ); + } +/* !close3 */ + else + { + *angle_in = FT_Atan2( d1.x, d1.y ); + *angle_mid = FT_Atan2( d2.x, d2.y ); + *angle_out = FT_Atan2( d3.x, d3.y ); + } + } + } + theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) ); + theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) ); + return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD && + theta2 < FT_SMALL_CUBIC_THRESHOLD ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** STROKE BORDERS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef enum FT_StrokeTags_ + { +/* on-curve point */ + FT_STROKE_TAG_ON = 1, +/* cubic off-point */ + FT_STROKE_TAG_CUBIC = 2, +/* sub-path start */ + FT_STROKE_TAG_BEGIN = 4, +/* sub-path end */ + FT_STROKE_TAG_END = 8 + } FT_StrokeTags; +#define FT_STROKE_TAG_BEGIN_END ( FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END ) + typedef struct FT_StrokeBorderRec_ + { + FT_UInt num_points; + FT_UInt max_points; + FT_Vector* points; + FT_Byte* tags; +/* TRUE for ends of lineto borders */ + FT_Bool movable; +/* index of current sub-path start point */ + FT_Int start; + FT_Memory memory; + FT_Bool valid; + } FT_StrokeBorderRec, *FT_StrokeBorder; + static FT_Error + ft_stroke_border_grow( FT_StrokeBorder border, + FT_UInt new_points ) + { + FT_UInt old_max = border->max_points; + FT_UInt new_max = border->num_points + new_points; + FT_Error error = FT_Err_Ok; + if ( new_max > old_max ) + { + FT_UInt cur_max = old_max; + FT_Memory memory = border->memory; + while ( cur_max < new_max ) + cur_max += ( cur_max >> 1 ) + 16; + if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) || + FT_RENEW_ARRAY( border->tags, old_max, cur_max ) ) + goto Exit; + border->max_points = cur_max; + } + Exit: + return error; + } + static void + ft_stroke_border_close( FT_StrokeBorder border, + FT_Bool reverse ) + { + FT_UInt start = border->start; + FT_UInt count = border->num_points; + FT_ASSERT( border->start >= 0 ); +/* don't record empty paths! */ + if ( count <= start + 1U ) + border->num_points = start; + else + { +/* copy the last point to the start of this sub-path, since */ +/* it contains the `adjusted' starting coordinates */ + border->num_points = --count; + border->points[start] = border->points[count]; + if ( reverse ) + { +/* reverse the points */ + { + FT_Vector* vec1 = border->points + start + 1; + FT_Vector* vec2 = border->points + count - 1; + for ( ; vec1 < vec2; vec1++, vec2-- ) + { + FT_Vector tmp; + tmp = *vec1; + *vec1 = *vec2; + *vec2 = tmp; + } + } +/* then the tags */ + { + FT_Byte* tag1 = border->tags + start + 1; + FT_Byte* tag2 = border->tags + count - 1; + for ( ; tag1 < tag2; tag1++, tag2-- ) + { + FT_Byte tmp; + tmp = *tag1; + *tag1 = *tag2; + *tag2 = tmp; + } + } + } + border->tags[start ] |= FT_STROKE_TAG_BEGIN; + border->tags[count - 1] |= FT_STROKE_TAG_END; + } + border->start = -1; + border->movable = FALSE; + } + static FT_Error + ft_stroke_border_lineto( FT_StrokeBorder border, + FT_Vector* to, + FT_Bool movable ) + { + FT_Error error = FT_Err_Ok; + FT_ASSERT( border->start >= 0 ); + if ( border->movable ) + { +/* move last point */ + border->points[border->num_points - 1] = *to; + } + else + { +/* don't add zero-length lineto */ + if ( border->num_points > 0 && + FT_IS_SMALL( border->points[border->num_points - 1].x - to->x ) && + FT_IS_SMALL( border->points[border->num_points - 1].y - to->y ) ) + return error; +/* add one point */ + error = ft_stroke_border_grow( border, 1 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + vec[0] = *to; + tag[0] = FT_STROKE_TAG_ON; + border->num_points += 1; + } + } + border->movable = movable; + return error; + } + static FT_Error + ft_stroke_border_conicto( FT_StrokeBorder border, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error; + FT_ASSERT( border->start >= 0 ); + error = ft_stroke_border_grow( border, 2 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + vec[0] = *control; + vec[1] = *to; + tag[0] = 0; + tag[1] = FT_STROKE_TAG_ON; + border->num_points += 2; + } + border->movable = FALSE; + return error; + } + static FT_Error + ft_stroke_border_cubicto( FT_StrokeBorder border, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error; + FT_ASSERT( border->start >= 0 ); + error = ft_stroke_border_grow( border, 3 ); + if ( !error ) + { + FT_Vector* vec = border->points + border->num_points; + FT_Byte* tag = border->tags + border->num_points; + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + tag[0] = FT_STROKE_TAG_CUBIC; + tag[1] = FT_STROKE_TAG_CUBIC; + tag[2] = FT_STROKE_TAG_ON; + border->num_points += 3; + } + border->movable = FALSE; + return error; + } +#define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 ) + static FT_Error + ft_stroke_border_arcto( FT_StrokeBorder border, + FT_Vector* center, + FT_Fixed radius, + FT_Angle angle_start, + FT_Angle angle_diff ) + { + FT_Angle total, angle, step, rotate, next, theta; + FT_Vector a, b, a2, b2; + FT_Fixed length; + FT_Error error = FT_Err_Ok; +/* compute start point */ + FT_Vector_From_Polar( &a, radius, angle_start ); + a.x += center->x; + a.y += center->y; + total = angle_diff; + angle = angle_start; + rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2; + while ( total != 0 ) + { + step = total; + if ( step > FT_ARC_CUBIC_ANGLE ) + step = FT_ARC_CUBIC_ANGLE; + else if ( step < -FT_ARC_CUBIC_ANGLE ) + step = -FT_ARC_CUBIC_ANGLE; + next = angle + step; + theta = step; + if ( theta < 0 ) + theta = -theta; + theta >>= 1; +/* compute end point */ + FT_Vector_From_Polar( &b, radius, next ); + b.x += center->x; + b.y += center->y; +/* compute first and second control points */ + length = FT_MulDiv( radius, FT_Sin( theta ) * 4, + ( 0x10000L + FT_Cos( theta ) ) * 3 ); + FT_Vector_From_Polar( &a2, length, angle + rotate ); + a2.x += a.x; + a2.y += a.y; + FT_Vector_From_Polar( &b2, length, next - rotate ); + b2.x += b.x; + b2.y += b.y; +/* add cubic arc */ + error = ft_stroke_border_cubicto( border, &a2, &b2, &b ); + if ( error ) + break; +/* process the rest of the arc ?? */ + a = b; + total -= step; + angle = next; + } + return error; + } + static FT_Error + ft_stroke_border_moveto( FT_StrokeBorder border, + FT_Vector* to ) + { +/* close current open path if any ? */ + if ( border->start >= 0 ) + ft_stroke_border_close( border, FALSE ); + border->start = border->num_points; + border->movable = FALSE; + return ft_stroke_border_lineto( border, to, FALSE ); + } + static void + ft_stroke_border_init( FT_StrokeBorder border, + FT_Memory memory ) + { + border->memory = memory; + border->points = NULL; + border->tags = NULL; + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + static void + ft_stroke_border_reset( FT_StrokeBorder border ) + { + border->num_points = 0; + border->start = -1; + border->valid = FALSE; + } + static void + ft_stroke_border_done( FT_StrokeBorder border ) + { + FT_Memory memory = border->memory; + FT_FREE( border->points ); + FT_FREE( border->tags ); + border->num_points = 0; + border->max_points = 0; + border->start = -1; + border->valid = FALSE; + } + static FT_Error + ft_stroke_border_get_counts( FT_StrokeBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_Error error = FT_Err_Ok; + FT_UInt num_points = 0; + FT_UInt num_contours = 0; + FT_UInt count = border->num_points; + FT_Vector* point = border->points; + FT_Byte* tags = border->tags; + FT_Int in_contour = 0; + for ( ; count > 0; count--, num_points++, point++, tags++ ) + { + if ( tags[0] & FT_STROKE_TAG_BEGIN ) + { + if ( in_contour != 0 ) + goto Fail; + in_contour = 1; + } + else if ( in_contour == 0 ) + goto Fail; + if ( tags[0] & FT_STROKE_TAG_END ) + { + in_contour = 0; + num_contours++; + } + } + if ( in_contour != 0 ) + goto Fail; + border->valid = TRUE; + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + Fail: + num_points = 0; + num_contours = 0; + goto Exit; + } + static void + ft_stroke_border_export( FT_StrokeBorder border, + FT_Outline* outline ) + { +/* copy point locations */ + FT_ARRAY_COPY( outline->points + outline->n_points, + border->points, + border->num_points ); +/* copy tags */ + { + FT_UInt count = border->num_points; + FT_Byte* read = border->tags; + FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points; + for ( ; count > 0; count--, read++, write++ ) + { + if ( *read & FT_STROKE_TAG_ON ) + *write = FT_CURVE_TAG_ON; + else if ( *read & FT_STROKE_TAG_CUBIC ) + *write = FT_CURVE_TAG_CUBIC; + else + *write = FT_CURVE_TAG_CONIC; + } + } +/* copy contours */ + { + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_Short* write = outline->contours + outline->n_contours; + FT_Short idx = (FT_Short)outline->n_points; + for ( ; count > 0; count--, tags++, idx++ ) + { + if ( *tags & FT_STROKE_TAG_END ) + { + *write++ = idx; + outline->n_contours++; + } + } + } + outline->n_points = (short)( outline->n_points + border->num_points ); + FT_ASSERT( FT_Outline_Check( outline ) == 0 ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** STROKER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI ) + typedef struct FT_StrokerRec_ + { +/* direction into curr join */ + FT_Angle angle_in; +/* direction out of join */ + FT_Angle angle_out; +/* current position */ + FT_Vector center; +/* length of last lineto */ + FT_Fixed line_length; +/* is this the start? */ + FT_Bool first_point; +/* is the subpath open? */ + FT_Bool subpath_open; +/* subpath start direction */ + FT_Angle subpath_angle; +/* subpath start position */ + FT_Vector subpath_start; +/* subpath start lineto len */ + FT_Fixed subpath_line_length; +/* use wide strokes logic? */ + FT_Bool handle_wide_strokes; + FT_Stroker_LineCap line_cap; + FT_Stroker_LineJoin line_join; + FT_Stroker_LineJoin line_join_saved; + FT_Fixed miter_limit; + FT_Fixed radius; + FT_StrokeBorderRec borders[2]; + FT_Library library; + } FT_StrokerRec; +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_New( FT_Library library, + FT_Stroker *astroker ) + { +/* assigned in FT_NEW */ + FT_Error error; + FT_Memory memory; + FT_Stroker stroker = NULL; + if ( !library ) + return FT_Err_Invalid_Argument; + memory = library->memory; + if ( !FT_NEW( stroker ) ) + { + stroker->library = library; + ft_stroke_border_init( &stroker->borders[0], memory ); + ft_stroke_border_init( &stroker->borders[1], memory ); + } + *astroker = stroker; + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( void ) + FT_Stroker_Set( FT_Stroker stroker, + FT_Fixed radius, + FT_Stroker_LineCap line_cap, + FT_Stroker_LineJoin line_join, + FT_Fixed miter_limit ) + { + stroker->radius = radius; + stroker->line_cap = line_cap; + stroker->line_join = line_join; + stroker->miter_limit = miter_limit; +/* ensure miter limit has sensible value */ + if ( stroker->miter_limit < 0x10000 ) + stroker->miter_limit = 0x10000; +/* save line join style: */ +/* line join style can be temporarily changed when stroking curves */ + stroker->line_join_saved = line_join; + FT_Stroker_Rewind( stroker ); + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( void ) + FT_Stroker_Rewind( FT_Stroker stroker ) + { + if ( stroker ) + { + ft_stroke_border_reset( &stroker->borders[0] ); + ft_stroke_border_reset( &stroker->borders[1] ); + } + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( void ) + FT_Stroker_Done( FT_Stroker stroker ) + { + if ( stroker ) + { + FT_Memory memory = stroker->library->memory; + ft_stroke_border_done( &stroker->borders[0] ); + ft_stroke_border_done( &stroker->borders[1] ); + stroker->library = NULL; + FT_FREE( stroker ); + } + } +/* create a circular arc at a corner or cap */ + static FT_Error + ft_stroker_arcto( FT_Stroker stroker, + FT_Int side ) + { + FT_Angle total, rotate; + FT_Fixed radius = stroker->radius; + FT_Error error = FT_Err_Ok; + FT_StrokeBorder border = stroker->borders + side; + rotate = FT_SIDE_TO_ROTATE( side ); + total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( total == FT_ANGLE_PI ) + total = -rotate * 2; + error = ft_stroke_border_arcto( border, + &stroker->center, + radius, + stroker->angle_in + rotate, + total ); + border->movable = FALSE; + return error; + } +/* add a cap at the end of an opened path */ + static FT_Error + ft_stroker_cap( FT_Stroker stroker, + FT_Angle angle, + FT_Int side ) + { + FT_Error error = FT_Err_Ok; + if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND ) + { +/* add a round cap */ + stroker->angle_in = angle; + stroker->angle_out = angle + FT_ANGLE_PI; + error = ft_stroker_arcto( stroker, side ); + } + else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) + { +/* add a square cap */ + FT_Vector delta, delta2; + FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); + FT_Fixed radius = stroker->radius; + FT_StrokeBorder border = stroker->borders + side; + FT_Vector_From_Polar( &delta2, radius, angle + rotate ); + FT_Vector_From_Polar( &delta, radius, angle ); + delta.x += stroker->center.x + delta2.x; + delta.y += stroker->center.y + delta2.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + FT_Vector_From_Polar( &delta2, radius, angle - rotate ); + FT_Vector_From_Polar( &delta, radius, angle ); + delta.x += delta2.x + stroker->center.x; + delta.y += delta2.y + stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + else if ( stroker->line_cap == FT_STROKER_LINECAP_BUTT ) + { +/* add a butt ending */ + FT_Vector delta; + FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); + FT_Fixed radius = stroker->radius; + FT_StrokeBorder border = stroker->borders + side; + FT_Vector_From_Polar( &delta, radius, angle + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + FT_Vector_From_Polar( &delta, radius, angle - rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + Exit: + return error; + } +/* process an inside corner, i.e. compute intersection */ + static FT_Error + ft_stroker_inside( FT_Stroker stroker, + FT_Int side, + FT_Fixed line_length ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Angle phi, theta, rotate; + FT_Fixed length, thcos; + FT_Vector delta; + FT_Error error = FT_Err_Ok; +/* use intersection of lines? */ + FT_Bool intersect; + rotate = FT_SIDE_TO_ROTATE( side ); + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; +/* Only intersect borders if between two lineto's and both */ +/* lines are long enough (line_length is zero for curves). */ + if ( !border->movable || line_length == 0 ) + intersect = FALSE; + else + { +/* compute minimum required length of lines */ + FT_Fixed min_length = ft_pos_abs( FT_MulFix( stroker->radius, + FT_Tan( theta ) ) ); + intersect = FT_BOOL( stroker->line_length >= min_length && + line_length >= min_length ); + } + if ( !intersect ) + { + FT_Vector_From_Polar( &delta, stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + border->movable = FALSE; + } + else + { +/* compute median angle */ + phi = stroker->angle_in + theta; + thcos = FT_Cos( theta ); + length = FT_DivFix( stroker->radius, thcos ); + FT_Vector_From_Polar( &delta, length, phi + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + } + error = ft_stroke_border_lineto( border, &delta, FALSE ); + return error; + } +/* process an outside corner, i.e. compute bevel/miter/round */ + static FT_Error + ft_stroker_outside( FT_Stroker stroker, + FT_Int side, + FT_Fixed line_length ) + { + FT_StrokeBorder border = stroker->borders + side; + FT_Error error; + FT_Angle rotate; + if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND ) + error = ft_stroker_arcto( stroker, side ); + else + { +/* this is a mitered (pointed) or beveled (truncated) corner */ + FT_Fixed sigma = 0, radius = stroker->radius; + FT_Angle theta = 0, phi = 0; + FT_Fixed thcos = 0; + FT_Bool bevel, fixed_bevel; + rotate = FT_SIDE_TO_ROTATE( side ); + bevel = + FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL ); + fixed_bevel = + FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE ); + if ( !bevel ) + { + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + if ( theta == FT_ANGLE_PI ) + { + theta = rotate; + phi = stroker->angle_in; + } + else + { + theta /= 2; + phi = stroker->angle_in + theta + rotate; + } + thcos = FT_Cos( theta ); + sigma = FT_MulFix( stroker->miter_limit, thcos ); +/* is miter limit exceeded? */ + if ( sigma < 0x10000L ) + { +/* don't create variable bevels for very small deviations; */ +/* FT_Sin(x) = 0 for x <= 57 */ + if ( fixed_bevel || ft_pos_abs( theta ) > 57 ) + bevel = TRUE; + } + } +/* this is a bevel (broken angle) */ + if ( bevel ) + { + if ( fixed_bevel ) + { +/* the outer corners are simply joined together */ + FT_Vector delta; +/* add bevel */ + FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } +/* variable bevel */ + else + { +/* the miter is truncated */ + FT_Vector middle, delta; + FT_Fixed length; +/* compute middle point */ + FT_Vector_From_Polar( &middle, + FT_MulFix( radius, stroker->miter_limit ), + phi ); + middle.x += stroker->center.x; + middle.y += stroker->center.y; +/* compute first angle point */ + length = FT_MulDiv( radius, 0x10000L - sigma, + ft_pos_abs( FT_Sin( theta ) ) ); + FT_Vector_From_Polar( &delta, length, phi + rotate ); + delta.x += middle.x; + delta.y += middle.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; +/* compute second angle point */ + FT_Vector_From_Polar( &delta, length, phi - rotate ); + delta.x += middle.x; + delta.y += middle.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; +/* finally, add an end point; only needed if not lineto */ +/* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } +/* this is a miter (intersection) */ + else + { + FT_Fixed length; + FT_Vector delta; + length = FT_DivFix( stroker->radius, thcos ); + FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; +/* now add an end point; only needed if not lineto */ +/* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + FT_Vector_From_Polar( &delta, + stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + Exit: + return error; + } + static FT_Error + ft_stroker_process_corner( FT_Stroker stroker, + FT_Fixed line_length ) + { + FT_Error error = FT_Err_Ok; + FT_Angle turn; + FT_Int inside_side; + turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); +/* no specific corner processing is required if the turn is 0 */ + if ( turn == 0 ) + goto Exit; +/* when we turn to the right, the inside side is 0 */ + inside_side = 0; +/* otherwise, the inside side is 1 */ + if ( turn < 0 ) + inside_side = 1; +/* process the inside side */ + error = ft_stroker_inside( stroker, inside_side, line_length ); + if ( error ) + goto Exit; +/* process the outside side */ + error = ft_stroker_outside( stroker, 1 - inside_side, line_length ); + Exit: + return error; + } +/* add two points to the left and right borders corresponding to the */ +/* start of the subpath */ + static FT_Error + ft_stroker_subpath_start( FT_Stroker stroker, + FT_Angle start_angle, + FT_Fixed line_length ) + { + FT_Vector delta; + FT_Vector point; + FT_Error error; + FT_StrokeBorder border; + FT_Vector_From_Polar( &delta, stroker->radius, + start_angle + FT_ANGLE_PI2 ); + point.x = stroker->center.x + delta.x; + point.y = stroker->center.y + delta.y; + border = stroker->borders; + error = ft_stroke_border_moveto( border, &point ); + if ( error ) + goto Exit; + point.x = stroker->center.x - delta.x; + point.y = stroker->center.y - delta.y; + border++; + error = ft_stroke_border_moveto( border, &point ); +/* save angle, position, and line length for last join */ +/* (line_length is zero for curves) */ + stroker->subpath_angle = start_angle; + stroker->first_point = FALSE; + stroker->subpath_line_length = line_length; + Exit: + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_LineTo( FT_Stroker stroker, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_StrokeBorder border; + FT_Vector delta; + FT_Angle angle; + FT_Int side; + FT_Fixed line_length; + delta.x = to->x - stroker->center.x; + delta.y = to->y - stroker->center.y; +/* a zero-length lineto is a no-op; avoid creating a spurious corner */ + if ( delta.x == 0 && delta.y == 0 ) + goto Exit; +/* compute length of line */ + line_length = FT_Vector_Length( &delta ); + angle = FT_Atan2( delta.x, delta.y ); + FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 ); +/* process corner if necessary */ + if ( stroker->first_point ) + { +/* This is the first segment of a subpath. We need to */ +/* add a point to each border at their respective starting */ +/* point locations. */ + error = ft_stroker_subpath_start( stroker, angle, line_length ); + if ( error ) + goto Exit; + } + else + { +/* process the current corner */ + stroker->angle_out = angle; + error = ft_stroker_process_corner( stroker, line_length ); + if ( error ) + goto Exit; + } +/* now add a line segment to both the `inside' and `outside' paths */ + for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) + { + FT_Vector point; + point.x = to->x + delta.x; + point.y = to->y + delta.y; +/* the ends of lineto borders are movable */ + error = ft_stroke_border_lineto( border, &point, TRUE ); + if ( error ) + goto Exit; + delta.x = -delta.x; + delta.y = -delta.y; + } + stroker->angle_in = angle; + stroker->center = *to; + stroker->line_length = line_length; + Exit: + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ConicTo( FT_Stroker stroker, + FT_Vector* control, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_Vector bez_stack[34]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 30; + FT_Bool first_arc = TRUE; +/* if all control points are coincident, this is a no-op; */ +/* avoid creating a spurious corner */ + if ( FT_IS_SMALL( stroker->center.x - control->x ) && + FT_IS_SMALL( stroker->center.y - control->y ) && + FT_IS_SMALL( control->x - to->x ) && + FT_IS_SMALL( control->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + arc = bez_stack; + arc[0] = *to; + arc[1] = *control; + arc[2] = stroker->center; + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_out; +/* initialize with current direction */ + angle_in = angle_out = stroker->angle_in; + if ( arc < limit && + !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + ft_conic_split( arc ); + arc += 2; + continue; + } + if ( first_arc ) + { + first_arc = FALSE; +/* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + FT_SMALL_CONIC_THRESHOLD / 4 ) + { +/* if the deviation from one arc to the next is too great, */ +/* add a round corner */ + stroker->center = arc[2]; + stroker->angle_out = angle_in; + stroker->line_join = FT_STROKER_LINEJOIN_ROUND; + error = ft_stroker_process_corner( stroker, 0 ); +/* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + if ( error ) + goto Exit; +/* the arc's angle is small enough; we can add it directly to each */ +/* border */ + { + FT_Vector ctrl, end; + FT_Angle theta, phi, rotate, alpha0 = 0; + FT_Fixed length; + FT_StrokeBorder border; + FT_Int side; + theta = FT_Angle_Diff( angle_in, angle_out ) / 2; + phi = angle_in + theta; + length = FT_DivFix( stroker->radius, FT_Cos( theta ) ); +/* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = FT_Atan2( arc[0].x - arc[2].x, arc[0].y - arc[2].y ); + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); +/* compute control point */ + FT_Vector_From_Polar( &ctrl, length, phi + rotate ); + ctrl.x += arc[1].x; + ctrl.y += arc[1].y; +/* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + if ( stroker->handle_wide_strokes ) + { + FT_Vector start; + FT_Angle alpha1; +/* determine whether the border radius is greater than the */ +/* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + alpha1 = FT_Atan2( end.x - start.x, end.y - start.y ); +/* is the direction of the border arc opposite to */ +/* that of the original arc? */ + if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) > + FT_ANGLE_PI / 2 ) + { + FT_Angle beta, gamma; + FT_Vector bvec, delta; + FT_Fixed blen, sinA, sinB, alen; +/* use the sine rule to find the intersection point */ + beta = FT_Atan2( arc[2].x - start.x, arc[2].y - start.y ); + gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + blen = FT_Vector_Length( &bvec ); + sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( FT_Sin( beta - gamma ) ); + alen = FT_MulDiv( blen, sinA, sinB ); + FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; +/* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_conicto( border, &ctrl, &start ); + if ( error ) + goto Exit; +/* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + continue; + } +/* else fall through */ + } +/* simply add an arc */ + error = ft_stroke_border_conicto( border, &ctrl, &end ); + if ( error ) + goto Exit; + } + } + arc -= 2; + stroker->angle_in = angle_out; + } + stroker->center = *to; + Exit: + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_CubicTo( FT_Stroker stroker, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_Error error = FT_Err_Ok; + FT_Vector bez_stack[37]; + FT_Vector* arc; + FT_Vector* limit = bez_stack + 32; + FT_Bool first_arc = TRUE; +/* if all control points are coincident, this is a no-op; */ +/* avoid creating a spurious corner */ + if ( FT_IS_SMALL( stroker->center.x - control1->x ) && + FT_IS_SMALL( stroker->center.y - control1->y ) && + FT_IS_SMALL( control1->x - control2->x ) && + FT_IS_SMALL( control1->y - control2->y ) && + FT_IS_SMALL( control2->x - to->x ) && + FT_IS_SMALL( control2->y - to->y ) ) + { + stroker->center = *to; + goto Exit; + } + arc = bez_stack; + arc[0] = *to; + arc[1] = *control2; + arc[2] = *control1; + arc[3] = stroker->center; + while ( arc >= bez_stack ) + { + FT_Angle angle_in, angle_mid, angle_out; +/* initialize with current direction */ + angle_in = angle_out = angle_mid = stroker->angle_in; + if ( arc < limit && + !ft_cubic_is_small_enough( arc, &angle_in, + &angle_mid, &angle_out ) ) + { + if ( stroker->first_point ) + stroker->angle_in = angle_in; + ft_cubic_split( arc ); + arc += 3; + continue; + } + if ( first_arc ) + { + first_arc = FALSE; +/* process corner if necessary */ + if ( stroker->first_point ) + error = ft_stroker_subpath_start( stroker, angle_in, 0 ); + else + { + stroker->angle_out = angle_in; + error = ft_stroker_process_corner( stroker, 0 ); + } + } + else if ( ft_pos_abs( FT_Angle_Diff( stroker->angle_in, angle_in ) ) > + FT_SMALL_CUBIC_THRESHOLD / 4 ) + { +/* if the deviation from one arc to the next is too great, */ +/* add a round corner */ + stroker->center = arc[3]; + stroker->angle_out = angle_in; + stroker->line_join = FT_STROKER_LINEJOIN_ROUND; + error = ft_stroker_process_corner( stroker, 0 ); +/* reinstate line join style */ + stroker->line_join = stroker->line_join_saved; + } + if ( error ) + goto Exit; +/* the arc's angle is small enough; we can add it directly to each */ +/* border */ + { + FT_Vector ctrl1, ctrl2, end; + FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0; + FT_Fixed length1, length2; + FT_StrokeBorder border; + FT_Int side; + theta1 = FT_Angle_Diff( angle_in, angle_mid ) / 2; + theta2 = FT_Angle_Diff( angle_mid, angle_out ) / 2; + phi1 = ft_angle_mean( angle_in, angle_mid ); + phi2 = ft_angle_mean( angle_mid, angle_out ); + length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) ); + length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) ); +/* compute direction of original arc */ + if ( stroker->handle_wide_strokes ) + alpha0 = FT_Atan2( arc[0].x - arc[3].x, arc[0].y - arc[3].y ); + for ( border = stroker->borders, side = 0; + side <= 1; + side++, border++ ) + { + rotate = FT_SIDE_TO_ROTATE( side ); +/* compute control points */ + FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); + ctrl1.x += arc[2].x; + ctrl1.y += arc[2].y; + FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); + ctrl2.x += arc[1].x; + ctrl2.y += arc[1].y; +/* compute end point */ + FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); + end.x += arc[0].x; + end.y += arc[0].y; + if ( stroker->handle_wide_strokes ) + { + FT_Vector start; + FT_Angle alpha1; +/* determine whether the border radius is greater than the */ +/* radius of curvature of the original arc */ + start = border->points[border->num_points - 1]; + alpha1 = FT_Atan2( end.x - start.x, end.y - start.y ); +/* is the direction of the border arc opposite to */ +/* that of the original arc? */ + if ( ft_pos_abs( FT_Angle_Diff( alpha0, alpha1 ) ) > + FT_ANGLE_PI / 2 ) + { + FT_Angle beta, gamma; + FT_Vector bvec, delta; + FT_Fixed blen, sinA, sinB, alen; +/* use the sine rule to find the intersection point */ + beta = FT_Atan2( arc[3].x - start.x, arc[3].y - start.y ); + gamma = FT_Atan2( arc[0].x - end.x, arc[0].y - end.y ); + bvec.x = end.x - start.x; + bvec.y = end.y - start.y; + blen = FT_Vector_Length( &bvec ); + sinA = ft_pos_abs( FT_Sin( alpha1 - gamma ) ); + sinB = ft_pos_abs( FT_Sin( beta - gamma ) ); + alen = FT_MulDiv( blen, sinA, sinB ); + FT_Vector_From_Polar( &delta, alen, beta ); + delta.x += start.x; + delta.y += start.y; +/* circumnavigate the negative sector backwards */ + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + error = ft_stroke_border_cubicto( border, + &ctrl2, + &ctrl1, + &start ); + if ( error ) + goto Exit; +/* and then move to the endpoint */ + error = ft_stroke_border_lineto( border, &end, FALSE ); + if ( error ) + goto Exit; + continue; + } +/* else fall through */ + } +/* simply add an arc */ + error = ft_stroke_border_cubicto( border, &ctrl1, &ctrl2, &end ); + if ( error ) + goto Exit; + } + } + arc -= 3; + stroker->angle_in = angle_out; + } + stroker->center = *to; + Exit: + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_BeginSubPath( FT_Stroker stroker, + FT_Vector* to, + FT_Bool open ) + { +/* We cannot process the first point, because there is not enough */ +/* information regarding its corner/cap. The latter will be processed */ +/* in the `FT_Stroker_EndSubPath' routine. */ +/* */ + stroker->first_point = TRUE; + stroker->center = *to; + stroker->subpath_open = open; +/* Determine if we need to check whether the border radius is greater */ +/* than the radius of curvature of a curve, to handle this case */ +/* specially. This is only required if bevel joins or butt caps may */ +/* be created, because round & miter joins and round & square caps */ +/* cover the negative sector created with wide strokes. */ + stroker->handle_wide_strokes = + FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_ROUND || + ( stroker->subpath_open && + stroker->line_cap == FT_STROKER_LINECAP_BUTT ) ); +/* record the subpath start point for each border */ + stroker->subpath_start = *to; + stroker->angle_in = 0; + return FT_Err_Ok; + } + static FT_Error + ft_stroker_add_reverse_left( FT_Stroker stroker, + FT_Bool open ) + { + FT_StrokeBorder right = stroker->borders + 0; + FT_StrokeBorder left = stroker->borders + 1; + FT_Int new_points; + FT_Error error = FT_Err_Ok; + FT_ASSERT( left->start >= 0 ); + new_points = left->num_points - left->start; + if ( new_points > 0 ) + { + error = ft_stroke_border_grow( right, (FT_UInt)new_points ); + if ( error ) + goto Exit; + { + FT_Vector* dst_point = right->points + right->num_points; + FT_Byte* dst_tag = right->tags + right->num_points; + FT_Vector* src_point = left->points + left->num_points - 1; + FT_Byte* src_tag = left->tags + left->num_points - 1; + while ( src_point >= left->points + left->start ) + { + *dst_point = *src_point; + *dst_tag = *src_tag; + if ( open ) + dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END; + else + { + FT_Byte ttag = + (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END ); +/* switch begin/end tags if necessary */ + if ( ttag == FT_STROKE_TAG_BEGIN || + ttag == FT_STROKE_TAG_END ) + dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END; + } + src_point--; + src_tag--; + dst_point++; + dst_tag++; + } + } + left->num_points = left->start; + right->num_points += new_points; + right->movable = FALSE; + left->movable = FALSE; + } + Exit: + return error; + } +/* documentation is in ftstroke.h */ +/* there's a lot of magic in this function! */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_EndSubPath( FT_Stroker stroker ) + { + FT_Error error = FT_Err_Ok; + if ( stroker->subpath_open ) + { + FT_StrokeBorder right = stroker->borders; +/* All right, this is an opened path, we need to add a cap between */ +/* right & left, add the reverse of left, then add a final cap */ +/* between left & right. */ + error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); + if ( error ) + goto Exit; +/* add reversed points from `left' to `right' */ + error = ft_stroker_add_reverse_left( stroker, TRUE ); + if ( error ) + goto Exit; +/* now add the final cap */ + stroker->center = stroker->subpath_start; + error = ft_stroker_cap( stroker, + stroker->subpath_angle + FT_ANGLE_PI, 0 ); + if ( error ) + goto Exit; +/* Now end the right subpath accordingly. The left one is */ +/* rewind and doesn't need further processing. */ + ft_stroke_border_close( right, FALSE ); + } + else + { + FT_Angle turn; + FT_Int inside_side; +/* close the path if needed */ + if ( stroker->center.x != stroker->subpath_start.x || + stroker->center.y != stroker->subpath_start.y ) + { + error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); + if ( error ) + goto Exit; + } +/* process the corner */ + stroker->angle_out = stroker->subpath_angle; + turn = FT_Angle_Diff( stroker->angle_in, + stroker->angle_out ); +/* no specific corner processing is required if the turn is 0 */ + if ( turn != 0 ) + { +/* when we turn to the right, the inside side is 0 */ + inside_side = 0; +/* otherwise, the inside side is 1 */ + if ( turn < 0 ) + inside_side = 1; + error = ft_stroker_inside( stroker, + inside_side, + stroker->subpath_line_length ); + if ( error ) + goto Exit; +/* process the outside side */ + error = ft_stroker_outside( stroker, + 1 - inside_side, + stroker->subpath_line_length ); + if ( error ) + goto Exit; + } +/* then end our two subpaths */ + ft_stroke_border_close( stroker->borders + 0, FALSE ); + ft_stroke_border_close( stroker->borders + 1, TRUE ); + } + Exit: + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt num_points = 0, num_contours = 0; + FT_Error error; + if ( !stroker || border > 1 ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + error = ft_stroke_border_get_counts( stroker->borders + border, + &num_points, &num_contours ); + Exit: + if ( anum_points ) + *anum_points = num_points; + if ( anum_contours ) + *anum_contours = num_contours; + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetCounts( FT_Stroker stroker, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt count1, count2, num_points = 0; + FT_UInt count3, count4, num_contours = 0; + FT_Error error; + error = ft_stroke_border_get_counts( stroker->borders + 0, + &count1, &count2 ); + if ( error ) + goto Exit; + error = ft_stroke_border_get_counts( stroker->borders + 1, + &count3, &count4 ); + if ( error ) + goto Exit; + num_points = count1 + count3; + num_contours = count2 + count4; + Exit: + *anum_points = num_points; + *anum_contours = num_contours; + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ) + { + if ( border == FT_STROKER_BORDER_LEFT || + border == FT_STROKER_BORDER_RIGHT ) + { + FT_StrokeBorder sborder = & stroker->borders[border]; + if ( sborder->valid ) + ft_stroke_border_export( sborder, outline ); + } + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ) + { + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline ); + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline ); + } +/* documentation is in ftstroke.h */ +/* + * The following is very similar to FT_Outline_Decompose, except + * that we do support opened paths, and do not scale the outline. + */ + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_ParseOutline( FT_Stroker stroker, + FT_Outline* outline, + FT_Bool opened ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + FT_Vector* point; + FT_Vector* limit; + char* tags; + FT_Error error; +/* index of contour in outline */ + FT_Int n; +/* index of first point in contour */ + FT_UInt first; +/* current point's state */ + FT_Int tag; + if ( !outline || !stroker ) + return FT_Err_Invalid_Argument; + FT_Stroker_Rewind( stroker ); + first = 0; + for ( n = 0; n < outline->n_contours; n++ ) + { +/* index of last point in contour */ + FT_UInt last; + last = outline->contours[n]; + limit = outline->points + last; +/* skip empty points; we don't stroke these */ + if ( last <= first ) + { + first = last + 1; + continue; + } + v_start = outline->points[first]; + v_last = outline->points[last]; + v_control = v_start; + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); +/* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; +/* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { +/* First point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { +/* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { +/* if both first and last points are conic, */ +/* start at their middle */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + } + point--; + tags--; + } + error = FT_Stroker_BeginSubPath( stroker, &v_start, opened ); + if ( error ) + goto Exit; + while ( point < limit ) + { + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { +/* emit a single line_to */ + case FT_CURVE_TAG_ON: + { + FT_Vector vec; + vec.x = point->x; + vec.y = point->y; + error = FT_Stroker_LineTo( stroker, &vec ); + if ( error ) + goto Exit; + continue; + } +/* consume conic arcs */ + case FT_CURVE_TAG_CONIC: + v_control.x = point->x; + v_control.y = point->y; + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + vec = point[0]; + if ( tag == FT_CURVE_TAG_ON ) + { + error = FT_Stroker_ConicTo( stroker, &v_control, &vec ); + if ( error ) + goto Exit; + continue; + } + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle ); + if ( error ) + goto Exit; + v_control = vec; + goto Do_Conic; + } + error = FT_Stroker_ConicTo( stroker, &v_control, &v_start ); + goto Close; +/* FT_CURVE_TAG_CUBIC */ + default: + { + FT_Vector vec1, vec2; + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + point += 2; + tags += 2; + vec1 = point[-2]; + vec2 = point[-1]; + if ( point <= limit ) + { + FT_Vector vec; + vec = point[0]; + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); + if ( error ) + goto Exit; + continue; + } + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start ); + goto Close; + } + } + } + Close: + if ( error ) + goto Exit; +/* don't try to end the path if no segments have been generated */ + if ( !stroker->first_point ) + { + error = FT_Stroker_EndSubPath( stroker ); + if ( error ) + goto Exit; + } + first = last + 1; + } + return FT_Err_Ok; + Exit: + return error; + Invalid_Outline: + return FT_Err_Invalid_Outline; + } +/* declare an extern to access `ft_outline_glyph_class' globally */ +/* allocated in `ftglyph.c', and use the FT_OUTLINE_GLYPH_CLASS_GET */ +/* macro to access it when FT_CONFIG_OPTION_PIC is defined */ + extern const FT_Glyph_Class ft_outline_glyph_class; +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_Stroke( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool destroy ) + { + FT_Error error = FT_Err_Invalid_Argument; + FT_Glyph glyph = NULL; + FT_Library library = stroker->library; + FT_UNUSED( library ); + if ( pglyph == NULL ) + goto Exit; + glyph = *pglyph; + if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET ) + goto Exit; + { + FT_Glyph copy; + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + glyph = copy; + } + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); + if ( error ) + goto Fail; + (void)FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); + FT_Outline_Done( glyph->library, outline ); + error = FT_Outline_New( glyph->library, + num_points, num_contours, outline ); + if ( error ) + goto Fail; + outline->n_points = 0; + outline->n_contours = 0; + FT_Stroker_Export( stroker, outline ); + } + if ( destroy ) + FT_Done_Glyph( *pglyph ); + *pglyph = glyph; + goto Exit; + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + if ( !destroy ) + *pglyph = NULL; + Exit: + return error; + } +/* documentation is in ftstroke.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Glyph_StrokeBorder( FT_Glyph *pglyph, + FT_Stroker stroker, + FT_Bool inside, + FT_Bool destroy ) + { + FT_Error error = FT_Err_Invalid_Argument; + FT_Glyph glyph = NULL; + FT_Library library = stroker->library; + FT_UNUSED( library ); + if ( pglyph == NULL ) + goto Exit; + glyph = *pglyph; + if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET ) + goto Exit; + { + FT_Glyph copy; + error = FT_Glyph_Copy( glyph, © ); + if ( error ) + goto Exit; + glyph = copy; + } + { + FT_OutlineGlyph oglyph = (FT_OutlineGlyph)glyph; + FT_StrokerBorder border; + FT_Outline* outline = &oglyph->outline; + FT_UInt num_points, num_contours; + border = FT_Outline_GetOutsideBorder( outline ); + if ( inside ) + { + if ( border == FT_STROKER_BORDER_LEFT ) + border = FT_STROKER_BORDER_RIGHT; + else + border = FT_STROKER_BORDER_LEFT; + } + error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); + if ( error ) + goto Fail; + (void)FT_Stroker_GetBorderCounts( stroker, border, + &num_points, &num_contours ); + FT_Outline_Done( glyph->library, outline ); + error = FT_Outline_New( glyph->library, + num_points, + num_contours, + outline ); + if ( error ) + goto Fail; + outline->n_points = 0; + outline->n_contours = 0; + FT_Stroker_ExportBorder( stroker, border, outline ); + } + if ( destroy ) + FT_Done_Glyph( *pglyph ); + *pglyph = glyph; + goto Exit; + Fail: + FT_Done_Glyph( glyph ); + glyph = NULL; + if ( !destroy ) + *pglyph = NULL; + Exit: + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftsynth.c */ +/* */ +/* FreeType synthesizing code for emboldening and slanting (body). */ +/* */ +/* Copyright 2000-2006, 2010, 2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftsynth.h */ +/* */ +/* FreeType synthesizing code for emboldening and slanting */ +/* (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 2006, 2008, 2012 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/********* *********/ +/********* WARNING, THIS IS ALPHA CODE! THIS API *********/ +/********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/ +/********* FREETYPE DEVELOPMENT TEAM *********/ +/********* *********/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* Main reason for not lifting the functions in this module to a */ +/* `standard' API is that the used parameters for emboldening and */ +/* slanting are not configurable. Consider the functions as a */ +/* code resource which should be copied into the application and */ +/* adapted to the particular needs. */ +#define __FTSYNTH_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 +FT_BEGIN_HEADER +/* Embolden a glyph by a `reasonable' value (which is highly a matter of */ +/* taste). This function is actually a convenience function, providing */ +/* a wrapper for @FT_Outline_Embolden and @FT_Bitmap_Embolden. */ +/* */ +/* For emboldened outlines the height, width, and advance metrics are */ +/* increased by the strength of the emboldening. You can also call */ +/* @FT_Outline_Get_CBox to get precise values. */ + FT_EXPORT( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); +/* Slant an outline glyph to the right by about 12 degrees. */ + FT_EXPORT( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); +/* */ +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_synth +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** EXPERIMENTAL OBLIQUING SUPPORT ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/* documentation is in ftsynth.h */ + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Oblique( FT_GlyphSlot slot ) + { + FT_Matrix transform; + FT_Outline* outline = &slot->outline; +/* only oblique outline glyphs */ + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + return; +/* we don't touch the advance width */ +/* For italic, simply apply a shear transform, with an angle */ +/* of about 12 degrees. */ + transform.xx = 0x10000L; + transform.yx = 0x00000L; + transform.xy = 0x0366AL; + transform.yy = 0x10000L; + FT_Outline_Transform( outline, &transform ); + } +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** EXPERIMENTAL EMBOLDENING SUPPORT ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/* documentation is in ftsynth.h */ + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Embolden( FT_GlyphSlot slot ) + { + FT_Library library = slot->library; + FT_Face face = slot->face; + FT_Error error; + FT_Pos xstr, ystr; + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && + slot->format != FT_GLYPH_FORMAT_BITMAP ) + return; +/* some reasonable strength */ + xstr = FT_MulFix( face->units_per_EM, + face->size->metrics.y_scale ) / 24; + ystr = xstr; + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { +/* ignore error */ + (void)FT_Outline_EmboldenXY( &slot->outline, xstr, ystr ); + } +/* slot->format == FT_GLYPH_FORMAT_BITMAP */ + else + { +/* round to full pixels */ + xstr &= ~63; + if ( xstr == 0 ) + xstr = 1 << 6; + ystr &= ~63; +/* + * XXX: overflow check for 16-bit system, for compatibility + * with FT_GlyphSlot_Embolden() since freetype-2.1.10. + * unfortunately, this function return no informations + * about the cause of error. + */ + if ( ( ystr >> 6 ) > FT_INT_MAX || ( ystr >> 6 ) < FT_INT_MIN ) + { + FT_TRACE1(( "FT_GlyphSlot_Embolden:" )); + FT_TRACE1(( "too strong embolding parameter ystr=%d\n", ystr )); + return; + } + error = FT_GlyphSlot_Own_Bitmap( slot ); + if ( error ) + return; + error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr ); + if ( error ) + return; + } + if ( slot->advance.x ) + slot->advance.x += xstr; + if ( slot->advance.y ) + slot->advance.y += ystr; + slot->metrics.width += xstr; + slot->metrics.height += ystr; + slot->metrics.horiAdvance += xstr; + slot->metrics.vertAdvance += ystr; +/* XXX: 16-bit overflow case must be excluded before here */ + if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) + slot->bitmap_top += (FT_Int)( ystr >> 6 ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ftwinfnt.c */ +/* */ +/* FreeType API for accessing Windows FNT specific info (body). */ +/* */ +/* Copyright 2003, 2004 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftwinfnt.h */ +/* */ +/* FreeType API for accessing Windows fnt-specific data. */ +/* */ +/* Copyright 2003, 2004, 2008 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. */ +/* */ +/***************************************************************************/ +#define __FTWINFNT_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* winfnt_fonts */ +/* */ +/* <Title> */ +/* Window FNT Files */ +/* */ +/* <Abstract> */ +/* Windows FNT specific API. */ +/* */ +/* <Description> */ +/* This section contains the declaration of Windows FNT specific */ +/* functions. */ +/* */ +/*************************************************************************/ +/************************************************************************* + * + * @enum: + * FT_WinFNT_ID_XXX + * + * @description: + * A list of valid values for the `charset' byte in + * @FT_WinFNT_HeaderRec. Exact mapping tables for the various cpXXXX + * encodings (except for cp1361) can be found at ftp://ftp.unicode.org + * in the MAPPINGS/VENDORS/MICSFT/WINDOWS subdirectory. cp1361 is + * roughly a superset of MAPPINGS/OBSOLETE/EASTASIA/KSC/JOHAB.TXT. + * + * @values: + * FT_WinFNT_ID_DEFAULT :: + * This is used for font enumeration and font creation as a + * `don't care' value. Valid font files don't contain this value. + * When querying for information about the character set of the font + * that is currently selected into a specified device context, this + * return value (of the related Windows API) simply denotes failure. + * + * FT_WinFNT_ID_SYMBOL :: + * There is no known mapping table available. + * + * FT_WinFNT_ID_MAC :: + * Mac Roman encoding. + * + * FT_WinFNT_ID_OEM :: + * From Michael Pöttgen <michael@poettgen.de>: + * + * The `Windows Font Mapping' article says that FT_WinFNT_ID_OEM + * is used for the charset of vector fonts, like `modern.fon', + * `roman.fon', and `script.fon' on Windows. + * + * The `CreateFont' documentation says: The FT_WinFNT_ID_OEM value + * specifies a character set that is operating-system dependent. + * + * The `IFIMETRICS' documentation from the `Windows Driver + * Development Kit' says: This font supports an OEM-specific + * character set. The OEM character set is system dependent. + * + * In general OEM, as opposed to ANSI (i.e., cp1252), denotes the + * second default codepage that most international versions of + * Windows have. It is one of the OEM codepages from + * + * http://www.microsoft.com/globaldev/reference/cphome.mspx, + * + * and is used for the `DOS boxes', to support legacy applications. + * A German Windows version for example usually uses ANSI codepage + * 1252 and OEM codepage 850. + * + * FT_WinFNT_ID_CP874 :: + * A superset of Thai TIS 620 and ISO 8859-11. + * + * FT_WinFNT_ID_CP932 :: + * A superset of Japanese Shift-JIS (with minor deviations). + * + * FT_WinFNT_ID_CP936 :: + * A superset of simplified Chinese GB 2312-1980 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP949 :: + * A superset of Korean Hangul KS~C 5601-1987 (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP950 :: + * A superset of traditional Chinese Big~5 ETen (with different + * ordering and minor deviations). + * + * FT_WinFNT_ID_CP1250 :: + * A superset of East European ISO 8859-2 (with slightly different + * ordering). + * + * FT_WinFNT_ID_CP1251 :: + * A superset of Russian ISO 8859-5 (with different ordering). + * + * FT_WinFNT_ID_CP1252 :: + * ANSI encoding. A superset of ISO 8859-1. + * + * FT_WinFNT_ID_CP1253 :: + * A superset of Greek ISO 8859-7 (with minor modifications). + * + * FT_WinFNT_ID_CP1254 :: + * A superset of Turkish ISO 8859-9. + * + * FT_WinFNT_ID_CP1255 :: + * A superset of Hebrew ISO 8859-8 (with some modifications). + * + * FT_WinFNT_ID_CP1256 :: + * A superset of Arabic ISO 8859-6 (with different ordering). + * + * FT_WinFNT_ID_CP1257 :: + * A superset of Baltic ISO 8859-13 (with some deviations). + * + * FT_WinFNT_ID_CP1258 :: + * For Vietnamese. This encoding doesn't cover all necessary + * characters. + * + * FT_WinFNT_ID_CP1361 :: + * Korean (Johab). + */ +#define FT_WinFNT_ID_CP1252 0 +#define FT_WinFNT_ID_DEFAULT 1 +#define FT_WinFNT_ID_SYMBOL 2 +#define FT_WinFNT_ID_MAC 77 +#define FT_WinFNT_ID_CP932 128 +#define FT_WinFNT_ID_CP949 129 +#define FT_WinFNT_ID_CP1361 130 +#define FT_WinFNT_ID_CP936 134 +#define FT_WinFNT_ID_CP950 136 +#define FT_WinFNT_ID_CP1253 161 +#define FT_WinFNT_ID_CP1254 162 +#define FT_WinFNT_ID_CP1258 163 +#define FT_WinFNT_ID_CP1255 177 +#define FT_WinFNT_ID_CP1256 178 +#define FT_WinFNT_ID_CP1257 186 +#define FT_WinFNT_ID_CP1251 204 +#define FT_WinFNT_ID_CP874 222 +#define FT_WinFNT_ID_CP1250 238 +#define FT_WinFNT_ID_OEM 255 +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_WinFNT_HeaderRec */ +/* */ +/* <Description> */ +/* Windows FNT Header info. */ +/* */ + typedef struct FT_WinFNT_HeaderRec_ + { + FT_UShort version; + FT_ULong file_size; + FT_Byte copyright[60]; + FT_UShort file_type; + FT_UShort nominal_point_size; + FT_UShort vertical_resolution; + FT_UShort horizontal_resolution; + FT_UShort ascent; + FT_UShort internal_leading; + FT_UShort external_leading; + FT_Byte italic; + FT_Byte underline; + FT_Byte strike_out; + FT_UShort weight; + FT_Byte charset; + FT_UShort pixel_width; + FT_UShort pixel_height; + FT_Byte pitch_and_family; + FT_UShort avg_width; + FT_UShort max_width; + FT_Byte first_char; + FT_Byte last_char; + FT_Byte default_char; + FT_Byte break_char; + FT_UShort bytes_per_row; + FT_ULong device_offset; + FT_ULong face_name_offset; + FT_ULong bits_pointer; + FT_ULong bits_offset; + FT_Byte reserved; + FT_ULong flags; + FT_UShort A_space; + FT_UShort B_space; + FT_UShort C_space; + FT_UShort color_table_offset; + FT_ULong reserved1[4]; + } FT_WinFNT_HeaderRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* FT_WinFNT_Header */ +/* */ +/* <Description> */ +/* A handle to an @FT_WinFNT_HeaderRec structure. */ +/* */ + typedef struct FT_WinFNT_HeaderRec_* FT_WinFNT_Header; +/********************************************************************** + * + * @function: + * FT_Get_WinFNT_Header + * + * @description: + * Retrieve a Windows FNT font info header. + * + * @input: + * face :: A handle to the input face. + * + * @output: + * aheader :: The WinFNT header. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function only works with Windows FNT faces, returning an error + * otherwise. + */ + FT_EXPORT( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); +/* */ +FT_END_HEADER +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ +/***************************************************************************/ +/* */ +/* svwinfnt.h */ +/* */ +/* The FreeType Windows FNT/FONT service (specification). */ +/* */ +/* Copyright 2003 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. */ +/* */ +/***************************************************************************/ +#define __SVWINFNT_H__ +FT_BEGIN_HEADER +#define FT_SERVICE_ID_WINFNT "winfonts" + typedef FT_Error + (*FT_WinFnt_GetHeaderFunc)( FT_Face face, + FT_WinFNT_HeaderRec *aheader ); + FT_DEFINE_SERVICE( WinFnt ) + { + FT_WinFnt_GetHeaderFunc get_header; + }; +/* */ +FT_END_HEADER +/* END */ +/* documentation is in ftwinfnt.h */ + FT_EXPORT_DEF( FT_Error ) + FT_Get_WinFNT_Header( FT_Face face, + FT_WinFNT_HeaderRec *header ) + { + FT_Service_WinFnt service; + FT_Error error; + error = FT_Err_Invalid_Argument; + if ( face != NULL ) + { + FT_FACE_LOOKUP_SERVICE( face, service, WINFNT ); + if ( service != NULL ) + { + error = service->get_header( face, header ); + } + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ftxf86.c */ +/* */ +/* FreeType utility file for X11 support (body). */ +/* */ +/* Copyright 2002, 2003, 2004 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftxf86.h */ +/* */ +/* Support functions for X11. */ +/* */ +/* Copyright 2002, 2003, 2004, 2006, 2007 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. */ +/* */ +/***************************************************************************/ +#define __FTXF86_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* font_formats */ +/* */ +/* <Title> */ +/* Font Formats */ +/* */ +/* <Abstract> */ +/* Getting the font format. */ +/* */ +/* <Description> */ +/* The single function in this section can be used to get the font */ +/* format. Note that this information is not needed normally; */ +/* however, there are special cases (like in PDF devices) where it is */ +/* important to differentiate, in spite of FreeType's uniform API. */ +/* */ +/* This function is in the X11/xf86 namespace for historical reasons */ +/* and in no way depends on that windowing system. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Get_X11_Font_Format */ +/* */ +/* <Description> */ +/* Return a string describing the format of a given face, using values */ +/* which can be used as an X11 FONT_PROPERTY. Possible values are */ +/* `TrueType', `Type~1', `BDF', `PCF', `Type~42', `CID~Type~1', `CFF', */ +/* `PFR', and `Windows~FNT'. */ +/* */ +/* <Input> */ +/* face :: */ +/* Input face handle. */ +/* */ +/* <Return> */ +/* Font format string. NULL in case of error. */ +/* */ + FT_EXPORT( const char* ) + FT_Get_X11_Font_Format( FT_Face face ); +/* */ +FT_END_HEADER +/***************************************************************************/ +/* */ +/* svxf86nm.h */ +/* */ +/* The FreeType XFree86 services (specification only). */ +/* */ +/* Copyright 2003 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. */ +/* */ +/***************************************************************************/ +#define __SVXF86NM_H__ +FT_BEGIN_HEADER +/* + * A trivial service used to return the name of a face's font driver, + * according to the XFree86 nomenclature. Note that the service data + * is a simple constant string pointer. + */ +#define FT_SERVICE_ID_XF86_NAME "xf86-driver-name" +#define FT_XF86_FORMAT_TRUETYPE "TrueType" +#define FT_XF86_FORMAT_TYPE_1 "Type 1" +#define FT_XF86_FORMAT_BDF "BDF" +#define FT_XF86_FORMAT_PCF "PCF" +#define FT_XF86_FORMAT_TYPE_42 "Type 42" +#define FT_XF86_FORMAT_CID "CID Type 1" +#define FT_XF86_FORMAT_CFF "CFF" +#define FT_XF86_FORMAT_PFR "PFR" +#define FT_XF86_FORMAT_WINFNT "Windows FNT" +/* */ +FT_END_HEADER +/* END */ +/* documentation is in ftxf86.h */ + FT_EXPORT_DEF( const char* ) + FT_Get_X11_Font_Format( FT_Face face ) + { + const char* result = NULL; + if ( face ) + FT_FACE_FIND_SERVICE( face, result, XF86_NAME ); + return result; + } +/* END */ +/* bdf.c + + FreeType font driver for bdf files + + Copyright (C) 2001, 2002 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. +*/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/* + * Copyright 2000 Computing Research Labs, New Mexico State University + * Copyright 2001-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 based on bdf.c,v 1.22 2000/03/16 20:08:50 */ +/* */ +/* taken from Mark Leisher's xmbdfed package */ +/* */ +/*************************************************************************/ +/* + * 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. + */ +#define __BDF_H__ +/* + * Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher + */ +FT_BEGIN_HEADER +/* Imported from bdfP.h */ +#define _bdf_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] & ( 1 << ( (e) & 31 ) ) ) +#define _bdf_set_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] |= ( 1 << ( (e) & 31 ) ) ) +#define _bdf_clear_glyph_modified( map, e ) \ + ( (map)[(e) >> 5] &= ~( 1 << ( (e) & 31 ) ) ) +/* end of bdfP.h */ +/*************************************************************************/ +/* */ +/* BDF font options macros and types. */ +/* */ +/*************************************************************************/ +/* Correct invalid metrics when loading. */ +#define BDF_CORRECT_METRICS 0x01 +/* Preserve the font comments. */ +#define BDF_KEEP_COMMENTS 0x02 +/* Keep the unencoded glyphs. */ +#define BDF_KEEP_UNENCODED 0x04 +/* Font has proportional spacing. */ +#define BDF_PROPORTIONAL 0x08 +/* Font has mono width. */ +#define BDF_MONOWIDTH 0x10 +/* Font has charcell spacing. */ +#define BDF_CHARCELL 0x20 +#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_ + { +/* Name of the property. */ + char* name; +/* Format of the property. */ + int format; +/* A builtin property. */ + int builtin; + union + { + char* atom; + long l; + unsigned long ul; +/* Value of the property. */ + } value; + } 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_ + { +/* Glyph name. */ + char* name; +/* Glyph encoding. */ + long encoding; +/* Scalable width. */ + unsigned short swidth; +/* Device width. */ + unsigned short dwidth; +/* Glyph bounding box. */ + bdf_bbx_t bbx; +/* Glyph bitmap. */ + unsigned char* bitmap; +/* Number of bytes used per row. */ + unsigned long bpr; +/* Number of bytes used for the bitmap. */ + unsigned short bytes; + } bdf_glyph_t; + typedef struct _hashnode_ + { + const char* key; + size_t data; + } _hashnode, *hashnode; + typedef struct hashtable_ + { + int limit; + int size; + int used; + hashnode* table; + } hashtable; + typedef struct bdf_glyphlist_t_ + { +/* Pad to 4-byte boundary. */ + unsigned short pad; +/* Bits per pixel. */ + unsigned short bpp; +/* Beginning encoding value of glyphs. */ + long start; +/* Ending encoding value of glyphs. */ + long end; +/* Glyphs themselves. */ + bdf_glyph_t* glyphs; +/* Glyph structures allocated. */ + unsigned long glyphs_size; +/* Glyph structures used. */ + unsigned long glyphs_used; +/* Overall bounding box of glyphs. */ + bdf_bbx_t bbx; + } bdf_glyphlist_t; + typedef struct bdf_font_t_ + { +/* Name of the font. */ + char* name; +/* Font bounding box. */ + bdf_bbx_t bbx; +/* Point size of the font. */ + long point_size; +/* Font horizontal resolution. */ + unsigned long resolution_x; +/* Font vertical resolution. */ + unsigned long resolution_y; +/* Font spacing value. */ + int spacing; +/* Logical width for monowidth font. */ + unsigned short monowidth; +/* Encoding of the default glyph. */ + long default_char; +/* Font ascent. */ + long font_ascent; +/* Font descent. */ + long font_descent; +/* Glyph structures allocated. */ + unsigned long glyphs_size; +/* Glyph structures used. */ + unsigned long glyphs_used; +/* Glyphs themselves. */ + bdf_glyph_t* glyphs; +/* Unencoded glyph struct. allocated. */ + unsigned long unencoded_size; +/* Unencoded glyph struct. used. */ + unsigned long unencoded_used; +/* Unencoded glyphs themselves. */ + bdf_glyph_t* unencoded; +/* Font properties allocated. */ + unsigned long props_size; +/* Font properties used. */ + unsigned long props_used; +/* Font properties themselves. */ + bdf_property_t* props; +/* Font comments. */ + char* comments; +/* Length of comment string. */ + unsigned long comments_len; +/* Storage used for glyph insertion. */ + bdf_glyphlist_t overflow; +/* Internal data for the font. */ + void* internal; +/* The size of the next two arrays must be in sync with the */ +/* size of the `have' array in the `bdf_parse_t' structure. */ +/* Bitmap indicating modified glyphs. */ + unsigned long nmod[34816]; +/* Bitmap indicating modified */ + unsigned long umod[34816]; +/* unencoded glyphs. */ +/* Boolean indicating font modified. */ + unsigned short modified; +/* Bits per pixel. */ + unsigned short bpp; + FT_Memory memory; + bdf_property_t* user_props; + unsigned long nuser_props; + hashtable 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_property( char* name, + bdf_font_t* font ); + FT_LOCAL( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ); +FT_END_HEADER +/* END */ +/* + * 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. */ +/* */ +/*************************************************************************/ +#define __BDFERROR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX BDF_Err_ +#define FT_ERR_BASE FT_Mod_Err_BDF +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_bdflib +/*************************************************************************/ +/* */ +/* Default BDF font options. */ +/* */ +/*************************************************************************/ + static const bdf_options_t _bdf_opts = + { +/* Correct metrics. */ + 1, +/* Preserve unencoded glyphs. */ + 1, +/* Preserve comments. */ + 0, +/* Default spacing. */ + BDF_PROPORTIONAL + }; +/*************************************************************************/ +/* */ +/* Builtin BDF font properties. */ +/* */ +/*************************************************************************/ +/* List of most properties that might appear in a font. Doesn't include */ +/* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ + static const bdf_property_t _bdf_properties[] = + { + { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, + { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, + { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, + { (char *)"COMMENT", BDF_ATOM, 1, { 0 } }, + { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } }, + { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, + { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } }, + { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"FONT", BDF_ATOM, 1, { 0 } }, + { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, + { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } }, + { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, + { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"NOTICE", BDF_ATOM, 1, { 0 } }, + { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, + { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } }, + { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, + { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, + { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"SLANT", BDF_ATOM, 1, { 0 } }, + { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"SPACING", BDF_ATOM, 1, { 0 } }, + { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, + { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, + { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, + { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, + { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } }, + { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, + { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } }, + { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, + { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, + }; + static const unsigned long + _num_bdf_properties = sizeof ( _bdf_properties ) / + sizeof ( _bdf_properties[0] ); +/* Auto correction messages. */ +#define ACMSG1 "FONT_ASCENT property missing. " \ + "Added `FONT_ASCENT %hd'.\n" +#define ACMSG2 "FONT_DESCENT property missing. " \ + "Added `FONT_DESCENT %hd'.\n" +#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n" +#define ACMSG4 "Font left bearing != actual left bearing. " \ + "Old: %hd New: %hd.\n" +#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" +#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n" +#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n" +#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" +#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" +#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" +#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" +#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n" +#define ACMSG13 "Glyph %ld extra rows removed.\n" +#define ACMSG14 "Glyph %ld extra columns removed.\n" +#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" +#define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n" +/* Error messages. */ +#define ERRMSG1 "[line %ld] Missing `%s' line.\n" +#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" +#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" +#define ERRMSG4 "[line %ld] BBX too big.\n" +#define ERRMSG5 "[line %ld] `%s' value too big.\n" +#define ERRMSG6 "[line %ld] Input line too long.\n" +#define ERRMSG7 "[line %ld] Font name too long.\n" +#define ERRMSG8 "[line %ld] Invalid `%s' value.\n" +#define ERRMSG9 "[line %ld] Invalid keyword.\n" +/* Debug messages. */ +/* no \n */ +#define DBGMSG1 " [%6ld] %s" +#define DBGMSG2 " (0x%lX)\n" +/*************************************************************************/ +/* */ +/* Hash table utilities for the properties. */ +/* */ +/*************************************************************************/ +/* XXX: Replace this with FreeType's hash functions */ +#define INITIAL_HT_SIZE 241 + typedef void + (*hash_free_func)( hashnode node ); + static hashnode* + hash_bucket( const char* key, + hashtable* ht ) + { + const char* kp = key; + unsigned long res = 0; + hashnode* bp = ht->table, *ndp; +/* Mocklisp hash function. */ + while ( *kp ) + res = ( res << 5 ) - res + *kp++; + ndp = bp + ( res % ht->size ); + while ( *ndp ) + { + kp = (*ndp)->key; + if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 ) + break; + ndp--; + if ( ndp < bp ) + ndp = bp + ( ht->size - 1 ); + } + return ndp; + } + static FT_Error + hash_rehash( hashtable* ht, + FT_Memory memory ) + { + hashnode* obp = ht->table, *bp, *nbp; + int i, sz = ht->size; + FT_Error error = BDF_Err_Ok; + ht->size <<= 1; + ht->limit = ht->size / 3; + if ( FT_NEW_ARRAY( ht->table, ht->size ) ) + goto Exit; + for ( i = 0, bp = obp; i < sz; i++, bp++ ) + { + if ( *bp ) + { + nbp = hash_bucket( (*bp)->key, ht ); + *nbp = *bp; + } + } + FT_FREE( obp ); + Exit: + return error; + } + static FT_Error + hash_init( hashtable* ht, + FT_Memory memory ) + { + int sz = INITIAL_HT_SIZE; + FT_Error error = BDF_Err_Ok; + ht->size = sz; + ht->limit = sz / 3; + ht->used = 0; + if ( FT_NEW_ARRAY( ht->table, sz ) ) + goto Exit; + Exit: + return error; + } + static void + hash_free( hashtable* ht, + FT_Memory memory ) + { + if ( ht != 0 ) + { + int i, sz = ht->size; + hashnode* bp = ht->table; + for ( i = 0; i < sz; i++, bp++ ) + FT_FREE( *bp ); + FT_FREE( ht->table ); + } + } + static FT_Error + hash_insert( char* key, + size_t data, + hashtable* ht, + FT_Memory memory ) + { + hashnode nn, *bp = hash_bucket( key, ht ); + FT_Error error = BDF_Err_Ok; + nn = *bp; + if ( !nn ) + { + if ( FT_NEW( nn ) ) + goto Exit; + *bp = nn; + nn->key = key; + nn->data = data; + if ( ht->used >= ht->limit ) + { + error = hash_rehash( ht, memory ); + if ( error ) + goto Exit; + } + ht->used++; + } + else + nn->data = data; + Exit: + return error; + } + static hashnode + hash_lookup( const char* key, + hashtable* ht ) + { + hashnode *np = hash_bucket( key, ht ); + return *np; + } +/*************************************************************************/ +/* */ +/* Utility types and functions. */ +/* */ +/*************************************************************************/ +/* Function type for parsing lines of a BDF font. */ + typedef FT_Error + (*_bdf_line_func_t)( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ); +/* List structure for splitting lines into fields. */ + typedef struct _bdf_list_t_ + { + char** field; + unsigned long size; + unsigned long used; + FT_Memory memory; + } _bdf_list_t; +/* Structure used while loading BDF fonts. */ + typedef struct _bdf_parse_t_ + { + unsigned long flags; + unsigned long cnt; + unsigned long row; + short minlb; + short maxlb; + short maxrb; + short maxas; + short maxds; + short rbearing; + char* glyph_name; + long glyph_enc; + bdf_font_t* font; + bdf_options_t* opts; +/* must be in sync with `nmod' and `umod' */ + unsigned long have[34816]; +/* arrays from `bdf_font_t' structure */ + _bdf_list_t list; + FT_Memory memory; + } _bdf_parse_t; +#define setsbit( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) +#define sbitset( m, cc ) \ + ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) + static void + _bdf_list_init( _bdf_list_t* list, + FT_Memory memory ) + { + FT_ZERO( list ); + list->memory = memory; + } + static void + _bdf_list_done( _bdf_list_t* list ) + { + FT_Memory memory = list->memory; + if ( memory ) + { + FT_FREE( list->field ); + FT_ZERO( list ); + } + } + static FT_Error + _bdf_list_ensure( _bdf_list_t* list, +/* same as _bdf_list_t.used */ + unsigned long num_items ) + { + FT_Error error = BDF_Err_Ok; + if ( num_items > list->size ) + { +/* same as _bdf_list_t.size */ + unsigned long oldsize = list->size; + unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5; + unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); + FT_Memory memory = list->memory; + if ( oldsize == bigsize ) + { + error = BDF_Err_Out_Of_Memory; + goto Exit; + } + else if ( newsize < oldsize || newsize > bigsize ) + newsize = bigsize; + if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) ) + goto Exit; + list->size = newsize; + } + Exit: + return error; + } + static void + _bdf_list_shift( _bdf_list_t* list, + unsigned long n ) + { + unsigned long i, u; + if ( list == 0 || list->used == 0 || n == 0 ) + return; + if ( n >= list->used ) + { + list->used = 0; + return; + } + for ( u = n, i = 0; u < list->used; i++, u++ ) + list->field[i] = list->field[u]; + list->used -= n; + } +/* An empty string for empty fields. */ +/* XXX eliminate this */ + static const char empty[1] = { 0 }; + static char * + _bdf_list_join( _bdf_list_t* list, + int c, + unsigned long *alen ) + { + unsigned long i, j; + char *fp, *dp; + *alen = 0; + if ( list == 0 || list->used == 0 ) + return 0; + dp = list->field[0]; + for ( i = j = 0; i < list->used; i++ ) + { + fp = list->field[i]; + while ( *fp ) + dp[j++] = *fp++; + if ( i + 1 < list->used ) + dp[j++] = (char)c; + } + if ( dp != empty ) + dp[j] = 0; + *alen = j; + return dp; + } +/* The code below ensures that we have at least 4 + 1 `field' */ +/* elements in `list' (which are possibly NULL) so that we */ +/* don't have to check the number of fields in most cases. */ + static FT_Error + _bdf_list_split( _bdf_list_t* list, + char* separators, + char* line, + unsigned long linelen ) + { + int mult, final_empty; + char *sp, *ep, *end; + char seps[32]; + FT_Error error = BDF_Err_Ok; +/* Initialize the list. */ + list->used = 0; + if ( list->size ) + { + list->field[0] = (char*)empty; + list->field[1] = (char*)empty; + list->field[2] = (char*)empty; + list->field[3] = (char*)empty; + list->field[4] = (char*)empty; + } +/* If the line is empty, then simply return. */ + if ( linelen == 0 || line[0] == 0 ) + goto Exit; +/* In the original code, if the `separators' parameter is NULL or */ +/* empty, the list is split into individual bytes. We don't need */ +/* this, so an error is signaled. */ + if ( separators == 0 || *separators == 0 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } +/* Prepare the separator bitmap. */ + FT_MEM_ZERO( seps, 32 ); +/* If the very last character of the separator string is a plus, then */ +/* set the `mult' flag to indicate that multiple separators should be */ +/* collapsed into one. */ + for ( mult = 0, sp = separators; sp && *sp; sp++ ) + { + if ( *sp == '+' && *( sp + 1 ) == 0 ) + mult = 1; + else + setsbit( seps, *sp ); + } +/* Break the line up into fields. */ + for ( final_empty = 0, sp = ep = line, end = sp + linelen; + sp < end && *sp; ) + { +/* Collect everything that is not a separator. */ + for ( ; *ep && !sbitset( seps, *ep ); ep++ ) + ; +/* Resize the list if necessary. */ + if ( list->used == list->size ) + { + error = _bdf_list_ensure( list, list->used + 1 ); + if ( error ) + goto Exit; + } +/* Assign the field appropriately. */ + list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty; + sp = ep; + if ( mult ) + { +/* If multiple separators should be collapsed, do it now by */ +/* setting all the separator characters to 0. */ + for ( ; *ep && sbitset( seps, *ep ); ep++ ) + *ep = 0; + } + else if ( *ep != 0 ) +/* Don't collapse multiple separators by making them 0, so just */ +/* make the one encountered 0. */ + *ep++ = 0; + final_empty = ( ep > sp && *ep == 0 ); + sp = ep; + } +/* Finally, NULL-terminate the list. */ + if ( list->used + final_empty >= list->size ) + { + error = _bdf_list_ensure( list, list->used + final_empty + 1 ); + if ( error ) + goto Exit; + } + if ( final_empty ) + list->field[list->used++] = (char*)empty; + list->field[list->used] = 0; + Exit: + return error; + } +/* this value cannot be stored in a 'char' */ +#define NO_SKIP 256 + static FT_Error + _bdf_readstream( FT_Stream stream, + _bdf_line_func_t callback, + void* client_data, + unsigned long *lno ) + { + _bdf_line_func_t cb; + unsigned long lineno, buf_size; + int refill, hold, to_skip; + ptrdiff_t bytes, start, end, cursor, avail; + char* buf = 0; + FT_Memory memory = stream->memory; + FT_Error error = BDF_Err_Ok; + if ( callback == 0 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } +/* initial size and allocation of the input buffer */ + buf_size = 1024; + if ( FT_NEW_ARRAY( buf, buf_size ) ) + goto Exit; + cb = callback; + lineno = 1; + buf[0] = 0; + start = 0; + end = 0; + avail = 0; + cursor = 0; + refill = 1; + to_skip = NO_SKIP; +/* make compiler happy */ + bytes = 0; + for (;;) + { + if ( refill ) + { + bytes = (ptrdiff_t)FT_Stream_TryRead( + stream, (FT_Byte*)buf + cursor, + (FT_ULong)( buf_size - cursor ) ); + avail = cursor + bytes; + cursor = 0; + refill = 0; + } + end = start; +/* should we skip an optional character like \n or \r? */ + if ( start < avail && buf[start] == to_skip ) + { + start += 1; + to_skip = NO_SKIP; + continue; + } +/* try to find the end of the line */ + while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) + end++; +/* if we hit the end of the buffer, try shifting its content */ +/* or even resizing it */ + if ( end >= avail ) + { +/* last line in file doesn't end in \r or \n */ + if ( bytes == 0 ) +/* ignore it then exit */ + break; + if ( start == 0 ) + { +/* this line is definitely too long; try resizing the input */ +/* buffer a bit to handle it. */ + FT_ULong new_size; +/* limit ourselves to 64KByte */ + if ( buf_size >= 65536UL ) + { + FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno )); + error = BDF_Err_Invalid_Argument; + goto Exit; + } + new_size = buf_size * 2; + if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) ) + goto Exit; + cursor = buf_size; + buf_size = new_size; + } + else + { + bytes = avail - start; + FT_MEM_COPY( buf, buf + start, bytes ); + cursor = bytes; + avail -= bytes; + start = 0; + } + refill = 1; + continue; + } +/* Temporarily NUL-terminate the line. */ + hold = buf[end]; + buf[end] = 0; +/* XXX: Use encoding independent value for 0x1a */ + if ( buf[start] != '#' && buf[start] != 0x1a && end > start ) + { + error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, + (void*)&cb, client_data ); +/* Redo if we have encountered CHARS without properties. */ + if ( error == -1 ) + error = (*cb)( buf + start, (unsigned long)( end - start ), lineno, + (void*)&cb, client_data ); + if ( error ) + break; + } + lineno += 1; + buf[end] = (char)hold; + start = end + 1; + if ( hold == '\n' ) + to_skip = '\r'; + else if ( hold == '\r' ) + to_skip = '\n'; + else + to_skip = NO_SKIP; + } + *lno = lineno; + Exit: + FT_FREE( buf ); + return error; + } +/* XXX: make this work with EBCDIC also */ + static const unsigned char a2i[128] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char odigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + static const unsigned char ddigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + static const unsigned char hdigits[32] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, + 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; +/* Routine to convert an ASCII string into an unsigned long integer. */ + static unsigned long + _bdf_atoul( char* s, + char** end, + int base ) + { + unsigned long v; + const unsigned char* dmap; + if ( s == 0 || *s == 0 ) + return 0; +/* Make sure the radix is something recognizable. Default to 10. */ + switch ( base ) + { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } +/* Check for the special hex prefix. */ + if ( *s == '0' && + ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) + { + base = 16; + dmap = hdigits; + s += 2; + } + for ( v = 0; sbitset( dmap, *s ); s++ ) + v = v * base + a2i[(int)*s]; + if ( end != 0 ) + *end = s; + return v; + } +/* Routine to convert an ASCII string into an signed long integer. */ + static long + _bdf_atol( char* s, + char** end, + int base ) + { + long v, neg; + const unsigned char* dmap; + if ( s == 0 || *s == 0 ) + return 0; +/* Make sure the radix is something recognizable. Default to 10. */ + switch ( base ) + { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } +/* Check for a minus sign. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } +/* Check for the special hex prefix. */ + if ( *s == '0' && + ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) + { + base = 16; + dmap = hdigits; + s += 2; + } + for ( v = 0; sbitset( dmap, *s ); s++ ) + v = v * base + a2i[(int)*s]; + if ( end != 0 ) + *end = s; + return ( !neg ) ? v : -v; + } +/* Routine to convert an ASCII string into an signed short integer. */ + static short + _bdf_atos( char* s, + char** end, + int base ) + { + short v, neg; + const unsigned char* dmap; + if ( s == 0 || *s == 0 ) + return 0; +/* Make sure the radix is something recognizable. Default to 10. */ + switch ( base ) + { + case 8: + dmap = odigits; + break; + case 16: + dmap = hdigits; + break; + default: + base = 10; + dmap = ddigits; + break; + } +/* Check for a minus. */ + neg = 0; + if ( *s == '-' ) + { + s++; + neg = 1; + } +/* Check for the special hex prefix. */ + if ( *s == '0' && + ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) + { + base = 16; + dmap = hdigits; + s += 2; + } + for ( v = 0; sbitset( dmap, *s ); s++ ) + v = (short)( v * base + a2i[(int)*s] ); + if ( end != 0 ) + *end = s; + return (short)( ( !neg ) ? v : -v ); + } +/* Routine to compare two glyphs by encoding so they can be sorted. */ + static int + by_encoding( const void* a, + const void* b ) + { + bdf_glyph_t *c1, *c2; + c1 = (bdf_glyph_t *)a; + c2 = (bdf_glyph_t *)b; + if ( c1->encoding < c2->encoding ) + return -1; + if ( c1->encoding > c2->encoding ) + return 1; + return 0; + } + static FT_Error + bdf_create_property( char* name, + int format, + bdf_font_t* font ) + { + size_t n; + bdf_property_t* p; + FT_Memory memory = font->memory; + FT_Error error = BDF_Err_Ok; +/* First check whether the property has */ +/* already been added or not. If it has, then */ +/* simply ignore it. */ + if ( hash_lookup( name, &(font->proptbl) ) ) + goto Exit; + if ( FT_RENEW_ARRAY( font->user_props, + font->nuser_props, + font->nuser_props + 1 ) ) + goto Exit; + p = font->user_props + font->nuser_props; + FT_ZERO( p ); + n = ft_strlen( name ) + 1; + if ( n > FT_ULONG_MAX ) + return BDF_Err_Invalid_Argument; + if ( FT_NEW_ARRAY( p->name, n ) ) + goto Exit; + FT_MEM_COPY( (char *)p->name, name, n ); + p->format = format; + p->builtin = 0; + n = _num_bdf_properties + font->nuser_props; + error = hash_insert( p->name, n, &(font->proptbl), memory ); + if ( error ) + goto Exit; + font->nuser_props++; + Exit: + return error; + } + FT_LOCAL_DEF( bdf_property_t * ) + bdf_get_property( char* name, + bdf_font_t* font ) + { + hashnode hn; + size_t propid; + if ( name == 0 || *name == 0 ) + return 0; + if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 ) + return 0; + propid = hn->data; + if ( propid >= _num_bdf_properties ) + return font->user_props + ( propid - _num_bdf_properties ); + return (bdf_property_t*)_bdf_properties + propid; + } +/*************************************************************************/ +/* */ +/* BDF font file parsing flags and functions. */ +/* */ +/*************************************************************************/ +/* Parse flags. */ +#define _BDF_START 0x0001 +#define _BDF_FONT_NAME 0x0002 +#define _BDF_SIZE 0x0004 +#define _BDF_FONT_BBX 0x0008 +#define _BDF_PROPS 0x0010 +#define _BDF_GLYPHS 0x0020 +#define _BDF_GLYPH 0x0040 +#define _BDF_ENCODING 0x0080 +#define _BDF_SWIDTH 0x0100 +#define _BDF_DWIDTH 0x0200 +#define _BDF_BBX 0x0400 +#define _BDF_BITMAP 0x0800 +#define _BDF_SWIDTH_ADJ 0x1000 +#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \ + _BDF_ENCODING | \ + _BDF_SWIDTH | \ + _BDF_DWIDTH | \ + _BDF_BBX | \ + _BDF_BITMAP ) +#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL +#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL + static FT_Error + _bdf_add_comment( bdf_font_t* font, + char* comment, + unsigned long len ) + { + char* cp; + FT_Memory memory = font->memory; + FT_Error error = BDF_Err_Ok; + if ( FT_RENEW_ARRAY( font->comments, + font->comments_len, + font->comments_len + len + 1 ) ) + goto Exit; + cp = font->comments + font->comments_len; + FT_MEM_COPY( cp, comment, len ); + cp[len] = '\n'; + font->comments_len += len + 1; + Exit: + return error; + } +/* Set the spacing from the font name if it exists, or set it to the */ +/* default specified in the options. */ + static FT_Error + _bdf_set_default_spacing( bdf_font_t* font, + bdf_options_t* opts, + unsigned long lineno ) + { + size_t len; + char name[256]; + _bdf_list_t list; + FT_Memory memory; + FT_Error error = BDF_Err_Ok; + if ( font == 0 || font->name == 0 || font->name[0] == 0 ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } + memory = font->memory; + _bdf_list_init( &list, memory ); + font->spacing = opts->font_spacing; + len = ft_strlen( font->name ) + 1; +/* Limit ourselves to 256 characters in the font name. */ + if ( len >= 256 ) + { + FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno )); + error = BDF_Err_Invalid_Argument; + goto Exit; + } + FT_MEM_COPY( name, font->name, len ); + error = _bdf_list_split( &list, (char *)"-", name, len ); + if ( error ) + goto Fail; + if ( list.used == 15 ) + { + switch ( list.field[11][0] ) + { + case 'C': + case 'c': + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + font->spacing = BDF_PROPORTIONAL; + break; + } + } + Fail: + _bdf_list_done( &list ); + Exit: + return error; + } +/* Determine whether the property is an atom or not. If it is, then */ +/* clean it up so the double quotes are removed if they exist. */ + static int + _bdf_is_atom( char* line, + unsigned long linelen, + char** name, + char** value, + bdf_font_t* font ) + { + int hold; + char *sp, *ep; + bdf_property_t* p; + *name = sp = ep = line; + while ( *ep && *ep != ' ' && *ep != '\t' ) + ep++; + hold = -1; + if ( *ep ) + { + hold = *ep; + *ep = 0; + } + p = bdf_get_property( sp, font ); +/* Restore the character that was saved before any return can happen. */ + if ( hold != -1 ) + *ep = (char)hold; +/* If the property exists and is not an atom, just return here. */ + if ( p && p->format != BDF_ATOM ) + return 0; +/* The property is an atom. Trim all leading and trailing whitespace */ +/* and double quotes for the atom value. */ + sp = ep; + ep = line + linelen; +/* Trim the leading whitespace if it exists. */ + if ( *sp ) + *sp++ = 0; + while ( *sp && + ( *sp == ' ' || *sp == '\t' ) ) + sp++; +/* Trim the leading double quote if it exists. */ + if ( *sp == '"' ) + sp++; + *value = sp; +/* Trim the trailing whitespace if it exists. */ + while ( ep > sp && + ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) ) + *--ep = 0; +/* Trim the trailing double quote if it exists. */ + if ( ep > sp && *( ep - 1 ) == '"' ) + *--ep = 0; + return 1; + } + static FT_Error + _bdf_add_property( bdf_font_t* font, + char* name, + char* value, + unsigned long lineno ) + { + size_t propid; + hashnode hn; + bdf_property_t *prop, *fp; + FT_Memory memory = font->memory; + FT_Error error = BDF_Err_Ok; +/* First, check whether the property already exists in the font. */ + if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 ) + { +/* The property already exists in the font, so simply replace */ +/* the value of the property with the current value. */ + fp = font->props + hn->data; + switch ( fp->format ) + { + case BDF_ATOM: +/* Delete the current atom if it exists. */ + FT_FREE( fp->value.atom ); + if ( value && value[0] != 0 ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + case BDF_INTEGER: + fp->value.l = _bdf_atol( value, 0, 10 ); + break; + case BDF_CARDINAL: + fp->value.ul = _bdf_atoul( value, 0, 10 ); + break; + default: + ; + } + goto Exit; + } +/* See whether this property type exists yet or not. */ +/* If not, create it. */ + hn = hash_lookup( name, &(font->proptbl) ); + if ( hn == 0 ) + { + error = bdf_create_property( name, BDF_ATOM, font ); + if ( error ) + goto Exit; + hn = hash_lookup( name, &(font->proptbl) ); + } +/* Allocate another property if this is overflow. */ + if ( font->props_used == font->props_size ) + { + if ( font->props_size == 0 ) + { + if ( FT_NEW_ARRAY( font->props, 1 ) ) + goto Exit; + } + else + { + if ( FT_RENEW_ARRAY( font->props, + font->props_size, + font->props_size + 1 ) ) + goto Exit; + } + fp = font->props + font->props_size; + FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) ); + font->props_size++; + } + propid = hn->data; + if ( propid >= _num_bdf_properties ) + prop = font->user_props + ( propid - _num_bdf_properties ); + else + prop = (bdf_property_t*)_bdf_properties + propid; + fp = font->props + font->props_used; + fp->name = prop->name; + fp->format = prop->format; + fp->builtin = prop->builtin; + switch ( prop->format ) + { + case BDF_ATOM: + fp->value.atom = 0; + if ( value != 0 && value[0] ) + { + if ( FT_STRDUP( fp->value.atom, value ) ) + goto Exit; + } + break; + case BDF_INTEGER: + fp->value.l = _bdf_atol( value, 0, 10 ); + break; + case BDF_CARDINAL: + fp->value.ul = _bdf_atoul( value, 0, 10 ); + break; + } +/* If the property happens to be a comment, then it doesn't need */ +/* to be added to the internal hash table. */ + if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) + { +/* Add the property to the font property table. */ + error = hash_insert( fp->name, + font->props_used, + (hashtable *)font->internal, + memory ); + if ( error ) + goto Exit; + } + font->props_used++; +/* Some special cases need to be handled here. The DEFAULT_CHAR */ +/* property needs to be located if it exists in the property list, the */ +/* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ +/* present, and the SPACING property should override the default */ +/* spacing. */ + if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 ) + font->default_char = fp->value.l; + else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 ) + font->font_ascent = fp->value.l; + else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 ) + font->font_descent = fp->value.l; + else if ( ft_memcmp( name, "SPACING", 7 ) == 0 ) + { + if ( !fp->value.atom ) + { + FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" )); + error = BDF_Err_Invalid_File_Format; + goto Exit; + } + if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) + font->spacing = BDF_PROPORTIONAL; + else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) + font->spacing = BDF_MONOWIDTH; + else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) + font->spacing = BDF_CHARCELL; + } + Exit: + return error; + } + static const unsigned char nibble_mask[8] = + { + 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE + }; +/* Actually parse the glyph info and bitmaps. */ + static FT_Error + _bdf_parse_glyphs( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + int c, mask_index; + char* s; + unsigned char* bp; + unsigned long i, slen, nibbles; + _bdf_parse_t* p; + bdf_glyph_t* glyph; + bdf_font_t* font; + FT_Memory memory; + FT_Error error = BDF_Err_Ok; + FT_UNUSED( call_data ); +/* only used in debug mode */ + FT_UNUSED( lineno ); + p = (_bdf_parse_t *)client_data; + font = p->font; + memory = font->memory; +/* Check for a comment. */ + if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) + { + linelen -= 7; + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = _bdf_add_comment( p->font, s, linelen ); + goto Exit; + } +/* The very first thing expected is the number of glyphs. */ + if ( !( p->flags & _BDF_GLYPHS ) ) + { + if ( ft_memcmp( line, "CHARS", 5 ) != 0 ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); + error = BDF_Err_Missing_Chars_Field; + goto Exit; + } + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 ); +/* Make sure the number of glyphs is non-zero. */ + if ( p->cnt == 0 ) + font->glyphs_size = 64; +/* Limit ourselves to 1,114,112 glyphs in the font (this is the */ +/* number of code points available in Unicode). */ + if ( p->cnt >= 0x110000UL ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" )); + error = BDF_Err_Invalid_Argument; + goto Exit; + } + if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) + goto Exit; + p->flags |= _BDF_GLYPHS; + goto Exit; + } +/* Check for the ENDFONT field. */ + if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 ) + { +/* Sort the glyphs by encoding. */ + ft_qsort( (char *)font->glyphs, + font->glyphs_used, + sizeof ( bdf_glyph_t ), + by_encoding ); + p->flags &= ~_BDF_START; + goto Exit; + } +/* Check for the ENDCHAR field. */ + if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 ) + { + p->glyph_enc = 0; + p->flags &= ~_BDF_GLYPH_BITS; + goto Exit; + } +/* Check whether a glyph is being scanned but should be */ +/* ignored because it is an unencoded glyph. */ + if ( ( p->flags & _BDF_GLYPH ) && + p->glyph_enc == -1 && + p->opts->keep_unencoded == 0 ) + goto Exit; +/* Check for the STARTCHAR field. */ + if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 ) + { +/* Set the character name in the parse info first until the */ +/* encoding can be checked for an unencoded character. */ + FT_FREE( p->glyph_name ); + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + _bdf_list_shift( &p->list, 1 ); + s = _bdf_list_join( &p->list, ' ', &slen ); + if ( !s ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" )); + error = BDF_Err_Invalid_File_Format; + goto Exit; + } + if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) ) + goto Exit; + FT_MEM_COPY( p->glyph_name, s, slen + 1 ); + p->flags |= _BDF_GLYPH; + FT_TRACE4(( DBGMSG1, lineno, s )); + goto Exit; + } +/* Check for the ENCODING field. */ + if ( ft_memcmp( line, "ENCODING", 8 ) == 0 ) + { + if ( !( p->flags & _BDF_GLYPH ) ) + { +/* Missing STARTCHAR field. */ + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); + error = BDF_Err_Missing_Startchar_Field; + goto Exit; + } + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 ); +/* Normalize negative encoding values. The specification only */ +/* allows -1, but we can be more generous here. */ + if ( p->glyph_enc < -1 ) + p->glyph_enc = -1; +/* Check for alternative encoding format. */ + if ( p->glyph_enc == -1 && p->list.used > 2 ) + p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 ); + if ( p->glyph_enc < -1 ) + p->glyph_enc = -1; + FT_TRACE4(( DBGMSG2, p->glyph_enc )); +/* Check that the encoding is in the Unicode range because */ +/* otherwise p->have (a bitmap with static size) overflows. */ + if ( p->glyph_enc > 0 && + (size_t)p->glyph_enc >= sizeof ( p->have ) / + sizeof ( unsigned long ) * 32 ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" )); + error = BDF_Err_Invalid_File_Format; + goto Exit; + } +/* Check whether this encoding has already been encountered. */ +/* If it has then change it to unencoded so it gets added if */ +/* indicated. */ + if ( p->glyph_enc >= 0 ) + { + if ( _bdf_glyph_modified( p->have, p->glyph_enc ) ) + { +/* Emit a message saying a glyph has been moved to the */ +/* unencoded area. */ + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12, + p->glyph_enc, p->glyph_name )); + p->glyph_enc = -1; + font->modified = 1; + } + else + _bdf_set_glyph_modified( p->have, p->glyph_enc ); + } + if ( p->glyph_enc >= 0 ) + { +/* Make sure there are enough glyphs allocated in case the */ +/* number of characters happen to be wrong. */ + if ( font->glyphs_used == font->glyphs_size ) + { + if ( FT_RENEW_ARRAY( font->glyphs, + font->glyphs_size, + font->glyphs_size + 64 ) ) + goto Exit; + font->glyphs_size += 64; + } + glyph = font->glyphs + font->glyphs_used++; + glyph->name = p->glyph_name; + glyph->encoding = p->glyph_enc; +/* Reset the initial glyph info. */ + p->glyph_name = 0; + } + else + { +/* Unencoded glyph. Check whether it should */ +/* be added or not. */ + if ( p->opts->keep_unencoded != 0 ) + { +/* Allocate the next unencoded glyph. */ + if ( font->unencoded_used == font->unencoded_size ) + { + if ( FT_RENEW_ARRAY( font->unencoded , + font->unencoded_size, + font->unencoded_size + 4 ) ) + goto Exit; + font->unencoded_size += 4; + } + glyph = font->unencoded + font->unencoded_used; + glyph->name = p->glyph_name; + glyph->encoding = font->unencoded_used++; + } + else +/* Free up the glyph name if the unencoded shouldn't be */ +/* kept. */ + FT_FREE( p->glyph_name ); + p->glyph_name = 0; + } +/* Clear the flags that might be added when width and height are */ +/* checked for consistency. */ + p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK ); + p->flags |= _BDF_ENCODING; + goto Exit; + } +/* Point at the glyph being constructed. */ + if ( p->glyph_enc == -1 ) + glyph = font->unencoded + ( font->unencoded_used - 1 ); + else + glyph = font->glyphs + ( font->glyphs_used - 1 ); +/* Check whether a bitmap is being constructed. */ + if ( p->flags & _BDF_BITMAP ) + { +/* If there are more rows than are specified in the glyph metrics, */ +/* ignore the remaining lines. */ + if ( p->row >= (unsigned long)glyph->bbx.height ) + { + if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) ) + { + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding )); + p->flags |= _BDF_GLYPH_HEIGHT_CHECK; + font->modified = 1; + } + goto Exit; + } +/* Only collect the number of nibbles indicated by the glyph */ +/* metrics. If there are more columns, they are simply ignored. */ + nibbles = glyph->bpr << 1; + bp = glyph->bitmap + p->row * glyph->bpr; + for ( i = 0; i < nibbles; i++ ) + { + c = line[i]; + if ( !sbitset( hdigits, c ) ) + break; + *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); + if ( i + 1 < nibbles && ( i & 1 ) ) + *++bp = 0; + } +/* If any line has not enough columns, */ +/* indicate they have been padded with zero bits. */ + if ( i < nibbles && + !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) + { + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding )); + p->flags |= _BDF_GLYPH_WIDTH_CHECK; + font->modified = 1; + } +/* Remove possible garbage at the right. */ + mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; + if ( glyph->bbx.width ) + *bp &= nibble_mask[mask_index]; +/* If any line has extra columns, indicate they have been removed. */ + if ( i == nibbles && + sbitset( hdigits, line[nibbles] ) && + !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) + { + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); + p->flags |= _BDF_GLYPH_WIDTH_CHECK; + font->modified = 1; + } + p->row++; + goto Exit; + } +/* Expect the SWIDTH (scalable width) field next. */ + if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 ) + { + if ( !( p->flags & _BDF_ENCODING ) ) + goto Missing_Encoding; + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); + p->flags |= _BDF_SWIDTH; + goto Exit; + } +/* Expect the DWIDTH (scalable width) field next. */ + if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 ) + { + if ( !( p->flags & _BDF_ENCODING ) ) + goto Missing_Encoding; + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); + if ( !( p->flags & _BDF_SWIDTH ) ) + { +/* Missing SWIDTH field. Emit an auto correction message and set */ +/* the scalable width from the device width. */ + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno )); + glyph->swidth = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + } + p->flags |= _BDF_DWIDTH; + goto Exit; + } +/* Expect the BBX field next. */ + if ( ft_memcmp( line, "BBX", 3 ) == 0 ) + { + if ( !( p->flags & _BDF_ENCODING ) ) + goto Missing_Encoding; + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); + glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); + glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); + glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); +/* Generate the ascent and descent of the character. */ + glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); + glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); +/* Determine the overall font bounding box as the characters are */ +/* loaded so corrections can be done later if indicated. */ + p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); + p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); + p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); + p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); + p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); + p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); + if ( !( p->flags & _BDF_DWIDTH ) ) + { +/* Missing DWIDTH field. Emit an auto correction message and set */ +/* the device width to the glyph width. */ + FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); + glyph->dwidth = glyph->bbx.width; + } +/* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ +/* value if necessary. */ + if ( p->opts->correct_metrics != 0 ) + { +/* Determine the point size of the glyph. */ + unsigned short sw = (unsigned short)FT_MulDiv( + glyph->dwidth, 72000L, + (FT_Long)( font->point_size * + font->resolution_x ) ); + if ( sw != glyph->swidth ) + { + glyph->swidth = sw; + if ( p->glyph_enc == -1 ) + _bdf_set_glyph_modified( font->umod, + font->unencoded_used - 1 ); + else + _bdf_set_glyph_modified( font->nmod, glyph->encoding ); + p->flags |= _BDF_SWIDTH_ADJ; + font->modified = 1; + } + } + p->flags |= _BDF_BBX; + goto Exit; + } +/* And finally, gather up the bitmap. */ + if ( ft_memcmp( line, "BITMAP", 6 ) == 0 ) + { + unsigned long bitmap_size; + if ( !( p->flags & _BDF_BBX ) ) + { +/* Missing BBX field. */ + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); + error = BDF_Err_Missing_Bbx_Field; + goto Exit; + } +/* Allocate enough space for the bitmap. */ + glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; + bitmap_size = glyph->bpr * glyph->bbx.height; + if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) + { + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); + error = BDF_Err_Bbx_Too_Big; + goto Exit; + } + else + glyph->bytes = (unsigned short)bitmap_size; + if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) ) + goto Exit; + p->row = 0; + p->flags |= _BDF_BITMAP; + goto Exit; + } + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno )); + error = BDF_Err_Invalid_File_Format; + goto Exit; + Missing_Encoding: +/* Missing ENCODING field. */ + FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); + error = BDF_Err_Missing_Encoding_Field; + Exit: + if ( error && ( p->flags & _BDF_GLYPH ) ) + FT_FREE( p->glyph_name ); + return error; + } +/* Load the font properties. */ + static FT_Error + _bdf_parse_properties( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long vlen; + _bdf_line_func_t* next; + _bdf_parse_t* p; + char* name; + char* value; + char nbuf[128]; + FT_Error error = BDF_Err_Ok; + FT_UNUSED( lineno ); + next = (_bdf_line_func_t *)call_data; + p = (_bdf_parse_t *) client_data; +/* Check for the end of the properties. */ + if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 ) + { +/* If the FONT_ASCENT or FONT_DESCENT properties have not been */ +/* encountered yet, then make sure they are added as properties and */ +/* make sure they are set from the font bounding box info. */ +/* */ +/* This is *always* done regardless of the options, because X11 */ +/* requires these two fields to compile fonts. */ + if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) + { + p->font->font_ascent = p->font->bbx.ascent; + ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); + error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); + p->font->modified = 1; + } + if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) + { + p->font->font_descent = p->font->bbx.descent; + ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); + error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); + p->font->modified = 1; + } + p->flags &= ~_BDF_PROPS; + *next = _bdf_parse_glyphs; + goto Exit; + } +/* Ignore the _XFREE86_GLYPH_RANGES properties. */ + if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) + goto Exit; +/* Handle COMMENT fields and properties in a special way to preserve */ +/* the spacing. */ + if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) + { + name = value = line; + value += 7; + if ( *value ) + *value++ = 0; + error = _bdf_add_property( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) + { + error = _bdf_add_property( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + else + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + name = p->list.field[0]; + _bdf_list_shift( &p->list, 1 ); + value = _bdf_list_join( &p->list, ' ', &vlen ); + error = _bdf_add_property( p->font, name, value, lineno ); + if ( error ) + goto Exit; + } + Exit: + return error; + } +/* Load the font header. */ + static FT_Error + _bdf_parse_start( char* line, + unsigned long linelen, + unsigned long lineno, + void* call_data, + void* client_data ) + { + unsigned long slen; + _bdf_line_func_t* next; + _bdf_parse_t* p; + bdf_font_t* font; + char *s; + FT_Memory memory = NULL; + FT_Error error = BDF_Err_Ok; +/* only used in debug mode */ + FT_UNUSED( lineno ); + next = (_bdf_line_func_t *)call_data; + p = (_bdf_parse_t *) client_data; + if ( p->font ) + memory = p->font->memory; +/* Check for a comment. This is done to handle those fonts that have */ +/* comments before the STARTFONT line for some reason. */ + if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->opts->keep_comments != 0 && p->font != 0 ) + { + linelen -= 7; + s = line + 7; + if ( *s != 0 ) + { + s++; + linelen--; + } + error = _bdf_add_comment( p->font, s, linelen ); + if ( error ) + goto Exit; +/* here font is not defined! */ + } + goto Exit; + } + if ( !( p->flags & _BDF_START ) ) + { + memory = p->memory; + if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 ) + { +/* we don't emit an error message since this code gets */ +/* explicitly caught one level higher */ + error = BDF_Err_Missing_Startfont_Field; + goto Exit; + } + p->flags = _BDF_START; + font = p->font = 0; + if ( FT_NEW( font ) ) + goto Exit; + p->font = font; + font->memory = p->memory; + p->memory = 0; +/* setup */ + { + size_t i; + bdf_property_t* prop; + error = hash_init( &(font->proptbl), memory ); + if ( error ) + goto Exit; + for ( i = 0, prop = (bdf_property_t*)_bdf_properties; + i < _num_bdf_properties; i++, prop++ ) + { + error = hash_insert( prop->name, i, + &(font->proptbl), memory ); + if ( error ) + goto Exit; + } + } + if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) ) + goto Exit; + error = hash_init( (hashtable *)p->font->internal,memory ); + if ( error ) + goto Exit; + p->font->spacing = p->opts->font_spacing; + p->font->default_char = -1; + goto Exit; + } +/* Check for the start of the properties. */ + if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 ) + { + if ( !( p->flags & _BDF_FONT_BBX ) ) + { +/* Missing the FONTBOUNDINGBOX field. */ + FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + error = BDF_Err_Missing_Fontboundingbox_Field; + goto Exit; + } + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; +/* at this point, `p->font' can't be NULL */ + p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 ); + if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) + { + p->font->props_size = 0; + goto Exit; + } + p->flags |= _BDF_PROPS; + *next = _bdf_parse_properties; + goto Exit; + } +/* Check for the FONTBOUNDINGBOX field. */ + if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) + { + if ( !( p->flags & _BDF_SIZE ) ) + { +/* Missing the SIZE field. */ + FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); + error = BDF_Err_Missing_Size_Field; + goto Exit; + } + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); + p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); + p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); + p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); + p->font->bbx.ascent = (short)( p->font->bbx.height + + p->font->bbx.y_offset ); + p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); + p->flags |= _BDF_FONT_BBX; + goto Exit; + } +/* The next thing to check for is the FONT field. */ + if ( ft_memcmp( line, "FONT", 4 ) == 0 ) + { + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + _bdf_list_shift( &p->list, 1 ); + s = _bdf_list_join( &p->list, ' ', &slen ); + if ( !s ) + { + FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" )); + error = BDF_Err_Invalid_File_Format; + goto Exit; + } +/* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ + FT_FREE( p->font->name ); + if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) ) + goto Exit; + FT_MEM_COPY( p->font->name, s, slen + 1 ); +/* If the font name is an XLFD name, set the spacing to the one in */ +/* the font name. If there is no spacing fall back on the default. */ + error = _bdf_set_default_spacing( p->font, p->opts, lineno ); + if ( error ) + goto Exit; + p->flags |= _BDF_FONT_NAME; + goto Exit; + } +/* Check for the SIZE field. */ + if ( ft_memcmp( line, "SIZE", 4 ) == 0 ) + { + if ( !( p->flags & _BDF_FONT_NAME ) ) + { +/* Missing the FONT field. */ + FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); + error = BDF_Err_Missing_Font_Field; + goto Exit; + } + error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); + if ( error ) + goto Exit; + p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 ); + p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 ); + p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 ); +/* Check for the bits per pixel field. */ + if ( p->list.used == 5 ) + { + unsigned short bitcount, i, shift; + p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 ); +/* Only values 1, 2, 4, 8 are allowed. */ + shift = p->font->bpp; + bitcount = 0; + for ( i = 0; shift > 0; i++ ) + { + if ( shift & 1 ) + bitcount = i; + shift >>= 1; + } + shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) ); + if ( p->font->bpp > shift || p->font->bpp != shift ) + { +/* select next higher value */ + p->font->bpp = (unsigned short)( shift << 1 ); + FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); + } + } + else + p->font->bpp = 1; + p->flags |= _BDF_SIZE; + goto Exit; + } +/* Check for the CHARS field -- font properties are optional */ + if ( ft_memcmp( line, "CHARS", 5 ) == 0 ) + { + char nbuf[128]; + if ( !( p->flags & _BDF_FONT_BBX ) ) + { +/* Missing the FONTBOUNDINGBOX field. */ + FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + error = BDF_Err_Missing_Fontboundingbox_Field; + goto Exit; + } +/* Add the two standard X11 properties which are required */ +/* for compiling fonts. */ + p->font->font_ascent = p->font->bbx.ascent; + ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); + error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); + p->font->font_descent = p->font->bbx.descent; + ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); + error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", + nbuf, lineno ); + if ( error ) + goto Exit; + FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); + p->font->modified = 1; + *next = _bdf_parse_glyphs; +/* A special return value. */ + error = -1; + goto Exit; + } + FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno )); + error = BDF_Err_Invalid_File_Format; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* API. */ +/* */ +/*************************************************************************/ + FT_LOCAL_DEF( FT_Error ) + bdf_load_font( FT_Stream stream, + FT_Memory extmemory, + bdf_options_t* opts, + bdf_font_t* *font ) + { +/* make compiler happy */ + unsigned long lineno = 0; + _bdf_parse_t *p = NULL; + FT_Memory memory = extmemory; + FT_Error error = BDF_Err_Ok; + if ( FT_NEW( p ) ) + goto Exit; + memory = NULL; + p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts ); + p->minlb = 32767; +/* only during font creation */ + p->memory = extmemory; + _bdf_list_init( &p->list, extmemory ); + error = _bdf_readstream( stream, _bdf_parse_start, + (void *)p, &lineno ); + if ( error ) + goto Fail; + if ( p->font != 0 ) + { +/* If the font is not proportional, set the font's monowidth */ +/* field to the width of the font bounding box. */ + memory = p->font->memory; + if ( p->font->spacing != BDF_PROPORTIONAL ) + p->font->monowidth = p->font->bbx.width; +/* If the number of glyphs loaded is not that of the original count, */ +/* indicate the difference. */ + if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, + p->font->glyphs_used + p->font->unencoded_used )); + p->font->modified = 1; + } +/* Once the font has been loaded, adjust the overall font metrics if */ +/* necessary. */ + if ( p->opts->correct_metrics != 0 && + ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) + { + if ( p->maxrb - p->minlb != p->font->bbx.width ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG3, + p->font->bbx.width, p->maxrb - p->minlb )); + p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); + p->font->modified = 1; + } + if ( p->font->bbx.x_offset != p->minlb ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG4, + p->font->bbx.x_offset, p->minlb )); + p->font->bbx.x_offset = p->minlb; + p->font->modified = 1; + } + if ( p->font->bbx.ascent != p->maxas ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG5, + p->font->bbx.ascent, p->maxas )); + p->font->bbx.ascent = p->maxas; + p->font->modified = 1; + } + if ( p->font->bbx.descent != p->maxds ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG6, + p->font->bbx.descent, p->maxds )); + p->font->bbx.descent = p->maxds; + p->font->bbx.y_offset = (short)( -p->maxds ); + p->font->modified = 1; + } + if ( p->maxas + p->maxds != p->font->bbx.height ) + { + FT_TRACE2(( "bdf_load_font: " ACMSG7, + p->font->bbx.height, p->maxas + p->maxds )); + p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); + } + if ( p->flags & _BDF_SWIDTH_ADJ ) + FT_TRACE2(( "bdf_load_font: " ACMSG8 )); + } + } + if ( p->flags & _BDF_START ) + { +/* The ENDFONT field was never reached or did not exist. */ + if ( !( p->flags & _BDF_GLYPHS ) ) + { +/* Error happened while parsing header. */ + FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); + error = BDF_Err_Corrupted_Font_Header; + goto Exit; + } + else + { +/* Error happened when parsing glyphs. */ + FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); + error = BDF_Err_Corrupted_Font_Glyphs; + goto Exit; + } + } + if ( p->font != 0 ) + { +/* Make sure the comments are NULL terminated if they exist. */ + memory = p->font->memory; + if ( p->font->comments_len > 0 ) + { + if ( FT_RENEW_ARRAY( p->font->comments, + p->font->comments_len, + p->font->comments_len + 1 ) ) + goto Fail; + p->font->comments[p->font->comments_len] = 0; + } + } + else if ( error == BDF_Err_Ok ) + error = BDF_Err_Invalid_File_Format; + *font = p->font; + Exit: + if ( p ) + { + _bdf_list_done( &p->list ); + memory = extmemory; + FT_FREE( p ); + } + return error; + Fail: + bdf_free_font( p->font ); + memory = extmemory; + FT_FREE( p->font ); + goto Exit; + } + FT_LOCAL_DEF( void ) + bdf_free_font( bdf_font_t* font ) + { + bdf_property_t* prop; + unsigned long i; + bdf_glyph_t* glyphs; + FT_Memory memory; + if ( font == 0 ) + return; + memory = font->memory; + FT_FREE( font->name ); +/* Free up the internal hash table of property names. */ + if ( font->internal ) + { + hash_free( (hashtable *)font->internal, memory ); + FT_FREE( font->internal ); + } +/* Free up the comment info. */ + FT_FREE( font->comments ); +/* Free up the properties. */ + for ( i = 0; i < font->props_size; i++ ) + { + if ( font->props[i].format == BDF_ATOM ) + FT_FREE( font->props[i].value.atom ); + } + FT_FREE( font->props ); +/* Free up the character info. */ + for ( i = 0, glyphs = font->glyphs; + i < font->glyphs_used; i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; + i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + FT_FREE( font->glyphs ); + FT_FREE( font->unencoded ); +/* Free up the overflow storage if it was used. */ + for ( i = 0, glyphs = font->overflow.glyphs; + i < font->overflow.glyphs_used; i++, glyphs++ ) + { + FT_FREE( glyphs->name ); + FT_FREE( glyphs->bitmap ); + } + FT_FREE( font->overflow.glyphs ); +/* bdf_cleanup */ + hash_free( &(font->proptbl), memory ); +/* Free up the user defined properties. */ + for ( prop = font->user_props, i = 0; + i < font->nuser_props; i++, prop++ ) + { + FT_FREE( prop->name ); + if ( prop->format == BDF_ATOM ) + FT_FREE( prop->value.atom ); + } + FT_FREE( font->user_props ); +/* FREE( font ); *//* XXX Fixme */ + } + FT_LOCAL_DEF( bdf_property_t * ) + bdf_get_font_property( bdf_font_t* font, + const char* name ) + { + hashnode hn; + if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 ) + return 0; + hn = hash_lookup( name, (hashtable *)font->internal ); + return hn ? ( font->props + hn->data ) : 0; + } +/* END */ +/* bdfdrivr.c + + FreeType font driver for bdf files + + Copyright (C) 2001-2008, 2011 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. +*/ +/* 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. +*/ +#define __BDFDRIVR_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_CharMap charmap_handle; +/* a single charmap per face */ + FT_CharMapRec charmap; + FT_UInt default_glyph; + } BDF_FaceRec, *BDF_Face; + FT_EXPORT_VAR( const FT_Driver_ClassRec ) bdf_driver_class; +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_bdfdriver + typedef struct BDF_CMapRec_ + { + FT_CMapRec cmap; +/* ftobjs.h: FT_CMap->clazz->size */ + FT_ULong num_encodings; + BDF_encoding_el* encodings; + } BDF_CMapRec, *BDF_CMap; + FT_CALLBACK_DEF( FT_Error ) + bdf_cmap_init( FT_CMap bdfcmap, + FT_Pointer init_data ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap ); + FT_UNUSED( init_data ); + cmap->num_encodings = face->bdffont->glyphs_used; + cmap->encodings = face->en_table; + return BDF_Err_Ok; + } + FT_CALLBACK_DEF( void ) + bdf_cmap_done( FT_CMap bdfcmap ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + cmap->encodings = NULL; + cmap->num_encodings = 0; + } + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_index( FT_CMap bdfcmap, + FT_UInt32 charcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; +/* num_encodings */ + FT_ULong min, max, mid; +/* encodings->glyph */ + FT_UShort result = 0; + min = 0; + max = cmap->num_encodings; + while ( min < max ) + { + FT_ULong code; + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + if ( charcode == code ) + { +/* increase glyph index by 1 -- */ +/* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + break; + } + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + return result; + } + FT_CALLBACK_DEF( FT_UInt ) + bdf_cmap_char_next( FT_CMap bdfcmap, + FT_UInt32 *acharcode ) + { + BDF_CMap cmap = (BDF_CMap)bdfcmap; + BDF_encoding_el* encodings = cmap->encodings; +/* num_encodings */ + FT_ULong min, max, mid; +/* encodings->glyph */ + FT_UShort result = 0; + FT_ULong charcode = *acharcode + 1; + min = 0; + max = cmap->num_encodings; + while ( min < max ) + { +/* same as BDF_encoding_el.enc */ + FT_ULong code; + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + if ( charcode == code ) + { +/* increase glyph index by 1 -- */ +/* we reserve slot 0 for the undefined glyph */ + result = encodings[mid].glyph + 1; + goto Exit; + } + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + charcode = 0; + if ( min < cmap->num_encodings ) + { + charcode = encodings[min].enc; + result = encodings[min].glyph + 1; + } + Exit: + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%x > 32bit API" )); + *acharcode = 0; +/* XXX: result should be changed to indicate an overflow error */ + } + else + *acharcode = (FT_UInt32)charcode; + return result; + } + FT_CALLBACK_TABLE_DEF + const FT_CMap_ClassRec bdf_cmap_class = + { + sizeof ( BDF_CMapRec ), + bdf_cmap_init, + bdf_cmap_done, + bdf_cmap_char_index, + bdf_cmap_char_next, + NULL, NULL, NULL, NULL, NULL + }; + static FT_Error + bdf_interpret_style( BDF_Face bdf ) + { + FT_Error error = BDF_Err_Ok; + FT_Face face = FT_FACE( bdf ); + FT_Memory memory = face->memory; + bdf_font_t* font = bdf->bdffont; + bdf_property_t* prop; + char* strings[4] = { NULL, NULL, NULL, NULL }; + size_t nn, len, lengths[4]; + face->style_flags = 0; + prop = bdf_get_font_property( font, (char *)"SLANT" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) + ? (char *)"Oblique" + : (char *)"Italic"; + } + prop = bdf_get_font_property( font, (char *)"WEIGHT_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = (char *)"Bold"; + } + prop = bdf_get_font_property( font, (char *)"SETWIDTH_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (char *)(prop->value.atom); + prop = bdf_get_font_property( font, (char *)"ADD_STYLE_NAME" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (char *)(prop->value.atom); + len = 0; + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + if ( len == 0 ) + { + strings[0] = (char *)"Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + { + char* s; + if ( FT_ALLOC( face->style_name, len ) ) + return error; + s = face->style_name; + for ( nn = 0; nn < 4; nn++ ) + { + char* src = strings[nn]; + len = lengths[nn]; + if ( src == NULL ) + continue; +/* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + ft_memcpy( s, src, len ); +/* need to convert spaces to dashes for */ +/* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + size_t mm; + for ( mm = 0; mm < len; mm++ ) + if ( s[mm] == ' ' ) + s[mm] = '-'; + } + s += len; + } + *s = 0; + } + return error; + } + FT_CALLBACK_DEF( void ) +/* BDF_Face */ + BDF_Face_Done( FT_Face bdfface ) + { + BDF_Face face = (BDF_Face)bdfface; + FT_Memory memory; + if ( !face ) + return; + memory = FT_FACE_MEMORY( face ); + bdf_free_font( face->bdffont ); + FT_FREE( face->en_table ); + FT_FREE( face->charset_encoding ); + FT_FREE( face->charset_registry ); + FT_FREE( bdfface->family_name ); + FT_FREE( bdfface->style_name ); + FT_FREE( bdfface->available_sizes ); + FT_FREE( face->bdffont ); + } + FT_CALLBACK_DEF( FT_Error ) + BDF_Face_Init( FT_Stream stream, +/* BDF_Face */ + FT_Face bdfface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error = BDF_Err_Ok; + BDF_Face face = (BDF_Face)bdfface; + FT_Memory memory = FT_FACE_MEMORY( face ); + bdf_font_t* font = NULL; + bdf_options_t options; + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_TRACE2(( "BDF driver\n" )); + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; +/* FZ XXX: options semantics */ + options.correct_metrics = 1; + options.keep_unencoded = 1; + options.keep_comments = 0; + options.font_spacing = BDF_PROPORTIONAL; + error = bdf_load_font( stream, memory, &options, &font ); + if ( error == BDF_Err_Missing_Startfont_Field ) + { + FT_TRACE2(( " not a BDF file\n" )); + goto Fail; + } + else if ( error ) + goto Exit; +/* we have a bdf font: let's construct the face object */ + face->bdffont = font; + { + bdf_property_t* prop = NULL; + FT_TRACE4(( " number of glyphs: allocated %d (used %d)\n", + font->glyphs_size, + font->glyphs_used )); + FT_TRACE4(( " number of unencoded glyphs: allocated %d (used %d)\n", + font->unencoded_size, + font->unencoded_used )); + bdfface->num_faces = 1; + bdfface->face_index = 0; + bdfface->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_FAST_GLYPHS; + prop = bdf_get_font_property( font, "SPACING" ); + if ( prop && prop->format == BDF_ATOM && + prop->value.atom && + ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || + *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) + bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; +/* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ +/* FZ XXX: I need a font to implement this */ + prop = bdf_get_font_property( font, "FAMILY_NAME" ); + if ( prop && prop->value.atom ) + { + if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) ) + goto Exit; + } + else + bdfface->family_name = 0; + if ( ( error = bdf_interpret_style( face ) ) != 0 ) + goto Exit; +/* the number of glyphs (with one slot for the undefined glyph */ +/* at position 0 and all unencoded glyphs) */ + bdfface->num_glyphs = font->glyphs_size + 1; + bdfface->num_fixed_sizes = 1; + if ( FT_NEW_ARRAY( bdfface->available_sizes, 1 ) ) + goto Exit; + { + FT_Bitmap_Size* bsize = bdfface->available_sizes; + FT_Short resolution_x = 0, resolution_y = 0; + FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); + bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); + prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); + if ( prop ) + bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 ); + else + bsize->width = (FT_Short)( bsize->height * 2/3 ); + prop = bdf_get_font_property( font, "POINT_SIZE" ); + if ( prop ) +/* convert from 722.7 decipoints to 72 points per inch */ + bsize->size = + (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L ); + else + bsize->size = bsize->width << 6; + prop = bdf_get_font_property( font, "PIXEL_SIZE" ); + if ( prop ) + bsize->y_ppem = (FT_Short)prop->value.l << 6; + prop = bdf_get_font_property( font, "RESOLUTION_X" ); + if ( prop ) + resolution_x = (FT_Short)prop->value.l; + prop = bdf_get_font_property( font, "RESOLUTION_Y" ); + if ( prop ) + resolution_y = (FT_Short)prop->value.l; + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = bsize->y_ppem * resolution_y / 72; + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; + else + bsize->x_ppem = bsize->y_ppem; + } +/* encoding table */ + { + bdf_glyph_t* cur = font->glyphs; + unsigned long n; + if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) ) + goto Exit; + face->default_glyph = 0; + for ( n = 0; n < font->glyphs_size; n++ ) + { + (face->en_table[n]).enc = cur[n].encoding; + FT_TRACE4(( " idx %d, val 0x%lX\n", n, cur[n].encoding )); + (face->en_table[n]).glyph = (FT_Short)n; + if ( cur[n].encoding == font->default_char ) + { + if ( n < FT_UINT_MAX ) + face->default_glyph = (FT_UInt)n; + else + FT_TRACE1(( "BDF_Face_Init:" + " idx %d is too large for this system\n", n )); + } + } + } +/* charmaps */ + { + bdf_property_t *charset_registry = 0, *charset_encoding = 0; + FT_Bool unicode_charmap = 0; + charset_registry = + bdf_get_font_property( font, "CHARSET_REGISTRY" ); + charset_encoding = + bdf_get_font_property( font, "CHARSET_ENCODING" ); + if ( charset_registry && charset_encoding ) + { + if ( charset_registry->format == BDF_ATOM && + charset_encoding->format == BDF_ATOM && + charset_registry->value.atom && + charset_encoding->value.atom ) + { + const char* s; + if ( FT_STRDUP( face->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( face->charset_registry, + charset_registry->value.atom ) ) + goto Exit; +/* Uh, oh, compare first letters manually to avoid dependency */ +/* on locales. */ + s = face->charset_registry; + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( face->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + } + { + FT_CharMapRec charmap; + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; +/* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + } + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); +#if 0 +/* Select default charmap */ + if ( bdfface->num_charmaps ) + bdfface->charmap = bdfface->charmaps[0]; +#endif + } + goto Exit; + } + } +/* otherwise assume Adobe standard encoding */ + { + FT_CharMapRec charmap; + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.platform_id = TT_PLATFORM_ADOBE; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); +/* Select default charmap */ + if ( bdfface->num_charmaps ) + bdfface->charmap = bdfface->charmaps[0]; + } + } + } + Exit: + return error; + Fail: + BDF_Face_Done( bdfface ); + return BDF_Err_Unknown_File_Format; + } + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; + FT_Select_Metrics( size->face, strike_index ); + size->metrics.ascender = bdffont->font_ascent << 6; + size->metrics.descender = -bdffont->font_descent << 6; + size->metrics.max_advance = bdffont->bbx.width << 6; + return BDF_Err_Ok; + } + FT_CALLBACK_DEF( FT_Error ) + BDF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FT_Face face = size->face; + FT_Bitmap_Size* bsize = face->available_sizes; + bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; + FT_Error error = BDF_Err_Invalid_Pixel_Size; + FT_Long height; + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = BDF_Err_Ok; + break; + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( bdffont->font_ascent + + bdffont->font_descent ) ) + error = BDF_Err_Ok; + break; + default: + error = BDF_Err_Unimplemented_Feature; + break; + } + if ( error ) + return error; + else + return BDF_Size_Select( size, 0 ); + } + FT_CALLBACK_DEF( FT_Error ) + BDF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); + FT_Face face = FT_FACE( bdf ); + FT_Error error = BDF_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + bdf_glyph_t glyph; + int bpp = bdf->bdffont->bpp; + FT_UNUSED( load_flags ); + if ( !face || glyph_index >= (FT_UInt)face->num_glyphs ) + { + error = BDF_Err_Invalid_Argument; + goto Exit; + } +/* index 0 is the undefined glyph */ + if ( glyph_index == 0 ) + glyph_index = bdf->default_glyph; + else + glyph_index--; +/* slot, bitmap => freetype, glyph => bdflib */ + glyph = bdf->bdffont->glyphs[glyph_index]; + bitmap->rows = glyph.bbx.height; + bitmap->width = glyph.bbx.width; + if ( glyph.bpr > INT_MAX ) + FT_TRACE1(( "BDF_Glyph_Load: too large pitch %d is truncated\n", + glyph.bpr )); +/* same as FT_Bitmap.pitch */ + bitmap->pitch = (int)glyph.bpr; +/* note: we don't allocate a new array to hold the bitmap; */ +/* we can simply point to it */ + ft_glyphslot_set_bitmap( slot, glyph.bitmap ); + switch ( bpp ) + { + case 1: + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + break; + case 2: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; + break; + case 4: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; + break; + case 8: + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + break; + } + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = glyph.bbx.x_offset; + slot->bitmap_top = glyph.bbx.ascent; + slot->metrics.horiAdvance = glyph.dwidth << 6; + slot->metrics.horiBearingX = glyph.bbx.x_offset << 6; + slot->metrics.horiBearingY = glyph.bbx.ascent << 6; + slot->metrics.width = bitmap->width << 6; + slot->metrics.height = bitmap->rows << 6; +/* + * XXX DWIDTH1 and VVECTOR should be parsed and + * used here, provided such fonts do exist. + */ + ft_synthesize_vertical_metrics( &slot->metrics, + bdf->bdffont->bbx.height << 6 ); + Exit: + return error; + } +/* + * + * BDF SERVICE + * + */ + static FT_Error + bdf_get_bdf_property( BDF_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + bdf_property_t* prop; + FT_ASSERT( face && face->bdffont ); + prop = bdf_get_font_property( face->bdffont, prop_name ); + if ( prop ) + { + switch ( prop->format ) + { + case BDF_ATOM: + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + break; + case BDF_INTEGER: + if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) + { + FT_TRACE1(( "bdf_get_bdf_property:" + " too large integer 0x%x is truncated\n" )); + } + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = (FT_Int32)prop->value.l; + break; + case BDF_CARDINAL: + if ( prop->value.ul > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "bdf_get_bdf_property:" + " too large cardinal 0x%x is truncated\n" )); + } + aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; + aproperty->u.cardinal = (FT_UInt32)prop->value.ul; + break; + default: + goto Fail; + } + return 0; + } + Fail: + return BDF_Err_Invalid_Argument; + } + static FT_Error + bdf_get_charset_id( BDF_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + *acharset_encoding = face->charset_encoding; + *acharset_registry = face->charset_registry; + return 0; + } + static const FT_Service_BDFRec bdf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, + (FT_BDF_GetPropertyFunc) bdf_get_bdf_property + }; +/* + * + * SERVICES LIST + * + */ + static const FT_ServiceDescRec bdf_services[] = + { + { FT_SERVICE_ID_BDF, &bdf_service_bdf }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_BDF }, + { NULL, NULL } + }; + FT_CALLBACK_DEF( FT_Module_Interface ) + bdf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + return ft_service_list_lookup( bdf_services, name ); + } + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec bdf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + "bdf", + 0x10000L, + 0x20000L, + 0, +/* FT_Module_Constructor */ + 0, +/* FT_Module_Destructor */ + 0, + bdf_driver_requester + }, + sizeof ( BDF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + BDF_Face_Init, + BDF_Face_Done, +/* FT_Size_InitFunc */ + 0, +/* FT_Size_DoneFunc */ + 0, +/* FT_Slot_InitFunc */ + 0, +/* FT_Slot_DoneFunc */ + 0, + BDF_Glyph_Load, +/* FT_Face_GetKerningFunc */ + 0, +/* FT_Face_AttachFunc */ + 0, +/* FT_Face_GetAdvancesFunc */ + 0, + BDF_Size_Request, + BDF_Size_Select + }; +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* cff.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* cffpic.c */ +/* */ +/* The FreeType position independent code services for cff module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* cffcmap.h */ +/* */ +/* CFF character mapping table (cmap) support (specification). */ +/* */ +/* Copyright 2002, 2003, 2006 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. */ +/* */ +/***************************************************************************/ +#define __CFFCMAP_H__ +/***************************************************************************/ +/* */ +/* cffobjs.h */ +/* */ +/* OpenType objects manager (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008 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. */ +/* */ +/***************************************************************************/ +#define __CFFOBJS_H__ +/***************************************************************************/ +/* */ +/* cfftypes.h */ +/* */ +/* Basic OpenType/CFF type definitions and interface (specification */ +/* only). */ +/* */ +/* Copyright 1996-2003, 2006-2008, 2010-2011 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. */ +/* */ +/***************************************************************************/ +#define __CFFTYPES_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Struct> */ +/* CFF_IndexRec */ +/* */ +/* <Description> */ +/* A structure used to model a CFF Index table. */ +/* */ +/* <Fields> */ +/* stream :: The source input stream. */ +/* */ +/* start :: The position of the first index byte in the */ +/* input stream. */ +/* */ +/* count :: The number of elements in the index. */ +/* */ +/* off_size :: The size in bytes of object offsets in index. */ +/* */ +/* data_offset :: The position of first data byte in the index's */ +/* bytes. */ +/* */ +/* data_size :: The size of the data table in this index. */ +/* */ +/* offsets :: A table of element offsets in the index. Must be */ +/* loaded explicitly. */ +/* */ +/* bytes :: If the index is loaded in memory, its bytes. */ +/* */ + typedef struct CFF_IndexRec_ + { + FT_Stream stream; + FT_ULong start; + FT_UInt count; + FT_Byte off_size; + FT_ULong data_offset; + FT_ULong data_size; + FT_ULong* offsets; + FT_Byte* bytes; + } CFF_IndexRec, *CFF_Index; + typedef struct CFF_EncodingRec_ + { + FT_UInt format; + FT_ULong offset; + FT_UInt count; +/* avoid dynamic allocations */ + FT_UShort sids [256]; + FT_UShort codes[256]; + } CFF_EncodingRec, *CFF_Encoding; + typedef struct CFF_CharsetRec_ + { + FT_UInt format; + FT_ULong offset; + FT_UShort* sids; +/* the inverse mapping of `sids'; only needed */ + FT_UShort* cids; +/* for CID-keyed fonts */ + FT_UInt max_cid; + FT_UInt num_glyphs; + } CFF_CharsetRec, *CFF_Charset; + typedef struct CFF_FontRecDictRec_ + { + FT_UInt version; + FT_UInt notice; + FT_UInt copyright; + FT_UInt full_name; + FT_UInt family_name; + FT_UInt weight; + FT_Bool is_fixed_pitch; + FT_Fixed italic_angle; + FT_Fixed underline_position; + FT_Fixed underline_thickness; + FT_Int paint_type; + FT_Int charstring_type; + FT_Matrix font_matrix; + FT_Bool has_font_matrix; +/* temporarily used as scaling value also */ + FT_ULong units_per_em; + FT_Vector font_offset; + FT_ULong unique_id; + FT_BBox font_bbox; + FT_Pos stroke_width; + FT_ULong charset_offset; + FT_ULong encoding_offset; + FT_ULong charstrings_offset; + FT_ULong private_offset; + FT_ULong private_size; + FT_Long synthetic_base; + FT_UInt embedded_postscript; +/* these should only be used for the top-level font dictionary */ + FT_UInt cid_registry; + FT_UInt cid_ordering; + FT_Long cid_supplement; + FT_Long cid_font_version; + FT_Long cid_font_revision; + FT_Long cid_font_type; + FT_ULong cid_count; + FT_ULong cid_uid_base; + FT_ULong cid_fd_array_offset; + FT_ULong cid_fd_select_offset; + FT_UInt cid_font_name; + } CFF_FontRecDictRec, *CFF_FontRecDict; + typedef struct CFF_PrivateRec_ + { + FT_Byte num_blue_values; + FT_Byte num_other_blues; + FT_Byte num_family_blues; + FT_Byte num_family_other_blues; + FT_Pos blue_values[14]; + FT_Pos other_blues[10]; + FT_Pos family_blues[14]; + FT_Pos family_other_blues[10]; + FT_Fixed blue_scale; + FT_Pos blue_shift; + FT_Pos blue_fuzz; + FT_Pos standard_width; + FT_Pos standard_height; + FT_Byte num_snap_widths; + FT_Byte num_snap_heights; + FT_Pos snap_widths[13]; + FT_Pos snap_heights[13]; + FT_Bool force_bold; + FT_Fixed force_bold_threshold; + FT_Int lenIV; + FT_Int language_group; + FT_Fixed expansion_factor; + FT_Long initial_random_seed; + FT_ULong local_subrs_offset; + FT_Pos default_width; + FT_Pos nominal_width; + } CFF_PrivateRec, *CFF_Private; + typedef struct CFF_FDSelectRec_ + { + FT_Byte format; + FT_UInt range_count; +/* that's the table, taken from the file `as is' */ + FT_Byte* data; + FT_UInt data_size; +/* small cache for format 3 only */ + FT_UInt cache_first; + FT_UInt cache_count; + FT_Byte cache_fd; + } CFF_FDSelectRec, *CFF_FDSelect; +/* A SubFont packs a font dict and a private dict together. They are */ +/* needed to support CID-keyed CFF fonts. */ + typedef struct CFF_SubFontRec_ + { + CFF_FontRecDictRec font_dict; + CFF_PrivateRec private_dict; + CFF_IndexRec local_subrs_index; +/* array of pointers into Local Subrs INDEX data */ + FT_Byte** local_subrs; + } CFF_SubFontRec, *CFF_SubFont; +#define CFF_MAX_CID_FONTS 256 + typedef struct CFF_FontRec_ + { + FT_Stream stream; + FT_Memory memory; + FT_UInt num_faces; + FT_UInt num_glyphs; + FT_Byte version_major; + FT_Byte version_minor; + FT_Byte header_size; + FT_Byte absolute_offsize; + CFF_IndexRec name_index; + CFF_IndexRec top_dict_index; + CFF_IndexRec global_subrs_index; + CFF_EncodingRec encoding; + CFF_CharsetRec charset; + CFF_IndexRec charstrings_index; + CFF_IndexRec font_dict_index; + CFF_IndexRec private_index; + CFF_IndexRec local_subrs_index; + FT_String* font_name; +/* array of pointers into Global Subrs INDEX data */ + FT_Byte** global_subrs; +/* array of pointers into String INDEX data stored at string_pool */ + FT_UInt num_strings; + FT_Byte** strings; + FT_Byte* string_pool; + CFF_SubFontRec top_font; + FT_UInt num_subfonts; + CFF_SubFont subfonts[CFF_MAX_CID_FONTS]; + CFF_FDSelectRec fd_select; +/* interface to PostScript hinter */ + PSHinter_Service pshinter; +/* interface to Postscript Names service */ + FT_Service_PsCMaps psnames; +/* since version 2.3.0 */ +/* font info dictionary */ + PS_FontInfoRec* font_info; +/* since version 2.3.6 */ + FT_String* registry; + FT_String* ordering; + } CFF_FontRec, *CFF_Font; +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Type> */ +/* CFF_Driver */ +/* */ +/* <Description> */ +/* A handle to an OpenType driver object. */ +/* */ + typedef struct CFF_DriverRec_* CFF_Driver; + typedef TT_Face CFF_Face; +/*************************************************************************/ +/* */ +/* <Type> */ +/* CFF_Size */ +/* */ +/* <Description> */ +/* A handle to an OpenType size object. */ +/* */ + typedef struct CFF_SizeRec_ + { + FT_SizeRec root; +/* 0xFFFFFFFF to indicate invalid */ + FT_ULong strike_index; + } CFF_SizeRec, *CFF_Size; +/*************************************************************************/ +/* */ +/* <Type> */ +/* CFF_GlyphSlot */ +/* */ +/* <Description> */ +/* A handle to an OpenType glyph slot object. */ +/* */ + typedef struct CFF_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_Bool hint; + FT_Bool scaled; + FT_Fixed x_scale; + FT_Fixed y_scale; + } CFF_GlyphSlotRec, *CFF_GlyphSlot; +/*************************************************************************/ +/* */ +/* <Type> */ +/* CFF_Internal */ +/* */ +/* <Description> */ +/* The interface to the `internal' field of `FT_Size'. */ +/* */ + typedef struct CFF_InternalRec_ + { + PSH_Globals topfont; + PSH_Globals subfonts[CFF_MAX_CID_FONTS]; + } CFF_InternalRec, *CFF_Internal; +/*************************************************************************/ +/* */ +/* Subglyph transformation record. */ +/* */ + typedef struct CFF_Transform_ + { +/* transformation matrix coefficients */ + FT_Fixed xx, xy; + FT_Fixed yx, yy; +/* offsets */ + FT_F26Dot6 ox, oy; + } CFF_Transform; +/***********************************************************************/ +/* */ +/* TrueType driver class. */ +/* */ + typedef struct CFF_DriverRec_ + { + FT_DriverRec root; + void* extension_component; + } CFF_DriverRec; + FT_LOCAL( FT_Error ) +/* CFF_Size */ + cff_size_init( FT_Size size ); + FT_LOCAL( void ) +/* CFF_Size */ + cff_size_done( FT_Size size ); + FT_LOCAL( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ); + FT_LOCAL( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ); + 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, +/* CFF_Face */ + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) +/* CFF_Face */ + cff_face_done( FT_Face face ); +/*************************************************************************/ +/* */ +/* Driver functions */ +/* */ + FT_LOCAL( FT_Error ) + cff_driver_init( FT_Module module ); + FT_LOCAL( void ) + cff_driver_done( FT_Module module ); +FT_END_HEADER +/* END */ +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; +/* up to 256 elements */ + FT_UShort* gids; + } 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 +/* END */ +/***************************************************************************/ +/* */ +/* cffpic.h */ +/* */ +/* The FreeType position independent code services for cff module. */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __CFFPIC_H__ +FT_BEGIN_HEADER +#define CFF_SERVICE_PS_INFO_GET cff_service_ps_info +#define CFF_SERVICE_GLYPH_DICT_GET cff_service_glyph_dict +#define CFF_SERVICE_PS_NAME_GET cff_service_ps_name +#define CFF_SERVICE_GET_CMAP_INFO_GET cff_service_get_cmap_info +#define CFF_SERVICE_CID_INFO_GET cff_service_cid_info +#define CFF_SERVICES_GET cff_services +#define CFF_CMAP_ENCODING_CLASS_REC_GET cff_cmap_encoding_class_rec +#define CFF_CMAP_UNICODE_CLASS_REC_GET cff_cmap_unicode_class_rec +#define CFF_FIELD_HANDLERS_GET cff_field_handlers +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* cfferrs.h */ +/* */ +/* CFF error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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. */ +/* */ +/*************************************************************************/ +#define __CFFERRS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CFF_Err_ +#define FT_ERR_BASE FT_Mod_Err_CFF +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* cffdrivr.c */ +/* */ +/* OpenType font driver implementation (body). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* cffdrivr.h */ +/* */ +/* High-level OpenType driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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__ +FT_BEGIN_HEADER + FT_DECLARE_DRIVER( cff_driver_class ) +FT_END_HEADER +/* __CFFDRIVER_H__ */ +#endif +/* END */ +/***************************************************************************/ +/* */ +/* cffgload.h */ +/* */ +/* OpenType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009 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. */ +/* */ +/***************************************************************************/ +#define __CFFGLOAD_H__ +FT_BEGIN_HEADER +#define CFF_MAX_OPERANDS 48 +#define CFF_MAX_SUBRS_CALLS 32 +#define CFF_MAX_TRANS_ELEMENTS 32 +/*************************************************************************/ +/* */ +/* <Structure> */ +/* CFF_Builder */ +/* */ +/* <Description> */ +/* A structure used during glyph loading to store its outline. */ +/* */ +/* <Fields> */ +/* memory :: The current memory object. */ +/* */ +/* face :: The current face object. */ +/* */ +/* glyph :: The current glyph slot. */ +/* */ +/* loader :: The current glyph loader. */ +/* */ +/* base :: The base glyph outline. */ +/* */ +/* current :: The current glyph outline. */ +/* */ +/* pos_x :: The horizontal translation (if composite glyph). */ +/* */ +/* pos_y :: The vertical translation (if composite glyph). */ +/* */ +/* left_bearing :: The left side bearing point. */ +/* */ +/* advance :: The horizontal advance vector. */ +/* */ +/* bbox :: Unused. */ +/* */ +/* path_begun :: A flag which indicates that a new path has begun. */ +/* */ +/* load_points :: If this flag is not set, no points are loaded. */ +/* */ +/* no_recurse :: Set but not used. */ +/* */ +/* metrics_only :: A boolean indicating that we only want to compute */ +/* the metrics of a given glyph, not load all of its */ +/* points. */ +/* */ +/* hints_funcs :: Auxiliary pointer for hinting. */ +/* */ +/* hints_globals :: Auxiliary pointer for hinting. */ +/* */ + typedef struct CFF_Builder_ + { + FT_Memory memory; + TT_Face face; + CFF_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + FT_Pos pos_x; + FT_Pos pos_y; + FT_Vector left_bearing; + FT_Vector advance; +/* bounding box */ + FT_BBox bbox; + FT_Bool path_begun; + FT_Bool load_points; + FT_Bool no_recurse; + FT_Bool metrics_only; +/* hinter-specific */ + void* hints_funcs; +/* hinter-specific */ + void* hints_globals; + } CFF_Builder; +/* execution context charstring zone */ + typedef struct CFF_Decoder_Zone_ + { + FT_Byte* base; + FT_Byte* limit; + FT_Byte* cursor; + } CFF_Decoder_Zone; + typedef struct CFF_Decoder_ + { + CFF_Builder builder; + CFF_Font cff; + FT_Fixed stack[CFF_MAX_OPERANDS + 1]; + FT_Fixed* top; + CFF_Decoder_Zone zones[CFF_MAX_SUBRS_CALLS + 1]; + CFF_Decoder_Zone* zone; + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + FT_Pos glyph_width; + FT_Pos nominal_width; + FT_Bool read_width; + FT_Bool width_only; + FT_Int num_hints; + FT_Fixed buildchar[CFF_MAX_TRANS_ELEMENTS]; + FT_UInt num_locals; + FT_UInt num_globals; + FT_Int locals_bias; + FT_Int globals_bias; + FT_Byte** locals; + FT_Byte** globals; +/* for pure CFF fonts only */ + FT_Byte** glyph_names; +/* number of glyphs in font */ + FT_UInt num_glyphs; + FT_Render_Mode hint_mode; + FT_Bool seac; + } CFF_Decoder; + 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 ); + FT_LOCAL( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ); +/* unused until we support pure CFF fonts */ +#if 0 +/* 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 ); +/* 0 */ +#endif + FT_LOCAL( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ); + FT_LOCAL( FT_Error ) + cff_slot_load( CFF_GlyphSlot glyph, + CFF_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* cffload.h */ +/* */ +/* OpenType & CFF data/program tables loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2007, 2008, 2010 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. */ +/* */ +/***************************************************************************/ +#define __CFFLOAD_H__ +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, + FT_Bool pure_cff ); + FT_LOCAL( void ) + cff_font_done( CFF_Font font ); + FT_LOCAL( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* cffparse.h */ +/* */ +/* CFF token stream parser (specification) */ +/* */ +/* Copyright 1996-2003, 2011 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 __CFF_PARSE_H__ +#define __CFF_PARSE_H__ +FT_BEGIN_HEADER +#define CFF_MAX_STACK_DEPTH 96 +#define CFF_CODE_TOPDICT 0x1000 +#define CFF_CODE_PRIVATE 0x2000 + typedef struct CFF_ParserRec_ + { + FT_Library library; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* cursor; + FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1]; + FT_Byte** top; + FT_UInt object_code; + void* object; + } CFF_ParserRec, *CFF_Parser; + FT_LOCAL( void ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object, + FT_Library library); + 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, +/* do not remove */ + cff_kind_max + }; +/* 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; + } CFF_Field_Handler; +FT_END_HEADER +/* __CFF_PARSE_H__ */ +#endif +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_cffdriver +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** F A C E S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \ + (FT_ULong)right ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_get_kerning */ +/* */ +/* <Description> */ +/* A driver method used to return the kerning vector between two */ +/* glyphs of the same face. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* left_glyph :: The index of the left glyph in the kern pair. */ +/* */ +/* right_glyph :: The index of the right glyph in the kern pair. */ +/* */ +/* <Output> */ +/* kerning :: The kerning vector. This is in font units for */ +/* scalable formats, and in pixels for fixed-sizes */ +/* formats. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only horizontal layouts (left-to-right & right-to-left) are */ +/* supported by this function. Other layouts, or more sophisticated */ +/* kernings, are out of scope of this method (the basic driver */ +/* interface is meant to be simple). */ +/* */ +/* They can be implemented by format-specific interfaces. */ +/* */ + FT_CALLBACK_DEF( FT_Error ) +/* TT_Face */ + cff_get_kerning( FT_Face ttface, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Face face = (TT_Face)ttface; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + kerning->x = 0; + kerning->y = 0; + if ( sfnt ) + kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); + return CFF_Err_Ok; + } +#undef PAIR_TAG +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_glyph_load */ +/* */ +/* <Description> */ +/* A driver method used to load a glyph within a given glyph slot. */ +/* */ +/* <Input> */ +/* slot :: A handle to the target slot object where the glyph */ +/* will be loaded. */ +/* */ +/* size :: A handle to the source face size at which the glyph */ +/* must be scaled, loaded, etc. */ +/* */ +/* glyph_index :: The index of the glyph in the font file. */ +/* */ +/* load_flags :: A flag indicating what to load for this glyph. The */ +/* FT_LOAD_??? constants can be used to control the */ +/* glyph loading process (e.g., whether the outline */ +/* should be scaled, whether to load bitmaps or not, */ +/* whether to hint the outline, etc). */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_CALLBACK_DEF( FT_Error ) +/* CFF_GlyphSlot */ + cff_glyph_load( FT_GlyphSlot cffslot, +/* CFF_Size */ + FT_Size cffsize, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + CFF_GlyphSlot slot = (CFF_GlyphSlot)cffslot; + CFF_Size size = (CFF_Size)cffsize; + if ( !slot ) + return CFF_Err_Invalid_Slot_Handle; +/* check whether we want a scaled outline or bitmap */ + if ( !size ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; +/* reset the size object if necessary */ + if ( load_flags & FT_LOAD_NO_SCALE ) + size = NULL; + if ( size ) + { +/* these two objects must have the same parent */ + if ( cffsize->face != cffslot->face ) + return CFF_Err_Invalid_Face_Handle; + } +/* now load the glyph outline if necessary */ + error = cff_slot_load( slot, size, glyph_index, load_flags ); +/* force drop-out mode to 2 - irrelevant now */ +/* slot->outline.dropout_mode = 2; */ + return error; + } + FT_CALLBACK_DEF( FT_Error ) + cff_get_advances( FT_Face face, + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed* advances ) + { + FT_UInt nn; + FT_Error error = CFF_Err_Ok; + FT_GlyphSlot slot = face->glyph; + flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; + for ( nn = 0; nn < count; nn++ ) + { + error = cff_glyph_load( slot, face->size, start + nn, flags ); + if ( error ) + break; + advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) + ? slot->linearVertAdvance + : slot->linearHoriAdvance; + } + return error; + } +/* + * GLYPH DICT SERVICE + * + */ + static FT_Error + cff_get_glyph_name( CFF_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + CFF_Font font = (CFF_Font)face->extra.data; + FT_String* gname; + FT_UShort sid; + FT_Error error; + if ( !font->psnames ) + { + FT_ERROR(( "cff_get_glyph_name:" + " cannot get glyph name from CFF & CEF fonts\n" + " " + " without the `PSNames' module\n" )); + error = CFF_Err_Missing_Module; + goto Exit; + } +/* first, locate the sid in the charset table */ + sid = font->charset.sids[glyph_index]; +/* now, lookup the name itself */ + gname = cff_index_get_sid_string( font, sid ); + if ( gname ) + FT_STRCPYN( buffer, gname, buffer_max ); + error = CFF_Err_Ok; + Exit: + return error; + } + static FT_UInt + cff_get_name_index( CFF_Face face, + FT_String* glyph_name ) + { + CFF_Font cff; + CFF_Charset charset; + FT_Service_PsCMaps psnames; + FT_String* name; + FT_UShort sid; + FT_UInt i; + cff = (CFF_FontRec *)face->extra.data; + charset = &cff->charset; + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + return 0; + for ( i = 0; i < cff->num_glyphs; i++ ) + { + sid = charset->sids[i]; + if ( sid > 390 ) + name = cff_index_get_string( cff, sid - 391 ); + else + name = (FT_String *)psnames->adobe_std_strings( sid ); + if ( !name ) + continue; + if ( !ft_strcmp( glyph_name, name ) ) + return i; + } + return 0; + } + FT_DEFINE_SERVICE_GLYPHDICTREC(cff_service_glyph_dict, + (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)cff_get_name_index + ) +/* + * POSTSCRIPT INFO SERVICE + * + */ + static FT_Int + cff_ps_has_glyph_names( FT_Face face ) + { + return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0; + } + static FT_Error + cff_ps_get_font_info( CFF_Face face, + PS_FontInfoRec* afont_info ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + FT_Error error = CFF_Err_Ok; + if ( cff && cff->font_info == NULL ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + PS_FontInfoRec *font_info = NULL; + FT_Memory memory = face->root.memory; + if ( FT_ALLOC( font_info, sizeof ( *font_info ) ) ) + goto Fail; + font_info->version = cff_index_get_sid_string( cff, + dict->version ); + font_info->notice = cff_index_get_sid_string( cff, + dict->notice ); + font_info->full_name = cff_index_get_sid_string( cff, + dict->full_name ); + font_info->family_name = cff_index_get_sid_string( cff, + dict->family_name ); + font_info->weight = cff_index_get_sid_string( cff, + dict->weight ); + font_info->italic_angle = dict->italic_angle; + font_info->is_fixed_pitch = dict->is_fixed_pitch; + font_info->underline_position = (FT_Short)dict->underline_position; + font_info->underline_thickness = (FT_Short)dict->underline_thickness; + cff->font_info = font_info; + } + if ( cff ) + *afont_info = *cff->font_info; + Fail: + return error; + } + FT_DEFINE_SERVICE_PSINFOREC(cff_service_ps_info, + (PS_GetFontInfoFunc) cff_ps_get_font_info, + (PS_GetFontExtraFunc) NULL, + (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, +/* unsupported with CFF fonts */ + (PS_GetFontPrivateFunc)NULL, +/* not implemented */ + (PS_GetFontValueFunc) NULL + ) +/* + * POSTSCRIPT NAME SERVICE + * + */ + static const char* + cff_get_ps_name( CFF_Face face ) + { + CFF_Font cff = (CFF_Font)face->extra.data; + return (const char*)cff->font_name; + } + FT_DEFINE_SERVICE_PSFONTNAMEREC(cff_service_ps_name, + (FT_PsName_GetFunc)cff_get_ps_name + ) +/* + * TT CMAP INFO + * + * If the charmap is a synthetic Unicode encoding cmap or + * a Type 1 standard (or expert) encoding cmap, hide TT CMAP INFO + * service defined in SFNT module. + * + * Otherwise call the service function in the sfnt module. + * + */ + static FT_Error + cff_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = FT_CMAP( charmap ); + FT_Error error = CFF_Err_Ok; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Library library = FT_FACE_LIBRARY( face ); + cmap_info->language = 0; + cmap_info->format = 0; + if ( cmap->clazz != &CFF_CMAP_ENCODING_CLASS_REC_GET && + cmap->clazz != &CFF_CMAP_UNICODE_CLASS_REC_GET ) + { + FT_Module sfnt = FT_Get_Module( library, "sfnt" ); + FT_Service_TTCMaps service = + (FT_Service_TTCMaps)ft_module_get_service( sfnt, + FT_SERVICE_ID_TT_CMAP ); + if ( service && service->get_cmap_info ) + error = service->get_cmap_info( charmap, cmap_info ); + } + return error; + } + FT_DEFINE_SERVICE_TTCMAPSREC(cff_service_get_cmap_info, + (TT_CMap_Info_GetFunc)cff_get_cmap_info + ) +/* + * CID INFO SERVICE + * + */ + static FT_Error + cff_get_ros( CFF_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ) + { + FT_Error error = CFF_Err_Ok; + CFF_Font cff = (CFF_Font)face->extra.data; + if ( cff ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + if ( dict->cid_registry == 0xFFFFU ) + { + error = CFF_Err_Invalid_Argument; + goto Fail; + } + if ( registry ) + { + if ( cff->registry == NULL ) + cff->registry = cff_index_get_sid_string( cff, + dict->cid_registry ); + *registry = cff->registry; + } + if ( ordering ) + { + if ( cff->ordering == NULL ) + cff->ordering = cff_index_get_sid_string( cff, + dict->cid_ordering ); + *ordering = cff->ordering; + } +/* + * XXX: According to Adobe TechNote #5176, the supplement in CFF + * can be a real number. We truncate it to fit public API + * since freetype-2.3.6. + */ + if ( supplement ) + { + if ( dict->cid_supplement < FT_INT_MIN || + dict->cid_supplement > FT_INT_MAX ) + FT_TRACE1(( "cff_get_ros: too large supplement %d is truncated\n", + dict->cid_supplement )); + *supplement = (FT_Int)dict->cid_supplement; + } + } + Fail: + return error; + } + static FT_Error + cff_get_is_cid( CFF_Face face, + FT_Bool *is_cid ) + { + FT_Error error = CFF_Err_Ok; + CFF_Font cff = (CFF_Font)face->extra.data; + *is_cid = 0; + if ( cff ) + { + CFF_FontRecDict dict = &cff->top_font.font_dict; + if ( dict->cid_registry != 0xFFFFU ) + *is_cid = 1; + } + return error; + } + static FT_Error + cff_get_cid_from_glyph_index( CFF_Face face, + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = CFF_Err_Ok; + CFF_Font cff; + cff = (CFF_Font)face->extra.data; + if ( cff ) + { + FT_UInt c; + CFF_FontRecDict dict = &cff->top_font.font_dict; + if ( dict->cid_registry == 0xFFFFU ) + { + error = CFF_Err_Invalid_Argument; + goto Fail; + } + if ( glyph_index > cff->num_glyphs ) + { + error = CFF_Err_Invalid_Argument; + goto Fail; + } + c = cff->charset.sids[glyph_index]; + if ( cid ) + *cid = c; + } + Fail: + return error; + } + FT_DEFINE_SERVICE_CIDREC(cff_service_cid_info, + (FT_CID_GetRegistryOrderingSupplementFunc)cff_get_ros, + (FT_CID_GetIsInternallyCIDKeyedFunc) cff_get_is_cid, + (FT_CID_GetCIDFromGlyphIndexFunc) cff_get_cid_from_glyph_index + ) +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** D R I V E R I N T E R F A C E ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES + FT_DEFINE_SERVICEDESCREC6(cff_services, + FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_CFF, + FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET, + FT_SERVICE_ID_GLYPH_DICT, &CFF_SERVICE_GLYPH_DICT_GET, + FT_SERVICE_ID_TT_CMAP, &CFF_SERVICE_GET_CMAP_INFO_GET, + FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET + ) +#else + FT_DEFINE_SERVICEDESCREC5(cff_services, + FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_CFF, + FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET, + FT_SERVICE_ID_TT_CMAP, &CFF_SERVICE_GET_CMAP_INFO_GET, + FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET + ) +#endif + FT_CALLBACK_DEF( FT_Module_Interface ) +/* CFF_Driver */ + cff_get_interface( FT_Module driver, + const char* module_interface ) + { + FT_Library library; + FT_Module sfnt; + FT_Module_Interface result; +/* CFF_SERVICES_GET derefers `library' in PIC mode */ + result = ft_service_list_lookup( CFF_SERVICES_GET, module_interface ); + if ( result != NULL ) + return result; +/* `driver' is not yet evaluated in non-PIC mode */ + if ( !driver ) + return NULL; + library = driver->library; + if ( !library ) + return NULL; +/* we pass our request to the `sfnt' module */ + sfnt = FT_Get_Module( library, "sfnt" ); + return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0; + } +/* The FT_DriverInterface structure is defined in ftdriver.h. */ +#define CFF_SIZE_SELECT cff_size_select + FT_DEFINE_DRIVER( cff_driver_class, + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + sizeof ( CFF_DriverRec ), + "cff", + 0x10000L, + 0x20000L, +/* module-specific interface */ + 0, + cff_driver_init, + cff_driver_done, + cff_get_interface, +/* now the specific driver fields */ + sizeof ( TT_FaceRec ), + sizeof ( CFF_SizeRec ), + sizeof ( CFF_GlyphSlotRec ), + cff_face_init, + cff_face_done, + cff_size_init, + cff_size_done, + cff_slot_init, + cff_slot_done, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + ft_stub_set_char_sizes, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + ft_stub_set_pixel_sizes, + cff_glyph_load, + cff_get_kerning, +/* FT_Face_AttachFunc */ + 0, + cff_get_advances, + cff_size_request, + CFF_SIZE_SELECT + ) +/* END */ +/***************************************************************************/ +/* */ +/* cffparse.c */ +/* */ +/* CFF token stream parser (body) */ +/* */ +/* Copyright 1996-2004, 2007-2012 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 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 trace_cffparse + FT_LOCAL_DEF( void ) + cff_parser_init( CFF_Parser parser, + FT_UInt code, + void* object, + FT_Library library) + { + FT_MEM_ZERO( parser, sizeof ( *parser ) ); + parser->top = parser->stack; + parser->object_code = code; + parser->object = object; + parser->library = library; + } +/* read an integer */ + static FT_Long + cff_parse_integer( FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Int v = *p++; + FT_Long val = 0; + if ( v == 28 ) + { + if ( p + 2 > limit ) + goto Bad; + val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] ); + p += 2; + } + else if ( v == 29 ) + { + if ( p + 4 > limit ) + goto Bad; + val = ( (FT_Long)p[0] << 24 ) | + ( (FT_Long)p[1] << 16 ) | + ( (FT_Long)p[2] << 8 ) | + p[3]; + p += 4; + } + else if ( v < 247 ) + { + val = v - 139; + } + else if ( v < 251 ) + { + if ( p + 1 > limit ) + goto Bad; + val = ( v - 247 ) * 256 + p[0] + 108; + p++; + } + else + { + if ( p + 1 > limit ) + goto Bad; + val = -( v - 251 ) * 256 - p[0] - 108; + p++; + } + Exit: + return val; + Bad: + val = 0; + FT_TRACE4(( "!!!END OF DATA:!!!" )); + goto Exit; + } + static const FT_Long power_tens[] = + { + 1L, + 10L, + 100L, + 1000L, + 10000L, + 100000L, + 1000000L, + 10000000L, + 100000000L, + 1000000000L + }; +/* read a real */ + static FT_Fixed + cff_parse_real( FT_Byte* start, + FT_Byte* limit, + FT_Long power_ten, + FT_Long* scaling ) + { + FT_Byte* p = start; + FT_UInt nib; + FT_UInt phase; + FT_Long result, number, exponent; + FT_Int sign = 0, exponent_sign = 0, have_overflow = 0; + FT_Long exponent_add, integer_length, fraction_length; + if ( scaling ) + *scaling = 0; + result = 0; + number = 0; + exponent = 0; + exponent_add = 0; + integer_length = 0; + fraction_length = 0; +/* First of all, read the integer part. */ + phase = 4; + for (;;) + { +/* If we entered this iteration with phase == 4, we need to */ +/* read a new byte. This also skips past the initial 0x1E. */ + if ( phase ) + { + p++; +/* Make sure we don't read past the end. */ + if ( p >= limit ) + goto Bad; + } +/* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib == 0xE ) + sign = 1; + else if ( nib > 9 ) + break; + else + { +/* Increase exponent if we can't add the digit. */ + if ( number >= 0xCCCCCCCL ) + exponent_add++; +/* Skip leading zeros. */ + else if ( nib || number ) + { + integer_length++; + number = number * 10 + nib; + } + } + } +/* Read fraction part, if any. */ + if ( nib == 0xa ) + for (;;) + { +/* If we entered this iteration with phase == 4, we need */ +/* to read a new byte. */ + if ( phase ) + { + p++; +/* Make sure we don't read past the end. */ + if ( p >= limit ) + goto Bad; + } +/* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; +/* Skip leading zeros if possible. */ + if ( !nib && !number ) + exponent_add--; +/* Only add digit if we don't overflow. */ + else if ( number < 0xCCCCCCCL && fraction_length < 9 ) + { + fraction_length++; + number = number * 10 + nib; + } + } +/* Read exponent, if any. */ + if ( nib == 12 ) + { + exponent_sign = 1; + nib = 11; + } + if ( nib == 11 ) + { + for (;;) + { +/* If we entered this iteration with phase == 4, */ +/* we need to read a new byte. */ + if ( phase ) + { + p++; +/* Make sure we don't read past the end. */ + if ( p >= limit ) + goto Bad; + } +/* Get the nibble. */ + nib = ( p[0] >> phase ) & 0xF; + phase = 4 - phase; + if ( nib >= 10 ) + break; +/* Arbitrarily limit exponent. */ + if ( exponent > 1000 ) + have_overflow = 1; + else + exponent = exponent * 10 + nib; + } + if ( exponent_sign ) + exponent = -exponent; + } + if ( !number ) + goto Exit; + if ( have_overflow ) + { + if ( exponent_sign ) + goto Underflow; + else + goto Overflow; + } +/* We don't check `power_ten' and `exponent_add'. */ + exponent += power_ten + exponent_add; + if ( scaling ) + { +/* Only use `fraction_length'. */ + fraction_length += integer_length; + exponent += integer_length; + if ( fraction_length <= 5 ) + { + if ( number > 0x7FFFL ) + { + result = FT_DivFix( number, 10 ); + *scaling = exponent - fraction_length + 1; + } + else + { + if ( exponent > 0 ) + { + FT_Long new_fraction_length, shift; +/* Make `scaling' as small as possible. */ + new_fraction_length = FT_MIN( exponent, 5 ); + shift = new_fraction_length - fraction_length; + if ( shift > 0 ) + { + exponent -= new_fraction_length; + number *= power_tens[shift]; + if ( number > 0x7FFFL ) + { + number /= 10; + exponent += 1; + } + } + else + exponent -= fraction_length; + } + else + exponent -= fraction_length; + result = number << 16; + *scaling = exponent; + } + } + else + { + if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL ) + { + result = FT_DivFix( number, power_tens[fraction_length - 4] ); + *scaling = exponent - 4; + } + else + { + result = FT_DivFix( number, power_tens[fraction_length - 5] ); + *scaling = exponent - 5; + } + } + } + else + { + integer_length += exponent; + fraction_length -= exponent; + if ( integer_length > 5 ) + goto Overflow; + if ( integer_length < -5 ) + goto Underflow; +/* Remove non-significant digits. */ + if ( integer_length < 0 ) + { + number /= power_tens[-integer_length]; + fraction_length += integer_length; + } +/* this can only happen if exponent was non-zero */ + if ( fraction_length == 10 ) + { + number /= 10; + fraction_length -= 1; + } +/* Convert into 16.16 format. */ + if ( fraction_length > 0 ) + { + if ( ( number / power_tens[fraction_length] ) > 0x7FFFL ) + goto Exit; + result = FT_DivFix( number, power_tens[fraction_length] ); + } + else + { + number *= power_tens[-fraction_length]; + if ( number > 0x7FFFL ) + goto Overflow; + result = number << 16; + } + } + Exit: + if ( sign ) + result = -result; + return result; + Overflow: + result = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + goto Exit; + Underflow: + result = 0; + FT_TRACE4(( "!!!UNDERFLOW:!!!" )); + goto Exit; + Bad: + result = 0; + FT_TRACE4(( "!!!END OF DATA:!!!" )); + goto Exit; + } +/* read a number, either integer or real */ + static FT_Long + cff_parse_num( FT_Byte** d ) + { + return **d == 30 ? ( cff_parse_real( d[0], d[1], 0, NULL ) >> 16 ) + : cff_parse_integer( d[0], d[1] ); + } +/* read a floating point number, either integer or real */ + static FT_Fixed + do_fixed( FT_Byte** d, + FT_Long scaling ) + { + if ( **d == 30 ) + return cff_parse_real( d[0], d[1], scaling, NULL ); + else + { + FT_Long val = cff_parse_integer( d[0], d[1] ); + if ( scaling ) + val *= power_tens[scaling]; + if ( val > 0x7FFF ) + { + val = 0x7FFFFFFFL; + goto Overflow; + } + else if ( val < -0x7FFF ) + { + val = -0x7FFFFFFFL; + goto Overflow; + } + return val << 16; + Overflow: + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + return val; + } + } +/* read a floating point number, either integer or real */ + static FT_Fixed + cff_parse_fixed( FT_Byte** d ) + { + return do_fixed( d, 0 ); + } +/* read a floating point number, either integer or real, */ +/* but return `10^scaling' times the number read in */ + static FT_Fixed + cff_parse_fixed_scaled( FT_Byte** d, + FT_Long scaling ) + { + return do_fixed( d, scaling ); + } +/* read a floating point number, either integer or real, */ +/* and return it as precise as possible -- `scaling' returns */ +/* the scaling factor (as a power of 10) */ + static FT_Fixed + cff_parse_fixed_dynamic( FT_Byte** d, + FT_Long* scaling ) + { + FT_ASSERT( scaling ); + if ( **d == 30 ) + return cff_parse_real( d[0], d[1], 0, scaling ); + else + { + FT_Long number; + FT_Int integer_length; + number = cff_parse_integer( d[0], d[1] ); + if ( number > 0x7FFFL ) + { + for ( integer_length = 5; integer_length < 10; integer_length++ ) + if ( number < power_tens[integer_length] ) + break; + if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL ) + { + *scaling = integer_length - 4; + return FT_DivFix( number, power_tens[integer_length - 4] ); + } + else + { + *scaling = integer_length - 5; + return FT_DivFix( number, power_tens[integer_length - 5] ); + } + } + else + { + *scaling = 0; + return number << 16; + } + } + } + static FT_Error + cff_parse_font_matrix( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_ULong* upm = &dict->units_per_em; + FT_Byte** data = parser->stack; + FT_Error error = CFF_Err_Stack_Underflow; + if ( parser->top >= parser->stack + 6 ) + { + FT_Long scaling; + error = CFF_Err_Ok; + dict->has_font_matrix = TRUE; +/* We expect a well-formed font matrix, this is, the matrix elements */ +/* `xx' and `yy' are of approximately the same magnitude. To avoid */ +/* loss of precision, we use the magnitude of element `xx' to scale */ +/* all other elements. The scaling factor is then contained in the */ +/* `units_per_em' value. */ + matrix->xx = cff_parse_fixed_dynamic( data++, &scaling ); + scaling = -scaling; + if ( scaling < 0 || scaling > 9 ) + { +/* Return default matrix in case of unlikely values. */ + FT_TRACE1(( "cff_parse_font_matrix:" + " strange scaling value for xx element (%d),\n" + " " + " using default matrix\n", scaling )); + matrix->xx = 0x10000L; + matrix->yx = 0; + matrix->xy = 0; + matrix->yy = 0x10000L; + offset->x = 0; + offset->y = 0; + *upm = 1; + goto Exit; + } + matrix->yx = cff_parse_fixed_scaled( data++, scaling ); + matrix->xy = cff_parse_fixed_scaled( data++, scaling ); + matrix->yy = cff_parse_fixed_scaled( data++, scaling ); + offset->x = cff_parse_fixed_scaled( data++, scaling ); + offset->y = cff_parse_fixed_scaled( data, scaling ); + *upm = power_tens[scaling]; + FT_TRACE4(( " [%f %f %f %f %f %f]\n", + (double)matrix->xx / *upm / 65536, + (double)matrix->xy / *upm / 65536, + (double)matrix->yx / *upm / 65536, + (double)matrix->yy / *upm / 65536, + (double)offset->x / *upm / 65536, + (double)offset->y / *upm / 65536 )); + } + Exit: + return error; + } + static FT_Error + cff_parse_font_bbox( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_BBox* bbox = &dict->font_bbox; + FT_Byte** data = parser->stack; + FT_Error error; + error = CFF_Err_Stack_Underflow; + if ( parser->top >= parser->stack + 4 ) + { + bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) ); + bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) ); + bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) ); + bbox->yMax = FT_RoundFix( cff_parse_fixed( data ) ); + error = CFF_Err_Ok; + FT_TRACE4(( " [%d %d %d %d]\n", + bbox->xMin / 65536, + bbox->yMin / 65536, + bbox->xMax / 65536, + bbox->yMax / 65536 )); + } + return error; + } + static FT_Error + cff_parse_private_dict( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + error = CFF_Err_Stack_Underflow; + if ( parser->top >= parser->stack + 2 ) + { + dict->private_size = cff_parse_num( data++ ); + dict->private_offset = cff_parse_num( data ); + FT_TRACE4(( " %lu %lu\n", + dict->private_size, dict->private_offset )); + error = CFF_Err_Ok; + } + return error; + } + static FT_Error + cff_parse_cid_ros( CFF_Parser parser ) + { + CFF_FontRecDict dict = (CFF_FontRecDict)parser->object; + FT_Byte** data = parser->stack; + FT_Error error; + error = CFF_Err_Stack_Underflow; + if ( parser->top >= parser->stack + 3 ) + { + dict->cid_registry = (FT_UInt)cff_parse_num( data++ ); + dict->cid_ordering = (FT_UInt)cff_parse_num( data++ ); + if ( **data == 30 ) + FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); + dict->cid_supplement = cff_parse_num( data ); + if ( dict->cid_supplement < 0 ) + FT_TRACE1(( "cff_parse_cid_ros: negative supplement %d is found\n", + dict->cid_supplement )); + error = CFF_Err_Ok; + FT_TRACE4(( " %d %d %d\n", + dict->cid_registry, + dict->cid_ordering, + dict->cid_supplement )); + } + return error; + } +#define CFF_FIELD_NUM( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_num ) +#define CFF_FIELD_FIXED( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_fixed ) +#define CFF_FIELD_FIXED_1000( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_fixed_thousand ) +#define CFF_FIELD_STRING( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_string ) +#define CFF_FIELD_BOOL( code, name, id ) \ + CFF_FIELD( code, name, id, cff_kind_bool ) +#define CFFCODE_TOPDICT 0x1000 +#define CFFCODE_PRIVATE 0x2000 +#undef CFF_FIELD +#undef CFF_FIELD_DELTA +#define CFF_FIELD_CALLBACK( code, name, id ) \ + { \ + cff_kind_callback, \ + code | CFFCODE, \ + 0, 0, \ + cff_parse_ ## name, \ + 0, 0 \ + }, +#define CFF_FIELD( code, name, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE( name ), \ + 0, 0, 0 \ + }, +#define CFF_FIELD_DELTA( code, name, max, id ) \ + { \ + cff_kind_delta, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + 0, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ) \ + }, + static const CFF_Field_Handler cff_field_handlers[] = + { +/***************************************************************************/ +/* */ +/* cfftoken.h */ +/* */ +/* CFF token definitions (specification only). */ +/* */ +/* Copyright 1996-2003, 2011 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 CFFCODE_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" ) + 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" ) + CFF_FIELD_CALLBACK( 0x118, multiple_master, "MultipleMaster" ) + CFF_FIELD_CALLBACK( 0x119, 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 CFFCODE_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" ) +/* END */ + { 0, 0, 0, 0, 0, 0, 0 } + }; + FT_LOCAL_DEF( FT_Error ) + cff_parser_run( CFF_Parser parser, + FT_Byte* start, + FT_Byte* limit ) + { + FT_Byte* p = start; + FT_Error error = CFF_Err_Ok; + FT_Library library = parser->library; + FT_UNUSED( library ); + parser->top = parser->stack; + parser->start = start; + parser->limit = limit; + parser->cursor = start; + while ( p < limit ) + { + FT_UInt v = *p; + if ( v >= 27 && v != 31 ) + { +/* it's a number; we will push its position on the stack */ + if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH ) + goto Stack_Overflow; + *parser->top ++ = p; +/* now, skip it */ + if ( v == 30 ) + { +/* skip real number */ + p++; + for (;;) + { +/* An unterminated floating point number at the */ +/* end of a dictionary is invalid but harmless. */ + if ( p >= limit ) + goto Exit; + v = p[0] >> 4; + if ( v == 15 ) + break; + v = p[0] & 0xF; + if ( v == 15 ) + break; + p++; + } + } + else if ( v == 28 ) + p += 2; + else if ( v == 29 ) + p += 4; + else if ( v > 246 ) + p += 1; + } + else + { +/* This is not a number, hence it's an operator. Compute its code */ +/* and look for it in our current list. */ + FT_UInt code; + FT_UInt num_args = (FT_UInt) + ( parser->top - parser->stack ); + const CFF_Field_Handler* field; + *parser->top = p; + code = v; + if ( v == 12 ) + { +/* two byte operator */ + p++; + if ( p >= limit ) + goto Syntax_Error; + code = 0x100 | p[0]; + } + code = code | parser->object_code; + for ( field = CFF_FIELD_HANDLERS_GET; field->kind; field++ ) + { + if ( field->code == (FT_Int)code ) + { +/* we found our field's handler; read it */ + FT_Long val; + FT_Byte* q = (FT_Byte*)parser->object + field->offset; +/* check that we have enough arguments -- except for */ +/* delta encoded arrays, which can be empty */ + if ( field->kind != cff_kind_delta && num_args < 1 ) + goto Stack_Underflow; + switch ( field->kind ) + { + case cff_kind_bool: + case cff_kind_string: + case cff_kind_num: + val = cff_parse_num( parser->stack ); + goto Store_Number; + case cff_kind_fixed: + val = cff_parse_fixed( parser->stack ); + goto Store_Number; + case cff_kind_fixed_thousand: + val = cff_parse_fixed_scaled( parser->stack, 3 ); + Store_Number: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; +/* for 64-bit systems */ + default: + *(FT_Long*)q = val; + } + break; + case cff_kind_delta: + { + FT_Byte* qcount = (FT_Byte*)parser->object + + field->count_offset; + FT_Byte** data = parser->stack; + if ( num_args > field->array_max ) + num_args = field->array_max; + FT_TRACE4(( " [" )); +/* store count */ + *qcount = (FT_Byte)num_args; + val = 0; + while ( num_args > 0 ) + { + val += cff_parse_num( data++ ); + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + case (16 / FT_CHAR_BIT): + *(FT_Short*)q = (FT_Short)val; + break; + case (32 / FT_CHAR_BIT): + *(FT_Int32*)q = (FT_Int)val; + break; +/* for 64-bit systems */ + default: + *(FT_Long*)q = val; + } + FT_TRACE4(( " %ld", val )); + q += field->size; + num_args--; + } + FT_TRACE4(( "]\n" )); + } + break; +/* callback */ + default: + error = field->reader( parser ); + if ( error ) + goto Exit; + } + goto Found; + } + } +/* this is an unknown operator, or it is unsupported; */ +/* we will ignore it for now. */ + Found: +/* clear stack */ + parser->top = parser->stack; + } + p++; + } + Exit: + return error; + Stack_Overflow: + error = CFF_Err_Invalid_Argument; + goto Exit; + Stack_Underflow: + error = CFF_Err_Invalid_Argument; + goto Exit; + Syntax_Error: + error = CFF_Err_Invalid_Argument; + goto Exit; + } +/* END */ +/***************************************************************************/ +/* */ +/* cffload.c */ +/* */ +/* OpenType and CFF data/program tables loader (body). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +#if 1 + static const FT_UShort cff_isoadobe_charset[229] = + { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228 + }; + static const FT_UShort cff_expert_charset[166] = + { + 0, 1, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 109, 110, + 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 326, 150, + 164, 169, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, + 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378 + }; + static const FT_UShort cff_expertsubset_charset[87] = + { + 0, 1, 231, 232, 235, 236, 237, 238, + 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, + 249, 250, 251, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, + 266, 109, 110, 267, 268, 269, 270, 272, + 300, 301, 302, 305, 314, 315, 158, 155, + 163, 320, 321, 322, 323, 324, 325, 326, + 150, 164, 169, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346 + }; + static const FT_UShort cff_standard_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, + 0, 111, 112, 113, 114, 0, 115, 116, + 117, 118, 119, 120, 121, 122, 0, 123, + 0, 124, 125, 126, 127, 128, 129, 130, + 131, 0, 132, 133, 0, 134, 135, 136, + 137, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 139, 0, 0, 0, 0, + 140, 141, 142, 143, 0, 0, 0, 0, + 0, 144, 0, 0, 0, 145, 0, 0, + 146, 147, 148, 149, 0, 0, 0, 0 + }; + static const FT_UShort cff_expert_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 229, 230, 0, 231, 232, 233, 234, + 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 27, 28, 249, 250, 251, 252, + 0, 253, 254, 255, 256, 257, 0, 0, + 0, 258, 0, 0, 259, 260, 261, 262, + 0, 0, 263, 264, 265, 0, 266, 109, + 110, 267, 268, 269, 0, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, + 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 304, 305, 306, 0, 0, 307, 308, + 309, 310, 311, 0, 312, 0, 0, 312, + 0, 0, 314, 315, 0, 0, 316, 317, + 318, 0, 0, 0, 158, 155, 163, 319, + 320, 321, 322, 323, 324, 325, 0, 0, + 326, 150, 164, 169, 327, 328, 329, 330, + 331, 332, 333, 334, 335, 336, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378 + }; +/* 1 */ +#endif + FT_LOCAL_DEF( FT_UShort ) + cff_get_standard_encoding( FT_UInt charcode ) + { + return (FT_UShort)( charcode < 256 ? cff_standard_encoding[charcode] + : 0 ); + } +/*************************************************************************/ +/* */ +/* 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 trace_cffload +/* read an offset from the index's stream current position */ + static FT_ULong + cff_index_read_offset( CFF_Index idx, + FT_Error *errorp ) + { + FT_Error error; + FT_Stream stream = idx->stream; + FT_Byte tmp[4]; + FT_ULong result = 0; + if ( !FT_STREAM_READ( tmp, idx->off_size ) ) + { + FT_Int nn; + for ( nn = 0; nn < idx->off_size; nn++ ) + result = ( result << 8 ) | tmp[nn]; + } + *errorp = error; + return result; + } + static FT_Error + cff_index_init( CFF_Index idx, + FT_Stream stream, + FT_Bool load ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UShort count; + FT_MEM_ZERO( idx, sizeof ( *idx ) ); + idx->stream = stream; + idx->start = FT_STREAM_POS(); + if ( !FT_READ_USHORT( count ) && + count > 0 ) + { + FT_Byte offsize; + FT_ULong size; +/* there is at least one element; read the offset size, */ +/* then access the offset table to compute the index's total size */ + if ( FT_READ_BYTE( offsize ) ) + goto Exit; + if ( offsize < 1 || offsize > 4 ) + { + error = CFF_Err_Invalid_Table; + goto Exit; + } + idx->count = count; + idx->off_size = offsize; + size = (FT_ULong)( count + 1 ) * offsize; + idx->data_offset = idx->start + 3 + size; + if ( FT_STREAM_SKIP( size - offsize ) ) + goto Exit; + size = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + if ( size == 0 ) + { + error = CFF_Err_Invalid_Table; + goto Exit; + } + idx->data_size = --size; + if ( load ) + { +/* load the data */ + if ( FT_FRAME_EXTRACT( size, idx->bytes ) ) + goto Exit; + } + else + { +/* skip the data */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + } + Exit: + if ( error ) + FT_FREE( idx->offsets ); + return error; + } + static void + cff_index_done( CFF_Index idx ) + { + if ( idx->stream ) + { + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + if ( idx->bytes ) + FT_FRAME_RELEASE( idx->bytes ); + FT_FREE( idx->offsets ); + FT_MEM_ZERO( idx, sizeof ( *idx ) ); + } + } + static FT_Error + cff_index_load_offsets( CFF_Index idx ) + { + FT_Error error = CFF_Err_Ok; + FT_Stream stream = idx->stream; + FT_Memory memory = stream->memory; + if ( idx->count > 0 && idx->offsets == NULL ) + { + FT_Byte offsize = idx->off_size; + FT_ULong data_size; + FT_Byte* p; + FT_Byte* p_end; + FT_ULong* poff; + data_size = (FT_ULong)( idx->count + 1 ) * offsize; + if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) || + FT_STREAM_SEEK( idx->start + 3 ) || + FT_FRAME_ENTER( data_size ) ) + goto Exit; + poff = idx->offsets; + p = (FT_Byte*)stream->cursor; + p_end = p + data_size; + switch ( offsize ) + { + case 1: + for ( ; p < p_end; p++, poff++ ) + poff[0] = p[0]; + break; + case 2: + for ( ; p < p_end; p += 2, poff++ ) + poff[0] = FT_PEEK_USHORT( p ); + break; + case 3: + for ( ; p < p_end; p += 3, poff++ ) + poff[0] = FT_PEEK_OFF3( p ); + break; + default: + for ( ; p < p_end; p += 4, poff++ ) + poff[0] = FT_PEEK_ULONG( p ); + } + FT_FRAME_EXIT(); + } + Exit: + if ( error ) + FT_FREE( idx->offsets ); + return error; + } +/* Allocate a table containing pointers to an index's elements. */ +/* The `pool' argument makes this function convert the index */ +/* entries to C-style strings (this is, NULL-terminated). */ + static FT_Error + cff_index_get_pointers( CFF_Index idx, + FT_Byte*** table, + FT_Byte** pool ) + { + FT_Error error = CFF_Err_Ok; + FT_Memory memory = idx->stream->memory; + FT_Byte** t = NULL; + FT_Byte* new_bytes = NULL; + *table = NULL; + if ( idx->offsets == NULL ) + { + error = cff_index_load_offsets( idx ); + if ( error ) + goto Exit; + } + if ( idx->count > 0 && + !FT_NEW_ARRAY( t, idx->count + 1 ) && + ( !pool || !FT_ALLOC( new_bytes, + idx->data_size + idx->count ) ) ) + { + FT_ULong n, cur_offset; + FT_ULong extra = 0; + FT_Byte* org_bytes = idx->bytes; +/* at this point, `idx->offsets' can't be NULL */ + cur_offset = idx->offsets[0] - 1; +/* sanity check */ + if ( cur_offset >= idx->data_size ) + { + FT_TRACE0(( "cff_index_get_pointers:" + " invalid first offset value %d set to zero\n", + cur_offset )); + cur_offset = 0; + } + if ( !pool ) + t[0] = org_bytes + cur_offset; + else + t[0] = new_bytes + cur_offset; + for ( n = 1; n <= idx->count; n++ ) + { + FT_ULong next_offset = idx->offsets[n] - 1; +/* empty slot + two sanity checks for invalid offset tables */ + if ( next_offset == 0 || + next_offset < cur_offset || + ( next_offset >= idx->data_size && n < idx->count ) ) + next_offset = cur_offset; + if ( !pool ) + t[n] = org_bytes + next_offset; + else + { + t[n] = new_bytes + next_offset + extra; + if ( next_offset != cur_offset ) + { + FT_MEM_COPY( t[n - 1], org_bytes + cur_offset, t[n] - t[n - 1] ); + t[n][0] = '\0'; + t[n] += 1; + extra++; + } + } + cur_offset = next_offset; + } + *table = t; + if ( pool ) + *pool = new_bytes; + } + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + cff_index_access_element( CFF_Index idx, + FT_UInt element, + FT_Byte** pbytes, + FT_ULong* pbyte_len ) + { + FT_Error error = CFF_Err_Ok; + if ( idx && idx->count > element ) + { +/* compute start and end offsets */ + FT_Stream stream = idx->stream; + FT_ULong off1, off2 = 0; +/* load offsets from file or the offset table */ + if ( !idx->offsets ) + { + FT_ULong pos = element * idx->off_size; + if ( FT_STREAM_SEEK( idx->start + 3 + pos ) ) + goto Exit; + off1 = cff_index_read_offset( idx, &error ); + if ( error ) + goto Exit; + if ( off1 != 0 ) + { + do + { + element++; + off2 = cff_index_read_offset( idx, &error ); + } + while ( off2 == 0 && element < idx->count ); + } + } +/* use offsets table */ + else + { + off1 = idx->offsets[element]; + if ( off1 ) + { + do + { + element++; + off2 = idx->offsets[element]; + } while ( off2 == 0 && element < idx->count ); + } + } +/* XXX: should check off2 does not exceed the end of this entry; */ +/* at present, only truncate off2 at the end of this stream */ + if ( off2 > stream->size + 1 || + idx->data_offset > stream->size - off2 + 1 ) + { + FT_ERROR(( "cff_index_access_element:" + " offset to next entry (%d)" + " exceeds the end of stream (%d)\n", + off2, stream->size - idx->data_offset + 1 )); + off2 = stream->size - idx->data_offset + 1; + } +/* access element */ + if ( off1 && off2 > off1 ) + { + *pbyte_len = off2 - off1; + if ( idx->bytes ) + { +/* this index was completely loaded in memory, that's easy */ + *pbytes = idx->bytes + off1 - 1; + } + else + { +/* this index is still on disk/file, access it through a frame */ + if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) || + FT_FRAME_EXTRACT( off2 - off1, *pbytes ) ) + goto Exit; + } + } + else + { +/* empty index element */ + *pbytes = 0; + *pbyte_len = 0; + } + } + else + error = CFF_Err_Invalid_Argument; + Exit: + return error; + } + FT_LOCAL_DEF( void ) + cff_index_forget_element( CFF_Index idx, + FT_Byte** pbytes ) + { + if ( idx->bytes == 0 ) + { + FT_Stream stream = idx->stream; + FT_FRAME_RELEASE( *pbytes ); + } + } +/* get an entry from Name INDEX */ + FT_LOCAL_DEF( FT_String* ) + cff_index_get_name( CFF_Font font, + FT_UInt element ) + { + CFF_Index idx = &font->name_index; + FT_Memory memory = idx->stream->memory; + FT_Byte* bytes; + FT_ULong byte_len; + FT_Error error; + FT_String* name = 0; + error = cff_index_access_element( idx, element, &bytes, &byte_len ); + if ( error ) + goto Exit; + if ( !FT_ALLOC( name, byte_len + 1 ) ) + { + FT_MEM_COPY( name, bytes, byte_len ); + name[byte_len] = 0; + } + cff_index_forget_element( idx, &bytes ); + Exit: + return name; + } +/* get an entry from String INDEX */ + FT_LOCAL_DEF( FT_String* ) + cff_index_get_string( CFF_Font font, + FT_UInt element ) + { + return ( element < font->num_strings ) + ? (FT_String*)font->strings[element] + : NULL; + } + FT_LOCAL_DEF( FT_String* ) + cff_index_get_sid_string( CFF_Font font, + FT_UInt sid ) + { +/* value 0xFFFFU indicates a missing dictionary entry */ + if ( sid == 0xFFFFU ) + return NULL; +/* if it is not a standard string, return it */ + if ( sid > 390 ) + return cff_index_get_string( font, sid - 391 ); +/* CID-keyed CFF fonts don't have glyph names */ + if ( !font->psnames ) + return NULL; +/* this is a standard string */ + return (FT_String *)font->psnames->adobe_std_strings( sid ); + } +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** FD Select table support ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ + static void + CFF_Done_FD_Select( CFF_FDSelect fdselect, + FT_Stream stream ) + { + if ( fdselect->data ) + FT_FRAME_RELEASE( fdselect->data ); + fdselect->data_size = 0; + fdselect->format = 0; + fdselect->range_count = 0; + } + static FT_Error + CFF_Load_FD_Select( CFF_FDSelect fdselect, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong offset ) + { + FT_Error error; + FT_Byte format; + FT_UInt num_ranges; +/* read format */ + if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) ) + goto Exit; + fdselect->format = format; +/* clear cache */ + fdselect->cache_count = 0; + switch ( format ) + { +/* format 0, that's simple */ + case 0: + fdselect->data_size = num_glyphs; + goto Load_Data; +/* format 3, a tad more complex */ + case 3: + if ( FT_READ_USHORT( num_ranges ) ) + goto Exit; + fdselect->data_size = num_ranges * 3 + 2; + Load_Data: + if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) ) + goto Exit; + break; +/* hmm... that's wrong */ + default: + error = CFF_Err_Invalid_File_Format; + } + Exit: + return error; + } + FT_LOCAL_DEF( FT_Byte ) + cff_fd_select_get( CFF_FDSelect fdselect, + FT_UInt glyph_index ) + { + FT_Byte fd = 0; + switch ( fdselect->format ) + { + case 0: + fd = fdselect->data[glyph_index]; + break; + case 3: +/* first, compare to cache */ + if ( (FT_UInt)( glyph_index - fdselect->cache_first ) < + fdselect->cache_count ) + { + fd = fdselect->cache_fd; + break; + } +/* then, lookup the ranges array */ + { + FT_Byte* p = fdselect->data; + FT_Byte* p_limit = p + fdselect->data_size; + FT_Byte fd2; + FT_UInt first, limit; + first = FT_NEXT_USHORT( p ); + do + { + if ( glyph_index < first ) + break; + fd2 = *p++; + limit = FT_NEXT_USHORT( p ); + if ( glyph_index < limit ) + { + fd = fd2; +/* update cache */ + fdselect->cache_first = first; + fdselect->cache_count = limit-first; + fdselect->cache_fd = fd2; + break; + } + first = limit; + } while ( p < p_limit ); + } + break; + default: + ; + } + return fd; + } +/*************************************************************************/ +/*************************************************************************/ +/*** ***/ +/*** CFF font support ***/ +/*** ***/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + cff_charset_compute_cids( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Memory memory ) + { + FT_Error error = CFF_Err_Ok; + FT_UInt i; + FT_Long j; + FT_UShort max_cid = 0; + if ( charset->max_cid > 0 ) + goto Exit; + for ( i = 0; i < num_glyphs; i++ ) + { + if ( charset->sids[i] > max_cid ) + max_cid = charset->sids[i]; + } + if ( FT_NEW_ARRAY( charset->cids, (FT_ULong)max_cid + 1 ) ) + goto Exit; +/* When multiple GIDs map to the same CID, we choose the lowest */ +/* GID. This is not described in any spec, but it matches the */ +/* behaviour of recent Acroread versions. */ + for ( j = num_glyphs - 1; j >= 0 ; j-- ) + charset->cids[charset->sids[j]] = (FT_UShort)j; + charset->max_cid = max_cid; + charset->num_glyphs = num_glyphs; + Exit: + return error; + } + FT_LOCAL_DEF( FT_UInt ) + cff_charset_cid_to_gindex( CFF_Charset charset, + FT_UInt cid ) + { + FT_UInt result = 0; + if ( cid <= charset->max_cid ) + result = charset->cids[cid]; + return result; + } + static void + cff_charset_free_cids( CFF_Charset charset, + FT_Memory memory ) + { + FT_FREE( charset->cids ); + charset->max_cid = 0; + } + static void + cff_charset_done( CFF_Charset charset, + FT_Stream stream ) + { + FT_Memory memory = stream->memory; + cff_charset_free_cids( charset, memory ); + FT_FREE( charset->sids ); + charset->format = 0; + charset->offset = 0; + } + static FT_Error + cff_charset_load( CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset, + FT_Bool invert ) + { + FT_Memory memory = stream->memory; + FT_Error error = CFF_Err_Ok; + FT_UShort glyph_sid; +/* If the the offset is greater than 2, we have to parse the */ +/* charset table. */ + if ( offset > 2 ) + { + FT_UInt j; + charset->offset = base_offset + offset; +/* Get the format of the table. */ + if ( FT_STREAM_SEEK( charset->offset ) || + FT_READ_BYTE( charset->format ) ) + goto Exit; +/* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; +/* assign the .notdef glyph */ + charset->sids[0] = 0; + switch ( charset->format ) + { + case 0: + if ( num_glyphs > 0 ) + { + if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) + goto Exit; + for ( j = 1; j < num_glyphs; j++ ) + charset->sids[j] = FT_GET_USHORT(); + FT_FRAME_EXIT(); + } + break; + case 1: + case 2: + { + FT_UInt nleft; + FT_UInt i; + j = 1; + while ( j < num_glyphs ) + { +/* Read the first glyph sid of the range. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; +/* Read the number of glyphs in the range. */ + if ( charset->format == 2 ) + { + if ( FT_READ_USHORT( nleft ) ) + goto Exit; + } + else + { + if ( FT_READ_BYTE( nleft ) ) + goto Exit; + } +/* try to rescue some of the SIDs if `nleft' is too large */ + if ( glyph_sid > 0xFFFFL - nleft ) + { + FT_ERROR(( "cff_charset_load: invalid SID range trimmed" + " nleft=%d -> %d\n", nleft, 0xFFFFL - glyph_sid )); + nleft = ( FT_UInt )( 0xFFFFL - glyph_sid ); + } +/* Fill in the range of sids -- `nleft + 1' glyphs. */ + for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) + charset->sids[j] = glyph_sid; + } + } + break; + default: + FT_ERROR(( "cff_charset_load: invalid table format\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } + else + { +/* Parse default tables corresponding to offset == 0, 1, or 2. */ +/* CFF specification intimates the following: */ +/* */ +/* In order to use a predefined charset, the following must be */ +/* true: The charset constructed for the glyphs in the font's */ +/* charstrings dictionary must match the predefined charset in */ +/* the first num_glyphs. */ +/* record charset type */ + charset->offset = offset; + switch ( (FT_UInt)offset ) + { + case 0: + if ( num_glyphs > 229 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" + "predefined charset (Adobe ISO-Latin)\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } +/* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; +/* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); + break; + case 1: + if ( num_glyphs > 166 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" + "predefined charset (Adobe Expert)\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } +/* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; +/* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); + break; + case 2: + if ( num_glyphs > 87 ) + { + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" + "predefined charset (Adobe Expert Subset)\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } +/* Allocate memory for sids. */ + if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + goto Exit; +/* Copy the predefined charset into the allocated memory. */ + FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); + break; + default: + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } +/* we have to invert the `sids' array for subsetted CID-keyed fonts */ + if ( invert ) + error = cff_charset_compute_cids( charset, num_glyphs, memory ); + Exit: +/* Clean up if there was an error. */ + if ( error ) + { + FT_FREE( charset->sids ); + FT_FREE( charset->cids ); + charset->format = 0; + charset->offset = 0; + charset->sids = 0; + } + return error; + } + static void + cff_encoding_done( CFF_Encoding encoding ) + { + encoding->format = 0; + encoding->offset = 0; + encoding->count = 0; + } + static FT_Error + cff_encoding_load( CFF_Encoding encoding, + CFF_Charset charset, + FT_UInt num_glyphs, + FT_Stream stream, + FT_ULong base_offset, + FT_ULong offset ) + { + FT_Error error = CFF_Err_Ok; + FT_UInt count; + FT_UInt j; + FT_UShort glyph_sid; + FT_UInt glyph_code; +/* Check for charset->sids. If we do not have this, we fail. */ + if ( !charset->sids ) + { + error = CFF_Err_Invalid_File_Format; + goto Exit; + } +/* Zero out the code to gid/sid mappings. */ + for ( j = 0; j < 256; j++ ) + { + encoding->sids [j] = 0; + encoding->codes[j] = 0; + } +/* Note: The encoding table in a CFF font is indexed by glyph index; */ +/* the first encoded glyph index is 1. Hence, we read the character */ +/* code (`glyph_code') at index j and make the assignment: */ +/* */ +/* encoding->codes[glyph_code] = j + 1 */ +/* */ +/* We also make the assignment: */ +/* */ +/* encoding->sids[glyph_code] = charset->sids[j + 1] */ +/* */ +/* This gives us both a code to GID and a code to SID mapping. */ + if ( offset > 1 ) + { + encoding->offset = base_offset + offset; +/* we need to parse the table to determine its size */ + if ( FT_STREAM_SEEK( encoding->offset ) || + FT_READ_BYTE( encoding->format ) || + FT_READ_BYTE( count ) ) + goto Exit; + switch ( encoding->format & 0x7F ) + { + case 0: + { + FT_Byte* p; +/* By convention, GID 0 is always ".notdef" and is never */ +/* coded in the font. Hence, the number of codes found */ +/* in the table is `count+1'. */ +/* */ + encoding->count = count + 1; + if ( FT_FRAME_ENTER( count ) ) + goto Exit; + p = (FT_Byte*)stream->cursor; + for ( j = 1; j <= count; j++ ) + { + glyph_code = *p++; +/* Make sure j is not too big. */ + if ( j < num_glyphs ) + { +/* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)j; +/* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[j]; + } + } + FT_FRAME_EXIT(); + } + break; + case 1: + { + FT_UInt nleft; + FT_UInt i = 1; + FT_UInt k; + encoding->count = 0; +/* Parse the Format1 ranges. */ + for ( j = 0; j < count; j++, i += nleft ) + { +/* Read the first glyph code of the range. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; +/* Read the number of codes in the range. */ + if ( FT_READ_BYTE( nleft ) ) + goto Exit; +/* Increment nleft, so we read `nleft + 1' codes/sids. */ + nleft++; +/* compute max number of character codes */ + if ( (FT_UInt)nleft > encoding->count ) + encoding->count = nleft; +/* Fill in the range of codes/sids. */ + for ( k = i; k < nleft + i; k++, glyph_code++ ) + { +/* Make sure k is not too big. */ + if ( k < num_glyphs && glyph_code < 256 ) + { +/* Assign code to GID mapping. */ + encoding->codes[glyph_code] = (FT_UShort)k; +/* Assign code to SID mapping. */ + encoding->sids[glyph_code] = charset->sids[k]; + } + } + } +/* simple check; one never knows what can be found in a font */ + if ( encoding->count > 256 ) + encoding->count = 256; + } + break; + default: + FT_ERROR(( "cff_encoding_load: invalid table format\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } +/* Parse supplemental encodings, if any. */ + if ( encoding->format & 0x80 ) + { + FT_UInt gindex; +/* count supplements */ + if ( FT_READ_BYTE( count ) ) + goto Exit; + for ( j = 0; j < count; j++ ) + { +/* Read supplemental glyph code. */ + if ( FT_READ_BYTE( glyph_code ) ) + goto Exit; +/* Read the SID associated with this glyph code. */ + if ( FT_READ_USHORT( glyph_sid ) ) + goto Exit; +/* Assign code to SID mapping. */ + encoding->sids[glyph_code] = glyph_sid; +/* First, look up GID which has been assigned to */ +/* SID glyph_sid. */ + for ( gindex = 0; gindex < num_glyphs; gindex++ ) + { + if ( charset->sids[gindex] == glyph_sid ) + { + encoding->codes[glyph_code] = (FT_UShort)gindex; + break; + } + } + } + } + } + else + { +/* We take into account the fact a CFF font can use a predefined */ +/* encoding without containing all of the glyphs encoded by this */ +/* encoding (see the note at the end of section 12 in the CFF */ +/* specification). */ + switch ( (FT_UInt)offset ) + { + case 0: +/* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_standard_encoding, 256 ); + goto Populate; + case 1: +/* First, copy the code to SID mapping. */ + FT_ARRAY_COPY( encoding->sids, cff_expert_encoding, 256 ); + Populate: +/* Construct code to GID mapping from code to SID mapping */ +/* and charset. */ + encoding->count = 0; + error = cff_charset_compute_cids( charset, num_glyphs, + stream->memory ); + if ( error ) + goto Exit; + for ( j = 0; j < 256; j++ ) + { + FT_UInt sid = encoding->sids[j]; + FT_UInt gid = 0; + if ( sid ) + gid = cff_charset_cid_to_gindex( charset, sid ); + if ( gid != 0 ) + { + encoding->codes[j] = (FT_UShort)gid; + encoding->count = j + 1; + } + else + { + encoding->codes[j] = 0; + encoding->sids [j] = 0; + } + } + break; + default: + FT_ERROR(( "cff_encoding_load: invalid table format\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } + Exit: +/* Clean up if there was an error. */ + return error; + } + static FT_Error + cff_subfont_load( CFF_SubFont font, + CFF_Index idx, + FT_UInt font_index, + FT_Stream stream, + FT_ULong base_offset, + FT_Library library ) + { + FT_Error error; + CFF_ParserRec parser; + FT_Byte* dict = NULL; + FT_ULong dict_len; + CFF_FontRecDict top = &font->font_dict; + CFF_Private priv = &font->private_dict; + cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict, library ); +/* set defaults */ + FT_MEM_ZERO( top, sizeof ( *top ) ); + top->underline_position = -100L << 16; + top->underline_thickness = 50L << 16; + top->charstring_type = 2; + top->font_matrix.xx = 0x10000L; + top->font_matrix.yy = 0x10000L; + top->cid_count = 8720; +/* we use the implementation specific SID value 0xFFFF to indicate */ +/* missing entries */ + top->version = 0xFFFFU; + top->notice = 0xFFFFU; + top->copyright = 0xFFFFU; + top->full_name = 0xFFFFU; + top->family_name = 0xFFFFU; + top->weight = 0xFFFFU; + top->embedded_postscript = 0xFFFFU; + top->cid_registry = 0xFFFFU; + top->cid_ordering = 0xFFFFU; + top->cid_font_name = 0xFFFFU; + error = cff_index_access_element( idx, font_index, &dict, &dict_len ); + if ( !error ) + { + FT_TRACE4(( " top dictionary:\n" )); + error = cff_parser_run( &parser, dict, dict + dict_len ); + } + cff_index_forget_element( idx, &dict ); + if ( error ) + goto Exit; +/* if it is a CID font, we stop there */ + if ( top->cid_registry != 0xFFFFU ) + goto Exit; +/* parse the private dictionary, if any */ + if ( top->private_offset && top->private_size ) + { +/* set defaults */ + FT_MEM_ZERO( priv, sizeof ( *priv ) ); + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = -1; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + cff_parser_init( &parser, CFF_CODE_PRIVATE, priv, library ); + if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) || + FT_FRAME_ENTER( font->font_dict.private_size ) ) + goto Exit; + FT_TRACE4(( " private dictionary:\n" )); + error = cff_parser_run( &parser, + (FT_Byte*)stream->cursor, + (FT_Byte*)stream->limit ); + FT_FRAME_EXIT(); + if ( error ) + goto Exit; +/* ensure that `num_blue_values' is even */ + priv->num_blue_values &= ~1; + } +/* read the local subrs, if any */ + if ( priv->local_subrs_offset ) + { + if ( FT_STREAM_SEEK( base_offset + top->private_offset + + priv->local_subrs_offset ) ) + goto Exit; + error = cff_index_init( &font->local_subrs_index, stream, 1 ); + if ( error ) + goto Exit; + error = cff_index_get_pointers( &font->local_subrs_index, + &font->local_subrs, NULL ); + if ( error ) + goto Exit; + } + Exit: + return error; + } + static void + cff_subfont_done( FT_Memory memory, + CFF_SubFont subfont ) + { + if ( subfont ) + { + cff_index_done( &subfont->local_subrs_index ); + FT_FREE( subfont->local_subrs ); + } + } + FT_LOCAL_DEF( FT_Error ) + cff_font_load( FT_Library library, + FT_Stream stream, + FT_Int face_index, + CFF_Font font, + FT_Bool pure_cff ) + { + static const FT_Frame_Field cff_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE CFF_FontRec + FT_FRAME_START( 4 ), + FT_FRAME_BYTE( version_major ), + FT_FRAME_BYTE( version_minor ), + FT_FRAME_BYTE( header_size ), + FT_FRAME_BYTE( absolute_offsize ), + FT_FRAME_END + }; + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong base_offset; + CFF_FontRecDict dict; + CFF_IndexRec string_index; + FT_Int subfont_index; + FT_ZERO( font ); + FT_ZERO( &string_index ); + font->stream = stream; + font->memory = memory; + dict = &font->top_font.font_dict; + base_offset = FT_STREAM_POS(); +/* read CFF font header */ + if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) ) + goto Exit; +/* check format */ + if ( font->version_major != 1 || + font->header_size < 4 || + font->absolute_offsize > 4 ) + { + FT_TRACE2(( " not a CFF font header\n" )); + error = CFF_Err_Unknown_File_Format; + goto Exit; + } +/* skip the rest of the header */ + if ( FT_STREAM_SKIP( font->header_size - 4 ) ) + goto Exit; +/* read the name, top dict, string and global subrs index */ + if ( FT_SET_ERROR( cff_index_init( &font->name_index, + stream, 0 ) ) || + FT_SET_ERROR( cff_index_init( &font->font_dict_index, + stream, 0 ) ) || + FT_SET_ERROR( cff_index_init( &string_index, + stream, 1 ) ) || + FT_SET_ERROR( cff_index_init( &font->global_subrs_index, + stream, 1 ) ) || + FT_SET_ERROR( cff_index_get_pointers( &string_index, + &font->strings, + &font->string_pool ) ) ) + goto Exit; + font->num_strings = string_index.count; + if ( pure_cff ) + { +/* well, we don't really forget the `disabled' fonts... */ + subfont_index = face_index; + if ( subfont_index >= (FT_Int)font->name_index.count ) + { + FT_ERROR(( "cff_font_load:" + " invalid subfont index for pure CFF font (%d)\n", + subfont_index )); + error = CFF_Err_Invalid_Argument; + goto Exit; + } + font->num_faces = font->name_index.count; + } + else + { + subfont_index = 0; + if ( font->name_index.count > 1 ) + { + FT_ERROR(( "cff_font_load:" + " invalid CFF font with multiple subfonts\n" + " " + " in SFNT wrapper\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + } +/* in case of a font format check, simply exit now */ + if ( face_index < 0 ) + goto Exit; +/* now, parse the top-level font dictionary */ + FT_TRACE4(( "parsing top-level\n" )); + error = cff_subfont_load( &font->top_font, + &font->font_dict_index, + subfont_index, + stream, + base_offset, + library ); + if ( error ) + goto Exit; + if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) ) + goto Exit; + error = cff_index_init( &font->charstrings_index, stream, 0 ); + if ( error ) + goto Exit; +/* now, check for a CID font */ + if ( dict->cid_registry != 0xFFFFU ) + { + CFF_IndexRec fd_index; + CFF_SubFont sub = NULL; + FT_UInt idx; +/* this is a CID-keyed font, we must now allocate a table of */ +/* sub-fonts, then load each of them separately */ + if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) ) + goto Exit; + error = cff_index_init( &fd_index, stream, 0 ); + if ( error ) + goto Exit; + if ( fd_index.count > CFF_MAX_CID_FONTS ) + { + FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" )); + goto Fail_CID; + } +/* allocate & read each font dict independently */ + font->num_subfonts = fd_index.count; + if ( FT_NEW_ARRAY( sub, fd_index.count ) ) + goto Fail_CID; +/* set up pointer table */ + for ( idx = 0; idx < fd_index.count; idx++ ) + font->subfonts[idx] = sub + idx; +/* now load each subfont independently */ + for ( idx = 0; idx < fd_index.count; idx++ ) + { + sub = font->subfonts[idx]; + FT_TRACE4(( "parsing subfont %u\n", idx )); + error = cff_subfont_load( sub, &fd_index, idx, + stream, base_offset, library ); + if ( error ) + goto Fail_CID; + } +/* now load the FD Select array */ + error = CFF_Load_FD_Select( &font->fd_select, + font->charstrings_index.count, + stream, + base_offset + dict->cid_fd_select_offset ); + Fail_CID: + cff_index_done( &fd_index ); + if ( error ) + goto Exit; + } + else + font->num_subfonts = 0; +/* read the charstrings index now */ + if ( dict->charstrings_offset == 0 ) + { + FT_ERROR(( "cff_font_load: no charstrings offset\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + font->num_glyphs = font->charstrings_index.count; + error = cff_index_get_pointers( &font->global_subrs_index, + &font->global_subrs, NULL ); + if ( error ) + goto Exit; +/* read the Charset and Encoding tables if available */ + if ( font->num_glyphs > 0 ) + { + FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff ); + error = cff_charset_load( &font->charset, font->num_glyphs, stream, + base_offset, dict->charset_offset, invert ); + if ( error ) + goto Exit; +/* CID-keyed CFFs don't have an encoding */ + if ( dict->cid_registry == 0xFFFFU ) + { + error = cff_encoding_load( &font->encoding, + &font->charset, + font->num_glyphs, + stream, + base_offset, + dict->encoding_offset ); + if ( error ) + goto Exit; + } + } +/* get the font name (/CIDFontName for CID-keyed fonts, */ +/* /FontName otherwise) */ + font->font_name = cff_index_get_name( font, subfont_index ); + Exit: + cff_index_done( &string_index ); + return error; + } + FT_LOCAL_DEF( void ) + cff_font_done( CFF_Font font ) + { + FT_Memory memory = font->memory; + FT_UInt idx; + cff_index_done( &font->global_subrs_index ); + cff_index_done( &font->font_dict_index ); + cff_index_done( &font->name_index ); + cff_index_done( &font->charstrings_index ); +/* release font dictionaries, but only if working with */ +/* a CID keyed CFF font */ + if ( font->num_subfonts > 0 ) + { + for ( idx = 0; idx < font->num_subfonts; idx++ ) + cff_subfont_done( memory, font->subfonts[idx] ); +/* the subfonts array has been allocated as a single block */ + FT_FREE( font->subfonts[0] ); + } + cff_encoding_done( &font->encoding ); + cff_charset_done( &font->charset, font->stream ); + cff_subfont_done( memory, &font->top_font ); + CFF_Done_FD_Select( &font->fd_select, font->stream ); + FT_FREE( font->font_info ); + FT_FREE( font->font_name ); + FT_FREE( font->global_subrs ); + FT_FREE( font->strings ); + FT_FREE( font->string_pool ); + } +/* END */ +/***************************************************************************/ +/* */ +/* cffobjs.c */ +/* */ +/* OpenType objects manager (body). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_cffobjs +/*************************************************************************/ +/* */ +/* SIZE FUNCTIONS */ +/* */ +/* Note that we store the global hints in the size's `internal' root */ +/* field. */ +/* */ +/*************************************************************************/ + static PSH_Globals_Funcs + cff_size_get_globals_funcs( CFF_Size size ) + { + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_Font)face->extra.data; + PSHinter_Service pshinter = font->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 ) +/* CFF_Size */ + cff_size_done( FT_Size cffsize ) + { + CFF_Size size = (CFF_Size)cffsize; + CFF_Face face = (CFF_Face)size->root.face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = (CFF_Internal)cffsize->internal; + if ( internal ) + { + PSH_Globals_Funcs funcs; + funcs = cff_size_get_globals_funcs( size ); + if ( funcs ) + { + FT_UInt i; + funcs->destroy( internal->topfont ); + for ( i = font->num_subfonts; i > 0; i-- ) + funcs->destroy( internal->subfonts[i - 1] ); + } +/* `internal' is freed by destroy_size (in ftobjs.c) */ + } + } +/* CFF and Type 1 private dictionaries have slightly different */ +/* structures; we need to synthesize a Type 1 dictionary on the fly */ + static void + cff_make_private_dict( CFF_SubFont subfont, + PS_Private priv ) + { + CFF_Private cpriv = &subfont->private_dict; + FT_UInt n, count; + FT_MEM_ZERO( priv, sizeof ( *priv ) ); + count = priv->num_blue_values = cpriv->num_blue_values; + for ( n = 0; n < count; n++ ) + priv->blue_values[n] = (FT_Short)cpriv->blue_values[n]; + count = priv->num_other_blues = cpriv->num_other_blues; + for ( n = 0; n < count; n++ ) + priv->other_blues[n] = (FT_Short)cpriv->other_blues[n]; + count = priv->num_family_blues = cpriv->num_family_blues; + for ( n = 0; n < count; n++ ) + priv->family_blues[n] = (FT_Short)cpriv->family_blues[n]; + count = priv->num_family_other_blues = cpriv->num_family_other_blues; + for ( n = 0; n < count; n++ ) + priv->family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n]; + priv->blue_scale = cpriv->blue_scale; + priv->blue_shift = (FT_Int)cpriv->blue_shift; + priv->blue_fuzz = (FT_Int)cpriv->blue_fuzz; + priv->standard_width[0] = (FT_UShort)cpriv->standard_width; + priv->standard_height[0] = (FT_UShort)cpriv->standard_height; + count = priv->num_snap_widths = cpriv->num_snap_widths; + for ( n = 0; n < count; n++ ) + priv->snap_widths[n] = (FT_Short)cpriv->snap_widths[n]; + count = priv->num_snap_heights = cpriv->num_snap_heights; + for ( n = 0; n < count; n++ ) + priv->snap_heights[n] = (FT_Short)cpriv->snap_heights[n]; + priv->force_bold = cpriv->force_bold; + priv->language_group = cpriv->language_group; + priv->lenIV = cpriv->lenIV; + } + FT_LOCAL_DEF( FT_Error ) +/* CFF_Size */ + cff_size_init( FT_Size cffsize ) + { + CFF_Size size = (CFF_Size)cffsize; + FT_Error error = CFF_Err_Ok; + PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size ); + if ( funcs ) + { + CFF_Face face = (CFF_Face)cffsize->face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = NULL; + PS_PrivateRec priv; + FT_Memory memory = cffsize->face->memory; + FT_UInt i; + if ( FT_NEW( internal ) ) + goto Exit; + cff_make_private_dict( &font->top_font, &priv ); + error = funcs->create( cffsize->face->memory, &priv, + &internal->topfont ); + if ( error ) + goto Exit; + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + cff_make_private_dict( sub, &priv ); + error = funcs->create( cffsize->face->memory, &priv, + &internal->subfonts[i - 1] ); + if ( error ) + goto Exit; + } + cffsize->internal = (FT_Size_Internal)(void*)internal; + } + size->strike_index = 0xFFFFFFFFUL; + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + cff_size_select( FT_Size size, + FT_ULong strike_index ) + { + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + cffsize->strike_index = strike_index; + FT_Select_Metrics( size->face, strike_index ); + funcs = cff_size_get_globals_funcs( cffsize ); + if ( funcs ) + { + CFF_Face face = (CFF_Face)size->face; + CFF_Font font = (CFF_Font)face->extra.data; + CFF_Internal internal = (CFF_Internal)size->internal; + FT_ULong top_upm = font->top_font.font_dict.units_per_em; + FT_UInt i; + funcs->set_scale( internal->topfont, + size->metrics.x_scale, size->metrics.y_scale, + 0, 0 ); + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + FT_ULong sub_upm = sub->font_dict.units_per_em; + FT_Pos x_scale, y_scale; + if ( top_upm != sub_upm ) + { + x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm ); + y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm ); + } + else + { + x_scale = size->metrics.x_scale; + y_scale = size->metrics.y_scale; + } + funcs->set_scale( internal->subfonts[i - 1], + x_scale, y_scale, 0, 0 ); + } + } + return CFF_Err_Ok; + } + FT_LOCAL_DEF( FT_Error ) + cff_size_request( FT_Size size, + FT_Size_Request req ) + { + CFF_Size cffsize = (CFF_Size)size; + PSH_Globals_Funcs funcs; + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + CFF_Face cffface = (CFF_Face)size->face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; + FT_ULong strike_index; + if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) ) + cffsize->strike_index = 0xFFFFFFFFUL; + else + return cff_size_select( size, strike_index ); + } + FT_Request_Metrics( size->face, req ); + funcs = cff_size_get_globals_funcs( cffsize ); + if ( funcs ) + { + CFF_Face cffface = (CFF_Face)size->face; + CFF_Font font = (CFF_Font)cffface->extra.data; + CFF_Internal internal = (CFF_Internal)size->internal; + FT_ULong top_upm = font->top_font.font_dict.units_per_em; + FT_UInt i; + funcs->set_scale( internal->topfont, + size->metrics.x_scale, size->metrics.y_scale, + 0, 0 ); + for ( i = font->num_subfonts; i > 0; i-- ) + { + CFF_SubFont sub = font->subfonts[i - 1]; + FT_ULong sub_upm = sub->font_dict.units_per_em; + FT_Pos x_scale, y_scale; + if ( top_upm != sub_upm ) + { + x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm ); + y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm ); + } + else + { + x_scale = size->metrics.x_scale; + y_scale = size->metrics.y_scale; + } + funcs->set_scale( internal->subfonts[i - 1], + x_scale, y_scale, 0, 0 ); + } + } + return CFF_Err_Ok; + } +/*************************************************************************/ +/* */ +/* SLOT FUNCTIONS */ +/* */ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + cff_slot_done( FT_GlyphSlot slot ) + { + slot->internal->glyph_hints = 0; + } + FT_LOCAL_DEF( FT_Error ) + cff_slot_init( FT_GlyphSlot slot ) + { + CFF_Face face = (CFF_Face)slot->face; + CFF_Font font = (CFF_Font)face->extra.data; + PSHinter_Service pshinter = font->pshinter; + if ( pshinter ) + { + FT_Module module; + module = FT_Get_Module( slot->face->driver->root.library, + "pshinter" ); + if ( module ) + { + T2_Hints_Funcs funcs; + funcs = pshinter->get_t2_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + return CFF_Err_Ok; + } +/*************************************************************************/ +/* */ +/* FACE FUNCTIONS */ +/* */ +/*************************************************************************/ + static FT_String* + cff_strcpy( FT_Memory memory, + const FT_String* source ) + { + FT_Error error; + FT_String* result; + (void)FT_STRDUP( result, source ); + FT_UNUSED( error ); + return result; + } +/* Strip all subset prefixes of the form `ABCDEF+'. Usually, there */ +/* is only one, but font names like `APCOOG+JFABTD+FuturaBQ-Bold' */ +/* have been seen in the wild. */ + static void + remove_subset_prefix( FT_String* name ) + { + FT_Int32 idx = 0; + FT_Int32 length = strlen( name ) + 1; + FT_Bool continue_search = 1; + while ( continue_search ) + { + if ( length >= 7 && name[6] == '+' ) + { + for ( idx = 0; idx < 6; idx++ ) + { +/* ASCII uppercase letters */ + if ( !( 'A' <= name[idx] && name[idx] <= 'Z' ) ) + continue_search = 0; + } + if ( continue_search ) + { + for ( idx = 7; idx < length; idx++ ) + name[idx - 7] = name[idx]; + length -= 7; + } + } + else + continue_search = 0; + } + } +/* Remove the style part from the family name (if present). */ + static void + remove_style( FT_String* family_name, + const FT_String* style_name ) + { + FT_Int32 family_name_length, style_name_length; + family_name_length = strlen( family_name ); + style_name_length = strlen( style_name ); + if ( family_name_length > style_name_length ) + { + FT_Int idx; + for ( idx = 1; idx <= style_name_length; ++idx ) + { + if ( family_name[family_name_length - idx] != + style_name[style_name_length - idx] ) + break; + } + if ( idx > style_name_length ) + { +/* family_name ends with style_name; remove it */ + idx = family_name_length - style_name_length - 1; +/* also remove special characters */ +/* between real family name and style */ + while ( idx > 0 && + ( family_name[idx] == '-' || + family_name[idx] == ' ' || + family_name[idx] == '_' || + family_name[idx] == '+' ) ) + --idx; + if ( idx > 0 ) + family_name[idx + 1] = '\0'; + } + } + } + FT_LOCAL_DEF( FT_Error ) + cff_face_init( FT_Stream stream, +/* CFF_Face */ + FT_Face cffface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + CFF_Face face = (CFF_Face)cffface; + FT_Error error; + SFNT_Service sfnt; + FT_Service_PsCMaps psnames; + PSHinter_Service pshinter; + FT_Bool pure_cff = 1; + FT_Bool sfnt_format = 0; + FT_Library library = cffface->driver->root.library; + sfnt = (SFNT_Service)FT_Get_Module_Interface( + library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "cff_face_init: cannot access `sfnt' module\n" )); + error = CFF_Err_Missing_Module; + goto Exit; + } + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + pshinter = (PSHinter_Service)FT_Get_Module_Interface( + library, "pshinter" ); + FT_TRACE2(( "CFF driver\n" )); +/* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; +/* check whether we have a valid OpenType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( !error ) + { +/* `OTTO'; OpenType/CFF font */ + if ( face->format_tag != TTAG_OTTO ) + { + FT_TRACE2(( " not an OpenType/CFF font\n" )); + error = CFF_Err_Unknown_File_Format; + goto Exit; + } +/* if we are performing a simple font format check, exit immediately */ + if ( face_index < 0 ) + return CFF_Err_Ok; + sfnt_format = 1; +/* now, the font can be either an OpenType/CFF font, or an SVG CEF */ +/* font; in the latter case it doesn't have a `head' table */ + error = face->goto_table( face, TTAG_head, stream, 0 ); + if ( !error ) + { + pure_cff = 0; +/* load font directory */ + error = sfnt->load_face( stream, face, face_index, + num_params, params ); + if ( error ) + goto Exit; + } + else + { +/* load the `cmap' table explicitly */ + error = sfnt->load_cmap( face, stream ); + if ( error ) + goto Exit; + } +/* now load the CFF part of the file */ + error = face->goto_table( face, TTAG_CFF, stream, 0 ); + if ( error ) + goto Exit; + } + else + { +/* rewind to start of file; we are going to load a pure-CFF font */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + error = CFF_Err_Ok; + } +/* now load and parse the CFF table in the file */ + { + CFF_Font cff = NULL; + CFF_FontRecDict dict; + FT_Memory memory = cffface->memory; + FT_Int32 flags; + FT_UInt i; + if ( FT_NEW( cff ) ) + goto Exit; + face->extra.data = cff; + error = cff_font_load( library, stream, face_index, cff, pure_cff ); + if ( error ) + goto Exit; + cff->pshinter = pshinter; + cff->psnames = psnames; + cffface->face_index = face_index; +/* Complement the root flags with some interesting information. */ +/* Note that this is only necessary for pure CFF and CEF fonts; */ +/* SFNT based fonts use the `name' table instead. */ + cffface->num_glyphs = cff->num_glyphs; + dict = &cff->top_font.font_dict; +/* we need the `PSNames' module for CFF and CEF formats */ +/* which aren't CID-keyed */ + if ( dict->cid_registry == 0xFFFFU && !psnames ) + { + FT_ERROR(( "cff_face_init:" + " cannot open CFF & CEF fonts\n" + " " + " without the `PSNames' module\n" )); + error = CFF_Err_Missing_Module; + goto Exit; + } + if ( !dict->has_font_matrix ) + dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM; +/* Normalize the font matrix so that `matrix->xx' is 1; the */ +/* scaling is done with `units_per_em' then (at this point, */ +/* it already contains the scaling factor, but without */ +/* normalization of the matrix). */ +/* */ +/* Note that the offsets must be expressed in integer font */ +/* units. */ + { + FT_Matrix* matrix = &dict->font_matrix; + FT_Vector* offset = &dict->font_offset; + FT_ULong* upm = &dict->units_per_em; + FT_Fixed temp = FT_ABS( matrix->yy ); + if ( temp != 0x10000L ) + { + *upm = FT_DivFix( *upm, temp ); + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + offset->x >>= 16; + offset->y >>= 16; + } + for ( i = cff->num_subfonts; i > 0; i-- ) + { + CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; + CFF_FontRecDict top = &cff->top_font.font_dict; + FT_Matrix* matrix; + FT_Vector* offset; + FT_ULong* upm; + FT_Fixed temp; + if ( sub->has_font_matrix ) + { + FT_Long scaling; +/* if we have a top-level matrix, */ +/* concatenate the subfont matrix */ + if ( top->has_font_matrix ) + { + if ( top->units_per_em > 1 && sub->units_per_em > 1 ) + scaling = FT_MIN( top->units_per_em, sub->units_per_em ); + else + scaling = 1; + FT_Matrix_Multiply_Scaled( &top->font_matrix, + &sub->font_matrix, + scaling ); + FT_Vector_Transform_Scaled( &sub->font_offset, + &top->font_matrix, + scaling ); + sub->units_per_em = FT_MulDiv( sub->units_per_em, + top->units_per_em, + scaling ); + } + } + else + { + sub->font_matrix = top->font_matrix; + sub->font_offset = top->font_offset; + sub->units_per_em = top->units_per_em; + } + matrix = &sub->font_matrix; + offset = &sub->font_offset; + upm = &sub->units_per_em; + temp = FT_ABS( matrix->yy ); + if ( temp != 0x10000L ) + { + *upm = FT_DivFix( *upm, temp ); + matrix->xx = FT_DivFix( matrix->xx, temp ); + matrix->yx = FT_DivFix( matrix->yx, temp ); + matrix->xy = FT_DivFix( matrix->xy, temp ); + matrix->yy = FT_DivFix( matrix->yy, temp ); + offset->x = FT_DivFix( offset->x, temp ); + offset->y = FT_DivFix( offset->y, temp ); + } + offset->x >>= 16; + offset->y >>= 16; + } + if ( pure_cff ) + { + char* style_name = NULL; +/* set up num_faces */ + cffface->num_faces = cff->num_faces; +/* compute number of glyphs */ + if ( dict->cid_registry != 0xFFFFU ) + cffface->num_glyphs = cff->charset.max_cid + 1; + else + cffface->num_glyphs = cff->charstrings_index.count; +/* set global bbox, as well as EM size */ + cffface->bbox.xMin = dict->font_bbox.xMin >> 16; + cffface->bbox.yMin = dict->font_bbox.yMin >> 16; +/* no `U' suffix here to 0xFFFF! */ + cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16; + cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16; + cffface->units_per_EM = (FT_UShort)( dict->units_per_em ); + cffface->ascender = (FT_Short)( cffface->bbox.yMax ); + cffface->descender = (FT_Short)( cffface->bbox.yMin ); + cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); + if ( cffface->height < cffface->ascender - cffface->descender ) + cffface->height = (FT_Short)( cffface->ascender - cffface->descender ); + cffface->underline_position = + (FT_Short)( dict->underline_position >> 16 ); + cffface->underline_thickness = + (FT_Short)( dict->underline_thickness >> 16 ); +/* retrieve font family & style name */ + cffface->family_name = cff_index_get_name( cff, face_index ); + if ( cffface->family_name ) + { + char* full = cff_index_get_sid_string( cff, + dict->full_name ); + char* fullp = full; + char* family = cffface->family_name; + char* family_name = NULL; + remove_subset_prefix( cffface->family_name ); + if ( dict->family_name ) + { + family_name = cff_index_get_sid_string( cff, + dict->family_name ); + if ( family_name ) + family = family_name; + } +/* We try to extract the style name from the full name. */ +/* We need to ignore spaces and dashes during the search. */ + if ( full && family ) + { + while ( *fullp ) + { +/* skip common characters at the start of both strings */ + if ( *fullp == *family ) + { + family++; + fullp++; + continue; + } +/* ignore spaces and dashes in full name during comparison */ + if ( *fullp == ' ' || *fullp == '-' ) + { + fullp++; + continue; + } +/* ignore spaces and dashes in family name during comparison */ + if ( *family == ' ' || *family == '-' ) + { + family++; + continue; + } + if ( !*family && *fullp ) + { +/* The full name begins with the same characters as the */ +/* family name, with spaces and dashes removed. In this */ +/* case, the remaining string in `fullp' will be used as */ +/* the style name. */ + style_name = cff_strcpy( memory, fullp ); +/* remove the style part from the family name (if present) */ + remove_style( cffface->family_name, style_name ); + } + break; + } + } + } + else + { + char *cid_font_name = + cff_index_get_sid_string( cff, + dict->cid_font_name ); +/* do we have a `/FontName' for a CID-keyed font? */ + if ( cid_font_name ) + cffface->family_name = cff_strcpy( memory, cid_font_name ); + } + if ( style_name ) + cffface->style_name = style_name; + else +/* assume "Regular" style if we don't know better */ + cffface->style_name = cff_strcpy( memory, (char *)"Regular" ); +/*******************************************************************/ +/* */ +/* Compute face flags. */ +/* */ +/* scalable outlines */ + flags = FT_FACE_FLAG_SCALABLE | +/* horizontal data */ + FT_FACE_FLAG_HORIZONTAL | +/* has native hinter */ + FT_FACE_FLAG_HINTER; + if ( sfnt_format ) + flags |= FT_FACE_FLAG_SFNT; +/* fixed width font? */ + if ( dict->is_fixed_pitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; +/* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ +#if 0 +/* kerning available? */ + if ( face->kern_pairs ) + flags |= FT_FACE_FLAG_KERNING; +#endif + cffface->face_flags = flags; +/*******************************************************************/ +/* */ +/* Compute style flags. */ +/* */ + flags = 0; + if ( dict->italic_angle ) + flags |= FT_STYLE_FLAG_ITALIC; + { + char *weight = cff_index_get_sid_string( cff, + dict->weight ); + if ( weight ) + if ( !ft_strcmp( weight, "Bold" ) || + !ft_strcmp( weight, "Black" ) ) + flags |= FT_STYLE_FLAG_BOLD; + } +/* double check */ + if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) + if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || + !ft_strncmp( cffface->style_name, "Black", 5 ) ) + flags |= FT_STYLE_FLAG_BOLD; + cffface->style_flags = flags; + } +#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES +/* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */ +/* has unset this flag because of the 3.0 `post' table. */ + if ( dict->cid_registry == 0xFFFFU ) + cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; +#endif + if ( dict->cid_registry != 0xFFFFU && pure_cff ) + cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; +/*******************************************************************/ +/* */ +/* Compute char maps. */ +/* */ +/* Try to synthesize a Unicode charmap if there is none available */ +/* already. If an OpenType font contains a Unicode "cmap", we */ +/* will use it, whatever be in the CFF part of the file. */ + { + FT_CharMapRec cmaprec; + FT_CharMap cmap; + FT_UInt nn; + CFF_Encoding encoding = &cff->encoding; + for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) + { + cmap = cffface->charmaps[nn]; +/* Windows Unicode? */ + if ( cmap->platform_id == TT_PLATFORM_MICROSOFT && + cmap->encoding_id == TT_MS_ID_UNICODE_CS ) + goto Skip_Unicode; +/* Apple Unicode platform id? */ + if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE ) +/* Apple Unicode */ + goto Skip_Unicode; + } +/* since CID-keyed fonts don't contain glyph names, we can't */ +/* construct a cmap */ + if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) + goto Exit; +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( nn + 1 > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "cff_face_init: no Unicode cmap is found, " + "and too many subtables (%d) to add synthesized cmap\n", + nn )); + goto Exit; + } +#endif +/* we didn't find a Unicode charmap -- synthesize one */ + cmaprec.face = cffface; + cmaprec.platform_id = TT_PLATFORM_MICROSOFT; + cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; + cmaprec.encoding = FT_ENCODING_UNICODE; + nn = (FT_UInt)cffface->num_charmaps; + error = FT_CMap_New( &CFF_CMAP_UNICODE_CLASS_REC_GET, NULL, + &cmaprec, NULL ); + if ( error && FT_Err_No_Unicode_Glyph_Name != error ) + goto Exit; + error = FT_Err_Ok; +/* if no Unicode charmap was previously selected, select this one */ + if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps ) + cffface->charmap = cffface->charmaps[nn]; + Skip_Unicode: +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( nn > FT_MAX_CHARMAP_CACHEABLE ) + { + FT_ERROR(( "cff_face_init: Unicode cmap is found, " + "but too many preceding subtables (%d) to access\n", + nn - 1 )); + goto Exit; + } +#endif + if ( encoding->count > 0 ) + { + FT_CMap_Class clazz; + cmaprec.face = cffface; +/* Adobe platform id */ + cmaprec.platform_id = TT_PLATFORM_ADOBE; + if ( encoding->offset == 0 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; + cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; + clazz = &CFF_CMAP_ENCODING_CLASS_REC_GET; + } + else if ( encoding->offset == 1 ) + { + cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; + cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; + clazz = &CFF_CMAP_ENCODING_CLASS_REC_GET; + } + else + { + cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; + cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; + clazz = &CFF_CMAP_ENCODING_CLASS_REC_GET; + } + error = FT_CMap_New( clazz, NULL, &cmaprec, NULL ); + } + } + } + Exit: + return error; + } + FT_LOCAL_DEF( void ) +/* CFF_Face */ + cff_face_done( FT_Face cffface ) + { + CFF_Face face = (CFF_Face)cffface; + FT_Memory memory; + SFNT_Service sfnt; + if ( !face ) + return; + memory = cffface->memory; + sfnt = (SFNT_Service)face->sfnt; + if ( sfnt ) + sfnt->done_face( face ); + { + CFF_Font cff = (CFF_Font)face->extra.data; + if ( cff ) + { + cff_font_done( cff ); + FT_FREE( face->extra.data ); + } + } + } + FT_LOCAL_DEF( FT_Error ) + cff_driver_init( FT_Module module ) + { + FT_UNUSED( module ); + return CFF_Err_Ok; + } + FT_LOCAL_DEF( void ) + cff_driver_done( FT_Module module ) + { + FT_UNUSED( module ); + } +/* END */ +/***************************************************************************/ +/* */ +/* cffgload.c */ +/* */ +/* OpenType Glyph Loader (body). */ +/* */ +/* Copyright 1996-2012 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 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 trace_cffgload + typedef enum CFF_Operator_ + { + cff_op_unknown = 0, + cff_op_rmoveto, + cff_op_hmoveto, + cff_op_vmoveto, + cff_op_rlineto, + cff_op_hlineto, + cff_op_vlineto, + cff_op_rrcurveto, + cff_op_hhcurveto, + cff_op_hvcurveto, + cff_op_rcurveline, + cff_op_rlinecurve, + cff_op_vhcurveto, + cff_op_vvcurveto, + cff_op_flex, + cff_op_hflex, + cff_op_hflex1, + cff_op_flex1, + cff_op_endchar, + cff_op_hstem, + cff_op_vstem, + cff_op_hstemhm, + cff_op_vstemhm, + cff_op_hintmask, + cff_op_cntrmask, +/* deprecated, acts as no-op */ + cff_op_dotsection, + cff_op_abs, + cff_op_add, + cff_op_sub, + cff_op_div, + cff_op_neg, + cff_op_random, + cff_op_mul, + cff_op_sqrt, + cff_op_blend, + cff_op_drop, + cff_op_exch, + cff_op_index, + cff_op_roll, + cff_op_dup, + cff_op_put, + cff_op_get, + cff_op_store, + cff_op_load, + cff_op_and, + cff_op_or, + cff_op_not, + cff_op_eq, + cff_op_ifelse, + cff_op_callsubr, + cff_op_callgsubr, + cff_op_return, +/* Type 1 opcodes: invalid but seen in real life */ + cff_op_hsbw, + cff_op_closepath, + cff_op_callothersubr, + cff_op_pop, + cff_op_seac, + cff_op_sbw, + cff_op_setcurrentpoint, +/* do not remove */ + cff_op_max + } CFF_Operator; +#define CFF_COUNT_CHECK_WIDTH 0x80 +#define CFF_COUNT_EXACT 0x40 +#define CFF_COUNT_CLEAR_STACK 0x20 +/* count values which have the `CFF_COUNT_CHECK_WIDTH' flag set are */ +/* used for checking the width and requested numbers of arguments */ +/* only; they are set to zero afterwards */ +/* the other two flags are informative only and unused currently */ + static const FT_Byte cff_argument_counts[] = + { +/* unknown */ + 0, +/* rmoveto */ + 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, + 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, +/* rlineto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, +/* rrcurveto */ + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, + 0 | CFF_COUNT_CLEAR_STACK, +/* flex */ + 13, + 7, + 9, + 11, +/* endchar */ + 0 | CFF_COUNT_CHECK_WIDTH, +/* hstem */ + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, + 2 | CFF_COUNT_CHECK_WIDTH, +/* hintmask */ + 0 | CFF_COUNT_CHECK_WIDTH, +/* cntrmask */ + 0 | CFF_COUNT_CHECK_WIDTH, +/* dotsection */ + 0, +/* abs */ + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, +/* blend */ + 1, +/* drop */ + 1, + 2, + 1, + 2, + 1, +/* put */ + 2, + 1, + 4, + 3, +/* and */ + 2, + 2, + 1, + 2, + 4, +/* callsubr */ + 1, + 1, + 0, +/* hsbw */ + 2, + 0, + 0, + 0, +/* seac */ + 5, +/* sbw */ + 4, +/* setcurrentpoint */ + 2 + }; +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/********** *********/ +/********** *********/ +/********** GENERIC CHARSTRING PARSING *********/ +/********** *********/ +/********** *********/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_builder_init */ +/* */ +/* <Description> */ +/* Initializes a given glyph builder. */ +/* */ +/* <InOut> */ +/* builder :: A pointer to the glyph builder to initialize. */ +/* */ +/* <Input> */ +/* face :: The current face object. */ +/* */ +/* size :: The current size object. */ +/* */ +/* glyph :: The current glyph object. */ +/* */ +/* hinting :: Whether hinting is active. */ +/* */ + static void + cff_builder_init( CFF_Builder* builder, + TT_Face face, + CFF_Size size, + CFF_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->path_begun = 0; + builder->load_points = 1; + builder->face = face; + builder->glyph = glyph; + builder->memory = face->root.memory; + if ( glyph ) + { + FT_GlyphLoader loader = glyph->root.internal->loader; + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + builder->hints_globals = 0; + builder->hints_funcs = 0; + if ( hinting && size ) + { + CFF_Internal internal = (CFF_Internal)size->root.internal; + builder->hints_globals = (void *)internal->topfont; + builder->hints_funcs = glyph->root.internal->glyph_hints; + } + } + builder->pos_x = 0; + builder->pos_y = 0; + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_builder_done */ +/* */ +/* <Description> */ +/* Finalizes a given glyph builder. Its contents can still be used */ +/* after the call, but the function saves important information */ +/* within the corresponding glyph slot. */ +/* */ +/* <Input> */ +/* builder :: A pointer to the glyph builder to finalize. */ +/* */ + static void + cff_builder_done( CFF_Builder* builder ) + { + CFF_GlyphSlot glyph = builder->glyph; + if ( glyph ) + glyph->root.outline = *builder->base; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_compute_bias */ +/* */ +/* <Description> */ +/* Computes the bias value in dependence of the number of glyph */ +/* subroutines. */ +/* */ +/* <Input> */ +/* in_charstring_type :: The `CharstringType' value of the top DICT */ +/* dictionary. */ +/* */ +/* num_subrs :: The number of glyph subroutines. */ +/* */ +/* <Return> */ +/* The bias value. */ + static FT_Int + cff_compute_bias( FT_Int in_charstring_type, + FT_UInt num_subrs ) + { + FT_Int result; + if ( in_charstring_type == 1 ) + result = 0; + else if ( num_subrs < 1240 ) + result = 107; + else if ( num_subrs < 33900U ) + result = 1131; + else + result = 32768U; + return result; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_decoder_init */ +/* */ +/* <Description> */ +/* Initializes a given glyph decoder. */ +/* */ +/* <InOut> */ +/* decoder :: A pointer to the glyph builder to initialize. */ +/* */ +/* <Input> */ +/* face :: The current face object. */ +/* */ +/* size :: The current size object. */ +/* */ +/* slot :: The current glyph object. */ +/* */ +/* hinting :: Whether hinting is active. */ +/* */ +/* hint_mode :: The hinting mode. */ +/* */ + FT_LOCAL_DEF( 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_Font cff = (CFF_Font)face->extra.data; +/* clear everything */ + FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); +/* initialize builder */ + cff_builder_init( &decoder->builder, face, size, slot, hinting ); +/* initialize Type2 decoder */ + decoder->cff = cff; + decoder->num_globals = cff->global_subrs_index.count; + decoder->globals = cff->global_subrs; + decoder->globals_bias = cff_compute_bias( + cff->top_font.font_dict.charstring_type, + decoder->num_globals ); + decoder->hint_mode = hint_mode; + } +/* this function is used to select the subfont */ +/* and the locals subrs array */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, + FT_UInt glyph_index ) + { + CFF_Builder *builder = &decoder->builder; + CFF_Font cff = (CFF_Font)builder->face->extra.data; + CFF_SubFont sub = &cff->top_font; + FT_Error error = CFF_Err_Ok; +/* manage CID fonts */ + if ( cff->num_subfonts ) + { + FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index ); + if ( fd_index >= cff->num_subfonts ) + { + FT_TRACE4(( "cff_decoder_prepare: invalid CID subfont index\n" )); + error = CFF_Err_Invalid_File_Format; + goto Exit; + } + FT_TRACE3(( "glyph index %d (subfont %d):\n", glyph_index, fd_index )); + sub = cff->subfonts[fd_index]; + if ( builder->hints_funcs && size ) + { + CFF_Internal internal = (CFF_Internal)size->root.internal; +/* for CFFs without subfonts, this value has already been set */ + builder->hints_globals = (void *)internal->subfonts[fd_index]; + } + } + decoder->num_locals = sub->local_subrs_index.count; + decoder->locals = sub->local_subrs; + decoder->locals_bias = cff_compute_bias( + decoder->cff->top_font.font_dict.charstring_type, + decoder->num_locals ); + decoder->glyph_width = sub->private_dict.default_width; + decoder->nominal_width = sub->private_dict.nominal_width; + Exit: + return error; + } +/* check that there is enough space for `count' more points */ + static FT_Error + check_points( CFF_Builder* builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } +/* add a new point, do not check space */ + static void + cff_builder_add_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + point->x = x >> 16; + point->y = y >> 16; + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + outline->n_points++; + } +/* check space for a new on-curve point, then add it */ + static FT_Error + cff_builder_add_point1( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + error = check_points( builder, 1 ); + if ( !error ) + cff_builder_add_point( builder, x, y, 1 ); + return error; + } +/* check space for a new contour, then add it */ + static FT_Error + cff_builder_add_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; + if ( !builder->load_points ) + { + outline->n_contours++; + return CFF_Err_Ok; + } + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + outline->n_contours++; + } + return error; + } +/* if a path was begun, add its first on-curve point */ + static FT_Error + cff_builder_start_point( CFF_Builder* builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = CFF_Err_Ok; +/* test whether we are building a new contour */ + if ( !builder->path_begun ) + { + builder->path_begun = 1; + error = cff_builder_add_contour( builder ); + if ( !error ) + error = cff_builder_add_point1( builder, x, y ); + } + return error; + } +/* close the current contour */ + static void + cff_builder_close_contour( CFF_Builder* builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + if ( !outline ) + return; + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; +/* We must not include the last point in the path if it */ +/* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; +/* `delete' last point only if it coincides with the first */ +/* point and if it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + if ( outline->n_contours > 0 ) + { +/* Don't add contours only consisting of one point, i.e., */ +/* check whether begin point and last point are the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + } + static FT_Int + cff_lookup_glyph_by_stdcharcode( CFF_Font cff, + FT_Int charcode ) + { + FT_UInt n; + FT_UShort glyph_sid; +/* CID-keyed fonts don't have glyph names */ + if ( !cff->charset.sids ) + return -1; +/* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; +/* Get code to SID mapping from `cff_standard_encoding'. */ + glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode ); + for ( n = 0; n < cff->num_glyphs; n++ ) + { + if ( cff->charset.sids[n] == glyph_sid ) + return n; + } + return -1; + } + static FT_Error + cff_get_glyph_data( TT_Face face, + FT_UInt glyph_index, + FT_Byte** pointer, + FT_ULong* length ) + { +/* 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 + { + CFF_Font cff = (CFF_Font)(face->extra.data); + return cff_index_access_element( &cff->charstrings_index, glyph_index, + pointer, length ); + } + } + static void + cff_free_glyph_data( TT_Face face, + FT_Byte** pointer, + FT_ULong length ) + { +/* 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 = length; + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, &data ); + } + else + { + CFF_Font cff = (CFF_Font)(face->extra.data); + cff_index_forget_element( &cff->charstrings_index, pointer ); + } + } + static FT_Error + cff_operator_seac( CFF_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + CFF_Builder* builder = &decoder->builder; + FT_Int bchar_index, achar_index; + TT_Face face = decoder->builder.face; + FT_Vector left_bearing, advance; + FT_Byte* charstring; + FT_ULong charstring_len; + FT_Pos glyph_width; + if ( decoder->seac ) + { + FT_ERROR(( "cff_operator_seac: invalid nested seac\n" )); + return CFF_Err_Syntax_Error; + } + adx += decoder->builder.left_bearing.x; + ady += decoder->builder.left_bearing.y; +/* Incremental fonts don't necessarily have valid charsets. */ +/* They use the character code, not the glyph index, in this case. */ + if ( face->root.internal->incremental_interface ) + { + bchar_index = bchar; + achar_index = achar; + } + else + { + CFF_Font cff = (CFF_Font)(face->extra.data); + bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar ); + achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar ); + } + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "cff_operator_seac:" + " invalid seac character code arguments\n" )); + return CFF_Err_Syntax_Error; + } +/* If we are trying to load a composite glyph, do not load the */ +/* accent character and return the array of subglyphs. */ + if ( builder->no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)builder->glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; +/* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + subg = loader->current.subglyphs; +/* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; +/* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)( adx >> 16 ); + subg->arg2 = (FT_Int)( ady >> 16 ); +/* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + loader->current.num_subglyphs = 2; + } + FT_GlyphLoader_Prepare( builder->loader ); +/* First load `bchar' in builder */ + error = cff_get_glyph_data( face, bchar_index, + &charstring, &charstring_len ); + if ( !error ) + { +/* the seac operator must not be nested */ + decoder->seac = TRUE; + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len ); + decoder->seac = FALSE; + cff_free_glyph_data( face, &charstring, charstring_len ); + if ( error ) + goto Exit; + } +/* Save the left bearing, advance and glyph width of the base */ +/* character as they will be erased by the next load. */ + left_bearing = builder->left_bearing; + advance = builder->advance; + glyph_width = decoder->glyph_width; + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->pos_x = adx - asb; + builder->pos_y = ady; +/* Now load `achar' on top of the base outline. */ + error = cff_get_glyph_data( face, achar_index, + &charstring, &charstring_len ); + if ( !error ) + { +/* the seac operator must not be nested */ + decoder->seac = TRUE; + error = cff_decoder_parse_charstrings( decoder, charstring, + charstring_len ); + decoder->seac = FALSE; + cff_free_glyph_data( face, &charstring, charstring_len ); + if ( error ) + goto Exit; + } +/* Restore the left side bearing, advance and glyph width */ +/* of the base character. */ + builder->left_bearing = left_bearing; + builder->advance = advance; + decoder->glyph_width = glyph_width; + builder->pos_x = 0; + builder->pos_y = 0; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* cff_decoder_parse_charstrings */ +/* */ +/* <Description> */ +/* Parses a given Type 2 charstrings program. */ +/* */ +/* <InOut> */ +/* decoder :: The current Type 1 decoder. */ +/* */ +/* <Input> */ +/* charstring_base :: The base of the charstring stream. */ +/* */ +/* charstring_len :: The length in bytes of the charstring stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + cff_decoder_parse_charstrings( CFF_Decoder* decoder, + FT_Byte* charstring_base, + FT_ULong charstring_len ) + { + FT_Error error; + CFF_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + CFF_Builder* builder = &decoder->builder; + FT_Pos x, y; + FT_Fixed seed; + FT_Fixed* stack; + FT_Int charstring_type = + decoder->cff->top_font.font_dict.charstring_type; + T2_Hints_Funcs hinter; +/* set default width */ + decoder->num_hints = 0; + decoder->read_width = 1; +/* compute random seed from stack address of parameter */ + seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed ^ + (FT_PtrDist)(char*)&decoder ^ + (FT_PtrDist)(char*)&charstring_base ) & + FT_ULONG_MAX ) ; + seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; + if ( seed == 0 ) + seed = 0x7384; +/* initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + stack = decoder->top; + hinter = (T2_Hints_Funcs)builder->hints_funcs; + builder->path_begun = 0; + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + error = CFF_Err_Ok; + x = builder->pos_x; + y = builder->pos_y; +/* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); +/* now execute loop */ + while ( ip < limit ) + { + CFF_Operator op; + FT_Byte v; +/********************************************************************/ +/* */ +/* Decode operator or operand */ +/* */ + v = *ip++; + if ( v >= 32 || v == 28 ) + { + FT_Int shift = 16; + FT_Int32 val; +/* this is an operand, push it on the stack */ + if ( v == 28 ) + { + if ( ip + 1 >= limit ) + goto Syntax_Error; + val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] ); + ip += 2; + } + else if ( v < 247 ) + val = (FT_Int32)v - 139; + else if ( v < 251 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = ( (FT_Int32)v - 247 ) * 256 + *ip++ + 108; + } + else if ( v < 255 ) + { + if ( ip >= limit ) + goto Syntax_Error; + val = -( (FT_Int32)v - 251 ) * 256 - *ip++ - 108; + } + else + { + if ( ip + 3 >= limit ) + goto Syntax_Error; + val = ( (FT_Int32)ip[0] << 24 ) | + ( (FT_Int32)ip[1] << 16 ) | + ( (FT_Int32)ip[2] << 8 ) | + ip[3]; + ip += 4; + if ( charstring_type == 2 ) + shift = 0; + } + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; + val <<= shift; + *decoder->top++ = val; + } + else + { +/* The specification says that normally arguments are to be taken */ +/* from the bottom of the stack. However, this seems not to be */ +/* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */ +/* arguments similar to a PS interpreter. */ + FT_Fixed* args = decoder->top; + FT_Int num_args = (FT_Int)( args - decoder->stack ); + FT_Int req_args; +/* find operator */ + op = cff_op_unknown; + switch ( v ) + { + case 1: + op = cff_op_hstem; + break; + case 3: + op = cff_op_vstem; + break; + case 4: + op = cff_op_vmoveto; + break; + case 5: + op = cff_op_rlineto; + break; + case 6: + op = cff_op_hlineto; + break; + case 7: + op = cff_op_vlineto; + break; + case 8: + op = cff_op_rrcurveto; + break; + case 9: + op = cff_op_closepath; + break; + case 10: + op = cff_op_callsubr; + break; + case 11: + op = cff_op_return; + break; + case 12: + { + if ( ip >= limit ) + goto Syntax_Error; + v = *ip++; + switch ( v ) + { + case 0: + op = cff_op_dotsection; + break; +/* this is actually the Type1 vstem3 operator */ + case 1: + op = cff_op_vstem; + break; +/* this is actually the Type1 hstem3 operator */ + case 2: + op = cff_op_hstem; + break; + case 3: + op = cff_op_and; + break; + case 4: + op = cff_op_or; + break; + case 5: + op = cff_op_not; + break; + case 6: + op = cff_op_seac; + break; + case 7: + op = cff_op_sbw; + break; + case 8: + op = cff_op_store; + break; + case 9: + op = cff_op_abs; + break; + case 10: + op = cff_op_add; + break; + case 11: + op = cff_op_sub; + break; + case 12: + op = cff_op_div; + break; + case 13: + op = cff_op_load; + break; + case 14: + op = cff_op_neg; + break; + case 15: + op = cff_op_eq; + break; + case 16: + op = cff_op_callothersubr; + break; + case 17: + op = cff_op_pop; + break; + case 18: + op = cff_op_drop; + break; + case 20: + op = cff_op_put; + break; + case 21: + op = cff_op_get; + break; + case 22: + op = cff_op_ifelse; + break; + case 23: + op = cff_op_random; + break; + case 24: + op = cff_op_mul; + break; + case 26: + op = cff_op_sqrt; + break; + case 27: + op = cff_op_dup; + break; + case 28: + op = cff_op_exch; + break; + case 29: + op = cff_op_index; + break; + case 30: + op = cff_op_roll; + break; + case 33: + op = cff_op_setcurrentpoint; + break; + case 34: + op = cff_op_hflex; + break; + case 35: + op = cff_op_flex; + break; + case 36: + op = cff_op_hflex1; + break; + case 37: + op = cff_op_flex1; + break; + default: + FT_TRACE4(( " unknown op (12, %d)\n", v )); + break; + } + } + break; + case 13: + op = cff_op_hsbw; + break; + case 14: + op = cff_op_endchar; + break; + case 16: + op = cff_op_blend; + break; + case 18: + op = cff_op_hstemhm; + break; + case 19: + op = cff_op_hintmask; + break; + case 20: + op = cff_op_cntrmask; + break; + case 21: + op = cff_op_rmoveto; + break; + case 22: + op = cff_op_hmoveto; + break; + case 23: + op = cff_op_vstemhm; + break; + case 24: + op = cff_op_rcurveline; + break; + case 25: + op = cff_op_rlinecurve; + break; + case 26: + op = cff_op_vvcurveto; + break; + case 27: + op = cff_op_hhcurveto; + break; + case 29: + op = cff_op_callgsubr; + break; + case 30: + op = cff_op_vhcurveto; + break; + case 31: + op = cff_op_hvcurveto; + break; + default: + FT_TRACE4(( " unknown op (%d)\n", v )); + break; + } + if ( op == cff_op_unknown ) + continue; +/* check arguments */ + req_args = cff_argument_counts[op]; + if ( req_args & CFF_COUNT_CHECK_WIDTH ) + { + if ( num_args > 0 && decoder->read_width ) + { +/* If `nominal_width' is non-zero, the number is really a */ +/* difference against `nominal_width'. Else, the number here */ +/* is truly a width, not a difference against `nominal_width'. */ +/* If the font does not set `nominal_width', then */ +/* `nominal_width' defaults to zero, and so we can set */ +/* `glyph_width' to `nominal_width' plus number on the stack */ +/* -- for either case. */ + FT_Int set_width_ok; + switch ( op ) + { + case cff_op_hmoveto: + case cff_op_vmoveto: + set_width_ok = num_args & 2; + break; + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: + case cff_op_rmoveto: + case cff_op_hintmask: + case cff_op_cntrmask: + set_width_ok = num_args & 1; + break; + case cff_op_endchar: +/* If there is a width specified for endchar, we either have */ +/* 1 argument or 5 arguments. We like to argue. */ + set_width_ok = ( num_args == 5 ) || ( num_args == 1 ); + break; + default: + set_width_ok = 0; + break; + } + if ( set_width_ok ) + { + decoder->glyph_width = decoder->nominal_width + + ( stack[0] >> 16 ); + if ( decoder->width_only ) + { +/* we only want the advance width; stop here */ + break; + } +/* Consumed an argument. */ + num_args--; + } + } + decoder->read_width = 0; + req_args = 0; + } + req_args &= 0x000F; + if ( num_args < req_args ) + goto Stack_Underflow; + args -= req_args; + num_args -= req_args; +/* At this point, `args' points to the first argument of the */ +/* operand in case `req_args' isn't zero. Otherwise, we have */ +/* to adjust `args' manually. */ +/* Note that we only pop arguments from the stack which we */ +/* really need and can digest so that we can continue in case */ +/* of superfluous stack elements. */ + switch ( op ) + { + case cff_op_hstem: + case cff_op_vstem: + case cff_op_hstemhm: + case cff_op_vstemhm: +/* the number of arguments is always even here */ + FT_TRACE4(( + op == cff_op_hstem ? " hstem\n" : + ( op == cff_op_vstem ? " vstem\n" : + ( op == cff_op_hstemhm ? " hstemhm\n" : " vstemhm\n" ) ) )); + if ( hinter ) + hinter->stems( hinter->hints, + ( op == cff_op_hstem || op == cff_op_hstemhm ), + num_args / 2, + args - ( num_args & ~1 ) ); + decoder->num_hints += num_args / 2; + args = stack; + break; + case cff_op_hintmask: + case cff_op_cntrmask: + FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" )); +/* implement vstem when needed -- */ +/* the specification doesn't say it, but this also works */ +/* with the 'cntrmask' operator */ +/* */ + if ( num_args > 0 ) + { + if ( hinter ) + hinter->stems( hinter->hints, + 0, + num_args / 2, + args - ( num_args & ~1 ) ); + decoder->num_hints += num_args / 2; + } +/* In a valid charstring there must be at least one byte */ +/* after `hintmask' or `cntrmask' (e.g., for a `return' */ +/* instruction). Additionally, there must be space for */ +/* `num_hints' bits. */ + if ( ( ip + ( ( decoder->num_hints + 7 ) >> 3 ) ) >= limit ) + goto Syntax_Error; + if ( hinter ) + { + if ( op == cff_op_hintmask ) + hinter->hintmask( hinter->hints, + builder->current->n_points, + decoder->num_hints, + ip ); + else + hinter->counter( hinter->hints, + decoder->num_hints, + ip ); + } + ip += ( decoder->num_hints + 7 ) >> 3; + args = stack; + break; + case cff_op_rmoveto: + FT_TRACE4(( " rmoveto\n" )); + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x += args[-2]; + y += args[-1]; + args = stack; + break; + case cff_op_vmoveto: + FT_TRACE4(( " vmoveto\n" )); + cff_builder_close_contour( builder ); + builder->path_begun = 0; + y += args[-1]; + args = stack; + break; + case cff_op_hmoveto: + FT_TRACE4(( " hmoveto\n" )); + cff_builder_close_contour( builder ); + builder->path_begun = 0; + x += args[-1]; + args = stack; + break; + case cff_op_rlineto: + FT_TRACE4(( " rlineto\n" )); + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_args / 2 ) ) + goto Fail; + if ( num_args < 2 ) + goto Stack_Underflow; + args -= num_args & ~1; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 1 ); + args += 2; + } + args = stack; + break; + case cff_op_hlineto: + case cff_op_vlineto: + { + FT_Int phase = ( op == cff_op_hlineto ); + FT_TRACE4(( op == cff_op_hlineto ? " hlineto\n" + : " vlineto\n" )); + if ( num_args < 0 ) + goto Stack_Underflow; +/* there exist subsetted fonts (found in PDFs) */ +/* which call `hlineto' without arguments */ + if ( num_args == 0 ) + break; + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_args ) ) + goto Fail; + args = stack; + while ( args < decoder->top ) + { + if ( phase ) + x += args[0]; + else + y += args[0]; + if ( cff_builder_add_point1( builder, x, y ) ) + goto Fail; + args++; + phase ^= 1; + } + args = stack; + } + break; + case cff_op_rrcurveto: + { + FT_Int nargs; + FT_TRACE4(( " rrcurveto\n" )); + if ( num_args < 6 ) + goto Stack_Underflow; + nargs = num_args - num_args % 6; + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, nargs / 2 ) ) + goto Fail; + args -= nargs; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args += 6; + } + args = stack; + } + break; + case cff_op_vvcurveto: + { + FT_Int nargs; + FT_TRACE4(( " vvcurveto\n" )); + if ( num_args < 4 ) + goto Stack_Underflow; +/* if num_args isn't of the form 4n or 4n+1, */ +/* we enforce it by clearing the second bit */ + nargs = num_args & ~2; + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + args -= nargs; + if ( nargs & 1 ) + { + x += args[0]; + args++; + nargs--; + } + if ( check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + while ( args < decoder->top ) + { + y += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + y += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; + } + break; + case cff_op_hhcurveto: + { + FT_Int nargs; + FT_TRACE4(( " hhcurveto\n" )); + if ( num_args < 4 ) + goto Stack_Underflow; +/* if num_args isn't of the form 4n or 4n+1, */ +/* we enforce it by clearing the second bit */ + nargs = num_args & ~2; + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + args -= nargs; + if ( nargs & 1 ) + { + y += args[0]; + args++; + nargs--; + } + if ( check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + while ( args < decoder->top ) + { + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; + } + break; + case cff_op_vhcurveto: + case cff_op_hvcurveto: + { + FT_Int phase; + FT_Int nargs; + FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto\n" + : " hvcurveto\n" )); + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + if ( num_args < 4 ) + goto Stack_Underflow; +/* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */ +/* we enforce it by clearing the second bit */ + nargs = num_args & ~2; + args -= nargs; + if ( check_points( builder, ( nargs / 4 ) * 3 ) ) + goto Stack_Underflow; + phase = ( op == cff_op_hvcurveto ); + while ( nargs >= 4 ) + { + nargs -= 4; + if ( phase ) + { + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + y += args[3]; + if ( nargs == 1 ) + x += args[4]; + cff_builder_add_point( builder, x, y, 1 ); + } + else + { + y += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[3]; + if ( nargs == 1 ) + y += args[4]; + cff_builder_add_point( builder, x, y, 1 ); + } + args += 4; + phase ^= 1; + } + args = stack; + } + break; + case cff_op_rlinecurve: + { + FT_Int num_lines; + FT_Int nargs; + FT_TRACE4(( " rlinecurve\n" )); + if ( num_args < 8 ) + goto Stack_Underflow; + nargs = num_args & ~1; + num_lines = ( nargs - 6 ) / 2; + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, num_lines + 3 ) ) + goto Fail; + args -= nargs; +/* first, add the line segments */ + while ( num_lines > 0 ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 1 ); + args += 2; + num_lines--; + } +/* then the curve */ + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + } + break; + case cff_op_rcurveline: + { + FT_Int num_curves; + FT_Int nargs; + FT_TRACE4(( " rcurveline\n" )); + if ( num_args < 8 ) + goto Stack_Underflow; + nargs = num_args - 2; + nargs = nargs - nargs % 6 + 2; + num_curves = ( nargs - 2 ) / 6; + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, num_curves * 3 + 2 ) ) + goto Fail; + args -= nargs; +/* first, add the curves */ + while ( num_curves > 0 ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args += 6; + num_curves--; + } +/* then the final line */ + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + } + break; + case cff_op_hflex1: + { + FT_Pos start_y; + FT_TRACE4(( " hflex1\n" )); +/* adding five more points: 4 control points, 1 on-curve point */ +/* -- make sure we have enough space for the start point if it */ +/* needs to be added */ + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; +/* record the starting point's y position for later use */ + start_y = y; +/* first control point */ + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); +/* second control point */ + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); +/* join point; on curve, with y-value the same as the last */ +/* control point's y-value */ + x += args[4]; + cff_builder_add_point( builder, x, y, 1 ); +/* third control point, with y-value the same as the join */ +/* point's y-value */ + x += args[5]; + cff_builder_add_point( builder, x, y, 0 ); +/* fourth control point */ + x += args[6]; + y += args[7]; + cff_builder_add_point( builder, x, y, 0 ); +/* ending point, with y-value the same as the start */ + x += args[8]; + y = start_y; + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + break; + } + case cff_op_hflex: + { + FT_Pos start_y; + FT_TRACE4(( " hflex\n" )); +/* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; +/* record the starting point's y-position for later use */ + start_y = y; +/* first control point */ + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); +/* second control point */ + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); +/* join point; on curve, with y-value the same as the last */ +/* control point's y-value */ + x += args[3]; + cff_builder_add_point( builder, x, y, 1 ); +/* third control point, with y-value the same as the join */ +/* point's y-value */ + x += args[4]; + cff_builder_add_point( builder, x, y, 0 ); +/* fourth control point */ + x += args[5]; + y = start_y; + cff_builder_add_point( builder, x, y, 0 ); +/* ending point, with y-value the same as the start point's */ +/* y-value -- we don't add this point, though */ + x += args[6]; + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + break; + } + case cff_op_flex1: + { +/* record start x, y values for */ + FT_Pos start_x, start_y; +/* alter use */ +/* used in horizontal/vertical */ + FT_Fixed dx = 0, dy = 0; +/* algorithm below */ + FT_Int horizontal, count; + FT_Fixed* temp; + FT_TRACE4(( " flex1\n" )); +/* adding six more points; 4 control points, 2 on-curve points */ + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; +/* record the starting point's x, y position for later use */ + start_x = x; + start_y = y; +/* XXX: figure out whether this is supposed to be a horizontal */ +/* or vertical flex; the Type 2 specification is vague... */ + temp = args; +/* grab up to the last argument */ + for ( count = 5; count > 0; count-- ) + { + dx += temp[0]; + dy += temp[1]; + temp += 2; + } + if ( dx < 0 ) + dx = -dx; + if ( dy < 0 ) + dy = -dy; +/* strange test, but here it is... */ + horizontal = ( dx > dy ); + for ( count = 5; count > 0; count-- ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, + (FT_Bool)( count == 3 ) ); + args += 2; + } +/* is last operand an x- or y-delta? */ + if ( horizontal ) + { + x += args[0]; + y = start_y; + } + else + { + x = start_x; + y += args[0]; + } + cff_builder_add_point( builder, x, y, 1 ); + args = stack; + break; + } + case cff_op_flex: + { + FT_UInt count; + FT_TRACE4(( " flex\n" )); + if ( cff_builder_start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Fail; + for ( count = 6; count > 0; count-- ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, + (FT_Bool)( count == 4 || count == 1 ) ); + args += 2; + } + args = stack; + } + break; + case cff_op_seac: + FT_TRACE4(( " seac\n" )); + error = cff_operator_seac( decoder, + args[0], args[1], args[2], + (FT_Int)( args[3] >> 16 ), + (FT_Int)( args[4] >> 16 ) ); +/* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); +/* return now! */ + FT_TRACE4(( "\n" )); + return error; + case cff_op_endchar: + FT_TRACE4(( " endchar\n" )); +/* We are going to emulate the seac operator. */ + if ( num_args >= 4 ) + { +/* Save glyph width so that the subglyphs don't overwrite it. */ + FT_Pos glyph_width = decoder->glyph_width; + error = cff_operator_seac( decoder, + 0L, args[-4], args[-3], + (FT_Int)( args[-2] >> 16 ), + (FT_Int)( args[-1] >> 16 ) ); + decoder->glyph_width = glyph_width; + } + else + { + if ( !error ) + error = CFF_Err_Ok; + cff_builder_close_contour( builder ); +/* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, + builder->current->n_points ) ) + goto Syntax_Error; +/* apply hints to the loaded glyph outline now */ + hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + } +/* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + } +/* return now! */ + FT_TRACE4(( "\n" )); + return error; + case cff_op_abs: + FT_TRACE4(( " abs\n" )); + if ( args[0] < 0 ) + args[0] = -args[0]; + args++; + break; + case cff_op_add: + FT_TRACE4(( " add\n" )); + args[0] += args[1]; + args++; + break; + case cff_op_sub: + FT_TRACE4(( " sub\n" )); + args[0] -= args[1]; + args++; + break; + case cff_op_div: + FT_TRACE4(( " div\n" )); + args[0] = FT_DivFix( args[0], args[1] ); + args++; + break; + case cff_op_neg: + FT_TRACE4(( " neg\n" )); + args[0] = -args[0]; + args++; + break; + case cff_op_random: + { + FT_Fixed Rand; + FT_TRACE4(( " rand\n" )); + Rand = seed; + if ( Rand >= 0x8000L ) + Rand++; + args[0] = Rand; + seed = FT_MulFix( seed, 0x10000L - seed ); + if ( seed == 0 ) + seed += 0x2873; + args++; + } + break; + case cff_op_mul: + FT_TRACE4(( " mul\n" )); + args[0] = FT_MulFix( args[0], args[1] ); + args++; + break; + case cff_op_sqrt: + FT_TRACE4(( " sqrt\n" )); + if ( args[0] > 0 ) + { + FT_Int count = 9; + FT_Fixed root = args[0]; + FT_Fixed new_root; + for (;;) + { + new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1; + if ( new_root == root || count <= 0 ) + break; + root = new_root; + } + args[0] = new_root; + } + else + args[0] = 0; + args++; + break; + case cff_op_drop: +/* nothing */ + FT_TRACE4(( " drop\n" )); + break; + case cff_op_exch: + { + FT_Fixed tmp; + FT_TRACE4(( " exch\n" )); + tmp = args[0]; + args[0] = args[1]; + args[1] = tmp; + args += 2; + } + break; + case cff_op_index: + { + FT_Int idx = (FT_Int)( args[0] >> 16 ); + FT_TRACE4(( " index\n" )); + if ( idx < 0 ) + idx = 0; + else if ( idx > num_args - 2 ) + idx = num_args - 2; + args[0] = args[-( idx + 1 )]; + args++; + } + break; + case cff_op_roll: + { + FT_Int count = (FT_Int)( args[0] >> 16 ); + FT_Int idx = (FT_Int)( args[1] >> 16 ); + FT_TRACE4(( " roll\n" )); + if ( count <= 0 ) + count = 1; + args -= count; + if ( args < stack ) + goto Stack_Underflow; + if ( idx >= 0 ) + { + while ( idx > 0 ) + { + FT_Fixed tmp = args[count - 1]; + FT_Int i; + for ( i = count - 2; i >= 0; i-- ) + args[i + 1] = args[i]; + args[0] = tmp; + idx--; + } + } + else + { + while ( idx < 0 ) + { + FT_Fixed tmp = args[0]; + FT_Int i; + for ( i = 0; i < count - 1; i++ ) + args[i] = args[i + 1]; + args[count - 1] = tmp; + idx++; + } + } + args += count; + } + break; + case cff_op_dup: + FT_TRACE4(( " dup\n" )); + args[1] = args[0]; + args += 2; + break; + case cff_op_put: + { + FT_Fixed val = args[0]; + FT_Int idx = (FT_Int)( args[1] >> 16 ); + FT_TRACE4(( " put\n" )); + if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) + decoder->buildchar[idx] = val; + } + break; + case cff_op_get: + { + FT_Int idx = (FT_Int)( args[0] >> 16 ); + FT_Fixed val = 0; + FT_TRACE4(( " get\n" )); + if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) + val = decoder->buildchar[idx]; + args[0] = val; + args++; + } + break; + case cff_op_store: + FT_TRACE4(( " store\n")); + goto Unimplemented; + case cff_op_load: + FT_TRACE4(( " load\n" )); + goto Unimplemented; + case cff_op_dotsection: +/* this operator is deprecated and ignored by the parser */ + FT_TRACE4(( " dotsection\n" )); + break; + case cff_op_closepath: +/* this is an invalid Type 2 operator; however, there */ +/* exist fonts which are incorrectly converted from probably */ +/* Type 1 to CFF, and some parsers seem to accept it */ + FT_TRACE4(( " closepath (invalid op)\n" )); + args = stack; + break; + case cff_op_hsbw: +/* this is an invalid Type 2 operator; however, there */ +/* exist fonts which are incorrectly converted from probably */ +/* Type 1 to CFF, and some parsers seem to accept it */ + FT_TRACE4(( " hsbw (invalid op)\n" )); + decoder->glyph_width = decoder->nominal_width + ( args[1] >> 16 ); + decoder->builder.left_bearing.x = args[0]; + decoder->builder.left_bearing.y = 0; + x = decoder->builder.pos_x + args[0]; + y = decoder->builder.pos_y; + args = stack; + break; + case cff_op_sbw: +/* this is an invalid Type 2 operator; however, there */ +/* exist fonts which are incorrectly converted from probably */ +/* Type 1 to CFF, and some parsers seem to accept it */ + FT_TRACE4(( " sbw (invalid op)\n" )); + decoder->glyph_width = decoder->nominal_width + ( args[2] >> 16 ); + decoder->builder.left_bearing.x = args[0]; + decoder->builder.left_bearing.y = args[1]; + x = decoder->builder.pos_x + args[0]; + y = decoder->builder.pos_y + args[1]; + args = stack; + break; + case cff_op_setcurrentpoint: +/* this is an invalid Type 2 operator; however, there */ +/* exist fonts which are incorrectly converted from probably */ +/* Type 1 to CFF, and some parsers seem to accept it */ + FT_TRACE4(( " setcurrentpoint (invalid op)\n" )); + x = decoder->builder.pos_x + args[0]; + y = decoder->builder.pos_y + args[1]; + args = stack; + break; + case cff_op_callothersubr: +/* this is an invalid Type 2 operator; however, there */ +/* exist fonts which are incorrectly converted from probably */ +/* Type 1 to CFF, and some parsers seem to accept it */ + FT_TRACE4(( " callothersubr (invalid op)\n" )); +/* subsequent `pop' operands should add the arguments, */ +/* this is the implementation described for `unknown' other */ +/* subroutines in the Type1 spec. */ +/* */ +/* XXX Fix return arguments (see discussion below). */ + args -= 2 + ( args[-2] >> 16 ); + if ( args < stack ) + goto Stack_Underflow; + break; + case cff_op_pop: +/* this is an invalid Type 2 operator; however, there */ +/* exist fonts which are incorrectly converted from probably */ +/* Type 1 to CFF, and some parsers seem to accept it */ + FT_TRACE4(( " pop (invalid op)\n" )); +/* XXX Increasing `args' is wrong: After a certain number of */ +/* `pop's we get a stack overflow. Reason for doing it is */ +/* code like this (actually found in a CFF font): */ +/* */ +/* 17 1 3 callothersubr */ +/* pop */ +/* callsubr */ +/* */ +/* Since we handle `callothersubr' as a no-op, and */ +/* `callsubr' needs at least one argument, `pop' can't be a */ +/* no-op too as it basically should be. */ +/* */ +/* The right solution would be to provide real support for */ +/* `callothersubr' as done in `t1decode.c', however, given */ +/* the fact that CFF fonts with `pop' are invalid, it is */ +/* questionable whether it is worth the time. */ + args++; + break; + case cff_op_and: + { + FT_Fixed cond = args[0] && args[1]; + FT_TRACE4(( " and\n" )); + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + case cff_op_or: + { + FT_Fixed cond = args[0] || args[1]; + FT_TRACE4(( " or\n" )); + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + case cff_op_eq: + { + FT_Fixed cond = !args[0]; + FT_TRACE4(( " eq\n" )); + args[0] = cond ? 0x10000L : 0; + args++; + } + break; + case cff_op_ifelse: + { + FT_Fixed cond = ( args[2] <= args[3] ); + FT_TRACE4(( " ifelse\n" )); + if ( !cond ) + args[0] = args[1]; + args++; + } + break; + case cff_op_callsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->locals_bias ); + FT_TRACE4(( " callsubr(%d)\n", idx )); + if ( idx >= decoder->num_locals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid local subr index\n" )); + goto Syntax_Error; + } + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } +/* save current instruction pointer */ + zone->cursor = ip; + zone++; + zone->base = decoder->locals[idx]; + zone->limit = decoder->locals[idx + 1]; + zone->cursor = zone->base; + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + case cff_op_callgsubr: + { + FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) + + decoder->globals_bias ); + FT_TRACE4(( " callgsubr(%d)\n", idx )); + if ( idx >= decoder->num_globals ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid global subr index\n" )); + goto Syntax_Error; + } + if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } +/* save current instruction pointer */ + zone->cursor = ip; + zone++; + zone->base = decoder->globals[idx]; + zone->limit = decoder->globals[idx + 1]; + zone->cursor = zone->base; + if ( !zone->base || zone->limit == zone->base ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + } + break; + case cff_op_return: + FT_TRACE4(( " return\n" )); + if ( decoder->zone <= decoder->zones ) + { + FT_ERROR(( "cff_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + decoder->zone--; + zone = decoder->zone; + ip = zone->cursor; + limit = zone->limit; + break; + default: + Unimplemented: + FT_ERROR(( "Unimplemented opcode: %d", ip[-1] )); + if ( ip[-1] == 12 ) + FT_ERROR(( " %d", ip[0] )); + FT_ERROR(( "\n" )); + return CFF_Err_Unimplemented_Feature; + } + decoder->top = args; + if ( decoder->top - stack >= CFF_MAX_OPERANDS ) + goto Stack_Overflow; +/* general operator processing */ + } +/* while ip < limit */ + } + FT_TRACE4(( "..end..\n\n" )); + Fail: + return error; + Syntax_Error: + FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" )); + return CFF_Err_Invalid_File_Format; + Stack_Underflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" )); + return CFF_Err_Too_Few_Arguments; + Stack_Overflow: + FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" )); + return CFF_Err_Stack_Overflow; + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/********** *********/ +/********** *********/ +/********** 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. *********/ +/********** *********/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* unused until we support pure CFF fonts */ +#if 0 + FT_LOCAL_DEF( FT_Error ) + cff_compute_max_advance( TT_Face face, + FT_Int* max_advance ) + { + FT_Error error = CFF_Err_Ok; + CFF_Decoder decoder; + FT_Int glyph_index; + CFF_Font cff = (CFF_Font)face->other; + *max_advance = 0; +/* Initialize load decoder */ + cff_decoder_init( &decoder, face, 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 = cff_decoder_prepare( &decoder, size, glyph_index ); + if ( !error ) + error = cff_decoder_parse_charstrings( &decoder, + charstring, + charstring_len ); + cff_free_glyph_data( face, &charstring, &charstring_len ); + } +/* ignore the error if one has occurred -- skip to next glyph */ + error = CFF_Err_Ok; + } + *max_advance = decoder.builder.advance.x; + return CFF_Err_Ok; + } +/* 0 */ +#endif + 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; + TT_Face face = (TT_Face)glyph->root.face; + FT_Bool hinting, force_scaling; + CFF_Font cff = (CFF_Font)face->extra.data; + 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 CFF_Err_Invalid_Argument; + } + } + else if ( glyph_index >= cff->num_glyphs ) + return CFF_Err_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; + } +/* 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 && + sfnt->load_eblc && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + TT_SBit_MetricsRec metrics; + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_Int)load_flags, + stream, + &glyph->root.bitmap, + &metrics ); + if ( !error ) + { + glyph->root.outline.n_points = 0; + glyph->root.outline.n_contours = 0; + glyph->root.metrics.width = (FT_Pos)metrics.width << 6; + glyph->root.metrics.height = (FT_Pos)metrics.height << 6; + glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; + glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; + glyph->root.metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; + glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; + glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; + glyph->root.metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; + 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; + } + return error; + } + } + } +/* return immediately if we only want the embedded bitmaps */ + if ( load_flags & FT_LOAD_SBITS_ONLY ) + return CFF_Err_Invalid_Argument; +/* 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_ULong 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 = cff->top_font.font_dict.units_per_em; + sub_upm = 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; + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); +/* by default */ + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + { + FT_Byte* charstring; + FT_ULong charstring_len; + cff_decoder_init( &decoder, face, size, glyph, hinting, + FT_LOAD_TARGET_MODE( load_flags ) ); + if ( load_flags & FT_LOAD_ADVANCE_ONLY ) + decoder.width_only = TRUE; + decoder.builder.no_recurse = + (FT_Bool)( load_flags & FT_LOAD_NO_RECURSE ); +/* now load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); + if ( error ) + goto Glyph_Build_Finished; + error = cff_decoder_prepare( &decoder, size, glyph_index ); + if ( error ) + goto Glyph_Build_Finished; + error = cff_decoder_parse_charstrings( &decoder, + charstring, + charstring_len ); + cff_free_glyph_data( face, &charstring, charstring_len ); + if ( error ) + goto Glyph_Build_Finished; +/* Control data and length may not be available for incremental */ +/* fonts. */ + if ( face->root.internal->incremental_interface ) + { + glyph->root.control_data = 0; + glyph->root.control_len = 0; + } + else +/* 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 = charstring_len; + } + } + Glyph_Build_Finished: +/* save new glyph tables, if no error */ + if ( !error ) + cff_builder_done( &decoder.builder ); +/* XXX: anything to do for broken glyph entry? */ + } +/* 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; + } + 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_Vector advance; + FT_Bool has_vertical_info; +/* 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 vtmx 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; + 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 ); + if ( !( font_offset.x == 0 && + font_offset.y == 0 ) ) + FT_Outline_Translate( &glyph->root.outline, + font_offset.x, font_offset.y ); + advance.x = metrics->horiAdvance; + advance.y = 0; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->horiAdvance = advance.x + font_offset.x; + advance.x = 0; + advance.y = metrics->vertAdvance; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->vertAdvance = advance.y + 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; + else + { + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + ft_synthesize_vertical_metrics( metrics, + metrics->vertAdvance ); + } + } + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* cffcmap.c */ +/* */ +/* CFF character mapping table (cmap) support (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2010 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_DEF( FT_Error ) + cff_cmap_encoding_init( 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; + cmap->gids = encoding->codes; + return 0; + } + FT_CALLBACK_DEF( void ) + cff_cmap_encoding_done( CFF_CMapStd cmap ) + { + cmap->gids = NULL; + } + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_index( CFF_CMapStd cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + if ( char_code < 256 ) + result = cmap->gids[char_code]; + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + cff_cmap_encoding_char_next( CFF_CMapStd cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + *pchar_code = 0; + if ( char_code < 255 ) + { + FT_UInt code = (FT_UInt)(char_code + 1); + for (;;) + { + if ( code >= 256 ) + break; + result = cmap->gids[code]; + if ( result != 0 ) + { + *pchar_code = code; + break; + } + code++; + } + } + return result; + } + FT_DEFINE_CMAP_CLASS(cff_cmap_encoding_class_rec, + sizeof ( CFF_CMapStdRec ), + (FT_CMap_InitFunc) cff_cmap_encoding_init, + (FT_CMap_DoneFunc) cff_cmap_encoding_done, + (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index, + (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next, + NULL, NULL, NULL, NULL, NULL + ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_DEF( const char* ) + cff_sid_to_glyph_name( TT_Face face, + FT_UInt idx ) + { + 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( PS_Unicodes unicodes ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); + 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; +/* can't build Unicode map for CID-keyed font */ +/* because we don't know glyph names. */ + if ( !charset->sids ) + return CFF_Err_No_Unicode_Glyph_Name; + return psnames->unicodes_init( memory, + unicodes, + cff->num_glyphs, + (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + FT_CALLBACK_DEF( void ) + cff_cmap_unicode_done( PS_Unicodes unicodes ) + { + FT_Face face = FT_CMAP_FACE( unicodes ); + 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( PS_Unicodes unicodes, + FT_UInt32 char_code ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); + 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_UInt32 ) + cff_cmap_unicode_char_next( PS_Unicodes unicodes, + FT_UInt32 *pchar_code ) + { + TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); + 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, + (FT_CMap_DoneFunc) cff_cmap_unicode_done, + (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index, + (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next, + NULL, NULL, NULL, NULL, NULL + ) +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* sfnt.c */ +/* */ +/* Single object library component. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* sfntpic.c */ +/* */ +/* The FreeType position independent code services for sfnt module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* sfntpic.h */ +/* */ +/* The FreeType position independent code services for sfnt module. */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __SFNTPIC_H__ +FT_BEGIN_HEADER +#define SFNT_SERVICES_GET sfnt_services +#define SFNT_SERVICE_GLYPH_DICT_GET sfnt_service_glyph_dict +#define SFNT_SERVICE_PS_NAME_GET sfnt_service_ps_name +#define TT_SERVICE_CMAP_INFO_GET tt_service_get_cmap_info +#define SFNT_SERVICES_GET sfnt_services +#define TT_CMAP_CLASSES_GET tt_cmap_classes +#define SFNT_SERVICE_SFNT_TABLE_GET sfnt_service_sfnt_table +#define SFNT_SERVICE_BDF_GET sfnt_service_bdf +#define SFNT_INTERFACE_GET sfnt_interface +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* sferrors.h */ +/* */ +/* SFNT error codes (specification only). */ +/* */ +/* Copyright 2001, 2004, 2012 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 SFNT error enumeration constants. */ +/* */ +/*************************************************************************/ +#define __SFERRORS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX SFNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_SFNT +#define FT_KEEP_ERR_PREFIX +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* ttload.c */ +/* */ +/* Load the basic TrueType tables, i.e., tables that can be either in */ +/* TTF or OTF fonts (body). */ +/* */ +/* Copyright 1996-2010, 2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ttload.h */ +/* */ +/* Load the basic TrueType tables, i.e., tables that can be either in */ +/* TTF or OTF fonts (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2005, 2006 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. */ +/* */ +/***************************************************************************/ +#define __TTLOAD_H__ +FT_BEGIN_HEADER + FT_LOCAL( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ); + FT_LOCAL( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ); + FT_LOCAL( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ); + FT_LOCAL( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ); + FT_LOCAL( void ) + tt_face_free_name( TT_Face face ); + FT_LOCAL( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ttload +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_lookup_table */ +/* */ +/* <Description> */ +/* Looks for a TrueType table by name. */ +/* */ +/* <Input> */ +/* face :: A face object handle. */ +/* */ +/* tag :: The searched tag. */ +/* */ +/* <Return> */ +/* A pointer to the table directory entry. 0 if not found. */ +/* */ + FT_LOCAL_DEF( TT_Table ) + tt_face_lookup_table( TT_Face face, + FT_ULong tag ) + { + TT_Table entry; + TT_Table limit; + FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", + face, + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + entry = face->dir_tables; + limit = entry + face->num_tables; + for ( ; entry < limit; entry++ ) + { +/* For compatibility with Windows, we consider */ +/* zero-length tables the same as missing tables. */ + if ( entry->Tag == tag ) + { + if ( entry->Length != 0 ) + { + FT_TRACE4(( "found table.\n" )); + return entry; + } + } + } + return NULL; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_goto_table */ +/* */ +/* <Description> */ +/* Looks for a TrueType table by name, then seek a stream to it. */ +/* */ +/* <Input> */ +/* face :: A face object handle. */ +/* */ +/* tag :: The searched tag. */ +/* */ +/* stream :: The stream to seek when the table is found. */ +/* */ +/* <Output> */ +/* length :: The length of the table if found, undefined otherwise. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_goto_table( TT_Face face, + FT_ULong tag, + FT_Stream stream, + FT_ULong* length ) + { + TT_Table table; + FT_Error error; + table = tt_face_lookup_table( face, tag ); + if ( table ) + { + if ( length ) + *length = table->Length; + if ( FT_STREAM_SEEK( table->Offset ) ) + goto Exit; + } + else + error = SFNT_Err_Table_Missing; + Exit: + return error; + } +/* Here, we */ +/* */ +/* - check that `num_tables' is valid (and adjust it if necessary) */ +/* */ +/* - look for a `head' table, check its size, and parse it to check */ +/* whether its `magic' field is correctly set */ +/* */ +/* - errors (except errors returned by stream handling) */ +/* */ +/* SFNT_Err_Unknown_File_Format: */ +/* no table is defined in directory, it is not sfnt-wrapped */ +/* data */ +/* SFNT_Err_Table_Missing: */ +/* table directory is valid, but essential tables */ +/* (head/bhed/SING) are missing */ +/* */ + static FT_Error + check_table_dir( SFNT_Header sfnt, + FT_Stream stream ) + { + FT_Error error; + FT_UShort nn, valid_entries = 0; + FT_UInt has_head = 0, has_sing = 0, has_meta = 0; + FT_ULong offset = sfnt->offset + 12; + static const FT_Frame_Field table_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_TableRec + FT_FRAME_START( 16 ), + FT_FRAME_ULONG( Tag ), + FT_FRAME_ULONG( CheckSum ), + FT_FRAME_ULONG( Offset ), + FT_FRAME_ULONG( Length ), + FT_FRAME_END + }; + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + for ( nn = 0; nn < sfnt->num_tables; nn++ ) + { + TT_TableRec table; + if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) + { + nn--; + FT_TRACE2(( "check_table_dir:" + " can read only %d table%s in font (instead of %d)\n", + nn, nn == 1 ? "" : "s", sfnt->num_tables )); + sfnt->num_tables = nn; + break; + } +/* we ignore invalid tables */ + if ( table.Offset + table.Length > stream->size ) + { + FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); + continue; + } + else + valid_entries++; + if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) + { + FT_UInt32 magic; + has_head = 1; +/* + * The table length should be 0x36, but certain font tools make it + * 0x38, so we will just check that it is greater. + * + * Note that according to the specification, the table must be + * padded to 32-bit lengths, but this doesn't apply to the value of + * its `Length' field! + * + */ + if ( table.Length < 0x36 ) + { + FT_TRACE2(( "check_table_dir: `head' table too small\n" )); + error = SFNT_Err_Table_Missing; + goto Exit; + } + if ( FT_STREAM_SEEK( table.Offset + 12 ) || + FT_READ_ULONG( magic ) ) + goto Exit; + if ( magic != 0x5F0F3CF5UL ) + { + FT_TRACE2(( "check_table_dir:" + " no magic number found in `head' table\n")); + error = SFNT_Err_Table_Missing; + goto Exit; + } + if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) + goto Exit; + } + else if ( table.Tag == TTAG_SING ) + has_sing = 1; + else if ( table.Tag == TTAG_META ) + has_meta = 1; + } + sfnt->num_tables = valid_entries; + if ( sfnt->num_tables == 0 ) + { + FT_TRACE2(( "check_table_dir: no tables found\n" )); + error = SFNT_Err_Unknown_File_Format; + goto Exit; + } +/* if `sing' and `meta' tables are present, there is no `head' table */ + if ( has_head || ( has_sing && has_meta ) ) + { + error = SFNT_Err_Ok; + goto Exit; + } + else + { + FT_TRACE2(( "check_table_dir:" )); + FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); + error = SFNT_Err_Table_Missing; + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_font_dir */ +/* */ +/* <Description> */ +/* Loads the header of a SFNT font file. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Output> */ +/* sfnt :: The SFNT header. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* The stream cursor must be at the beginning of the font directory. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_font_dir( TT_Face face, + FT_Stream stream ) + { + SFNT_HeaderRec sfnt; + FT_Error error; + FT_Memory memory = stream->memory; + TT_TableRec* entry; + FT_Int nn; + static const FT_Frame_Field offset_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE SFNT_HeaderRec + FT_FRAME_START( 8 ), + FT_FRAME_USHORT( num_tables ), + FT_FRAME_USHORT( search_range ), + FT_FRAME_USHORT( entry_selector ), + FT_FRAME_USHORT( range_shift ), + FT_FRAME_END + }; + FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); +/* read the offset table */ + sfnt.offset = FT_STREAM_POS(); + if ( FT_READ_ULONG( sfnt.format_tag ) || + FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) + goto Exit; +/* many fonts don't have these fields set correctly */ +#if 0 + if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || + sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) + return SFNT_Err_Unknown_File_Format; +#endif +/* load the table directory */ + FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); + FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); + if ( sfnt.format_tag != TTAG_OTTO ) + { +/* check first */ + error = check_table_dir( &sfnt, stream ); + if ( error ) + { + FT_TRACE2(( "tt_face_load_font_dir:" + " invalid table directory for TrueType\n" )); + goto Exit; + } + } + face->num_tables = sfnt.num_tables; + face->format_tag = sfnt.format_tag; + if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) + goto Exit; + if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || + FT_FRAME_ENTER( face->num_tables * 16L ) ) + goto Exit; + entry = face->dir_tables; + FT_TRACE2(( "\n" + " tag offset length checksum\n" + " ----------------------------------\n" )); + for ( nn = 0; nn < sfnt.num_tables; nn++ ) + { + entry->Tag = FT_GET_TAG4(); + entry->CheckSum = FT_GET_ULONG(); + entry->Offset = FT_GET_LONG(); + entry->Length = FT_GET_LONG(); +/* ignore invalid tables */ + if ( entry->Offset + entry->Length > stream->size ) + continue; + else + { + FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx\n", + (FT_Char)( entry->Tag >> 24 ), + (FT_Char)( entry->Tag >> 16 ), + (FT_Char)( entry->Tag >> 8 ), + (FT_Char)( entry->Tag ), + entry->Offset, + entry->Length, + entry->CheckSum )); + entry++; + } + } + FT_FRAME_EXIT(); + FT_TRACE2(( "table directory loaded\n\n" )); + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_any */ +/* */ +/* <Description> */ +/* Loads any font table into client memory. */ +/* */ +/* <Input> */ +/* face :: The face object to look for. */ +/* */ +/* tag :: The tag of table to load. Use the value 0 if you want */ +/* to access the whole font file, else set this parameter */ +/* to a valid TrueType table tag that you can forge with */ +/* the MAKE_TT_TAG macro. */ +/* */ +/* offset :: The starting offset in the table (or the file if */ +/* tag == 0). */ +/* */ +/* length :: The address of the decision variable: */ +/* */ +/* If length == NULL: */ +/* Loads the whole table. Returns an error if */ +/* `offset' == 0! */ +/* */ +/* If *length == 0: */ +/* Exits immediately; returning the length of the given */ +/* table or of the font file, depending on the value of */ +/* `tag'. */ +/* */ +/* If *length != 0: */ +/* Loads the next `length' bytes of table or font, */ +/* starting at offset `offset' (in table or font too). */ +/* */ +/* <Output> */ +/* buffer :: The address of target buffer. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_any( TT_Face face, + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + FT_Error error; + FT_Stream stream; + TT_Table table; + FT_ULong size; + if ( tag != 0 ) + { +/* look for tag in font directory */ + table = tt_face_lookup_table( face, tag ); + if ( !table ) + { + error = SFNT_Err_Table_Missing; + goto Exit; + } + offset += table->Offset; + size = table->Length; + } + else +/* tag == 0 -- the user wants to access the font file directly */ + size = face->root.stream->size; + if ( length && *length == 0 ) + { + *length = size; + return SFNT_Err_Ok; + } + if ( length ) + size = *length; + stream = face->root.stream; +/* the `if' is syntactic sugar for picky compilers */ + if ( FT_STREAM_READ_AT( offset, buffer, size ) ) + goto Exit; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_generic_header */ +/* */ +/* <Description> */ +/* Loads the TrueType table `head' or `bhed'. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + static FT_Error + tt_face_load_generic_header( TT_Face face, + FT_Stream stream, + FT_ULong tag ) + { + FT_Error error; + TT_Header* header; + static const FT_Frame_Field header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Header + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Table_Version ), + FT_FRAME_ULONG ( Font_Revision ), + FT_FRAME_LONG ( CheckSum_Adjust ), + FT_FRAME_LONG ( Magic_Number ), + FT_FRAME_USHORT( Flags ), + FT_FRAME_USHORT( Units_Per_EM ), + FT_FRAME_LONG ( Created[0] ), + FT_FRAME_LONG ( Created[1] ), + FT_FRAME_LONG ( Modified[0] ), + FT_FRAME_LONG ( Modified[1] ), + FT_FRAME_SHORT ( xMin ), + FT_FRAME_SHORT ( yMin ), + FT_FRAME_SHORT ( xMax ), + FT_FRAME_SHORT ( yMax ), + FT_FRAME_USHORT( Mac_Style ), + FT_FRAME_USHORT( Lowest_Rec_PPEM ), + FT_FRAME_SHORT ( Font_Direction ), + FT_FRAME_SHORT ( Index_To_Loc_Format ), + FT_FRAME_SHORT ( Glyph_Data_Format ), + FT_FRAME_END + }; + error = face->goto_table( face, tag, stream, 0 ); + if ( error ) + goto Exit; + header = &face->header; + if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) + goto Exit; + FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); + FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + tt_face_load_head( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_head ); + } + FT_LOCAL_DEF( FT_Error ) + tt_face_load_bhed( TT_Face face, + FT_Stream stream ) + { + return tt_face_load_generic_header( face, stream, TTAG_bhed ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_max_profile */ +/* */ +/* <Description> */ +/* Loads the maximum profile into a face object. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_maxp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_MaxProfile* maxProfile = &face->max_profile; + static const FT_Frame_Field maxp_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_MaxProfile + FT_FRAME_START( 6 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( numGlyphs ), + FT_FRAME_END + }; + static const FT_Frame_Field maxp_fields_extra[] = + { + FT_FRAME_START( 26 ), + FT_FRAME_USHORT( maxPoints ), + FT_FRAME_USHORT( maxContours ), + FT_FRAME_USHORT( maxCompositePoints ), + FT_FRAME_USHORT( maxCompositeContours ), + FT_FRAME_USHORT( maxZones ), + FT_FRAME_USHORT( maxTwilightPoints ), + FT_FRAME_USHORT( maxStorage ), + FT_FRAME_USHORT( maxFunctionDefs ), + FT_FRAME_USHORT( maxInstructionDefs ), + FT_FRAME_USHORT( maxStackElements ), + FT_FRAME_USHORT( maxSizeOfInstructions ), + FT_FRAME_USHORT( maxComponentElements ), + FT_FRAME_USHORT( maxComponentDepth ), + FT_FRAME_END + }; + error = face->goto_table( face, TTAG_maxp, stream, 0 ); + if ( error ) + goto Exit; + if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) + goto Exit; + maxProfile->maxPoints = 0; + maxProfile->maxContours = 0; + maxProfile->maxCompositePoints = 0; + maxProfile->maxCompositeContours = 0; + maxProfile->maxZones = 0; + maxProfile->maxTwilightPoints = 0; + maxProfile->maxStorage = 0; + maxProfile->maxFunctionDefs = 0; + maxProfile->maxInstructionDefs = 0; + maxProfile->maxStackElements = 0; + maxProfile->maxSizeOfInstructions = 0; + maxProfile->maxComponentElements = 0; + maxProfile->maxComponentDepth = 0; + if ( maxProfile->version >= 0x10000L ) + { + if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) ) + goto Exit; +/* XXX: an adjustment that is necessary to load certain */ +/* broken fonts like `Keystrokes MT' :-( */ +/* */ +/* We allocate 64 function entries by default when */ +/* the maxFunctionDefs value is smaller. */ + if ( maxProfile->maxFunctionDefs < 64 ) + maxProfile->maxFunctionDefs = 64; +/* we add 4 phantom points later */ + if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) + { + FT_TRACE0(( "tt_face_load_maxp:" + " too much twilight points in `maxp' table;\n" + " " + " some glyphs might be rendered incorrectly\n" )); + maxProfile->maxTwilightPoints = 0xFFFFU - 4; + } +/* we arbitrarily limit recursion to avoid stack exhaustion */ + if ( maxProfile->maxComponentDepth > 100 ) + { + FT_TRACE0(( "tt_face_load_maxp:" + " abnormally large component depth (%d) set to 100\n", + maxProfile->maxComponentDepth )); + maxProfile->maxComponentDepth = 100; + } + } + FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_name */ +/* */ +/* <Description> */ +/* Loads the name records. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_name( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_pos, table_len; + FT_ULong storage_start, storage_limit; + FT_UInt count; + TT_NameTable table; + static const FT_Frame_Field name_table_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameTableRec + FT_FRAME_START( 6 ), + FT_FRAME_USHORT( format ), + FT_FRAME_USHORT( numNameRecords ), + FT_FRAME_USHORT( storageOffset ), + FT_FRAME_END + }; + static const FT_Frame_Field name_record_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_NameEntryRec +/* no FT_FRAME_START */ + FT_FRAME_USHORT( platformID ), + FT_FRAME_USHORT( encodingID ), + FT_FRAME_USHORT( languageID ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_USHORT( stringLength ), + FT_FRAME_USHORT( stringOffset ), + FT_FRAME_END + }; + table = &face->name_table; + table->stream = stream; + error = face->goto_table( face, TTAG_name, stream, &table_len ); + if ( error ) + goto Exit; + table_pos = FT_STREAM_POS(); + if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) ) + goto Exit; +/* Some popular Asian fonts have an invalid `storageOffset' value */ +/* (it should be at least "6 + 12*num_names"). However, the string */ +/* offsets, computed as "storageOffset + entry->stringOffset", are */ +/* valid pointers within the name table... */ +/* */ +/* We thus can't check `storageOffset' right now. */ +/* */ + storage_start = table_pos + 6 + 12*table->numNameRecords; + storage_limit = table_pos + table_len; + if ( storage_start > storage_limit ) + { + FT_ERROR(( "tt_face_load_name: invalid `name' table\n" )); + error = SFNT_Err_Name_Table_Missing; + goto Exit; + } +/* Allocate the array of name records. */ + count = table->numNameRecords; + table->numNameRecords = 0; + if ( FT_NEW_ARRAY( table->names, count ) || + FT_FRAME_ENTER( count * 12 ) ) + goto Exit; +/* Load the name records and determine how much storage is needed */ +/* to hold the strings themselves. */ + { + TT_NameEntryRec* entry = table->names; + for ( ; count > 0; count-- ) + { + if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) ) + continue; +/* check that the name is not empty */ + if ( entry->stringLength == 0 ) + continue; +/* check that the name string is within the table */ + entry->stringOffset += table_pos + table->storageOffset; + if ( entry->stringOffset < storage_start || + entry->stringOffset + entry->stringLength > storage_limit ) + { +/* invalid entry - ignore it */ + entry->stringOffset = 0; + entry->stringLength = 0; + continue; + } + entry++; + } + table->numNameRecords = (FT_UInt)( entry - table->names ); + } + FT_FRAME_EXIT(); +/* everything went well, update face->num_names */ + face->num_names = (FT_UShort) table->numNameRecords; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_free_names */ +/* */ +/* <Description> */ +/* Frees the name records. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ + FT_LOCAL_DEF( void ) + tt_face_free_name( TT_Face face ) + { + FT_Memory memory = face->root.driver->root.memory; + TT_NameTable table = &face->name_table; + TT_NameEntry entry = table->names; + FT_UInt count = table->numNameRecords; + if ( table->names ) + { + for ( ; count > 0; count--, entry++ ) + { + FT_FREE( entry->string ); + entry->stringLength = 0; + } +/* free strings table */ + FT_FREE( table->names ); + } + table->numNameRecords = 0; + table->format = 0; + table->storageOffset = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_cmap */ +/* */ +/* <Description> */ +/* Loads the cmap directory in a face object. The cmaps themselves */ +/* are loaded on demand in the `ttcmap.c' module. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cmap( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size ); + if ( error ) + goto Exit; + if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) + face->cmap_size = 0; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_os2 */ +/* */ +/* <Description> */ +/* Loads the OS2 table. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_os2( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_OS2* os2; + static const FT_Frame_Field os2_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_OS2 + FT_FRAME_START( 78 ), + FT_FRAME_USHORT( version ), + FT_FRAME_SHORT ( xAvgCharWidth ), + FT_FRAME_USHORT( usWeightClass ), + FT_FRAME_USHORT( usWidthClass ), + FT_FRAME_SHORT ( fsType ), + FT_FRAME_SHORT ( ySubscriptXSize ), + FT_FRAME_SHORT ( ySubscriptYSize ), + FT_FRAME_SHORT ( ySubscriptXOffset ), + FT_FRAME_SHORT ( ySubscriptYOffset ), + FT_FRAME_SHORT ( ySuperscriptXSize ), + FT_FRAME_SHORT ( ySuperscriptYSize ), + FT_FRAME_SHORT ( ySuperscriptXOffset ), + FT_FRAME_SHORT ( ySuperscriptYOffset ), + FT_FRAME_SHORT ( yStrikeoutSize ), + FT_FRAME_SHORT ( yStrikeoutPosition ), + FT_FRAME_SHORT ( sFamilyClass ), + FT_FRAME_BYTE ( panose[0] ), + FT_FRAME_BYTE ( panose[1] ), + FT_FRAME_BYTE ( panose[2] ), + FT_FRAME_BYTE ( panose[3] ), + FT_FRAME_BYTE ( panose[4] ), + FT_FRAME_BYTE ( panose[5] ), + FT_FRAME_BYTE ( panose[6] ), + FT_FRAME_BYTE ( panose[7] ), + FT_FRAME_BYTE ( panose[8] ), + FT_FRAME_BYTE ( panose[9] ), + FT_FRAME_ULONG ( ulUnicodeRange1 ), + FT_FRAME_ULONG ( ulUnicodeRange2 ), + FT_FRAME_ULONG ( ulUnicodeRange3 ), + FT_FRAME_ULONG ( ulUnicodeRange4 ), + FT_FRAME_BYTE ( achVendID[0] ), + FT_FRAME_BYTE ( achVendID[1] ), + FT_FRAME_BYTE ( achVendID[2] ), + FT_FRAME_BYTE ( achVendID[3] ), + FT_FRAME_USHORT( fsSelection ), + FT_FRAME_USHORT( usFirstCharIndex ), + FT_FRAME_USHORT( usLastCharIndex ), + FT_FRAME_SHORT ( sTypoAscender ), + FT_FRAME_SHORT ( sTypoDescender ), + FT_FRAME_SHORT ( sTypoLineGap ), + FT_FRAME_USHORT( usWinAscent ), + FT_FRAME_USHORT( usWinDescent ), + FT_FRAME_END + }; + static const FT_Frame_Field os2_fields_extra[] = + { + FT_FRAME_START( 8 ), + FT_FRAME_ULONG( ulCodePageRange1 ), + FT_FRAME_ULONG( ulCodePageRange2 ), + FT_FRAME_END + }; + static const FT_Frame_Field os2_fields_extra2[] = + { + FT_FRAME_START( 10 ), + FT_FRAME_SHORT ( sxHeight ), + FT_FRAME_SHORT ( sCapHeight ), + FT_FRAME_USHORT( usDefaultChar ), + FT_FRAME_USHORT( usBreakChar ), + FT_FRAME_USHORT( usMaxContext ), + FT_FRAME_END + }; +/* We now support old Mac fonts where the OS/2 table doesn't */ +/* exist. Simply put, we set the `version' field to 0xFFFF */ +/* and test this value each time we need to access the table. */ + error = face->goto_table( face, TTAG_OS2, stream, 0 ); + if ( error ) + goto Exit; + os2 = &face->os2; + if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) ) + goto Exit; + os2->ulCodePageRange1 = 0; + os2->ulCodePageRange2 = 0; + os2->sxHeight = 0; + os2->sCapHeight = 0; + os2->usDefaultChar = 0; + os2->usBreakChar = 0; + os2->usMaxContext = 0; + if ( os2->version >= 0x0001 ) + { +/* only version 1 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) ) + goto Exit; + if ( os2->version >= 0x0002 ) + { +/* only version 2 tables */ + if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) ) + goto Exit; + } + } + FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); + FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); + FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); + FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); + FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_postscript */ +/* */ +/* <Description> */ +/* Loads the Postscript table. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_post( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + TT_Postscript* post = &face->postscript; + static const FT_Frame_Field post_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_Postscript + FT_FRAME_START( 32 ), + FT_FRAME_ULONG( FormatType ), + FT_FRAME_ULONG( italicAngle ), + FT_FRAME_SHORT( underlinePosition ), + FT_FRAME_SHORT( underlineThickness ), + FT_FRAME_ULONG( isFixedPitch ), + FT_FRAME_ULONG( minMemType42 ), + FT_FRAME_ULONG( maxMemType42 ), + FT_FRAME_ULONG( minMemType1 ), + FT_FRAME_ULONG( maxMemType1 ), + FT_FRAME_END + }; + error = face->goto_table( face, TTAG_post, stream, 0 ); + if ( error ) + return error; + if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) + return error; +/* we don't load the glyph names, we do that in another */ +/* module (ttpost). */ + FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); + FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch + ? " yes" : " no" )); + return SFNT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_pclt */ +/* */ +/* <Description> */ +/* Loads the PCL 5 Table. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_pclt( TT_Face face, + FT_Stream stream ) + { + static const FT_Frame_Field pclt_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_PCLT + FT_FRAME_START( 54 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_ULONG ( FontNumber ), + FT_FRAME_USHORT( Pitch ), + FT_FRAME_USHORT( xHeight ), + FT_FRAME_USHORT( Style ), + FT_FRAME_USHORT( TypeFamily ), + FT_FRAME_USHORT( CapHeight ), + FT_FRAME_BYTES ( TypeFace, 16 ), + FT_FRAME_BYTES ( CharacterComplement, 8 ), + FT_FRAME_BYTES ( FileName, 6 ), + FT_FRAME_CHAR ( StrokeWeight ), + FT_FRAME_CHAR ( WidthType ), + FT_FRAME_BYTE ( SerifStyle ), + FT_FRAME_BYTE ( Reserved ), + FT_FRAME_END + }; + FT_Error error; + TT_PCLT* pclt = &face->pclt; +/* optional table */ + error = face->goto_table( face, TTAG_PCLT, stream, 0 ); + if ( error ) + goto Exit; + if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) ) + goto Exit; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_gasp */ +/* */ +/* <Description> */ +/* Loads the `gasp' table into a face object. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_gasp( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt j,num_ranges; + TT_GaspRange gaspranges = NULL; +/* the gasp table is optional */ + error = face->goto_table( face, TTAG_gasp, stream, 0 ); + if ( error ) + goto Exit; + if ( FT_FRAME_ENTER( 4L ) ) + goto Exit; + face->gasp.version = FT_GET_USHORT(); + face->gasp.numRanges = FT_GET_USHORT(); + FT_FRAME_EXIT(); +/* only support versions 0 and 1 of the table */ + if ( face->gasp.version >= 2 ) + { + face->gasp.numRanges = 0; + error = SFNT_Err_Invalid_Table; + goto Exit; + } + num_ranges = face->gasp.numRanges; + FT_TRACE3(( "numRanges: %u\n", num_ranges )); + if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) + goto Exit; + gaspranges = face->gasp.gaspRanges; + for ( j = 0; j < num_ranges; j++ ) + { + gaspranges[j].maxPPEM = FT_GET_USHORT(); + gaspranges[j].gaspFlag = FT_GET_USHORT(); + FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", + j, + gaspranges[j].maxPPEM, + gaspranges[j].gaspFlag )); + } + FT_FRAME_EXIT(); + Exit: + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ttmtx.c */ +/* */ +/* Load the metrics tables common to TTF and OTF fonts (body). */ +/* */ +/* Copyright 2006-2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ttmtx.h */ +/* */ +/* Load the metrics tables common to TTF and OTF fonts (specification). */ +/* */ +/* Copyright 2006 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. */ +/* */ +/***************************************************************************/ +#define __TTMTX_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + FT_LOCAL( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ); + FT_LOCAL( FT_Error ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short* abearing, + FT_UShort* aadvance ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ttmtx +/* + * Unfortunately, we can't enable our memory optimizations if + * FT_CONFIG_OPTION_OLD_INTERNALS is defined. This is because at least + * one rogue client (libXfont in the X.Org XServer) is directly accessing + * the metrics. + */ +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_hmtx */ +/* */ +/* <Description> */ +/* Load the `hmtx' or `vmtx' table into a face object. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* vertical :: A boolean flag. If set, load `vmtx'. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hmtx( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + FT_ULong tag, table_size; + FT_ULong* ptable_offset; + FT_ULong* ptable_size; + if ( vertical ) + { + tag = TTAG_vmtx; + ptable_offset = &face->vert_metrics_offset; + ptable_size = &face->vert_metrics_size; + } + else + { + tag = TTAG_hmtx; + ptable_offset = &face->horz_metrics_offset; + ptable_size = &face->horz_metrics_size; + } + error = face->goto_table( face, tag, stream, &table_size ); + if ( error ) + goto Fail; + *ptable_size = table_size; + *ptable_offset = FT_STREAM_POS(); + Fail: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_hhea */ +/* */ +/* <Description> */ +/* Load the `hhea' or 'vhea' table into a face object. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: The input stream. */ +/* */ +/* vertical :: A boolean flag. If set, load `vhea'. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hhea( TT_Face face, + FT_Stream stream, + FT_Bool vertical ) + { + FT_Error error; + TT_HoriHeader* header; + static const FT_Frame_Field metrics_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_HoriHeader + FT_FRAME_START( 36 ), + FT_FRAME_ULONG ( Version ), + FT_FRAME_SHORT ( Ascender ), + FT_FRAME_SHORT ( Descender ), + FT_FRAME_SHORT ( Line_Gap ), + FT_FRAME_USHORT( advance_Width_Max ), + FT_FRAME_SHORT ( min_Left_Side_Bearing ), + FT_FRAME_SHORT ( min_Right_Side_Bearing ), + FT_FRAME_SHORT ( xMax_Extent ), + FT_FRAME_SHORT ( caret_Slope_Rise ), + FT_FRAME_SHORT ( caret_Slope_Run ), + FT_FRAME_SHORT ( caret_Offset ), + FT_FRAME_SHORT ( Reserved[0] ), + FT_FRAME_SHORT ( Reserved[1] ), + FT_FRAME_SHORT ( Reserved[2] ), + FT_FRAME_SHORT ( Reserved[3] ), + FT_FRAME_SHORT ( metric_Data_Format ), + FT_FRAME_USHORT( number_Of_HMetrics ), + FT_FRAME_END + }; + if ( vertical ) + { + void *v = &face->vertical; + error = face->goto_table( face, TTAG_vhea, stream, 0 ); + if ( error ) + goto Fail; + header = (TT_HoriHeader*)v; + } + else + { + error = face->goto_table( face, TTAG_hhea, stream, 0 ); + if ( error ) + goto Fail; + header = &face->horizontal; + } + if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) + goto Fail; + FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); + FT_TRACE3(( "Descender: %5d\n", header->Descender )); + FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); + header->long_metrics = NULL; + header->short_metrics = NULL; + Fail: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_get_metrics */ +/* */ +/* <Description> */ +/* Returns the horizontal or vertical metrics in font units for a */ +/* given glyph. The metrics are the left side bearing (resp. top */ +/* side bearing) and advance width (resp. advance height). */ +/* */ +/* <Input> */ +/* header :: A pointer to either the horizontal or vertical metrics */ +/* structure. */ +/* */ +/* idx :: The glyph index. */ +/* */ +/* <Output> */ +/* bearing :: The bearing, either left side or top side. */ +/* */ +/* advance :: The advance width resp. advance height. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_get_metrics( TT_Face face, + FT_Bool vertical, + FT_UInt gindex, + FT_Short *abearing, + FT_UShort *aadvance ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + TT_HoriHeader* header; + FT_ULong table_pos, table_size, table_end; + FT_UShort k; + if ( vertical ) + { + void* v = &face->vertical; + header = (TT_HoriHeader*)v; + table_pos = face->vert_metrics_offset; + table_size = face->vert_metrics_size; + } + else + { + header = &face->horizontal; + table_pos = face->horz_metrics_offset; + table_size = face->horz_metrics_size; + } + table_end = table_pos + table_size; + k = header->number_Of_HMetrics; + if ( k > 0 ) + { + if ( gindex < (FT_UInt)k ) + { + table_pos += 4 * gindex; + if ( table_pos + 4 > table_end ) + goto NoData; + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) || + FT_READ_SHORT( *abearing ) ) + goto NoData; + } + else + { + table_pos += 4 * ( k - 1 ); + if ( table_pos + 4 > table_end ) + goto NoData; + if ( FT_STREAM_SEEK( table_pos ) || + FT_READ_USHORT( *aadvance ) ) + goto NoData; + table_pos += 4 + 2 * ( gindex - k ); + if ( table_pos + 2 > table_end ) + *abearing = 0; + else + { + if ( !FT_STREAM_SEEK( table_pos ) ) + (void)FT_READ_SHORT( *abearing ); + } + } + } + else + { + NoData: + *abearing = 0; + *aadvance = 0; + } + return SFNT_Err_Ok; + } +/* END */ +/***************************************************************************/ +/* */ +/* ttcmap.c */ +/* */ +/* TrueType character mapping table (cmap) support (body). */ +/* */ +/* Copyright 2002-2010, 2012 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. */ +/* */ +/***************************************************************************/ +/* must come before FT_INTERNAL_VALIDATE_H */ +/***************************************************************************/ +/* */ +/* ttcmap.h */ +/* */ +/* TrueType character mapping table (cmap) support (specification). */ +/* */ +/* Copyright 2002-2005, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __TTCMAP_H__ +FT_BEGIN_HEADER +#define TT_CMAP_FLAG_UNSORTED 1 +#define TT_CMAP_FLAG_OVERLAPPING 2 + typedef struct TT_CMapRec_ + { + FT_CMapRec cmap; +/* pointer to in-memory cmap table */ + FT_Byte* data; +/* for format 4 only */ + FT_Int flags; + } TT_CMapRec, *TT_CMap; + typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; + typedef FT_Error + (*TT_CMap_ValidateFunc)( FT_Byte* data, + FT_Validator valid ); + typedef struct TT_CMap_ClassRec_ + { + FT_CMap_ClassRec clazz; + FT_UInt format; + TT_CMap_ValidateFunc validate; + TT_CMap_Info_GetFunc get_cmap_info; + } TT_CMap_ClassRec; +#define FT_DEFINE_TT_CMAP( class_, \ + size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_, \ + format_, \ + validate_, \ + get_cmap_info_ ) \ + FT_CALLBACK_TABLE_DEF \ + const TT_CMap_ClassRec class_ = \ + { \ + { size_, \ + init_, \ + done_, \ + char_index_, \ + char_next_, \ + char_var_index_, \ + char_var_default_, \ + variant_list_, \ + charvariant_list_, \ + variantchar_list_ \ + }, \ + \ + format_, \ + validate_, \ + get_cmap_info_ \ + }; + typedef struct TT_ValidatorRec_ + { + FT_ValidatorRec validator; + FT_UInt num_glyphs; + } TT_ValidatorRec, *TT_Validator; +#define TT_VALIDATOR( x ) ( (TT_Validator)( x ) ) +#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs + FT_LOCAL( FT_Error ) + tt_face_build_cmaps( TT_Face face ); +/* used in tt-cmaps service */ + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ttcmap +#define TT_PEEK_SHORT FT_PEEK_SHORT +#define TT_PEEK_USHORT FT_PEEK_USHORT +#define TT_PEEK_UINT24 FT_PEEK_UOFF3 +#define TT_PEEK_LONG FT_PEEK_LONG +#define TT_PEEK_ULONG FT_PEEK_ULONG +#define TT_NEXT_SHORT FT_NEXT_SHORT +#define TT_NEXT_USHORT FT_NEXT_USHORT +#define TT_NEXT_UINT24 FT_NEXT_UOFF3 +#define TT_NEXT_LONG FT_NEXT_LONG +#define TT_NEXT_ULONG FT_NEXT_ULONG + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_init( TT_CMap cmap, + FT_Byte* table ) + { + cmap->data = table; + return SFNT_Err_Ok; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 0 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 0 */ +/* length 2 USHORT table length in bytes */ +/* language 4 USHORT Mac language code */ +/* glyph_ids 6 BYTE[256] array of glyph indices */ +/* 262 */ +/* */ + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; + FT_UInt length = TT_NEXT_USHORT( p ); + if ( table + length > valid->limit || length < 262 ) + FT_INVALID_TOO_SHORT; +/* check glyph indices whenever necessary */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt n, idx; + p = table + 6; + for ( n = 0; n < 256; n++ ) + { + idx = *p++; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + return char_code < 256 ? table[6 + char_code] : 0; + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap0_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 charcode = *pchar_code; + FT_UInt32 result = 0; + FT_UInt gindex = 0; +/* go to glyph IDs */ + table += 6; + while ( ++charcode < 256 ) + { + gindex = table[charcode]; + if ( gindex != 0 ) + { + result = charcode; + break; + } + } + *pchar_code = result; + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + cmap_info->format = 0; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap0_class_rec, + sizeof ( TT_CMapRec ), + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap0_char_index, + (FT_CMap_CharNextFunc) tt_cmap0_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + (TT_CMap_ValidateFunc)tt_cmap0_validate, + (TT_CMap_Info_GetFunc)tt_cmap0_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 2 *****/ +/***** *****/ +/***** This is used for certain CJK encodings that encode text in a *****/ +/***** mixed 8/16 bits encoding along the following lines: *****/ +/***** *****/ +/***** * Certain byte values correspond to an 8-bit character code *****/ +/***** (typically in the range 0..127 for ASCII compatibility). *****/ +/***** *****/ +/***** * Certain byte values signal the first byte of a 2-byte *****/ +/***** character code (but these values are also valid as the *****/ +/***** second byte of a 2-byte character). *****/ +/***** *****/ +/***** The following charmap lookup and iteration functions all *****/ +/***** assume that the value "charcode" correspond to following: *****/ +/***** *****/ +/***** - For one byte characters, "charcode" is simply the *****/ +/***** character code. *****/ +/***** *****/ +/***** - For two byte characters, "charcode" is the 2-byte *****/ +/***** character code in big endian format. More exactly: *****/ +/***** *****/ +/***** (charcode >> 8) is the first byte value *****/ +/***** (charcode & 0xFF) is the second byte value *****/ +/***** *****/ +/***** Note that not all values of "charcode" are valid according *****/ +/***** to these rules, and the function moderately check the *****/ +/***** arguments. *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 2 */ +/* length 2 USHORT table length in bytes */ +/* language 4 USHORT Mac language code */ +/* keys 6 USHORT[256] sub-header keys */ +/* subs 518 SUBHEAD[NSUBS] sub-headers array */ +/* glyph_ids 518+NSUB*8 USHORT[] glyph ID array */ +/* */ +/* The `keys' table is used to map charcode high-bytes to sub-headers. */ +/* The value of `NSUBS' is the number of sub-headers defined in the */ +/* table and is computed by finding the maximum of the `keys' table. */ +/* */ +/* Note that for any n, `keys[n]' is a byte offset within the `subs' */ +/* table, i.e., it is the corresponding sub-header index multiplied */ +/* by 8. */ +/* */ +/* Each sub-header has the following format: */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* first 0 USHORT first valid low-byte */ +/* count 2 USHORT number of valid low-bytes */ +/* delta 4 SHORT see below */ +/* offset 6 USHORT see below */ +/* */ +/* A sub-header defines, for each high-byte, the range of valid */ +/* low-bytes within the charmap. Note that the range defined by `first' */ +/* and `count' must be completely included in the interval [0..255] */ +/* according to the specification. */ +/* */ +/* If a character code is contained within a given sub-header, then */ +/* mapping it to a glyph index is done as follows: */ +/* */ +/* * The value of `offset' is read. This is a _byte_ distance from the */ +/* location of the `offset' field itself into a slice of the */ +/* `glyph_ids' table. Let's call it `slice' (it is a USHORT[] too). */ +/* */ +/* * The value `slice[char.lo - first]' is read. If it is 0, there is */ +/* no glyph for the charcode. Otherwise, the value of `delta' is */ +/* added to it (modulo 65536) to form a new glyph index. */ +/* */ +/* It is up to the validation routine to check that all offsets fall */ +/* within the glyph IDs table (and not within the `subs' table itself or */ +/* outside of the CMap). */ +/* */ + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_validate( FT_Byte* table, + FT_Validator valid ) + { +/* skip format */ + FT_Byte* p = table + 2; + FT_UInt length = TT_PEEK_USHORT( p ); + FT_UInt n, max_subs; +/* keys table */ + FT_Byte* keys; +/* sub-headers */ + FT_Byte* subs; +/* glyph ID array */ + FT_Byte* glyph_ids; + if ( table + length > valid->limit || length < 6 + 512 ) + FT_INVALID_TOO_SHORT; + keys = table + 6; +/* parse keys to compute sub-headers count */ + p = keys; + max_subs = 0; + for ( n = 0; n < 256; n++ ) + { + FT_UInt idx = TT_NEXT_USHORT( p ); +/* value must be multiple of 8 */ + if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) + FT_INVALID_DATA; + idx >>= 3; + if ( idx > max_subs ) + max_subs = idx; + } + FT_ASSERT( p == table + 518 ); + subs = p; + glyph_ids = subs + (max_subs + 1) * 8; + if ( glyph_ids > valid->limit ) + FT_INVALID_TOO_SHORT; +/* parse sub-headers */ + for ( n = 0; n <= max_subs; n++ ) + { + FT_UInt first_code, code_count, offset; + FT_Int delta; + FT_Byte* ids; + first_code = TT_NEXT_USHORT( p ); + code_count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT( p ); + offset = TT_NEXT_USHORT( p ); +/* many Dynalab fonts have empty sub-headers */ + if ( code_count == 0 ) + continue; +/* check range within 0..255 */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + if ( first_code >= 256 || first_code + code_count > 256 ) + FT_INVALID_DATA; + } +/* check offset */ + if ( offset != 0 ) + { + ids = p - 2 + offset; + if ( ids < glyph_ids || ids + code_count*2 > table + length ) + FT_INVALID_OFFSET; +/* check glyph IDs */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_Byte* limit = p + code_count * 2; + FT_UInt idx; + for ( ; p < limit; ) + { + idx = TT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = ( idx + delta ) & 0xFFFFU; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + } + return SFNT_Err_Ok; + } +/* return sub header corresponding to a given character code */ +/* NULL on invalid charcode */ + static FT_Byte* + tt_cmap2_get_subheader( FT_Byte* table, + FT_UInt32 char_code ) + { + FT_Byte* result = NULL; + if ( char_code < 0x10000UL ) + { + FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); + FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); +/* keys table */ + FT_Byte* p = table + 6; +/* subheaders table */ + FT_Byte* subs = table + 518; + FT_Byte* sub; + if ( char_hi == 0 ) + { +/* an 8-bit character code -- we use subHeader 0 in this case */ +/* to test whether the character code is in the charmap */ +/* */ +/* jump to first sub-header */ + sub = subs; +/* check that the sub-header for this byte is 0, which */ +/* indicates that it is really a valid one-byte value */ +/* Otherwise, return 0 */ +/* */ + p += char_lo * 2; + if ( TT_PEEK_USHORT( p ) != 0 ) + goto Exit; + } + else + { +/* a 16-bit character code */ +/* jump to key entry */ + p += char_hi * 2; +/* jump to sub-header */ + sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); +/* check that the high byte isn't a valid one-byte value */ + if ( sub == subs ) + goto Exit; + } + result = sub; + } + Exit: + return result; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* subheader; + subheader = tt_cmap2_get_subheader( table, char_code ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt idx = (FT_UInt)(char_code & 0xFF); + FT_UInt start, count; + FT_Int delta; + FT_UInt offset; + start = TT_NEXT_USHORT( p ); + count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT ( p ); + offset = TT_PEEK_USHORT( p ); + idx -= start; + if ( idx < count && offset != 0 ) + { + p += offset + 2 * idx; + idx = TT_PEEK_USHORT( p ); + if ( idx != 0 ) + result = (FT_UInt)( idx + delta ) & 0xFFFFU; + } + } + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap2_char_next( TT_CMap cmap, + FT_UInt32 *pcharcode ) + { + FT_Byte* table = cmap->data; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 charcode = *pcharcode + 1; + FT_Byte* subheader; + while ( charcode < 0x10000UL ) + { + subheader = tt_cmap2_get_subheader( table, charcode ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_Int delta = TT_NEXT_SHORT ( p ); + FT_UInt offset = TT_PEEK_USHORT( p ); + FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); + FT_UInt pos, idx; + if ( offset == 0 ) + goto Next_SubHeader; + if ( char_lo < start ) + { + char_lo = start; + pos = 0; + } + else + pos = (FT_UInt)( char_lo - start ); + p += offset + pos * 2; + charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; + for ( ; pos < count; pos++, charcode++ ) + { + idx = TT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + gindex = ( idx + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = charcode; + goto Exit; + } + } + } + } +/* jump to next sub-header, i.e. higher byte value */ + Next_SubHeader: + charcode = FT_PAD_FLOOR( charcode, 256 ) + 256; + } + Exit: + *pcharcode = result; + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + cmap_info->format = 2; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap2_class_rec, + sizeof ( TT_CMapRec ), + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap2_char_index, + (FT_CMap_CharNextFunc) tt_cmap2_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 2, + (TT_CMap_ValidateFunc)tt_cmap2_validate, + (TT_CMap_Info_GetFunc)tt_cmap2_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 4 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 4 */ +/* length 2 USHORT table length */ +/* in bytes */ +/* language 4 USHORT Mac language code */ +/* */ +/* segCountX2 6 USHORT 2*NUM_SEGS */ +/* searchRange 8 USHORT 2*(1 << LOG_SEGS) */ +/* entrySelector 10 USHORT LOG_SEGS */ +/* rangeShift 12 USHORT segCountX2 - */ +/* searchRange */ +/* */ +/* endCount 14 USHORT[NUM_SEGS] end charcode for */ +/* each segment; last */ +/* is 0xFFFF */ +/* */ +/* pad 14+NUM_SEGS*2 USHORT padding */ +/* */ +/* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */ +/* each segment */ +/* */ +/* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */ +/* segment */ +/* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */ +/* each segment; can be */ +/* zero */ +/* */ +/* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph ID */ +/* ranges */ +/* */ +/* Character codes are modelled by a series of ordered (increasing) */ +/* intervals called segments. Each segment has start and end codes, */ +/* provided by the `startCount' and `endCount' arrays. Segments must */ +/* not overlap, and the last segment should always contain the value */ +/* 0xFFFF for `endCount'. */ +/* */ +/* The fields `searchRange', `entrySelector' and `rangeShift' are better */ +/* ignored (they are traces of over-engineering in the TrueType */ +/* specification). */ +/* */ +/* Each segment also has a signed `delta', as well as an optional offset */ +/* within the `glyphIds' table. */ +/* */ +/* If a segment's idOffset is 0, the glyph index corresponding to any */ +/* charcode within the segment is obtained by adding the value of */ +/* `idDelta' directly to the charcode, modulo 65536. */ +/* */ +/* Otherwise, a glyph index is taken from the glyph IDs sub-array for */ +/* the segment, and the value of `idDelta' is added to it. */ +/* */ +/* */ +/* Finally, note that a lot of fonts contain an invalid last segment, */ +/* where `start' and `end' are correctly set to 0xFFFF but both `delta' */ +/* and `offset' are incorrect (e.g., `opens___.ttf' which comes with */ +/* OpenOffice.org). We need special code to deal with them correctly. */ +/* */ + typedef struct TT_CMap4Rec_ + { + TT_CMapRec cmap; +/* current charcode */ + FT_UInt32 cur_charcode; +/* current glyph index */ + FT_UInt cur_gindex; + FT_UInt num_ranges; + FT_UInt cur_range; + FT_UInt cur_start; + FT_UInt cur_end; + FT_Int cur_delta; + FT_Byte* cur_values; + } TT_CMap4Rec, *TT_CMap4; + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_init( TT_CMap4 cmap, + FT_Byte* table ) + { + FT_Byte* p; + cmap->cmap.data = table; + p = table + 6; + cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + cmap->cur_gindex = 0; + return SFNT_Err_Ok; + } + static FT_Int + tt_cmap4_set_range( TT_CMap4 cmap, + FT_UInt range_index ) + { + FT_Byte* table = cmap->cmap.data; + FT_Byte* p; + FT_UInt num_ranges = cmap->num_ranges; + while ( range_index < num_ranges ) + { + FT_UInt offset; + p = table + 14 + range_index * 2; + cmap->cur_end = FT_PEEK_USHORT( p ); + p += 2 + num_ranges * 2; + cmap->cur_start = FT_PEEK_USHORT( p ); + p += num_ranges * 2; + cmap->cur_delta = FT_PEEK_SHORT( p ); + p += num_ranges * 2; + offset = FT_PEEK_USHORT( p ); +/* some fonts have an incorrect last segment; */ +/* we have to catch it */ + if ( range_index >= num_ranges - 1 && + cmap->cur_start == 0xFFFFU && + cmap->cur_end == 0xFFFFU ) + { + TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face; + FT_Byte* limit = face->cmap_table + face->cmap_size; + if ( offset && p + offset + 2 > limit ) + { + cmap->cur_delta = 1; + offset = 0; + } + } + if ( offset != 0xFFFFU ) + { + cmap->cur_values = offset ? p + offset : NULL; + cmap->cur_range = range_index; + return 0; + } +/* we skip empty segments */ + range_index++; + } + return -1; + } +/* search the index of the charcode next to cmap->cur_charcode; */ +/* caller should call tt_cmap4_set_range with proper range */ +/* before calling this function */ +/* */ + static void + tt_cmap4_next( TT_CMap4 cmap ) + { + FT_UInt charcode; + if ( cmap->cur_charcode >= 0xFFFFUL ) + goto Fail; + charcode = (FT_UInt)cmap->cur_charcode + 1; + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + for ( ;; ) + { + FT_Byte* values = cmap->cur_values; + FT_UInt end = cmap->cur_end; + FT_Int delta = cmap->cur_delta; + if ( charcode <= end ) + { + if ( values ) + { + FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); + do + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU ); + if ( gindex != 0 ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } + } while ( ++charcode <= end ); + } + else + { + do + { + FT_UInt gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU ); + if ( gindex != 0 ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } while ( ++charcode <= end ); + } + } +/* we need to find another range */ + if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) + break; + if ( charcode < cmap->cur_start ) + charcode = cmap->cur_start; + } + Fail: + cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + cmap->cur_gindex = 0; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_validate( FT_Byte* table, + FT_Validator valid ) + { +/* skip format */ + FT_Byte* p = table + 2; + FT_UInt length = TT_NEXT_USHORT( p ); + FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; + FT_UInt num_segs; + FT_Error error = SFNT_Err_Ok; + if ( length < 16 ) + FT_INVALID_TOO_SHORT; +/* in certain fonts, the `length' field is invalid and goes */ +/* out of bound. We try to correct this here... */ + if ( table + length > valid->limit ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_TOO_SHORT; + length = (FT_UInt)( valid->limit - table ); + } + p = table + 6; +/* read segCountX2 */ + num_segs = TT_NEXT_USHORT( p ); + if ( valid->level >= FT_VALIDATE_PARANOID ) + { +/* check that we have an even value here */ + if ( num_segs & 1 ) + FT_INVALID_DATA; + } + num_segs /= 2; + if ( length < 16 + num_segs * 2 * 4 ) + FT_INVALID_TOO_SHORT; +/* check the search parameters - even though we never use them */ +/* */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { +/* check the values of `searchRange', `entrySelector', `rangeShift' */ + FT_UInt search_range = TT_NEXT_USHORT( p ); + FT_UInt entry_selector = TT_NEXT_USHORT( p ); + FT_UInt range_shift = TT_NEXT_USHORT( p ); +/* must be even values */ + if ( ( search_range | range_shift ) & 1 ) + FT_INVALID_DATA; + search_range /= 2; + range_shift /= 2; +/* `search range' is the greatest power of 2 that is <= num_segs */ + if ( search_range > num_segs || + search_range * 2 < num_segs || + search_range + range_shift != num_segs || + search_range != ( 1U << entry_selector ) ) + FT_INVALID_DATA; + } + ends = table + 14; + starts = table + 16 + num_segs * 2; + deltas = starts + num_segs * 2; + offsets = deltas + num_segs * 2; + glyph_ids = offsets + num_segs * 2; +/* check last segment; its end count value must be 0xFFFF */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + p = ends + ( num_segs - 1 ) * 2; + if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) + FT_INVALID_DATA; + } + { + FT_UInt start, end, offset, n; + FT_UInt last_start = 0, last_end = 0; + FT_Int delta; + FT_Byte* p_start = starts; + FT_Byte* p_end = ends; + FT_Byte* p_delta = deltas; + FT_Byte* p_offset = offsets; + for ( n = 0; n < num_segs; n++ ) + { + p = p_offset; + start = TT_NEXT_USHORT( p_start ); + end = TT_NEXT_USHORT( p_end ); + delta = TT_NEXT_SHORT( p_delta ); + offset = TT_NEXT_USHORT( p_offset ); + if ( start > end ) + FT_INVALID_DATA; +/* this test should be performed at default validation level; */ +/* unfortunately, some popular Asian fonts have overlapping */ +/* ranges in their charmaps */ +/* */ + if ( start <= last_end && n > 0 ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + else + { +/* allow overlapping segments, provided their start points */ +/* and end points, respectively, are in ascending order */ +/* */ + if ( last_start > start || last_end > end ) + error |= TT_CMAP_FLAG_UNSORTED; + else + error |= TT_CMAP_FLAG_OVERLAPPING; + } + } + if ( offset && offset != 0xFFFFU ) + { +/* start of glyph ID array */ + p += offset; +/* check that we point within the glyph IDs table only */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > table + length ) + FT_INVALID_DATA; + } +/* Some fonts handle the last segment incorrectly. In */ +/* theory, 0xFFFF might point to an ordinary glyph -- */ +/* a cmap 4 is versatile and could be used for any */ +/* encoding, not only Unicode. However, reality shows */ +/* that far too many fonts are sloppy and incorrectly */ +/* set all fields but `start' and `end' for the last */ +/* segment if it contains only a single character. */ +/* */ +/* We thus omit the test here, delaying it to the */ +/* routines which actually access the cmap. */ + else if ( n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU ) ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > valid->limit ) + FT_INVALID_DATA; + } +/* check glyph indices within the segment range */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt i, idx; + for ( i = start; i < end; i++ ) + { + idx = FT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( idx + delta ) & 0xFFFFU; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + else if ( offset == 0xFFFFU ) + { +/* some fonts (erroneously?) use a range offset of 0xFFFF */ +/* to mean missing glyph in cmap table */ +/* */ + if ( valid->level >= FT_VALIDATE_PARANOID || + n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU ) ) + FT_INVALID_DATA; + } + last_start = start; + last_end = end; + } + } + return error; + } + static FT_UInt + tt_cmap4_char_map_linear( TT_CMap cmap, + FT_UInt32* pcharcode, + FT_Bool next ) + { + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt i, num_segs; + FT_UInt32 charcode = *pcharcode; + FT_UInt gindex = 0; + FT_Byte* p; + p = cmap->data + 6; + num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); + num_segs = num_segs2 >> 1; + if ( !num_segs ) + return 0; + if ( next ) + charcode++; +/* linear search */ + for ( ; charcode <= 0xFFFFU; charcode++ ) + { + FT_Byte* q; +/* ends table */ + p = cmap->data + 14; +/* starts table */ + q = cmap->data + 16 + num_segs2; + for ( i = 0; i < num_segs; i++ ) + { + end = TT_NEXT_USHORT( p ); + start = TT_NEXT_USHORT( q ); + if ( charcode >= start && charcode <= end ) + { + p = q - 2 + num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); +/* some fonts have an incorrect last segment; */ +/* we have to catch it */ + if ( i >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) + { + TT_Face face = (TT_Face)cmap->cmap.charmap.face; + FT_Byte* limit = face->cmap_table + face->cmap_size; + if ( offset && p + offset + 2 > limit ) + { + delta = 1; + offset = 0; + } + } + if ( offset == 0xFFFFU ) + continue; + if ( offset ) + { + p += offset + ( charcode - start ) * 2; + gindex = TT_PEEK_USHORT( p ); + if ( gindex != 0 ) + gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; + } + else + gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU; + break; + } + } + if ( !next || gindex ) + break; + } + if ( next && gindex ) + *pcharcode = charcode; + return gindex; + } + static FT_UInt + tt_cmap4_char_map_binary( TT_CMap cmap, + FT_UInt32* pcharcode, + FT_Bool next ) + { + FT_UInt num_segs2, start, end, offset; + FT_Int delta; + FT_UInt max, min, mid, num_segs; + FT_UInt charcode = (FT_UInt)*pcharcode; + FT_UInt gindex = 0; + FT_Byte* p; + p = cmap->data + 6; + num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); + if ( !num_segs2 ) + return 0; + num_segs = num_segs2 >> 1; +/* make compiler happy */ + mid = num_segs; + end = 0xFFFFU; + if ( next ) + charcode++; + min = 0; + max = num_segs; +/* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + if ( charcode < start ) + max = mid; + else if ( charcode > end ) + min = mid + 1; + else + { + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); +/* some fonts have an incorrect last segment; */ +/* we have to catch it */ + if ( mid >= num_segs - 1 && + start == 0xFFFFU && end == 0xFFFFU ) + { + TT_Face face = (TT_Face)cmap->cmap.charmap.face; + FT_Byte* limit = face->cmap_table + face->cmap_size; + if ( offset && p + offset + 2 > limit ) + { + delta = 1; + offset = 0; + } + } +/* search the first segment containing `charcode' */ + if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING ) + { + FT_UInt i; +/* call the current segment `max' */ + max = mid; + if ( offset == 0xFFFFU ) + mid = max + 1; +/* search in segments before the current segment */ + for ( i = max ; i > 0; i-- ) + { + FT_UInt prev_end; + FT_Byte* old_p; + old_p = p; + p = cmap->data + 14 + ( i - 1 ) * 2; + prev_end = TT_PEEK_USHORT( p ); + if ( charcode > prev_end ) + { + p = old_p; + break; + } + end = prev_end; + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + if ( offset != 0xFFFFU ) + mid = i - 1; + } +/* no luck */ + if ( mid == max + 1 ) + { + if ( i != max ) + { + p = cmap->data + 14 + max * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + mid = max; +/* search in segments after the current segment */ + for ( i = max + 1; i < num_segs; i++ ) + { + FT_UInt next_end, next_start; + p = cmap->data + 14 + i * 2; + next_end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + next_start = TT_PEEK_USHORT( p ); + if ( charcode < next_start ) + break; + end = next_end; + start = next_start; + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + if ( offset != 0xFFFFU ) + mid = i; + } + i--; +/* still no luck */ + if ( mid == max ) + { + mid = i; + break; + } + } +/* end, start, delta, and offset are for the i'th segment */ + if ( mid != i ) + { + p = cmap->data + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + } + } + else + { + if ( offset == 0xFFFFU ) + break; + } + if ( offset ) + { + p += offset + ( charcode - start ) * 2; + gindex = TT_PEEK_USHORT( p ); + if ( gindex != 0 ) + gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; + } + else + gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU; + break; + } + } + if ( next ) + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; +/* if `charcode' is not in any segment, then `mid' is */ +/* the segment nearest to `charcode' */ +/* */ + if ( charcode > end ) + { + mid++; + if ( mid == num_segs ) + return 0; + } + if ( tt_cmap4_set_range( cmap4, mid ) ) + { + if ( gindex ) + *pcharcode = charcode; + } + else + { + cmap4->cur_charcode = charcode; + if ( gindex ) + cmap4->cur_gindex = gindex; + else + { + cmap4->cur_charcode = charcode; + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + } + if ( gindex ) + *pcharcode = cmap4->cur_charcode; + } + } + return gindex; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + if ( char_code >= 0x10000UL ) + return 0; + if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) + return tt_cmap4_char_map_linear( cmap, &char_code, 0 ); + else + return tt_cmap4_char_map_binary( cmap, &char_code, 0 ); + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap4_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt gindex; + if ( *pchar_code >= 0xFFFFU ) + return 0; + if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) + gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 ); + else + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; +/* no need to search */ + if ( *pchar_code == cmap4->cur_charcode ) + { + tt_cmap4_next( cmap4 ); + gindex = cmap4->cur_gindex; + if ( gindex ) + *pchar_code = cmap4->cur_charcode; + } + else + gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 ); + } + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + cmap_info->format = 4; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap4_class_rec, + sizeof ( TT_CMap4Rec ), + (FT_CMap_InitFunc) tt_cmap4_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap4_char_index, + (FT_CMap_CharNextFunc) tt_cmap4_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 4, + (TT_CMap_ValidateFunc)tt_cmap4_validate, + (TT_CMap_Info_GetFunc)tt_cmap4_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 6 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 4 */ +/* length 2 USHORT table length in bytes */ +/* language 4 USHORT Mac language code */ +/* */ +/* first 6 USHORT first segment code */ +/* count 8 USHORT segment size in chars */ +/* glyphIds 10 USHORT[count] glyph IDs */ +/* */ +/* A very simplified segment mapping. */ +/* */ + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length, count; + if ( table + 10 > valid->limit ) + FT_INVALID_TOO_SHORT; + p = table + 2; + length = TT_NEXT_USHORT( p ); +/* skip language and start index */ + p = table + 8; + count = TT_NEXT_USHORT( p ); + if ( table + length > valid->limit || length < 10 + count * 2 ) + FT_INVALID_TOO_SHORT; +/* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx = (FT_UInt)( char_code - start ); + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap6_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx; + if ( char_code >= 0x10000UL ) + goto Exit; + if ( char_code < start ) + char_code = start; + idx = (FT_UInt)( char_code - start ); + p += 2 * idx; + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + result = char_code; + break; + } + char_code++; + } + Exit: + *pchar_code = result; + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + cmap_info->format = 6; + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap6_class_rec, + sizeof ( TT_CMapRec ), + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap6_char_index, + (FT_CMap_CharNextFunc) tt_cmap6_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 6, + (TT_CMap_ValidateFunc)tt_cmap6_validate, + (TT_CMap_Info_GetFunc)tt_cmap6_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 8 *****/ +/***** *****/ +/***** It is hard to completely understand what the OpenType spec *****/ +/***** says about this format, but here is my conclusion. *****/ +/***** *****/ +/***** The purpose of this format is to easily map UTF-16 text to *****/ +/***** glyph indices. Basically, the `char_code' must be in one of *****/ +/***** the following formats: *****/ +/***** *****/ +/***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ +/***** Area (i.e. U+D800-U+DFFF). *****/ +/***** *****/ +/***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ +/***** `char_code = (char_hi << 16) | char_lo', then both *****/ +/***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ +/***** Area. *****/ +/***** *****/ +/***** The `is32' table embedded in the charmap indicates whether a *****/ +/***** given 16-bit value is in the surrogates area or not. *****/ +/***** *****/ +/***** So, for any given `char_code', we can assert the following: *****/ +/***** *****/ +/***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ +/***** *****/ +/***** If `char_hi != 0' then we must have both *****/ +/***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 8 */ +/* reserved 2 USHORT reserved */ +/* length 4 ULONG length in bytes */ +/* language 8 ULONG Mac language code */ +/* is32 12 BYTE[8192] 32-bitness bitmap */ +/* count 8204 ULONG number of groups */ +/* */ +/* This header is followed by `count' groups of the following format: */ +/* */ +/* start 0 ULONG first charcode */ +/* end 4 ULONG last charcode */ +/* startId 8 ULONG start glyph ID for the group */ +/* */ + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_Byte* is32; + FT_UInt32 length; + FT_UInt32 num_groups; + if ( table + 16 + 8192 > valid->limit ) + FT_INVALID_TOO_SHORT; + length = TT_NEXT_ULONG( p ); + if ( length > (FT_UInt32)( valid->limit - table ) || length < 8192 + 16 ) + FT_INVALID_TOO_SHORT; + is32 = table + 12; +/* skip `is32' array */ + p = is32 + 8192; + num_groups = TT_NEXT_ULONG( p ); + if ( p + num_groups * 12 > valid->limit ) + FT_INVALID_TOO_SHORT; +/* check groups, they must be in increasing order */ + { + FT_UInt32 n, start, end, start_id, count, last = 0; + for ( n = 0; n < num_groups; n++ ) + { + FT_UInt hi, lo; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + if ( start > end ) + FT_INVALID_DATA; + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + count = (FT_UInt32)( end - start + 1 ); + if ( start & ~0xFFFFU ) + { +/* start_hi != 0; check that is32[i] is 1 for each i in */ +/* the `hi' and `lo' of the range [start..end] */ + for ( ; count > 0; count--, start++ ) + { + hi = (FT_UInt)( start >> 16 ); + lo = (FT_UInt)( start & 0xFFFFU ); + if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + } + } + else + { +/* start_hi == 0; check that is32[i] is 0 for each i in */ +/* the range [start..end] */ +/* end_hi cannot be != 0! */ + if ( end & ~0xFFFFU ) + FT_INVALID_DATA; + for ( ; count > 0; count--, start++ ) + { + lo = (FT_UInt)( start & 0xFFFFU ); + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) + FT_INVALID_DATA; + } + } + } + last = end; + } + } + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + if ( char_code < start ) + break; + if ( char_code <= end ) + { + result = (FT_UInt)( start_id + char_code - start ); + break; + } + } + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap8_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* table = cmap->data; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + p = table + 8208; + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + if ( char_code < start ) + char_code = start; + if ( char_code <= end ) + { + gindex = (FT_UInt)( char_code - start + start_id ); + if ( gindex != 0 ) + { + result = char_code; + goto Exit; + } + } + } + Exit: + *pchar_code = result; + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + cmap_info->format = 8; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap8_class_rec, + sizeof ( TT_CMapRec ), + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap8_char_index, + (FT_CMap_CharNextFunc) tt_cmap8_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 8, + (TT_CMap_ValidateFunc)tt_cmap8_validate, + (TT_CMap_Info_GetFunc)tt_cmap8_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 10 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 10 */ +/* reserved 2 USHORT reserved */ +/* length 4 ULONG length in bytes */ +/* language 8 ULONG Mac language code */ +/* */ +/* start 12 ULONG first char in range */ +/* count 16 ULONG number of chars in range */ +/* glyphIds 20 USHORT[count] glyph indices covered */ +/* */ + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_ULong length, count; + if ( table + 20 > valid->limit ) + FT_INVALID_TOO_SHORT; + length = TT_NEXT_ULONG( p ); + p = table + 16; + count = TT_NEXT_ULONG( p ); + if ( length > (FT_ULong)( valid->limit - table ) || + length < 20 + count * 2 ) + FT_INVALID_TOO_SHORT; +/* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx = (FT_ULong)( char_code - start ); + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap10_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + if ( char_code < start ) + char_code = start; + idx = (FT_UInt32)( char_code - start ); + p += 2 * idx; + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + break; + char_code++; + } + *pchar_code = char_code; + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + cmap_info->format = 10; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap10_class_rec, + sizeof ( TT_CMapRec ), + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap10_char_index, + (FT_CMap_CharNextFunc) tt_cmap10_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 10, + (TT_CMap_ValidateFunc)tt_cmap10_validate, + (TT_CMap_Info_GetFunc)tt_cmap10_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 12 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 12 */ +/* reserved 2 USHORT reserved */ +/* length 4 ULONG length in bytes */ +/* language 8 ULONG Mac language code */ +/* count 12 ULONG number of groups */ +/* 16 */ +/* */ +/* This header is followed by `count' groups of the following format: */ +/* */ +/* start 0 ULONG first charcode */ +/* end 4 ULONG last charcode */ +/* startId 8 ULONG start glyph ID for the group */ +/* */ + typedef struct TT_CMap12Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + } TT_CMap12Rec, *TT_CMap12; + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_init( TT_CMap12 cmap, + FT_Byte* table ) + { + cmap->cmap.data = table; + table += 12; + cmap->num_groups = FT_PEEK_ULONG( table ); + cmap->valid = 0; + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + p = table + 4; + length = TT_NEXT_ULONG( p ); + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + if ( length > (FT_ULong)( valid->limit - table ) || + length < 16 + 12 * num_groups ) + FT_INVALID_TOO_SHORT; +/* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, start_id, last = 0; + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + if ( start > end ) + FT_INVALID_DATA; + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + last = end; + } + } + return SFNT_Err_Ok; + } +/* search the index of the charcode next to cmap->cur_charcode */ +/* cmap->cur_group should be set up properly by caller */ +/* */ + static void + tt_cmap12_next( TT_CMap12 cmap ) + { + FT_Byte* p; + FT_ULong start, end, start_id, char_code; + FT_ULong n; + FT_UInt gindex; + if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) + goto Fail; + char_code = cmap->cur_charcode + 1; + n = cmap->cur_group; + for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + { + p = cmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_PEEK_ULONG( p ); + if ( char_code < start ) + char_code = start; + for ( ; char_code <= end; char_code++ ) + { + gindex = (FT_UInt)( start_id + char_code - start ); + if ( gindex ) + { + cmap->cur_charcode = char_code;; + cmap->cur_gindex = gindex; + cmap->cur_group = n; + return; + } + } + } + Fail: + cmap->valid = 0; + } + static FT_UInt + tt_cmap12_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code; + FT_UInt32 start, end, start_id; + FT_UInt32 max, min, mid; + if ( !num_groups ) + return 0; +/* make compiler happy */ + mid = num_groups; + end = 0xFFFFFFFFUL; + if ( next ) + char_code++; + min = 0; + max = num_groups; +/* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + start_id = TT_PEEK_ULONG( p ); + gindex = (FT_UInt)( start_id + char_code - start ); + break; + } + } + if ( next ) + { + TT_CMap12 cmap12 = (TT_CMap12)cmap; +/* if `char_code' is not in any group, then `mid' is */ +/* the group nearest to `char_code' */ +/* */ + if ( char_code > end ) + { + mid++; + if ( mid == num_groups ) + return 0; + } + cmap12->valid = 1; + cmap12->cur_charcode = char_code; + cmap12->cur_group = mid; + if ( !gindex ) + { + tt_cmap12_next( cmap12 ); + if ( cmap12->valid ) + gindex = cmap12->cur_gindex; + } + else + cmap12->cur_gindex = gindex; + if ( gindex ) + *pchar_code = cmap12->cur_charcode; + } + return gindex; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + return tt_cmap12_char_map_binary( cmap, &char_code, 0 ); + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap12_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + TT_CMap12 cmap12 = (TT_CMap12)cmap; + FT_ULong gindex; + if ( cmap12->cur_charcode >= 0xFFFFFFFFUL ) + return 0; +/* no need to search */ + if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) + { + tt_cmap12_next( cmap12 ); + if ( cmap12->valid ) + { + gindex = cmap12->cur_gindex; +/* XXX: check cur_charcode overflow is expected */ + if ( gindex ) + *pchar_code = (FT_UInt32)cmap12->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 ); +/* XXX: check gindex overflow is expected */ + return (FT_UInt32)gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + cmap_info->format = 12; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap12_class_rec, + sizeof ( TT_CMap12Rec ), + (FT_CMap_InitFunc) tt_cmap12_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap12_char_index, + (FT_CMap_CharNextFunc) tt_cmap12_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 12, + (TT_CMap_ValidateFunc)tt_cmap12_validate, + (TT_CMap_Info_GetFunc)tt_cmap12_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 13 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 13 */ +/* reserved 2 USHORT reserved */ +/* length 4 ULONG length in bytes */ +/* language 8 ULONG Mac language code */ +/* count 12 ULONG number of groups */ +/* 16 */ +/* */ +/* This header is followed by `count' groups of the following format: */ +/* */ +/* start 0 ULONG first charcode */ +/* end 4 ULONG last charcode */ +/* glyphId 8 ULONG glyph ID for the whole group */ +/* */ + typedef struct TT_CMap13Rec_ + { + TT_CMapRec cmap; + FT_Bool valid; + FT_ULong cur_charcode; + FT_UInt cur_gindex; + FT_ULong cur_group; + FT_ULong num_groups; + } TT_CMap13Rec, *TT_CMap13; + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_init( TT_CMap13 cmap, + FT_Byte* table ) + { + cmap->cmap.data = table; + table += 12; + cmap->num_groups = FT_PEEK_ULONG( table ); + cmap->valid = 0; + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + p = table + 4; + length = TT_NEXT_ULONG( p ); + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + if ( length > (FT_ULong)( valid->limit - table ) || + length < 16 + 12 * num_groups ) + FT_INVALID_TOO_SHORT; +/* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, glyph_id, last = 0; + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + glyph_id = TT_NEXT_ULONG( p ); + if ( start > end ) + FT_INVALID_DATA; + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( glyph_id >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + last = end; + } + } + return SFNT_Err_Ok; + } +/* search the index of the charcode next to cmap->cur_charcode */ +/* cmap->cur_group should be set up properly by caller */ +/* */ + static void + tt_cmap13_next( TT_CMap13 cmap ) + { + FT_Byte* p; + FT_ULong start, end, glyph_id, char_code; + FT_ULong n; + FT_UInt gindex; + if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) + goto Fail; + char_code = cmap->cur_charcode + 1; + n = cmap->cur_group; + for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + { + p = cmap->cmap.data + 16 + 12 * n; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + glyph_id = TT_PEEK_ULONG( p ); + if ( char_code < start ) + char_code = start; + if ( char_code <= end ) + { + gindex = (FT_UInt)glyph_id; + if ( gindex ) + { + cmap->cur_charcode = char_code;; + cmap->cur_gindex = gindex; + cmap->cur_group = n; + return; + } + } + } + Fail: + cmap->valid = 0; + } + static FT_UInt + tt_cmap13_char_map_binary( TT_CMap cmap, + FT_UInt32* pchar_code, + FT_Bool next ) + { + FT_UInt gindex = 0; + FT_Byte* p = cmap->data + 12; + FT_UInt32 num_groups = TT_PEEK_ULONG( p ); + FT_UInt32 char_code = *pchar_code; + FT_UInt32 start, end; + FT_UInt32 max, min, mid; + if ( !num_groups ) + return 0; +/* make compiler happy */ + mid = num_groups; + end = 0xFFFFFFFFUL; + if ( next ) + char_code++; + min = 0; + max = num_groups; +/* binary search */ + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = cmap->data + 16 + 12 * mid; + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + if ( char_code < start ) + max = mid; + else if ( char_code > end ) + min = mid + 1; + else + { + gindex = (FT_UInt)TT_PEEK_ULONG( p ); + break; + } + } + if ( next ) + { + TT_CMap13 cmap13 = (TT_CMap13)cmap; +/* if `char_code' is not in any group, then `mid' is */ +/* the group nearest to `char_code' */ + if ( char_code > end ) + { + mid++; + if ( mid == num_groups ) + return 0; + } + cmap13->valid = 1; + cmap13->cur_charcode = char_code; + cmap13->cur_group = mid; + if ( !gindex ) + { + tt_cmap13_next( cmap13 ); + if ( cmap13->valid ) + gindex = cmap13->cur_gindex; + } + else + cmap13->cur_gindex = gindex; + if ( gindex ) + *pchar_code = cmap13->cur_charcode; + } + return gindex; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + return tt_cmap13_char_map_binary( cmap, &char_code, 0 ); + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap13_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + TT_CMap13 cmap13 = (TT_CMap13)cmap; + FT_UInt gindex; + if ( cmap13->cur_charcode >= 0xFFFFFFFFUL ) + return 0; +/* no need to search */ + if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) + { + tt_cmap13_next( cmap13 ); + if ( cmap13->valid ) + { + gindex = cmap13->cur_gindex; + if ( gindex ) + *pchar_code = cmap13->cur_charcode; + } + else + gindex = 0; + } + else + gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 ); + return gindex; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap13_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + cmap_info->format = 13; + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + return SFNT_Err_Ok; + } + FT_DEFINE_TT_CMAP( + tt_cmap13_class_rec, + sizeof ( TT_CMap13Rec ), + (FT_CMap_InitFunc) tt_cmap13_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap13_char_index, + (FT_CMap_CharNextFunc) tt_cmap13_char_next, + NULL, + NULL, + NULL, + NULL, + NULL, + 13, + (TT_CMap_ValidateFunc)tt_cmap13_validate, + (TT_CMap_Info_GetFunc)tt_cmap13_get_info ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FORMAT 14 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* TABLE OVERVIEW */ +/* -------------- */ +/* */ +/* NAME OFFSET TYPE DESCRIPTION */ +/* */ +/* format 0 USHORT must be 14 */ +/* length 2 ULONG table length in bytes */ +/* numSelector 6 ULONG number of variation sel. records */ +/* */ +/* Followed by numSelector records, each of which looks like */ +/* */ +/* varSelector 0 UINT24 Unicode codepoint of sel. */ +/* defaultOff 3 ULONG offset to a default UVS table */ +/* describing any variants to be found in */ +/* the normal Unicode subtable. */ +/* nonDefOff 7 ULONG offset to a non-default UVS table */ +/* describing any variants not in the */ +/* standard cmap, with GIDs here */ +/* (either offset may be 0 NULL) */ +/* */ +/* Selectors are sorted by code point. */ +/* */ +/* A default Unicode Variation Selector (UVS) subtable is just a list of */ +/* ranges of code points which are to be found in the standard cmap. No */ +/* glyph IDs (GIDs) here. */ +/* */ +/* numRanges 0 ULONG number of ranges following */ +/* */ +/* A range looks like */ +/* */ +/* uniStart 0 UINT24 code point of the first character in */ +/* this range */ +/* additionalCnt 3 UBYTE count of additional characters in this */ +/* range (zero means a range of a single */ +/* character) */ +/* */ +/* Ranges are sorted by `uniStart'. */ +/* */ +/* A non-default Unicode Variation Selector (UVS) subtable is a list of */ +/* mappings from codepoint to GID. */ +/* */ +/* numMappings 0 ULONG number of mappings */ +/* */ +/* A range looks like */ +/* */ +/* uniStart 0 UINT24 code point of the first character in */ +/* this range */ +/* GID 3 USHORT and its GID */ +/* */ +/* Ranges are sorted by `uniStart'. */ + typedef struct TT_CMap14Rec_ + { + TT_CMapRec cmap; + FT_ULong num_selectors; +/* This array is used to store the results of various + * cmap 14 query functions. The data is overwritten + * on each call to these functions. + */ + FT_UInt32 max_results; + FT_UInt32* results; + FT_Memory memory; + } TT_CMap14Rec, *TT_CMap14; + FT_CALLBACK_DEF( void ) + tt_cmap14_done( TT_CMap14 cmap ) + { + FT_Memory memory = cmap->memory; + cmap->max_results = 0; + if ( memory != NULL && cmap->results != NULL ) + FT_FREE( cmap->results ); + } + static FT_Error + tt_cmap14_ensure( TT_CMap14 cmap, + FT_UInt32 num_results, + FT_Memory memory ) + { + FT_UInt32 old_max = cmap->max_results; + FT_Error error = SFNT_Err_Ok; + if ( num_results > cmap->max_results ) + { + cmap->memory = memory; + if ( FT_QRENEW_ARRAY( cmap->results, old_max, num_results ) ) + return error; + cmap->max_results = num_results; + } + return error; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_init( TT_CMap14 cmap, + FT_Byte* table ) + { + cmap->cmap.data = table; + table += 6; + cmap->num_selectors = FT_PEEK_ULONG( table ); + cmap->max_results = 0; + cmap->results = NULL; + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; + FT_ULong length = TT_NEXT_ULONG( p ); + FT_ULong num_selectors = TT_NEXT_ULONG( p ); + if ( length > (FT_ULong)( valid->limit - table ) || + length < 10 + 11 * num_selectors ) + FT_INVALID_TOO_SHORT; +/* check selectors, they must be in increasing order */ + { +/* we start lastVarSel at 1 because a variant selector value of 0 + * isn't valid. + */ + FT_ULong n, lastVarSel = 1; + for ( n = 0; n < num_selectors; n++ ) + { + FT_ULong varSel = TT_NEXT_UINT24( p ); + FT_ULong defOff = TT_NEXT_ULONG( p ); + FT_ULong nondefOff = TT_NEXT_ULONG( p ); + if ( defOff >= length || nondefOff >= length ) + FT_INVALID_TOO_SHORT; + if ( varSel < lastVarSel ) + FT_INVALID_DATA; + lastVarSel = varSel + 1; +/* check the default table (these glyphs should be reached */ +/* through the normal Unicode cmap, no GIDs, just check order) */ + if ( defOff != 0 ) + { + FT_Byte* defp = table + defOff; + FT_ULong numRanges = TT_NEXT_ULONG( defp ); + FT_ULong i; + FT_ULong lastBase = 0; + if ( defp + numRanges * 4 > valid->limit ) + FT_INVALID_TOO_SHORT; + for ( i = 0; i < numRanges; ++i ) + { + FT_ULong base = TT_NEXT_UINT24( defp ); + FT_ULong cnt = FT_NEXT_BYTE( defp ); +/* end of Unicode */ + if ( base + cnt >= 0x110000UL ) + FT_INVALID_DATA; + if ( base < lastBase ) + FT_INVALID_DATA; + lastBase = base + cnt + 1U; + } + } +/* and the non-default table (these glyphs are specified here) */ + if ( nondefOff != 0 ) + { + FT_Byte* ndp = table + nondefOff; + FT_ULong numMappings = TT_NEXT_ULONG( ndp ); + FT_ULong i, lastUni = 0; + if ( numMappings * 4 > (FT_ULong)( valid->limit - ndp ) ) + FT_INVALID_TOO_SHORT; + for ( i = 0; i < numMappings; ++i ) + { + FT_ULong uni = TT_NEXT_UINT24( ndp ); + FT_ULong gid = TT_NEXT_USHORT( ndp ); +/* end of Unicode */ + if ( uni >= 0x110000UL ) + FT_INVALID_DATA; + if ( uni < lastUni ) + FT_INVALID_DATA; + lastUni = uni + 1U; + if ( valid->level >= FT_VALIDATE_TIGHT && + gid >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + return SFNT_Err_Ok; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_UNUSED( cmap ); + FT_UNUSED( char_code ); +/* This can't happen */ + return 0; + } + FT_CALLBACK_DEF( FT_UInt32 ) + tt_cmap14_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UNUSED( cmap ); +/* This can't happen */ + *pchar_code = 0; + return 0; + } + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_UNUSED( cmap ); + cmap_info->format = 14; +/* subtable 14 does not define a language field */ + cmap_info->language = 0xFFFFFFFFUL; + return SFNT_Err_Ok; + } + static FT_UInt + tt_cmap14_char_map_def_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_UInt32 numRanges = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + min = 0; + max = numRanges; + base += 4; +/* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 4 * mid; + FT_ULong start = TT_NEXT_UINT24( p ); + FT_UInt cnt = FT_NEXT_BYTE( p ); + if ( char_code < start ) + max = mid; + else if ( char_code > start+cnt ) + min = mid + 1; + else + return TRUE; + } + return FALSE; + } + static FT_UInt + tt_cmap14_char_map_nondef_binary( FT_Byte *base, + FT_UInt32 char_code ) + { + FT_UInt32 numMappings = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + min = 0; + max = numMappings; + base += 4; +/* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 5 * mid; + FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); + if ( char_code < uni ) + max = mid; + else if ( char_code > uni ) + min = mid + 1; + else + return TT_PEEK_USHORT( p ); + } + return 0; + } + static FT_Byte* + tt_cmap14_find_variant( FT_Byte *base, + FT_UInt32 variantCode ) + { + FT_UInt32 numVar = TT_PEEK_ULONG( base ); + FT_UInt32 max, min; + min = 0; + max = numVar; + base += 4; +/* binary search */ + while ( min < max ) + { + FT_UInt32 mid = ( min + max ) >> 1; + FT_Byte* p = base + 11 * mid; + FT_ULong varSel = TT_NEXT_UINT24( p ); + if ( variantCode < varSel ) + max = mid; + else if ( variantCode > varSel ) + min = mid + 1; + else + return p; + } + return NULL; + } + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_var_index( TT_CMap cmap, + TT_CMap ucmap, + FT_UInt32 charcode, + FT_UInt32 variantSelector ) + { + FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); + FT_ULong defOff; + FT_ULong nondefOff; + if ( !p ) + return 0; + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_PEEK_ULONG( p ); + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) + { +/* This is the default variant of this charcode. GID not stored */ +/* here; stored in the normal Unicode charmap instead. */ + return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode ); + } + if ( nondefOff != 0 ) + return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, + charcode ); + return 0; + } + FT_CALLBACK_DEF( FT_Int ) + tt_cmap14_char_var_isdefault( TT_CMap cmap, + FT_UInt32 charcode, + FT_UInt32 variantSelector ) + { + FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); + FT_ULong defOff; + FT_ULong nondefOff; + if ( !p ) + return -1; + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) + return 1; + if ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, + charcode ) != 0 ) + return 0; + return -1; + } + FT_CALLBACK_DEF( FT_UInt32* ) + tt_cmap14_variants( TT_CMap cmap, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14)cmap; + FT_UInt32 count = cmap14->num_selectors; + FT_Byte* p = cmap->data + 10; + FT_UInt32* result; + FT_UInt32 i; + if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) + return NULL; + result = cmap14->results; + for ( i = 0; i < count; ++i ) + { + result[i] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 8; + } + result[i] = 0; + return result; + } + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_char_variants( TT_CMap cmap, + FT_Memory memory, + FT_UInt32 charCode ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 count = cmap14->num_selectors; + FT_Byte* p = cmap->data + 10; + FT_UInt32* q; + if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) + return NULL; + for ( q = cmap14->results; count > 0; --count ) + { + FT_UInt32 varSel = TT_NEXT_UINT24( p ); + FT_ULong defOff = TT_NEXT_ULONG( p ); + FT_ULong nondefOff = TT_NEXT_ULONG( p ); + if ( ( defOff != 0 && + tt_cmap14_char_map_def_binary( cmap->data + defOff, + charCode ) ) || + ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, + charCode ) != 0 ) ) + { + q[0] = varSel; + q++; + } + } + q[0] = 0; + return cmap14->results; + } + static FT_UInt + tt_cmap14_def_char_count( FT_Byte *p ) + { + FT_UInt32 numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); + FT_UInt tot = 0; +/* point to the first `cnt' field */ + p += 3; + for ( ; numRanges > 0; numRanges-- ) + { + tot += 1 + p[0]; + p += 4; + } + return tot; + } + static FT_UInt32* + tt_cmap14_get_def_chars( TT_CMap cmap, + FT_Byte* p, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numRanges; + FT_UInt cnt; + FT_UInt32* q; + cnt = tt_cmap14_def_char_count( p ); + numRanges = (FT_UInt32)TT_NEXT_ULONG( p ); + if ( tt_cmap14_ensure( cmap14, ( cnt + 1 ), memory ) ) + return NULL; + for ( q = cmap14->results; numRanges > 0; --numRanges ) + { + FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); + cnt = FT_NEXT_BYTE( p ) + 1; + do + { + q[0] = uni; + uni += 1; + q += 1; + } while ( --cnt != 0 ); + } + q[0] = 0; + return cmap14->results; + } + static FT_UInt32* + tt_cmap14_get_nondef_chars( TT_CMap cmap, + FT_Byte *p, + FT_Memory memory ) + { + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numMappings; + FT_UInt i; + FT_UInt32 *ret; + numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); + if ( tt_cmap14_ensure( cmap14, ( numMappings + 1 ), memory ) ) + return NULL; + ret = cmap14->results; + for ( i = 0; i < numMappings; ++i ) + { + ret[i] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + } + ret[i] = 0; + return ret; + } + FT_CALLBACK_DEF( FT_UInt32 * ) + tt_cmap14_variant_chars( TT_CMap cmap, + FT_Memory memory, + FT_UInt32 variantSelector ) + { + FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6, + variantSelector ); + FT_UInt32 *ret; + FT_Int i; + FT_ULong defOff; + FT_ULong nondefOff; + if ( !p ) + return NULL; + defOff = TT_NEXT_ULONG( p ); + nondefOff = TT_NEXT_ULONG( p ); + if ( defOff == 0 && nondefOff == 0 ) + return NULL; + if ( defOff == 0 ) + return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, + memory ); + else if ( nondefOff == 0 ) + return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, + memory ); + else + { +/* Both a default and a non-default glyph set? That's probably not */ +/* good font design, but the spec allows for it... */ + TT_CMap14 cmap14 = (TT_CMap14) cmap; + FT_UInt32 numRanges; + FT_UInt32 numMappings; + FT_UInt32 duni; + FT_UInt32 dcnt; + FT_UInt32 nuni; + FT_Byte* dp; + FT_UInt di, ni, k; + p = cmap->data + nondefOff; + dp = cmap->data + defOff; + numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); + dcnt = tt_cmap14_def_char_count( dp ); + numRanges = (FT_UInt32)TT_NEXT_ULONG( dp ); + if ( numMappings == 0 ) + return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, + memory ); + if ( dcnt == 0 ) + return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, + memory ); + if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) + return NULL; + ret = cmap14->results; + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + di = 1; + nuni = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + ni = 1; + i = 0; + for ( ;; ) + { + if ( nuni > duni + dcnt ) + { + for ( k = 0; k <= dcnt; ++k ) + ret[i++] = duni + k; + ++di; + if ( di > numRanges ) + break; + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + } + else + { + if ( nuni < duni ) + ret[i++] = nuni; +/* If it is within the default range then ignore it -- */ +/* that should not have happened */ + ++ni; + if ( ni > numMappings ) + break; + nuni = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + } + } + if ( ni <= numMappings ) + { +/* If we get here then we have run out of all default ranges. */ +/* We have read one non-default mapping which we haven't stored */ +/* and there may be others that need to be read. */ + ret[i++] = nuni; + while ( ni < numMappings ) + { + ret[i++] = (FT_UInt32)TT_NEXT_UINT24( p ); + p += 2; + ++ni; + } + } + else if ( di <= numRanges ) + { +/* If we get here then we have run out of all non-default */ +/* mappings. We have read one default range which we haven't */ +/* stored and there may be others that need to be read. */ + for ( k = 0; k <= dcnt; ++k ) + ret[i++] = duni + k; + while ( di < numRanges ) + { + duni = (FT_UInt32)TT_NEXT_UINT24( dp ); + dcnt = FT_NEXT_BYTE( dp ); + for ( k = 0; k <= dcnt; ++k ) + ret[i++] = duni + k; + ++di; + } + } + ret[i] = 0; + return ret; + } + } + FT_DEFINE_TT_CMAP( + tt_cmap14_class_rec, + sizeof ( TT_CMap14Rec ), + (FT_CMap_InitFunc) tt_cmap14_init, + (FT_CMap_DoneFunc) tt_cmap14_done, + (FT_CMap_CharIndexFunc)tt_cmap14_char_index, + (FT_CMap_CharNextFunc) tt_cmap14_char_next, +/* Format 14 extension functions */ + (FT_CMap_CharVarIndexFunc) tt_cmap14_char_var_index, + (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault, + (FT_CMap_VariantListFunc) tt_cmap14_variants, + (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants, + (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars, + 14, + (TT_CMap_ValidateFunc)tt_cmap14_validate, + (TT_CMap_Info_GetFunc)tt_cmap14_get_info ) + static const TT_CMap_Class tt_cmap_classes[] = + { +#define TTCMAPCITEM( a ) &a, +/***************************************************************************/ +/* */ +/* ttcmapc.h */ +/* */ +/* TT CMAP classes definitions (specification only). */ +/* */ +/* Copyright 2009 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ + TTCMAPCITEM( tt_cmap0_class_rec ) + TTCMAPCITEM( tt_cmap2_class_rec ) + TTCMAPCITEM( tt_cmap4_class_rec ) + TTCMAPCITEM( tt_cmap6_class_rec ) + TTCMAPCITEM( tt_cmap8_class_rec ) + TTCMAPCITEM( tt_cmap10_class_rec ) + TTCMAPCITEM( tt_cmap12_class_rec ) + TTCMAPCITEM( tt_cmap13_class_rec ) + TTCMAPCITEM( tt_cmap14_class_rec ) +/* END */ + NULL, + }; +/* parse the `cmap' table and build the corresponding TT_CMap objects */ +/* in the current face */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_build_cmaps( TT_Face face ) + { + FT_Byte* table = face->cmap_table; + FT_Byte* limit = table + face->cmap_size; + FT_UInt volatile num_cmaps; + FT_Byte* volatile p = table; + FT_Library library = FT_FACE_LIBRARY( face ); + FT_UNUSED( library ); + if ( !p || p + 4 > limit ) + return SFNT_Err_Invalid_Table; +/* only recognize format 0 */ + if ( TT_NEXT_USHORT( p ) != 0 ) + { + p -= 2; + FT_ERROR(( "tt_face_build_cmaps:" + " unsupported `cmap' table format = %d\n", + TT_PEEK_USHORT( p ) )); + return SFNT_Err_Invalid_Table; + } + num_cmaps = TT_NEXT_USHORT( p ); +#ifdef FT_MAX_CHARMAP_CACHEABLE + if ( num_cmaps > FT_MAX_CHARMAP_CACHEABLE ) + FT_ERROR(( "tt_face_build_cmaps: too many cmap subtables (%d)\n" + " subtable #%d and higher are loaded" + " but cannot be searched\n", + num_cmaps, FT_MAX_CHARMAP_CACHEABLE + 1 )); +#endif + for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) + { + FT_CharMapRec charmap; + FT_UInt32 offset; + charmap.platform_id = TT_NEXT_USHORT( p ); + charmap.encoding_id = TT_NEXT_USHORT( p ); + charmap.face = FT_FACE( face ); +/* will be filled later */ + charmap.encoding = FT_ENCODING_NONE; + offset = TT_NEXT_ULONG( p ); + if ( offset && offset <= face->cmap_size - 2 ) + { + FT_Byte* volatile cmap = table + offset; + volatile FT_UInt format = TT_PEEK_USHORT( cmap ); + const TT_CMap_Class* volatile pclazz = TT_CMAP_CLASSES_GET; + TT_CMap_Class volatile clazz; + for ( ; *pclazz; pclazz++ ) + { + clazz = *pclazz; + if ( clazz->format == format ) + { + volatile TT_ValidatorRec valid; + volatile FT_Error error = SFNT_Err_Ok; + ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, + FT_VALIDATE_DEFAULT ); + valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs; + if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer) == 0 ) + { +/* validate this cmap sub-table */ + error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); + } + if ( valid.validator.error == 0 ) + { + FT_CMap ttcmap; +/* It might make sense to store the single variation */ +/* selector cmap somewhere special. But it would have to be */ +/* in the public FT_FaceRec, and we can't change that. */ + if ( !FT_CMap_New( (FT_CMap_Class)clazz, + cmap, &charmap, &ttcmap ) ) + { +/* it is simpler to directly set `flags' than adding */ +/* a parameter to FT_CMap_New */ + ((TT_CMap)ttcmap)->flags = (FT_Int)error; + } + } + else + { + FT_TRACE0(( "tt_face_build_cmaps:" + " broken cmap sub-table ignored\n" )); + } + break; + } + } + if ( *pclazz == NULL ) + { + FT_TRACE0(( "tt_face_build_cmaps:" + " unsupported cmap sub-table ignored\n" )); + } + } + } + return SFNT_Err_Ok; + } + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = (FT_CMap)charmap; + TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + return clazz->get_cmap_info( charmap, cmap_info ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ttkern.c */ +/* */ +/* Load the basic TrueType kerning table. This doesn't handle */ +/* kerning data within the GPOS table at the moment. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ttkern.h */ +/* */ +/* Load the basic TrueType kerning table. This doesn't handle */ +/* kerning data within the GPOS table at the moment. */ +/* */ +/* Copyright 1996-2001, 2002, 2005, 2007 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. */ +/* */ +/***************************************************************************/ +#define __TTKERN_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ); + FT_LOCAL( void ) + tt_face_done_kern( TT_Face face ); + FT_LOCAL( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); +#define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ttkern +#undef TT_KERN_INDEX +#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + FT_LOCAL_DEF( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt nn, num_tables; + FT_UInt32 avail = 0, ordered = 0; +/* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, &table_size ); + if ( error ) + goto Exit; +/* the case of a malformed table */ + if ( table_size < 4 ) + { + FT_ERROR(( "tt_face_load_kern:" + " kerning table is too small - ignored\n" )); + error = SFNT_Err_Table_Missing; + goto Exit; + } + if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) + { + FT_ERROR(( "tt_face_load_kern:" + " could not extract kerning table\n" )); + goto Exit; + } + face->kern_table_size = table_size; + p = face->kern_table; + p_limit = p + table_size; +/* skip version */ + p += 2; + num_tables = FT_NEXT_USHORT( p ); +/* we only support up to 32 sub-tables */ + if ( num_tables > 32 ) + num_tables = 32; + for ( nn = 0; nn < num_tables; nn++ ) + { + FT_UInt num_pairs, length, coverage; + FT_Byte* p_next; + FT_UInt32 mask = (FT_UInt32)1UL << nn; + if ( p + 6 > p_limit ) + break; + p_next = p; +/* skip version */ + p += 2; + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + if ( length <= 6 ) + break; + p_next += length; +/* handle broken table */ + if ( p_next > p_limit ) + p_next = p_limit; +/* only use horizontal kerning tables */ + if ( ( coverage & ~8 ) != 0x0001 || + p + 8 > p_limit ) + goto NextTable; + num_pairs = FT_NEXT_USHORT( p ); + p += 6; +/* handle broken count */ + if ( ( p_next - p ) < 6 * (int)num_pairs ) + num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); + avail |= mask; +/* + * Now check whether the pairs in this table are ordered. + * We then can use binary search. + */ + if ( num_pairs > 0 ) + { + FT_ULong count; + FT_ULong old_pair; + old_pair = FT_NEXT_ULONG( p ); + p += 2; + for ( count = num_pairs - 1; count > 0; count-- ) + { + FT_UInt32 cur_pair; + cur_pair = FT_NEXT_ULONG( p ); + if ( cur_pair <= old_pair ) + break; + p += 2; + old_pair = cur_pair; + } + if ( count == 0 ) + ordered |= mask; + } + NextTable: + p = p_next; + } + face->num_kern_tables = nn; + face->kern_avail_bits = avail; + face->kern_order_bits = ordered; + Exit: + return error; + } + FT_LOCAL_DEF( void ) + tt_face_done_kern( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_FRAME_RELEASE( face->kern_table ); + face->kern_table_size = 0; + face->num_kern_tables = 0; + face->kern_avail_bits = 0; + face->kern_order_bits = 0; + } + FT_LOCAL_DEF( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Int result = 0; + FT_UInt count, mask = 1; + FT_Byte* p = face->kern_table; + FT_Byte* p_limit = p + face->kern_table_size; + p += 4; + mask = 0x0001; + for ( count = face->num_kern_tables; + count > 0 && p + 6 <= p_limit; + count--, mask <<= 1 ) + { + FT_Byte* base = p; + FT_Byte* next = base; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt length = FT_NEXT_USHORT( p ); + FT_UInt coverage = FT_NEXT_USHORT( p ); + FT_UInt num_pairs; + FT_Int value = 0; + FT_UNUSED( version ); + next = base + length; +/* handle broken table */ + if ( next > p_limit ) + next = p_limit; + if ( ( face->kern_avail_bits & mask ) == 0 ) + goto NextTable; + if ( p + 8 > next ) + goto NextTable; + num_pairs = FT_NEXT_USHORT( p ); + p += 6; +/* handle broken count */ + if ( ( next - p ) < 6 * (int)num_pairs ) + num_pairs = (FT_UInt)( ( next - p ) / 6 ); + switch ( coverage >> 8 ) + { + case 0: + { + FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); +/* binary search */ + if ( face->kern_order_bits & mask ) + { + FT_UInt min = 0; + FT_UInt max = num_pairs; + while ( min < max ) + { + FT_UInt mid = ( min + max ) >> 1; + FT_Byte* q = p + 6 * mid; + FT_ULong key; + key = FT_NEXT_ULONG( q ); + if ( key == key0 ) + { + value = FT_PEEK_SHORT( q ); + goto Found; + } + if ( key < key0 ) + min = mid + 1; + else + max = mid; + } + } +/* linear search */ + else + { + FT_UInt count2; + for ( count2 = num_pairs; count2 > 0; count2-- ) + { + FT_ULong key = FT_NEXT_ULONG( p ); + if ( key == key0 ) + { + value = FT_PEEK_SHORT( p ); + goto Found; + } + p += 2; + } + } + } + break; +/* + * We don't support format 2 because we haven't seen a single font + * using it in real life... + */ + default: + ; + } + goto NextTable; + Found: +/* override or add */ + if ( coverage & 8 ) + result = value; + else + result += value; + NextTable: + p = next; + } + return result; + } +#undef TT_KERN_INDEX +/* END */ +/***************************************************************************/ +/* */ +/* sfobjs.c */ +/* */ +/* SFNT object management (base). */ +/* */ +/* Copyright 1996-2008, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* sfobjs.h */ +/* */ +/* SFNT object management (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ +#define __SFOBJS_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) + sfnt_done_face( TT_Face face ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttbdf.h */ +/* */ +/* TrueType and OpenType embedded BDF properties (specification). */ +/* */ +/* Copyright 2005 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. */ +/* */ +/***************************************************************************/ +#define __TTBDF_H__ +FT_BEGIN_HEADER + FT_LOCAL( void ) + tt_face_free_bdf_props( TT_Face face ); + FT_LOCAL( FT_Error ) + tt_face_find_bdf_prop( TT_Face face, + const char* property_name, + BDF_PropertyRec *aprop ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_sfobjs +/* convert a UTF-16 name entry to ASCII */ + static FT_String* + tt_name_entry_ascii_from_utf16( TT_NameEntry entry, + FT_Memory memory ) + { + FT_String* string = NULL; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + len = (FT_UInt)entry->stringLength / 2; + if ( FT_NEW_ARRAY( string, len + 1 ) ) + return NULL; + for ( n = 0; n < len; n++ ) + { + code = FT_NEXT_USHORT( read ); + if ( code == 0 ) + break; + if ( code < 32 || code > 127 ) + code = '?'; + string[n] = (char)code; + } + string[n] = 0; + return string; + } +/* convert an Apple Roman or symbol name entry to ASCII */ + static FT_String* + tt_name_entry_ascii_from_other( TT_NameEntry entry, + FT_Memory memory ) + { + FT_String* string = NULL; + FT_UInt len, code, n; + FT_Byte* read = (FT_Byte*)entry->string; + FT_Error error; + len = (FT_UInt)entry->stringLength; + if ( FT_NEW_ARRAY( string, len + 1 ) ) + return NULL; + for ( n = 0; n < len; n++ ) + { + code = *read++; + if ( code == 0 ) + break; + if ( code < 32 || code > 127 ) + code = '?'; + string[n] = (char)code; + } + string[n] = 0; + return string; + } + typedef FT_String* (*TT_NameEntry_ConvertFunc)( TT_NameEntry entry, + FT_Memory memory ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_get_name */ +/* */ +/* <Description> */ +/* Returns a given ENGLISH name record in ASCII. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* nameid :: The name id of the name record to return. */ +/* */ +/* <InOut> */ +/* name :: The address of a string pointer. NULL if no name is */ +/* present. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + static FT_Error + tt_face_get_name( TT_Face face, + FT_UShort nameid, + FT_String** name ) + { + FT_Memory memory = face->root.memory; + FT_Error error = SFNT_Err_Ok; + FT_String* result = NULL; + FT_UShort n; + TT_NameEntryRec* rec; + FT_Int found_apple = -1; + FT_Int found_apple_roman = -1; + FT_Int found_apple_english = -1; + FT_Int found_win = -1; + FT_Int found_unicode = -1; + FT_Bool is_english = 0; + TT_NameEntry_ConvertFunc convert; + FT_ASSERT( name ); + rec = face->name_table.names; + for ( n = 0; n < face->num_names; n++, rec++ ) + { +/* According to the OpenType 1.3 specification, only Microsoft or */ +/* Apple platform IDs might be used in the `name' table. The */ +/* `Unicode' platform is reserved for the `cmap' table, and the */ +/* `ISO' one is deprecated. */ +/* */ +/* However, the Apple TrueType specification doesn't say the same */ +/* thing and goes to suggest that all Unicode `name' table entries */ +/* should be coded in UTF-16 (in big-endian format I suppose). */ +/* */ + if ( rec->nameID == nameid && rec->stringLength > 0 ) + { + switch ( rec->platformID ) + { + case TT_PLATFORM_APPLE_UNICODE: + case TT_PLATFORM_ISO: +/* there is `languageID' to check there. We should use this */ +/* field only as a last solution when nothing else is */ +/* available. */ +/* */ + found_unicode = n; + break; + case TT_PLATFORM_MACINTOSH: +/* This is a bit special because some fonts will use either */ +/* an English language id, or a Roman encoding id, to indicate */ +/* the English version of its font name. */ +/* */ + if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) + found_apple_english = n; + else if ( rec->encodingID == TT_MAC_ID_ROMAN ) + found_apple_roman = n; + break; + case TT_PLATFORM_MICROSOFT: +/* we only take a non-English name when there is nothing */ +/* else available in the font */ +/* */ + if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) + { + switch ( rec->encodingID ) + { + case TT_MS_ID_SYMBOL_CS: + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_UCS_4: + is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); + found_win = n; + break; + default: + ; + } + } + break; + default: + ; + } + } + } + found_apple = found_apple_roman; + if ( found_apple_english >= 0 ) + found_apple = found_apple_english; +/* some fonts contain invalid Unicode or Macintosh formatted entries; */ +/* we will thus favor names encoded in Windows formats if available */ +/* (provided it is an English name) */ +/* */ + convert = NULL; + if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) + { + rec = face->name_table.names + found_win; + switch ( rec->encodingID ) + { +/* all Unicode strings are encoded using UTF-16BE */ + case TT_MS_ID_UNICODE_CS: + case TT_MS_ID_SYMBOL_CS: + convert = tt_name_entry_ascii_from_utf16; + break; + case TT_MS_ID_UCS_4: +/* Apparently, if this value is found in a name table entry, it is */ +/* documented as `full Unicode repertoire'. Experience with the */ +/* MsGothic font shipped with Windows Vista shows that this really */ +/* means UTF-16 encoded names (UCS-4 values are only used within */ +/* charmaps). */ + convert = tt_name_entry_ascii_from_utf16; + break; + default: + ; + } + } + else if ( found_apple >= 0 ) + { + rec = face->name_table.names + found_apple; + convert = tt_name_entry_ascii_from_other; + } + else if ( found_unicode >= 0 ) + { + rec = face->name_table.names + found_unicode; + convert = tt_name_entry_ascii_from_utf16; + } + if ( rec && convert ) + { + if ( rec->string == NULL ) + { + FT_Stream stream = face->name_table.stream; + if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || + FT_STREAM_SEEK( rec->stringOffset ) || + FT_STREAM_READ( rec->string, rec->stringLength ) ) + { + FT_FREE( rec->string ); + rec->stringLength = 0; + result = NULL; + goto Exit; + } + } + result = convert( rec, memory ); + } + Exit: + *name = result; + return error; + } + static FT_Encoding + sfnt_find_encoding( int platform_id, + int encoding_id ) + { + typedef struct TEncoding_ + { + int platform_id; + int encoding_id; + FT_Encoding encoding; + } TEncoding; + static + const TEncoding tt_encodings[] = + { + { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE }, + { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_SJIS }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, FT_ENCODING_GB2312 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_BIG5 }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_WANSUNG }, + { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_JOHAB } + }; + const TEncoding *cur, *limit; + cur = tt_encodings; + limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] ); + for ( ; cur < limit; cur++ ) + { + if ( cur->platform_id == platform_id ) + { + if ( cur->encoding_id == encoding_id || + cur->encoding_id == -1 ) + return cur->encoding; + } + } + return FT_ENCODING_NONE; + } +/* Fill in face->ttc_header. If the font is not a TTC, it is */ +/* synthesized into a TTC with one offset table. */ + static FT_Error + sfnt_open_font( FT_Stream stream, + TT_Face face ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_ULong tag, offset; + static const FT_Frame_Field ttc_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TTC_HeaderRec + FT_FRAME_START( 8 ), + FT_FRAME_LONG( version ), +/* this is ULong in the specs */ + FT_FRAME_LONG( count ), + FT_FRAME_END + }; + face->ttc_header.tag = 0; + face->ttc_header.version = 0; + face->ttc_header.count = 0; + offset = FT_STREAM_POS(); + if ( FT_READ_ULONG( tag ) ) + return error; + if ( tag != 0x00010000UL && + tag != TTAG_ttcf && + tag != TTAG_OTTO && + tag != TTAG_true && + tag != TTAG_typ1 && + tag != 0x00020000UL ) + { + FT_TRACE2(( " not a font using the SFNT container format\n" )); + return SFNT_Err_Unknown_File_Format; + } + face->ttc_header.tag = TTAG_ttcf; + if ( tag == TTAG_ttcf ) + { + FT_Int n; + FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); + if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) + return error; + if ( face->ttc_header.count == 0 ) + return SFNT_Err_Invalid_Table; +/* a rough size estimate: let's conservatively assume that there */ +/* is just a single table info in each subfont header (12 + 16*1 = */ +/* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ +/* size of the TTC header plus `28*count' bytes for all subfont */ +/* headers */ + if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) + return SFNT_Err_Array_Too_Large; +/* now read the offsets of each font in the file */ + if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + return error; + if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) + return error; + for ( n = 0; n < face->ttc_header.count; n++ ) + face->ttc_header.offsets[n] = FT_GET_ULONG(); + FT_FRAME_EXIT(); + } + else + { + FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); + face->ttc_header.version = 1 << 16; + face->ttc_header.count = 1; + if ( FT_NEW( face->ttc_header.offsets ) ) + return error; + face->ttc_header.offsets[0] = offset; + } + return error; + } + FT_LOCAL_DEF( FT_Error ) + sfnt_init_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library = face->root.driver->root.library; + SFNT_Service sfnt; +/* for now, parameters are unused */ + FT_UNUSED( num_params ); + FT_UNUSED( params ); + sfnt = (SFNT_Service)face->sfnt; + if ( !sfnt ) + { + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "sfnt_init_face: cannot access `sfnt' module\n" )); + return SFNT_Err_Missing_Module; + } + face->sfnt = sfnt; + face->goto_table = sfnt->goto_table; + } + FT_FACE_FIND_GLOBAL_SERVICE( face, face->psnames, POSTSCRIPT_CMAPS ); + FT_TRACE2(( "SFNT driver\n" )); + error = sfnt_open_font( stream, face ); + if ( error ) + return error; + FT_TRACE2(( "sfnt_init_face: %08p, %ld\n", face, face_index )); + if ( face_index < 0 ) + face_index = 0; + if ( face_index >= face->ttc_header.count ) + return SFNT_Err_Invalid_Argument; + if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ) + return error; +/* check that we have a valid TrueType file */ + error = sfnt->load_font_dir( face, stream ); + if ( error ) + return error; + face->root.num_faces = face->ttc_header.count; + face->root.face_index = face_index; + return error; + } +#define LOAD_( x ) \ + do { \ + FT_TRACE2(( "`" #x "' " )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_ ## x( face, stream ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : ( error == SFNT_Err_Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) +#define LOADM_( x, vertical ) \ + do { \ + FT_TRACE2(( "`%s" #x "' ", \ + vertical ? "vertical " : "" )); \ + FT_TRACE3(( "-->\n" )); \ + \ + error = sfnt->load_ ## x( face, stream, vertical ); \ + \ + FT_TRACE2(( "%s\n", ( !error ) \ + ? "loaded" \ + : ( error == SFNT_Err_Table_Missing ) \ + ? "missing" \ + : "failed to load" )); \ + FT_TRACE3(( "\n" )); \ + } while ( 0 ) +#define GET_NAME( id, field ) \ + do { \ + error = tt_face_get_name( face, TT_NAME_ID_ ## id, field ); \ + if ( error ) \ + goto Exit; \ + } while ( 0 ) + FT_LOCAL_DEF( FT_Error ) + sfnt_load_face( FT_Stream stream, + TT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Error psnames_error; + FT_Bool has_outline; + FT_Bool is_apple_sbit; + FT_Bool ignore_preferred_family = FALSE; + FT_Bool ignore_preferred_subfamily = FALSE; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + FT_UNUSED( face_index ); +/* Check parameters */ + { + FT_Int i; + for ( i = 0; i < num_params; i++ ) + { + if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY ) + ignore_preferred_family = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY ) + ignore_preferred_subfamily = TRUE; + } + } +/* Load tables */ +/* We now support two SFNT-based bitmapped font formats. They */ +/* are recognized easily as they do not include a `glyf' */ +/* table. */ +/* */ +/* The first format comes from Apple, and uses a table named */ +/* `bhed' instead of `head' to store the font header (using */ +/* the same format). It also doesn't include horizontal and */ +/* vertical metrics tables (i.e. `hhea' and `vhea' tables are */ +/* missing). */ +/* */ +/* The other format comes from Microsoft, and is used with */ +/* WinCE/PocketPC. It looks like a standard TTF, except that */ +/* it doesn't contain outlines. */ +/* */ + FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); +/* do we have outlines in there? */ + has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 || + tt_face_lookup_table( face, TTAG_glyf ) != 0 || + tt_face_lookup_table( face, TTAG_CFF ) != 0 ); + is_apple_sbit = 0; +/* if this font doesn't contain outlines, we try to load */ +/* a `bhed' table */ + if ( !has_outline && sfnt->load_bhed ) + { + LOAD_( bhed ); + is_apple_sbit = FT_BOOL( !error ); + } +/* load the font header (`head' table) if this isn't an Apple */ +/* sbit font file */ + if ( !is_apple_sbit ) + { + LOAD_( head ); + if ( error ) + goto Exit; + } + if ( face->header.Units_Per_EM == 0 ) + { + error = SFNT_Err_Invalid_Table; + goto Exit; + } +/* the following tables are often not present in embedded TrueType */ +/* fonts within PDF documents, so don't check for them. */ + LOAD_( maxp ); + LOAD_( cmap ); +/* the following tables are optional in PCL fonts -- */ +/* don't check for errors */ + LOAD_( name ); + LOAD_( post ); + psnames_error = error; +/* do not load the metrics headers and tables if this is an Apple */ +/* sbit font file */ + if ( !is_apple_sbit ) + { +/* load the `hhea' and `hmtx' tables */ + LOADM_( hhea, 0 ); + if ( !error ) + { + LOADM_( hmtx, 0 ); + if ( error == SFNT_Err_Table_Missing ) + { + error = SFNT_Err_Hmtx_Table_Missing; +/* If this is an incrementally loaded font and there are */ +/* overriding metrics, tolerate a missing `hmtx' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = SFNT_Err_Ok; + } + } + } + else if ( error == SFNT_Err_Table_Missing ) + { +/* No `hhea' table necessary for SFNT Mac fonts. */ + if ( face->format_tag == TTAG_true ) + { + FT_TRACE2(( "This is an SFNT Mac font.\n" )); + has_outline = 0; + error = SFNT_Err_Ok; + } + else + { + error = SFNT_Err_Horiz_Header_Missing; +/* If this is an incrementally loaded font and there are */ +/* overriding metrics, tolerate a missing `hhea' table. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs-> + get_glyph_metrics ) + { + face->horizontal.number_Of_HMetrics = 0; + error = SFNT_Err_Ok; + } + } + } + if ( error ) + goto Exit; +/* try to load the `vhea' and `vmtx' tables */ + LOADM_( hhea, 1 ); + if ( !error ) + { + LOADM_( hmtx, 1 ); + if ( !error ) + face->vertical_info = 1; + } + if ( error && error != SFNT_Err_Table_Missing ) + goto Exit; + LOAD_( os2 ); + if ( error ) + { +/* we treat the table as missing if there are any errors */ + face->os2.version = 0xFFFFU; + } + } +/* the optional tables */ +/* embedded bitmap support */ + if ( sfnt->load_eblc ) + { + LOAD_( eblc ); + if ( error ) + { +/* a font which contains neither bitmaps nor outlines is */ +/* still valid (although rather useless in most cases); */ +/* however, you can find such stripped fonts in PDFs */ + if ( error == SFNT_Err_Table_Missing ) + error = SFNT_Err_Ok; + else + goto Exit; + } + } + LOAD_( pclt ); + if ( error ) + { + if ( error != SFNT_Err_Table_Missing ) + goto Exit; + face->pclt.Version = 0; + } +/* consider the kerning and gasp tables as optional */ + LOAD_( gasp ); + LOAD_( kern ); + face->root.num_glyphs = face->max_profile.numGlyphs; +/* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ +/* a WWS-only font face. `WWS' stands for `weight', width', and */ +/* `slope', a term used by Microsoft's Windows Presentation */ +/* Foundation (WPF). This flag has been introduced in version */ +/* 1.5 of the OpenType specification (May 2008). */ + face->root.family_name = NULL; + face->root.style_name = NULL; + if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 256 ) + { + if ( !ignore_preferred_family ) + GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); + if ( !face->root.family_name ) + GET_NAME( FONT_FAMILY, &face->root.family_name ); + if ( !ignore_preferred_subfamily ) + GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name ) + GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); + } + else + { + GET_NAME( WWS_FAMILY, &face->root.family_name ); + if ( !face->root.family_name && !ignore_preferred_family ) + GET_NAME( PREFERRED_FAMILY, &face->root.family_name ); + if ( !face->root.family_name ) + GET_NAME( FONT_FAMILY, &face->root.family_name ); + GET_NAME( WWS_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name && !ignore_preferred_subfamily ) + GET_NAME( PREFERRED_SUBFAMILY, &face->root.style_name ); + if ( !face->root.style_name ) + GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); + } +/* now set up root fields */ + { + FT_Face root = &face->root; + FT_Long flags = root->face_flags; +/*********************************************************************/ +/* */ +/* Compute face flags. */ +/* */ + if ( has_outline == TRUE ) +/* scalable outlines */ + flags |= FT_FACE_FLAG_SCALABLE; +/* The sfnt driver only supports bitmap fonts natively, thus we */ +/* don't set FT_FACE_FLAG_HINTER. */ +/* SFNT file format */ + flags |= FT_FACE_FLAG_SFNT | +/* horizontal data */ + FT_FACE_FLAG_HORIZONTAL; + if ( psnames_error == SFNT_Err_Ok && + face->postscript.FormatType != 0x00030000L ) + flags |= FT_FACE_FLAG_GLYPH_NAMES; +/* fixed width font? */ + if ( face->postscript.isFixedPitch ) + flags |= FT_FACE_FLAG_FIXED_WIDTH; +/* vertical information? */ + if ( face->vertical_info ) + flags |= FT_FACE_FLAG_VERTICAL; +/* kerning available ? */ + if ( TT_FACE_HAS_KERNING( face ) ) + flags |= FT_FACE_FLAG_KERNING; +/* Don't bother to load the tables unless somebody asks for them. */ +/* No need to do work which will (probably) not be used. */ + if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && + tt_face_lookup_table( face, TTAG_fvar ) != 0 && + tt_face_lookup_table( face, TTAG_gvar ) != 0 ) + flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; + root->face_flags = flags; +/*********************************************************************/ +/* */ +/* Compute style flags. */ +/* */ + flags = 0; + if ( has_outline == TRUE && face->os2.version != 0xFFFFU ) + { +/* We have an OS/2 table; use the `fsSelection' field. Bit 9 */ +/* indicates an oblique font face. This flag has been */ +/* introduced in version 1.5 of the OpenType specification. */ +/* bit 9 */ + if ( face->os2.fsSelection & 512 ) + flags |= FT_STYLE_FLAG_ITALIC; +/* bit 0 */ + else if ( face->os2.fsSelection & 1 ) + flags |= FT_STYLE_FLAG_ITALIC; +/* bit 5 */ + if ( face->os2.fsSelection & 32 ) + flags |= FT_STYLE_FLAG_BOLD; + } + else + { +/* this is an old Mac font, use the header field */ + if ( face->header.Mac_Style & 1 ) + flags |= FT_STYLE_FLAG_BOLD; + if ( face->header.Mac_Style & 2 ) + flags |= FT_STYLE_FLAG_ITALIC; + } + root->style_flags = flags; +/*********************************************************************/ +/* */ +/* Polish the charmaps. */ +/* */ +/* Try to set the charmap encoding according to the platform & */ +/* encoding ID of each charmap. */ +/* */ +/* ignore errors */ + tt_face_build_cmaps( face ); +/* set the encoding fields */ + { + FT_Int m; + for ( m = 0; m < root->num_charmaps; m++ ) + { + FT_CharMap charmap = root->charmaps[m]; + charmap->encoding = sfnt_find_encoding( charmap->platform_id, + charmap->encoding_id ); +#if 0 + if ( root->charmap == NULL && + charmap->encoding == FT_ENCODING_UNICODE ) + { +/* set 'root->charmap' to the first Unicode encoding we find */ + root->charmap = charmap; + } +#endif + } + } +/* + * Now allocate the root array of FT_Bitmap_Size records and + * populate them. Unfortunately, it isn't possible to indicate bit + * depths in the FT_Bitmap_Size record. This is a design error. + */ + { + FT_UInt i, count; + count = face->sbit_num_strikes; + if ( count > 0 ) + { + FT_Memory memory = face->root.stream->memory; + FT_UShort em_size = face->header.Units_Per_EM; + FT_Short avgwidth = face->os2.xAvgCharWidth; + FT_Size_Metrics metrics; + if ( em_size == 0 || face->os2.version == 0xFFFFU ) + { + avgwidth = 0; + em_size = 1; + } + if ( FT_NEW_ARRAY( root->available_sizes, count ) ) + goto Exit; + for ( i = 0; i < count; i++ ) + { + FT_Bitmap_Size* bsize = root->available_sizes + i; + error = sfnt->load_strike_metrics( face, i, &metrics ); + if ( error ) + goto Exit; + bsize->height = (FT_Short)( metrics.height >> 6 ); + bsize->width = (FT_Short)( + ( avgwidth * metrics.x_ppem + em_size / 2 ) / em_size ); + bsize->x_ppem = metrics.x_ppem << 6; + bsize->y_ppem = metrics.y_ppem << 6; +/* assume 72dpi */ + bsize->size = metrics.y_ppem << 6; + } + root->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + root->num_fixed_sizes = (FT_Int)count; + } + } +/* a font with no bitmaps and no outlines is scalable; */ +/* it has only empty glyphs then */ + if ( !FT_HAS_FIXED_SIZES( root ) && !FT_IS_SCALABLE( root ) ) + root->face_flags |= FT_FACE_FLAG_SCALABLE; +/*********************************************************************/ +/* */ +/* Set up metrics. */ +/* */ + if ( FT_IS_SCALABLE( root ) ) + { +/* XXX What about if outline header is missing */ +/* (e.g. sfnt wrapped bitmap)? */ + root->bbox.xMin = face->header.xMin; + root->bbox.yMin = face->header.yMin; + root->bbox.xMax = face->header.xMax; + root->bbox.yMax = face->header.yMax; + root->units_per_EM = face->header.Units_Per_EM; +/* XXX: Computing the ascender/descender/height is very different */ +/* from what the specification tells you. Apparently, we */ +/* must be careful because */ +/* */ +/* - not all fonts have an OS/2 table; in this case, we take */ +/* the values in the horizontal header. However, these */ +/* values very often are not reliable. */ +/* */ +/* - otherwise, the correct typographic values are in the */ +/* sTypoAscender, sTypoDescender & sTypoLineGap fields. */ +/* */ +/* However, certain fonts have these fields set to 0. */ +/* Rather, they have usWinAscent & usWinDescent correctly */ +/* set (but with different values). */ +/* */ +/* As an example, Arial Narrow is implemented through four */ +/* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */ +/* */ +/* Strangely, all fonts have the same values in their */ +/* sTypoXXX fields, except ARIALNB which sets them to 0. */ +/* */ +/* On the other hand, they all have different */ +/* usWinAscent/Descent values -- as a conclusion, the OS/2 */ +/* table cannot be used to compute the text height reliably! */ +/* */ +/* The ascender and descender are taken from the `hhea' table. */ +/* If zero, they are taken from the `OS/2' table. */ + root->ascender = face->horizontal.Ascender; + root->descender = face->horizontal.Descender; + root->height = (FT_Short)( root->ascender - root->descender + + face->horizontal.Line_Gap ); + if ( !( root->ascender || root->descender ) ) + { + if ( face->os2.version != 0xFFFFU ) + { + if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) + { + root->ascender = face->os2.sTypoAscender; + root->descender = face->os2.sTypoDescender; + root->height = (FT_Short)( root->ascender - root->descender + + face->os2.sTypoLineGap ); + } + else + { + root->ascender = (FT_Short)face->os2.usWinAscent; + root->descender = -(FT_Short)face->os2.usWinDescent; + root->height = (FT_UShort)( root->ascender - root->descender ); + } + } + } + root->max_advance_width = face->horizontal.advance_Width_Max; + root->max_advance_height = (FT_Short)( face->vertical_info + ? face->vertical.advance_Height_Max + : root->height ); +/* See http://www.microsoft.com/OpenType/OTSpec/post.htm -- */ +/* Adjust underline position from top edge to centre of */ +/* stroke to convert TrueType meaning to FreeType meaning. */ + root->underline_position = face->postscript.underlinePosition - + face->postscript.underlineThickness / 2; + root->underline_thickness = face->postscript.underlineThickness; + } + } + Exit: + FT_TRACE2(( "sfnt_load_face: done\n" )); + return error; + } +#undef LOAD_ +#undef LOADM_ +#undef GET_NAME + FT_LOCAL_DEF( void ) + sfnt_done_face( TT_Face face ) + { + FT_Memory memory; + SFNT_Service sfnt; + if ( !face ) + return; + memory = face->root.memory; + sfnt = (SFNT_Service)face->sfnt; + if ( sfnt ) + { +/* destroy the postscript names table if it is loaded */ + if ( sfnt->free_psnames ) + sfnt->free_psnames( face ); +/* destroy the embedded bitmaps table if it is loaded */ + if ( sfnt->free_eblc ) + sfnt->free_eblc( face ); + } +/* freeing the embedded BDF properties */ + tt_face_free_bdf_props( face ); +/* freeing the kerning table */ + tt_face_done_kern( face ); +/* freeing the collection table */ + FT_FREE( face->ttc_header.offsets ); + face->ttc_header.count = 0; +/* freeing table directory */ + FT_FREE( face->dir_tables ); + face->num_tables = 0; + { + FT_Stream stream = FT_FACE_STREAM( face ); +/* simply release the 'cmap' table frame */ + FT_FRAME_RELEASE( face->cmap_table ); + face->cmap_size = 0; + } +/* freeing the horizontal metrics */ + { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_FRAME_RELEASE( face->horz_metrics ); + FT_FRAME_RELEASE( face->vert_metrics ); + face->horz_metrics_size = 0; + face->vert_metrics_size = 0; + } +/* freeing the vertical ones, if any */ + if ( face->vertical_info ) + { + FT_FREE( face->vertical.long_metrics ); + FT_FREE( face->vertical.short_metrics ); + face->vertical_info = 0; + } +/* freeing the gasp table */ + FT_FREE( face->gasp.gaspRanges ); + face->gasp.numRanges = 0; +/* freeing the name table */ + if ( sfnt ) + sfnt->free_name( face ); +/* freeing family and style name */ + FT_FREE( face->root.family_name ); + FT_FREE( face->root.style_name ); +/* freeing sbit size table */ + FT_FREE( face->root.available_sizes ); + face->root.num_fixed_sizes = 0; + FT_FREE( face->postscript_name ); + face->sfnt = 0; + } +/* END */ +/***************************************************************************/ +/* */ +/* sfdriver.c */ +/* */ +/* High-level SFNT driver interface (body). */ +/* */ +/* Copyright 1996-2007, 2009-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* sfdriver.h */ +/* */ +/* High-level SFNT driver interface (specification). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define __SFDRIVER_H__ +FT_BEGIN_HEADER + FT_DECLARE_MODULE( sfnt_module_class ) +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttsbit.h */ +/* */ +/* TrueType and OpenType embedded bitmap support (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. */ +/* */ +/***************************************************************************/ +#define __TTSBIT_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + tt_face_load_eblc( TT_Face face, + FT_Stream stream ); + FT_LOCAL( void ) + tt_face_free_eblc( TT_Face face ); + FT_LOCAL( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ); + FT_LOCAL( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ); + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttpost.h */ +/* */ +/* Postcript name table processing for TrueType and OpenType fonts */ +/* (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ +#define __TTPOST_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ); + FT_LOCAL( void ) + tt_face_free_ps_names( TT_Face face ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_sfdriver +/* + * SFNT TABLE SERVICE + * + */ + static void* + get_sfnt_table( TT_Face face, + FT_Sfnt_Tag tag ) + { + void* table; + switch ( tag ) + { + case ft_sfnt_head: + table = &face->header; + break; + case ft_sfnt_hhea: + table = &face->horizontal; + break; + case ft_sfnt_vhea: + table = face->vertical_info ? &face->vertical : 0; + break; + case ft_sfnt_os2: + table = face->os2.version == 0xFFFFU ? 0 : &face->os2; + break; + case ft_sfnt_post: + table = &face->postscript; + break; + case ft_sfnt_maxp: + table = &face->max_profile; + break; + case ft_sfnt_pclt: + table = face->pclt.Version ? &face->pclt : 0; + break; + default: + table = 0; + } + return table; + } + static FT_Error + sfnt_table_info( TT_Face face, + FT_UInt idx, + FT_ULong *tag, + FT_ULong *offset, + FT_ULong *length ) + { + if ( !offset || !length ) + return SFNT_Err_Invalid_Argument; + if ( !tag ) + *length = face->num_tables; + else + { + if ( idx >= face->num_tables ) + return SFNT_Err_Table_Missing; + *tag = face->dir_tables[idx].Tag; + *offset = face->dir_tables[idx].Offset; + *length = face->dir_tables[idx].Length; + } + return SFNT_Err_Ok; + } + FT_DEFINE_SERVICE_SFNT_TABLEREC( + sfnt_service_sfnt_table, + (FT_SFNT_TableLoadFunc)tt_face_load_any, + (FT_SFNT_TableGetFunc) get_sfnt_table, + (FT_SFNT_TableInfoFunc)sfnt_table_info ) +/* + * GLYPH DICT SERVICE + * + */ + static FT_Error + sfnt_get_glyph_name( TT_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_String* gname; + FT_Error error; + error = tt_face_get_ps_name( face, glyph_index, &gname ); + if ( !error ) + FT_STRCPYN( buffer, gname, buffer_max ); + return error; + } + static FT_UInt + sfnt_get_name_index( TT_Face face, + FT_String* glyph_name ) + { + FT_Face root = &face->root; + FT_UInt i, max_gid = FT_UINT_MAX; + if ( root->num_glyphs < 0 ) + return 0; + else if ( (FT_ULong)root->num_glyphs < FT_UINT_MAX ) + max_gid = (FT_UInt)root->num_glyphs; + else + FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08x\n", + FT_UINT_MAX, root->num_glyphs )); + for ( i = 0; i < max_gid; i++ ) + { + FT_String* gname; + FT_Error error = tt_face_get_ps_name( face, i, &gname ); + if ( error ) + continue; + if ( !ft_strcmp( glyph_name, gname ) ) + return i; + } + return 0; + } + FT_DEFINE_SERVICE_GLYPHDICTREC( + sfnt_service_glyph_dict, + (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index ) +/* + * POSTSCRIPT NAME SERVICE + * + */ + static const char* + sfnt_get_ps_name( TT_Face face ) + { + FT_Int n, found_win, found_apple; + const char* result = NULL; +/* shouldn't happen, but just in case to avoid memory leaks */ + if ( face->postscript_name ) + return face->postscript_name; +/* scan the name table to see whether we have a Postscript name here, */ +/* either in Macintosh or Windows platform encodings */ + found_win = -1; + found_apple = -1; + for ( n = 0; n < face->num_names; n++ ) + { + TT_NameEntryRec* name = face->name_table.names + n; + if ( name->nameID == 6 && name->stringLength > 0 ) + { + if ( name->platformID == 3 && + name->encodingID == 1 && + name->languageID == 0x409 ) + found_win = n; + if ( name->platformID == 1 && + name->encodingID == 0 && + name->languageID == 0 ) + found_apple = n; + } + } + if ( found_win != -1 ) + { + FT_Memory memory = face->root.memory; + TT_NameEntryRec* name = face->name_table.names + found_win; + FT_UInt len = name->stringLength / 2; + FT_Error error = SFNT_Err_Ok; + FT_UNUSED( error ); + if ( !FT_ALLOC( result, name->stringLength + 1 ) ) + { + FT_Stream stream = face->name_table.stream; + FT_String* r = (FT_String*)result; + FT_Byte* p = (FT_Byte*)name->string; + if ( FT_STREAM_SEEK( name->stringOffset ) || + FT_FRAME_ENTER( name->stringLength ) ) + { + FT_FREE( result ); + name->stringLength = 0; + name->stringOffset = 0; + FT_FREE( name->string ); + goto Exit; + } + p = (FT_Byte*)stream->cursor; + for ( ; len > 0; len--, p += 2 ) + { + if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 ) + *r++ = p[1]; + } + *r = '\0'; + FT_FRAME_EXIT(); + } + goto Exit; + } + if ( found_apple != -1 ) + { + FT_Memory memory = face->root.memory; + TT_NameEntryRec* name = face->name_table.names + found_apple; + FT_UInt len = name->stringLength; + FT_Error error = SFNT_Err_Ok; + FT_UNUSED( error ); + if ( !FT_ALLOC( result, len + 1 ) ) + { + FT_Stream stream = face->name_table.stream; + if ( FT_STREAM_SEEK( name->stringOffset ) || + FT_STREAM_READ( result, len ) ) + { + name->stringOffset = 0; + name->stringLength = 0; + FT_FREE( name->string ); + FT_FREE( result ); + goto Exit; + } + ((char*)result)[len] = '\0'; + } + } + Exit: + face->postscript_name = result; + return result; + } + FT_DEFINE_SERVICE_PSFONTNAMEREC( + sfnt_service_ps_name, + (FT_PsName_GetFunc)sfnt_get_ps_name ) +/* + * TT CMAP INFO + */ + FT_DEFINE_SERVICE_TTCMAPSREC( + tt_service_get_cmap_info, + (TT_CMap_Info_GetFunc)tt_get_cmap_info ) + static FT_Error + sfnt_get_charset_id( TT_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + BDF_PropertyRec encoding, registry; + FT_Error error; +/* XXX: I don't know whether this is correct, since + * tt_face_find_bdf_prop only returns something correct if we have + * previously selected a size that is listed in the BDF table. + * Should we change the BDF table format to include single offsets + * for `CHARSET_REGISTRY' and `CHARSET_ENCODING'? + */ + error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry ); + if ( !error ) + { + error = tt_face_find_bdf_prop( face, "CHARSET_ENCODING", &encoding ); + if ( !error ) + { + if ( registry.type == BDF_PROPERTY_TYPE_ATOM && + encoding.type == BDF_PROPERTY_TYPE_ATOM ) + { + *acharset_encoding = encoding.u.atom; + *acharset_registry = registry.u.atom; + } + else + error = SFNT_Err_Invalid_Argument; + } + } + return error; + } + FT_DEFINE_SERVICE_BDFRec( + sfnt_service_bdf, + (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, + (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop ) +/* + * SERVICE LIST + */ + FT_DEFINE_SERVICEDESCREC5( + sfnt_services, + FT_SERVICE_ID_SFNT_TABLE, &SFNT_SERVICE_SFNT_TABLE_GET, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &SFNT_SERVICE_PS_NAME_GET, + FT_SERVICE_ID_GLYPH_DICT, &SFNT_SERVICE_GLYPH_DICT_GET, + FT_SERVICE_ID_BDF, &SFNT_SERVICE_BDF_GET, + FT_SERVICE_ID_TT_CMAP, &TT_SERVICE_CMAP_INFO_GET ) + FT_CALLBACK_DEF( FT_Module_Interface ) + sfnt_get_interface( FT_Module module, + const char* module_interface ) + { +/* SFNT_SERVICES_GET derefers `library' in PIC mode */ + FT_UNUSED( module ); + return ft_service_list_lookup( SFNT_SERVICES_GET, module_interface ); + } +#define PUT_EMBEDDED_BITMAPS( a ) a +#define PUT_PS_NAMES( a ) a + FT_DEFINE_SFNT_INTERFACE( + sfnt_interface, + tt_face_goto_table, + sfnt_init_face, + sfnt_load_face, + sfnt_done_face, + sfnt_get_interface, + tt_face_load_any, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_load_sfnt_header_stub, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_load_directory_stub, + tt_face_load_head, + tt_face_load_hhea, + tt_face_load_cmap, + tt_face_load_maxp, + tt_face_load_os2, + tt_face_load_post, + tt_face_load_name, + tt_face_free_name, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_load_hdmx_stub, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_free_hdmx_stub, + tt_face_load_kern, + tt_face_load_gasp, + tt_face_load_pclt, +/* see `ttload.h' */ + PUT_EMBEDDED_BITMAPS( tt_face_load_bhed ), +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_set_sbit_strike_stub, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_load_sbit_stub, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_find_sbit_image, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_load_sbit_metrics, + PUT_EMBEDDED_BITMAPS( tt_face_load_sbit_image ), +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_free_sbit_stub, +/* see `ttpost.h' */ + PUT_PS_NAMES( tt_face_get_ps_name ), + PUT_PS_NAMES( tt_face_free_ps_names ), +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_load_charmap_stub, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + tt_face_free_charmap_stub, +/* since version 2.1.8 */ + tt_face_get_kerning, +/* since version 2.2 */ + tt_face_load_font_dir, + tt_face_load_hmtx, +/* see `ttsbit.h' and `sfnt.h' */ + PUT_EMBEDDED_BITMAPS( tt_face_load_eblc ), + PUT_EMBEDDED_BITMAPS( tt_face_free_eblc ), + PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), + PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), + tt_face_get_metrics + ) + FT_DEFINE_MODULE( + sfnt_module_class, +/* not a font driver or renderer */ + 0, + sizeof ( FT_ModuleRec ), +/* driver name */ + "sfnt", +/* driver version 1.0 */ + 0x10000L, +/* driver requires FreeType 2.0 or higher */ + 0x20000L, +/* module specific interface */ + (const void*)&SFNT_INTERFACE_GET, + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) sfnt_get_interface ) +/* END */ +/***************************************************************************/ +/* */ +/* ttsbit.c */ +/* */ +/* TrueType and OpenType embedded bitmap support (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ +/* 2010 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. */ +/* */ +/***************************************************************************/ +/* + * Alas, the memory-optimized sbit loader can't be used when implementing + * the `old internals' hack + */ +/***************************************************************************/ +/* */ +/* ttsbit0.c */ +/* */ +/* TrueType and OpenType embedded bitmap support (body). */ +/* This is a heap-optimized version. */ +/* */ +/* Copyright 2005, 2006, 2007, 2008, 2009 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 included by ttsbit.c */ +/*************************************************************************/ +/* */ +/* 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 trace_ttsbit + FT_LOCAL_DEF( FT_Error ) + tt_face_load_eblc( TT_Face face, + FT_Stream stream ) + { + FT_Error error = SFNT_Err_Ok; + FT_Fixed version; + FT_ULong num_strikes, table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt count; + face->sbit_num_strikes = 0; +/* this table is optional */ + error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); + if ( error ) + error = face->goto_table( face, TTAG_bloc, stream, &table_size ); + if ( error ) + goto Exit; + if ( table_size < 8 ) + { + FT_ERROR(( "tt_face_load_sbit_strikes: table too short\n" )); + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) + goto Exit; + face->sbit_table_size = table_size; + p = face->sbit_table; + p_limit = p + table_size; + version = FT_NEXT_ULONG( p ); + num_strikes = FT_NEXT_ULONG( p ); + if ( version != 0x00020000UL || num_strikes >= 0x10000UL ) + { + FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version\n" )); + error = SFNT_Err_Invalid_File_Format; + goto Fail; + } +/* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 + 48UL * count > table_size ) + count = (FT_UInt)( ( p_limit - p ) / 48 ); + face->sbit_num_strikes = count; + FT_TRACE3(( "sbit_num_strikes: %u\n", count )); + Exit: + return error; + Fail: + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + goto Exit; + } + FT_LOCAL_DEF( void ) + tt_face_free_eblc( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_num_strikes = 0; + } + FT_LOCAL_DEF( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_Size_Request req, + FT_ULong* astrike_index ) + { + return FT_Match_Size( (FT_Face)face, req, 0, astrike_index ); + } + FT_LOCAL_DEF( FT_Error ) + tt_face_load_strike_metrics( TT_Face face, + FT_ULong strike_index, + FT_Size_Metrics* metrics ) + { + FT_Byte* strike; + if ( strike_index >= (FT_ULong)face->sbit_num_strikes ) + return SFNT_Err_Invalid_Argument; + strike = face->sbit_table + 8 + strike_index * 48; + metrics->x_ppem = (FT_UShort)strike[44]; + metrics->y_ppem = (FT_UShort)strike[45]; +/* hori.ascender */ + metrics->ascender = (FT_Char)strike[16] << 6; +/* hori.descender */ + metrics->descender = (FT_Char)strike[17] << 6; + metrics->height = metrics->ascender - metrics->descender; +/* XXX: Is this correct? */ +/* min_origin_SB */ + metrics->max_advance = ( (FT_Char)strike[22] + +/* max_width */ + strike[18] + +/* min_advance_SB */ + (FT_Char)strike[23] + ) << 6; + return SFNT_Err_Ok; + } + typedef struct TT_SBitDecoderRec_ + { + TT_Face face; + FT_Stream stream; + FT_Bitmap* bitmap; + TT_SBit_Metrics metrics; + FT_Bool metrics_loaded; + FT_Bool bitmap_allocated; + FT_Byte bit_depth; + FT_ULong ebdt_start; + FT_ULong ebdt_size; + FT_ULong strike_index_array; + FT_ULong strike_index_count; + FT_Byte* eblc_base; + FT_Byte* eblc_limit; + } TT_SBitDecoderRec, *TT_SBitDecoder; + static FT_Error + tt_sbit_decoder_init( TT_SBitDecoder decoder, + TT_Face face, + FT_ULong strike_index, + TT_SBit_MetricsRec* metrics ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + FT_ULong ebdt_size; + error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); + if ( error ) + goto Exit; + decoder->face = face; + decoder->stream = stream; + decoder->bitmap = &face->root.glyph->bitmap; + decoder->metrics = metrics; + decoder->metrics_loaded = 0; + decoder->bitmap_allocated = 0; + decoder->ebdt_start = FT_STREAM_POS(); + decoder->ebdt_size = ebdt_size; + decoder->eblc_base = face->sbit_table; + decoder->eblc_limit = face->sbit_table + face->sbit_table_size; +/* now find the strike corresponding to the index */ + { + FT_Byte* p; + if ( 8 + 48 * strike_index + 3 * 4 + 34 + 1 > face->sbit_table_size ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + p = decoder->eblc_base + 8 + 48 * strike_index; + decoder->strike_index_array = FT_NEXT_ULONG( p ); + p += 4; + decoder->strike_index_count = FT_NEXT_ULONG( p ); + p += 34; + decoder->bit_depth = *p; + if ( decoder->strike_index_array > face->sbit_table_size || + decoder->strike_index_array + 8 * decoder->strike_index_count > + face->sbit_table_size ) + error = SFNT_Err_Invalid_File_Format; + } + Exit: + return error; + } + static void + tt_sbit_decoder_done( TT_SBitDecoder decoder ) + { + FT_UNUSED( decoder ); + } + static FT_Error + tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder ) + { + FT_Error error = SFNT_Err_Ok; + FT_UInt width, height; + FT_Bitmap* map = decoder->bitmap; + FT_Long size; + if ( !decoder->metrics_loaded ) + { + error = SFNT_Err_Invalid_Argument; + goto Exit; + } + width = decoder->metrics->width; + height = decoder->metrics->height; + map->width = (int)width; + map->rows = (int)height; + switch ( decoder->bit_depth ) + { + case 1: + map->pixel_mode = FT_PIXEL_MODE_MONO; + map->pitch = ( map->width + 7 ) >> 3; + break; + case 2: + map->pixel_mode = FT_PIXEL_MODE_GRAY2; + map->pitch = ( map->width + 3 ) >> 2; + break; + case 4: + map->pixel_mode = FT_PIXEL_MODE_GRAY4; + map->pitch = ( map->width + 1 ) >> 1; + break; + case 8: + map->pixel_mode = FT_PIXEL_MODE_GRAY; + map->pitch = map->width; + break; + default: + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + size = map->rows * map->pitch; +/* check that there is no empty image */ + if ( size == 0 ) +/* exit successfully! */ + goto Exit; + error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); + if ( error ) + goto Exit; + decoder->bitmap_allocated = 1; + Exit: + return error; + } + static FT_Error + tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, + FT_Byte* *pp, + FT_Byte* limit, + FT_Bool big ) + { + FT_Byte* p = *pp; + TT_SBit_Metrics metrics = decoder->metrics; + if ( p + 5 > limit ) + goto Fail; + metrics->height = p[0]; + metrics->width = p[1]; + metrics->horiBearingX = (FT_Char)p[2]; + metrics->horiBearingY = (FT_Char)p[3]; + metrics->horiAdvance = p[4]; + p += 5; + if ( big ) + { + if ( p + 3 > limit ) + goto Fail; + metrics->vertBearingX = (FT_Char)p[0]; + metrics->vertBearingY = (FT_Char)p[1]; + metrics->vertAdvance = p[2]; + p += 3; + } + decoder->metrics_loaded = 1; + *pp = p; + return SFNT_Err_Ok; + Fail: + return SFNT_Err_Invalid_Argument; + } +/* forward declaration */ + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos ); + typedef FT_Error (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* plimit, + FT_Int x_pos, + FT_Int y_pos ); + static FT_Error + tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_Byte* line; + FT_Int bit_height, bit_width, pitch, width, height, h; + FT_Bitmap* bitmap; + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } +/* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + width = decoder->metrics->width; + height = decoder->metrics->height; + if ( x_pos < 0 || x_pos + width > bit_width || + y_pos < 0 || y_pos + height > bit_height ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + if ( p + ( ( width + 7 ) >> 3 ) * height > limit ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } +/* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; +/* the easy one */ + if ( x_pos == 0 ) + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w; + for ( w = width; w >= 8; w -= 8 ) + { + write[0] = (FT_Byte)( write[0] | *p++ ); + write += 1; + } + if ( w > 0 ) + write[0] = (FT_Byte)( write[0] | ( *p++ & ( 0xFF00U >> w ) ) ); + } + } +/* x_pos > 0 */ + else + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w; + FT_UInt wval = 0; + for ( w = width; w >= 8; w -= 8 ) + { + wval = (FT_UInt)( wval | *p++ ); + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + write += 1; + wval <<= 8; + } + if ( w > 0 ) + wval = (FT_UInt)( wval | ( *p++ & ( 0xFF00U >> w ) ) ); +/* all bits read and there are `x_pos + w' bits to be written */ + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + if ( x_pos + w > 8 ) + { + write++; + wval <<= 8; + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + } + } + } + Exit: + return error; + } +/* + * Load a bit-aligned bitmap (with pointer `p') into a line-aligned bitmap + * (with pointer `write'). In the example below, the width is 3 pixel, + * and `x_pos' is 1 pixel. + * + * p p+1 + * | | | + * | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |... + * | | | + * +-------+ +-------+ +-------+ ... + * . . . + * . . . + * v . . + * +-------+ . . + * | | . + * | 7 6 5 4 3 2 1 0 | . + * | | . + * write . . + * . . + * v . + * +-------+ . + * | | + * | 7 6 5 4 3 2 1 0 | + * | | + * write+1 . + * . + * v + * +-------+ + * | | + * | 7 6 5 4 3 2 1 0 | + * | | + * write+2 + * + */ + static FT_Error + tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_Byte* line; + FT_Int bit_height, bit_width, pitch, width, height, h, nbits; + FT_Bitmap* bitmap; + FT_UShort rval; + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } +/* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + width = decoder->metrics->width; + height = decoder->metrics->height; + if ( x_pos < 0 || x_pos + width > bit_width || + y_pos < 0 || y_pos + height > bit_height ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + if ( p + ( ( width * height + 7 ) >> 3 ) > limit ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } +/* now do the blit */ +/* adjust `line' to point to the first byte of the bitmap */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; +/* the higher byte of `rval' is used as a buffer */ + rval = 0; + nbits = 0; + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w = width; +/* handle initial byte (in target bitmap) specially if necessary */ + if ( x_pos ) + { + w = ( width < 8 - x_pos ) ? width : 8 - x_pos; + if ( h == height ) + { + rval = *p++; + nbits = x_pos; + } + else if ( nbits < w ) + { + if ( p < limit ) + rval |= *p++; + nbits += 8 - w; + } + else + { + rval >>= 8; + nbits -= w; + } + *write++ |= ( ( rval >> nbits ) & 0xFF ) & + ( ~( 0xFF << w ) << ( 8 - w - x_pos ) ); + rval <<= 8; + w = width - w; + } +/* handle medial bytes */ + for ( ; w >= 8; w -= 8 ) + { + rval |= *p++; + *write++ |= ( rval >> nbits ) & 0xFF; + rval <<= 8; + } +/* handle final byte if necessary */ + if ( w > 0 ) + { + if ( nbits < w ) + { + if ( p < limit ) + rval |= *p++; + *write |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits += 8 - w; + rval <<= 8; + } + else + { + *write |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w ); + nbits -= w; + } + } + } + Exit: + return error; + } + static FT_Error + tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_UInt num_components, nn; + FT_Char horiBearingX = decoder->metrics->horiBearingX; + FT_Char horiBearingY = decoder->metrics->horiBearingY; + FT_Byte horiAdvance = decoder->metrics->horiAdvance; + FT_Char vertBearingX = decoder->metrics->vertBearingX; + FT_Char vertBearingY = decoder->metrics->vertBearingY; + FT_Byte vertAdvance = decoder->metrics->vertAdvance; + if ( p + 2 > limit ) + goto Fail; + num_components = FT_NEXT_USHORT( p ); + if ( p + 4 * num_components > limit ) + goto Fail; + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } + for ( nn = 0; nn < num_components; nn++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + FT_Byte dx = FT_NEXT_BYTE( p ); + FT_Byte dy = FT_NEXT_BYTE( p ); +/* NB: a recursive call */ + error = tt_sbit_decoder_load_image( decoder, gindex, + x_pos + dx, y_pos + dy ); + if ( error ) + break; + } + decoder->metrics->horiBearingX = horiBearingX; + decoder->metrics->horiBearingY = horiBearingY; + decoder->metrics->horiAdvance = horiAdvance; + decoder->metrics->vertBearingX = vertBearingX; + decoder->metrics->vertBearingY = vertBearingY; + decoder->metrics->vertAdvance = vertAdvance; + decoder->metrics->width = (FT_UInt)decoder->bitmap->width; + decoder->metrics->height = (FT_UInt)decoder->bitmap->rows; + Exit: + return error; + Fail: + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + static FT_Error + tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, + FT_UInt glyph_format, + FT_ULong glyph_start, + FT_ULong glyph_size, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error; + FT_Stream stream = decoder->stream; + FT_Byte* p; + FT_Byte* p_limit; + FT_Byte* data; +/* seek into the EBDT table now */ + if ( glyph_start + glyph_size > decoder->ebdt_size ) + { + error = SFNT_Err_Invalid_Argument; + goto Exit; + } + if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || + FT_FRAME_EXTRACT( glyph_size, data ) ) + goto Exit; + p = data; + p_limit = p + glyph_size; +/* read the data, depending on the glyph format */ + switch ( glyph_format ) + { + case 1: + case 2: + case 8: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); + break; + case 6: + case 7: + case 9: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); + break; + default: + error = SFNT_Err_Ok; + } + if ( error ) + goto Fail; + { + TT_SBitDecoder_LoadFunc loader; + switch ( glyph_format ) + { + case 1: + case 6: + loader = tt_sbit_decoder_load_byte_aligned; + break; + case 2: + case 5: + case 7: + loader = tt_sbit_decoder_load_bit_aligned; + break; + case 8: + if ( p + 1 > p_limit ) + goto Fail; +/* skip padding */ + p += 1; +/* fall-through */ + case 9: + loader = tt_sbit_decoder_load_compound; + break; + default: + goto Fail; + } + error = loader( decoder, p, p_limit, x_pos, y_pos ); + } + Fail: + FT_FRAME_RELEASE( data ); + Exit: + return error; + } + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos ) + { +/* + * First, we find the correct strike range that applies to this + * glyph index. + */ + FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; + FT_Byte* p_limit = decoder->eblc_limit; + FT_ULong num_ranges = decoder->strike_index_count; + FT_UInt start, end, index_format, image_format; + FT_ULong image_start = 0, image_end = 0, image_offset; + for ( ; num_ranges > 0; num_ranges-- ) + { + start = FT_NEXT_USHORT( p ); + end = FT_NEXT_USHORT( p ); + if ( glyph_index >= start && glyph_index <= end ) + goto FoundRange; +/* ignore index offset */ + p += 4; + } + goto NoBitmap; + FoundRange: + image_offset = FT_NEXT_ULONG( p ); +/* overflow check */ + if ( decoder->eblc_base + decoder->strike_index_array + image_offset < + decoder->eblc_base ) + goto Failure; + p = decoder->eblc_base + decoder->strike_index_array + image_offset; + if ( p + 8 > p_limit ) + goto NoBitmap; +/* now find the glyph's location and extend within the ebdt table */ + index_format = FT_NEXT_USHORT( p ); + image_format = FT_NEXT_USHORT( p ); + image_offset = FT_NEXT_ULONG ( p ); + switch ( index_format ) + { +/* 4-byte offsets relative to `image_offset' */ + case 1: + { + p += 4 * ( glyph_index - start ); + if ( p + 8 > p_limit ) + goto NoBitmap; + image_start = FT_NEXT_ULONG( p ); + image_end = FT_NEXT_ULONG( p ); +/* missing glyph */ + if ( image_start == image_end ) + goto NoBitmap; + } + break; +/* big metrics, constant image size */ + case 2: + { + FT_ULong image_size; + if ( p + 12 > p_limit ) + goto NoBitmap; + image_size = FT_NEXT_ULONG( p ); + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + image_start = image_size * ( glyph_index - start ); + image_end = image_start + image_size; + } + break; +/* 2-byte offsets relative to 'image_offset' */ + case 3: + { + p += 2 * ( glyph_index - start ); + if ( p + 4 > p_limit ) + goto NoBitmap; + image_start = FT_NEXT_USHORT( p ); + image_end = FT_NEXT_USHORT( p ); +/* missing glyph */ + if ( image_start == image_end ) + goto NoBitmap; + } + break; +/* sparse glyph array with (glyph,offset) pairs */ + case 4: + { + FT_ULong mm, num_glyphs; + if ( p + 4 > p_limit ) + goto NoBitmap; + num_glyphs = FT_NEXT_ULONG( p ); +/* overflow check */ + if ( p + ( num_glyphs + 1 ) * 4 < p ) + goto Failure; + if ( p + ( num_glyphs + 1 ) * 4 > p_limit ) + goto NoBitmap; + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + if ( gindex == glyph_index ) + { + image_start = FT_NEXT_USHORT( p ); + p += 2; + image_end = FT_PEEK_USHORT( p ); + break; + } + p += 2; + } + if ( mm >= num_glyphs ) + goto NoBitmap; + } + break; +/* constant metrics with sparse glyph codes */ + case 5: + { + FT_ULong image_size, mm, num_glyphs; + if ( p + 16 > p_limit ) + goto NoBitmap; + image_size = FT_NEXT_ULONG( p ); + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + num_glyphs = FT_NEXT_ULONG( p ); +/* overflow check */ + if ( p + 2 * num_glyphs < p ) + goto Failure; + if ( p + 2 * num_glyphs > p_limit ) + goto NoBitmap; + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + if ( gindex == glyph_index ) + break; + } + if ( mm >= num_glyphs ) + goto NoBitmap; + image_start = image_size * mm; + image_end = image_start + image_size; + } + break; + default: + goto NoBitmap; + } + if ( image_start > image_end ) + goto NoBitmap; + image_end -= image_start; + image_start = image_offset + image_start; + return tt_sbit_decoder_load_bitmap( decoder, + image_format, + image_start, + image_end, + x_pos, + y_pos ); + Failure: + return SFNT_Err_Invalid_Table; + NoBitmap: + return SFNT_Err_Invalid_Argument; + } + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ) + { + TT_SBitDecoderRec decoder[1]; + FT_Error error; + FT_UNUSED( load_flags ); + FT_UNUSED( stream ); + FT_UNUSED( map ); + error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); + if ( !error ) + { + error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, 0 ); + tt_sbit_decoder_done( decoder ); + } + return error; + } +/* EOF */ +/* END */ +/***************************************************************************/ +/* */ +/* ttpost.c */ +/* */ +/* Postcript name table processing for TrueType and OpenType fonts */ +/* (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2007, 2008, 2009, 2010 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 post table is not completely loaded by the core engine. This */ +/* file loads the missing PS glyph names and implements an API to access */ +/* them. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* 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 trace_ttpost +/* If this configuration macro is defined, we rely on the `PSNames' */ +/* module to grab the glyph names. */ +#define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) ) + static FT_Error + load_format_20( TT_Face face, + FT_Stream stream, + FT_Long post_limit ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_Int num_glyphs; + FT_UShort num_names; + FT_UShort* glyph_indices = 0; + FT_Char** name_strings = 0; + if ( FT_READ_USHORT( num_glyphs ) ) + goto Exit; +/* UNDOCUMENTED! The number of glyphs in this table can be smaller */ +/* than the value in the maxp table (cf. cyberbit.ttf). */ +/* There already exist fonts which have more than 32768 glyph names */ +/* in this table, so the test for this threshold has been dropped. */ + if ( num_glyphs > face->max_profile.numGlyphs ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } +/* load the indices */ + { + FT_Int n; + if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * 2L ) ) + goto Fail; + for ( n = 0; n < num_glyphs; n++ ) + glyph_indices[n] = FT_GET_USHORT(); + FT_FRAME_EXIT(); + } +/* compute number of names stored in table */ + { + FT_Int n; + num_names = 0; + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Int idx; + idx = glyph_indices[n]; + if ( idx >= 258 ) + { + idx -= 257; + if ( idx > num_names ) + num_names = (FT_UShort)idx; + } + } + } +/* now load the name strings */ + { + FT_UShort n; + if ( FT_NEW_ARRAY( name_strings, num_names ) ) + goto Fail; + for ( n = 0; n < num_names; n++ ) + { + FT_UInt len; + if ( FT_STREAM_POS() >= post_limit ) + break; + else + { + FT_TRACE6(( "load_format_20: %d byte left in post table\n", + post_limit - FT_STREAM_POS() )); + if ( FT_READ_BYTE( len ) ) + goto Fail1; + } + if ( (FT_Int)len > post_limit || + FT_STREAM_POS() > post_limit - (FT_Int)len ) + { + FT_ERROR(( "load_format_20:" + " exceeding string length (%d)," + " truncating at end of post table (%d byte left)\n", + len, post_limit - FT_STREAM_POS() )); + len = FT_MAX( 0, post_limit - FT_STREAM_POS() ); + } + if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || + FT_STREAM_READ( name_strings[n], len ) ) + goto Fail1; + name_strings[n][len] = '\0'; + } + if ( n < num_names ) + { + FT_ERROR(( "load_format_20:" + " all entries in post table are already parsed," + " using NULL names for gid %d - %d\n", + n, num_names - 1 )); + for ( ; n < num_names; n++ ) + if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) + goto Fail1; + else + name_strings[n][0] = '\0'; + } + } +/* all right, set table fields and exit successfully */ + { + TT_Post_20 table = &face->postscript_names.names.format_20; + table->num_glyphs = (FT_UShort)num_glyphs; + table->num_names = (FT_UShort)num_names; + table->glyph_indices = glyph_indices; + table->glyph_names = name_strings; + } + return SFNT_Err_Ok; + Fail1: + { + FT_UShort n; + for ( n = 0; n < num_names; n++ ) + FT_FREE( name_strings[n] ); + } + Fail: + FT_FREE( name_strings ); + FT_FREE( glyph_indices ); + Exit: + return error; + } + static FT_Error + load_format_25( TT_Face face, + FT_Stream stream, + FT_Long post_limit ) + { + FT_Memory memory = stream->memory; + FT_Error error; + FT_Int num_glyphs; + FT_Char* offset_table = 0; + FT_UNUSED( post_limit ); +/* UNDOCUMENTED! This value appears only in the Apple TT specs. */ + if ( FT_READ_USHORT( num_glyphs ) ) + goto Exit; +/* check the number of glyphs */ + if ( num_glyphs > face->max_profile.numGlyphs || num_glyphs > 258 ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || + FT_STREAM_READ( offset_table, num_glyphs ) ) + goto Fail; +/* now check the offset table */ + { + FT_Int n; + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Long idx = (FT_Long)n + offset_table[n]; + if ( idx < 0 || idx > num_glyphs ) + { + error = SFNT_Err_Invalid_File_Format; + goto Fail; + } + } + } +/* OK, set table fields and exit successfully */ + { + TT_Post_25 table = &face->postscript_names.names.format_25; + table->num_glyphs = (FT_UShort)num_glyphs; + table->offsets = offset_table; + } + return SFNT_Err_Ok; + Fail: + FT_FREE( offset_table ); + Exit: + return error; + } + static FT_Error + load_post_names( TT_Face face ) + { + FT_Stream stream; + FT_Error error; + FT_Fixed format; + FT_ULong post_len; + FT_Long post_limit; +/* get a stream for the face's resource */ + stream = face->root.stream; +/* seek to the beginning of the PS names table */ + error = face->goto_table( face, TTAG_post, stream, &post_len ); + if ( error ) + goto Exit; + post_limit = FT_STREAM_POS() + post_len; + format = face->postscript.FormatType; +/* go to beginning of subtable */ + if ( FT_STREAM_SKIP( 32 ) ) + goto Exit; +/* now read postscript table */ + if ( format == 0x00020000L ) + error = load_format_20( face, stream, post_limit ); + else if ( format == 0x00028000L ) + error = load_format_25( face, stream, post_limit ); + else + error = SFNT_Err_Invalid_File_Format; + face->postscript_names.loaded = 1; + Exit: + return error; + } + FT_LOCAL_DEF( void ) + tt_face_free_ps_names( TT_Face face ) + { + FT_Memory memory = face->root.memory; + TT_Post_Names names = &face->postscript_names; + FT_Fixed format; + if ( names->loaded ) + { + format = face->postscript.FormatType; + if ( format == 0x00020000L ) + { + TT_Post_20 table = &names->names.format_20; + FT_UShort n; + FT_FREE( table->glyph_indices ); + table->num_glyphs = 0; + for ( n = 0; n < table->num_names; n++ ) + FT_FREE( table->glyph_names[n] ); + FT_FREE( table->glyph_names ); + table->num_names = 0; + } + else if ( format == 0x00028000L ) + { + TT_Post_25 table = &names->names.format_25; + FT_FREE( table->offsets ); + table->num_glyphs = 0; + } + } + names->loaded = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_get_ps_name */ +/* */ +/* <Description> */ +/* Get the PostScript glyph name of a glyph. */ +/* */ +/* <Input> */ +/* face :: A handle to the parent face. */ +/* */ +/* idx :: The glyph index. */ +/* */ +/* <InOut> */ +/* PSname :: The address of a string pointer. Will be NULL in case */ +/* of error, otherwise it is a pointer to the glyph name. */ +/* */ +/* You must not modify the returned string! */ +/* */ +/* <Output> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_get_ps_name( TT_Face face, + FT_UInt idx, + FT_String** PSname ) + { + FT_Error error; + TT_Post_Names names; + FT_Fixed format; + FT_Service_PsCMaps psnames; + if ( !face ) + return SFNT_Err_Invalid_Face_Handle; + if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) + return SFNT_Err_Invalid_Glyph_Index; + psnames = (FT_Service_PsCMaps)face->psnames; + if ( !psnames ) + return SFNT_Err_Unimplemented_Feature; + names = &face->postscript_names; +/* `.notdef' by default */ + *PSname = MAC_NAME( 0 ); + format = face->postscript.FormatType; + if ( format == 0x00010000L ) + { +/* paranoid checking */ + if ( idx < 258 ) + *PSname = MAC_NAME( idx ); + } + else if ( format == 0x00020000L ) + { + TT_Post_20 table = &names->names.format_20; + if ( !names->loaded ) + { + error = load_post_names( face ); + if ( error ) + goto End; + } + if ( idx < (FT_UInt)table->num_glyphs ) + { + FT_UShort name_index = table->glyph_indices[idx]; + if ( name_index < 258 ) + *PSname = MAC_NAME( name_index ); + else + *PSname = (FT_String*)table->glyph_names[name_index - 258]; + } + } + else if ( format == 0x00028000L ) + { + TT_Post_25 table = &names->names.format_25; + if ( !names->loaded ) + { + error = load_post_names( face ); + if ( error ) + goto End; + } +/* paranoid checking */ + if ( idx < (FT_UInt)table->num_glyphs ) + { + idx += table->offsets[idx]; + *PSname = MAC_NAME( idx ); + } + } +/* nothing to do for format == 0x00030000L */ + End: + return SFNT_Err_Ok; + } +/* END */ +/***************************************************************************/ +/* */ +/* ttbdf.c */ +/* */ +/* TrueType and OpenType embedded BDF properties (body). */ +/* */ +/* Copyright 2005, 2006, 2010 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 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 trace_ttbdf + FT_LOCAL_DEF( void ) + tt_face_free_bdf_props( TT_Face face ) + { + TT_BDF bdf = &face->bdf; + if ( bdf->loaded ) + { + FT_Stream stream = FT_FACE(face)->stream; + if ( bdf->table != NULL ) + FT_FRAME_RELEASE( bdf->table ); + bdf->table_end = NULL; + bdf->strings = NULL; + bdf->strings_size = 0; + } + } + static FT_Error + tt_face_load_bdf_props( TT_Face face, + FT_Stream stream ) + { + TT_BDF bdf = &face->bdf; + FT_ULong length; + FT_Error error; + FT_ZERO( bdf ); + error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); + if ( error || + length < 8 || + FT_FRAME_EXTRACT( length, bdf->table ) ) + { + error = SFNT_Err_Invalid_Table; + goto Exit; + } + bdf->table_end = bdf->table + length; + { + FT_Byte* p = bdf->table; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt num_strikes = FT_NEXT_USHORT( p ); + FT_ULong strings = FT_NEXT_ULONG ( p ); + FT_UInt count; + FT_Byte* strike; + if ( version != 0x0001 || + strings < 8 || + ( strings - 8 ) / 4 < num_strikes || + strings + 1 > length ) + { + goto BadTable; + } + bdf->num_strikes = num_strikes; + bdf->strings = bdf->table + strings; + bdf->strings_size = length - strings; + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + count * 4; + for ( ; count > 0; count-- ) + { + FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); +/* + * We don't need to check the value sets themselves, since this + * is done later. + */ + strike += 10 * num_items; + p += 4; + } + if ( strike > bdf->strings ) + goto BadTable; + } + bdf->loaded = 1; + Exit: + return error; + BadTable: + FT_FRAME_RELEASE( bdf->table ); + FT_ZERO( bdf ); + error = SFNT_Err_Invalid_Table; + goto Exit; + } + FT_LOCAL_DEF( FT_Error ) + tt_face_find_bdf_prop( TT_Face face, + const char* property_name, + BDF_PropertyRec *aprop ) + { + TT_BDF bdf = &face->bdf; + FT_Size size = FT_FACE(face)->size; + FT_Error error = SFNT_Err_Ok; + FT_Byte* p; + FT_UInt count; + FT_Byte* strike; + FT_Offset property_len; + aprop->type = BDF_PROPERTY_TYPE_NONE; + if ( bdf->loaded == 0 ) + { + error = tt_face_load_bdf_props( face, FT_FACE( face )->stream ); + if ( error ) + goto Exit; + } + count = bdf->num_strikes; + p = bdf->table + 8; + strike = p + 4 * count; + error = SFNT_Err_Invalid_Argument; + if ( size == NULL || property_name == NULL ) + goto Exit; + property_len = ft_strlen( property_name ); + if ( property_len == 0 ) + goto Exit; + for ( ; count > 0; count-- ) + { + FT_UInt _ppem = FT_NEXT_USHORT( p ); + FT_UInt _count = FT_NEXT_USHORT( p ); + if ( _ppem == size->metrics.y_ppem ) + { + count = _count; + goto FoundStrike; + } + strike += 10 * _count; + } + goto Exit; + FoundStrike: + p = strike; + for ( ; count > 0; count-- ) + { + FT_UInt type = FT_PEEK_USHORT( p + 4 ); + if ( ( type & 0x10 ) != 0 ) + { + FT_UInt32 name_offset = FT_PEEK_ULONG( p ); + FT_UInt32 value = FT_PEEK_ULONG( p + 6 ); +/* be a bit paranoid for invalid entries here */ + if ( name_offset < bdf->strings_size && + property_len < bdf->strings_size - name_offset && + ft_strncmp( property_name, + (const char*)bdf->strings + name_offset, + bdf->strings_size - name_offset ) == 0 ) + { + switch ( type & 0x0F ) + { +/* string */ + case 0x00: +/* atoms */ + case 0x01: +/* check that the content is really 0-terminated */ + if ( value < bdf->strings_size && + ft_memchr( bdf->strings + value, 0, bdf->strings_size ) ) + { + aprop->type = BDF_PROPERTY_TYPE_ATOM; + aprop->u.atom = (const char*)bdf->strings + value; + error = SFNT_Err_Ok; + goto Exit; + } + break; + case 0x02: + aprop->type = BDF_PROPERTY_TYPE_INTEGER; + aprop->u.integer = (FT_Int32)value; + error = SFNT_Err_Ok; + goto Exit; + case 0x03: + aprop->type = BDF_PROPERTY_TYPE_CARDINAL; + aprop->u.cardinal = value; + error = SFNT_Err_Ok; + goto Exit; + default: + ; + } + } + } + p += 10; + } + Exit: + return error; + } +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* pshinter.c */ +/* */ +/* FreeType PostScript Hinting module */ +/* */ +/* Copyright 2001, 2003 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* pshpic.c */ +/* */ +/* The FreeType position independent code services for pshinter module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pshpic.h */ +/* */ +/* The FreeType position independent code services for pshinter module. */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __PSHPIC_H__ +FT_BEGIN_HEADER +#define PSHINTER_INTERFACE_GET pshinter_interface +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* pshnterr.h */ +/* */ +/* PS Hinter error codes (specification only). */ +/* */ +/* Copyright 2003, 2012 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 PSHinter error enumeration constants. */ +/* */ +/*************************************************************************/ +#define __PSHNTERR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSH_Err_ +#define FT_ERR_BASE FT_Mod_Err_PShinter +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* pshrec.c */ +/* */ +/* FreeType PostScript hints recorder (body). */ +/* */ +/* Copyright 2001, 2002, 2003, 2004, 2007, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pshrec.h */ +/* */ +/* Postscript (Type1/Type2) hints recorder (specification). */ +/* */ +/* Copyright 2001, 2002, 2003, 2006, 2008 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 functions defined here are called from the Type 1, CID and CFF */ +/* font drivers to record the hints of a given character/glyph. */ +/* */ +/* The hints are recorded in a unified format, and are later processed */ +/* by the `optimizer' and `fitter' to adjust the outlines to the pixel */ +/* grid. */ +/* */ +/**************************************************************************/ +#define __PSHREC_H__ +/***************************************************************************/ +/* */ +/* pshglob.h */ +/* */ +/* PostScript hinter global hinting management. */ +/* */ +/* Copyright 2001, 2002, 2003 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. */ +/* */ +/***************************************************************************/ +#define __PSHGLOB_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** GLOBAL HINTS INTERNALS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* @constant: */ +/* PS_GLOBALS_MAX_BLUE_ZONES */ +/* */ +/* @description: */ +/* The maximum number of blue zones in a font global hints structure. */ +/* See @PS_Globals_BluesRec. */ +/* */ +#define PS_GLOBALS_MAX_BLUE_ZONES 16 +/*************************************************************************/ +/* */ +/* @constant: */ +/* PS_GLOBALS_MAX_STD_WIDTHS */ +/* */ +/* @description: */ +/* The maximum number of standard and snap widths in either the */ +/* horizontal or vertical direction. See @PS_Globals_WidthsRec. */ +/* */ +#define PS_GLOBALS_MAX_STD_WIDTHS 16 +/* standard and snap width */ + typedef struct PSH_WidthRec_ + { + FT_Int org; + FT_Pos cur; + FT_Pos fit; + } PSH_WidthRec, *PSH_Width; +/* standard and snap widths table */ + typedef struct PSH_WidthsRec_ + { + FT_UInt count; + PSH_WidthRec widths[PS_GLOBALS_MAX_STD_WIDTHS]; + } PSH_WidthsRec, *PSH_Widths; + typedef struct PSH_DimensionRec_ + { + PSH_WidthsRec stdw; + FT_Fixed scale_mult; + FT_Fixed scale_delta; + } PSH_DimensionRec, *PSH_Dimension; +/* blue zone descriptor */ + typedef struct PSH_Blue_ZoneRec_ + { + FT_Int org_ref; + FT_Int org_delta; + FT_Int org_top; + FT_Int org_bottom; + FT_Pos cur_ref; + FT_Pos cur_delta; + FT_Pos cur_bottom; + FT_Pos cur_top; + } PSH_Blue_ZoneRec, *PSH_Blue_Zone; + typedef struct PSH_Blue_TableRec_ + { + FT_UInt count; + PSH_Blue_ZoneRec zones[PS_GLOBALS_MAX_BLUE_ZONES]; + } PSH_Blue_TableRec, *PSH_Blue_Table; +/* blue zones table */ + typedef struct PSH_BluesRec_ + { + PSH_Blue_TableRec normal_top; + PSH_Blue_TableRec normal_bottom; + PSH_Blue_TableRec family_top; + PSH_Blue_TableRec family_bottom; + FT_Fixed blue_scale; + FT_Int blue_shift; + FT_Int blue_threshold; + FT_Int blue_fuzz; + FT_Bool no_overshoots; + } PSH_BluesRec, *PSH_Blues; +/* font globals. */ +/* dimension 0 => X coordinates + vertical hints/stems */ +/* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PSH_GlobalsRec_ + { + FT_Memory memory; + PSH_DimensionRec dimension[2]; + PSH_BluesRec blues; + } PSH_GlobalsRec; +#define PSH_BLUE_ALIGN_NONE 0 +#define PSH_BLUE_ALIGN_TOP 1 +#define PSH_BLUE_ALIGN_BOT 2 + typedef struct PSH_AlignmentRec_ + { + int align; + FT_Pos align_top; + FT_Pos align_bot; + } PSH_AlignmentRec, *PSH_Alignment; + FT_LOCAL( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ); +#if 0 +/* snap a stem width to fitter coordinates. `org_width' is in font */ +/* units. The result is in device pixels (26.6 format). */ + FT_LOCAL( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ); +#endif + FT_LOCAL( FT_Error ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ); +/* snap a stem to one or two blue zones */ + FT_LOCAL( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ); +/* */ +#ifdef DEBUG_HINTER + extern PSH_Globals ps_debug_globals; +#endif +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** GLYPH HINTS RECORDER INTERNALS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* handle to hint record */ + typedef struct PS_HintRec_* PS_Hint; +/* hint types */ + typedef enum PS_Hint_Type_ + { + PS_HINT_TYPE_1 = 1, + PS_HINT_TYPE_2 = 2 + } PS_Hint_Type; +/* hint flags */ + typedef enum PS_Hint_Flags_ + { + PS_HINT_FLAG_GHOST = 1, + PS_HINT_FLAG_BOTTOM = 2 + } PS_Hint_Flags; +/* hint descriptor */ + typedef struct PS_HintRec_ + { + FT_Int pos; + FT_Int len; + FT_UInt flags; + } PS_HintRec; +#define ps_hint_is_active( x ) ( (x)->flags & PS_HINT_FLAG_ACTIVE ) +#define ps_hint_is_ghost( x ) ( (x)->flags & PS_HINT_FLAG_GHOST ) +#define ps_hint_is_bottom( x ) ( (x)->flags & PS_HINT_FLAG_BOTTOM ) +/* hints table descriptor */ + typedef struct PS_Hint_TableRec_ + { + FT_UInt num_hints; + FT_UInt max_hints; + PS_Hint hints; + } PS_Hint_TableRec, *PS_Hint_Table; +/* hint and counter mask descriptor */ + typedef struct PS_MaskRec_ + { + FT_UInt num_bits; + FT_UInt max_bits; + FT_Byte* bytes; + FT_UInt end_point; + } PS_MaskRec, *PS_Mask; +/* masks and counters table descriptor */ + typedef struct PS_Mask_TableRec_ + { + FT_UInt num_masks; + FT_UInt max_masks; + PS_Mask masks; + } PS_Mask_TableRec, *PS_Mask_Table; +/* dimension-specific hints descriptor */ + typedef struct PS_DimensionRec_ + { + PS_Hint_TableRec hints; + PS_Mask_TableRec masks; + PS_Mask_TableRec counters; + } PS_DimensionRec, *PS_Dimension; +/* glyph hints descriptor */ +/* dimension 0 => X coordinates + vertical hints/stems */ +/* dimension 1 => Y coordinates + horizontal hints/stems */ + typedef struct PS_HintsRec_ + { + FT_Memory memory; + FT_Error error; + FT_UInt32 magic; + PS_Hint_Type hint_type; + PS_DimensionRec dimension[2]; + } PS_HintsRec, *PS_Hints; +/* */ +/* initialize hints recorder */ + FT_LOCAL( FT_Error ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ); +/* finalize hints recorder */ + FT_LOCAL( void ) + ps_hints_done( PS_Hints hints ); +/* initialize Type1 hints recorder interface */ + FT_LOCAL( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ); +/* initialize Type2 hints recorder interface */ + FT_LOCAL( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ); +#ifdef DEBUG_HINTER + extern PS_Hints ps_debug_hints; + extern int ps_debug_no_horz_hints; + extern int ps_debug_no_vert_hints; +#endif +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* pshalgo.h */ +/* */ +/* PostScript hinting algorithm (specification). */ +/* */ +/* Copyright 2001, 2002, 2003, 2008 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. */ +/* */ +/***************************************************************************/ +#define __PSHALGO_H__ +FT_BEGIN_HEADER +/* handle to Hint structure */ + typedef struct PSH_HintRec_* PSH_Hint; +/* hint bit-flags */ + typedef enum PSH_Hint_Flags_ + { + PSH_HINT_GHOST = PS_HINT_FLAG_GHOST, + PSH_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM, + PSH_HINT_ACTIVE = 4, + PSH_HINT_FITTED = 8 + } PSH_Hint_Flags; +#define psh_hint_is_active( x ) ( ( (x)->flags & PSH_HINT_ACTIVE ) != 0 ) +#define psh_hint_is_ghost( x ) ( ( (x)->flags & PSH_HINT_GHOST ) != 0 ) +#define psh_hint_is_fitted( x ) ( ( (x)->flags & PSH_HINT_FITTED ) != 0 ) +#define psh_hint_activate( x ) (x)->flags |= PSH_HINT_ACTIVE +#define psh_hint_deactivate( x ) (x)->flags &= ~PSH_HINT_ACTIVE +#define psh_hint_set_fitted( x ) (x)->flags |= PSH_HINT_FITTED +/* hint structure */ + typedef struct PSH_HintRec_ + { + FT_Int org_pos; + FT_Int org_len; + FT_Pos cur_pos; + FT_Pos cur_len; + FT_UInt flags; + PSH_Hint parent; + FT_Int order; + } PSH_HintRec; +/* this is an interpolation zone used for strong points; */ +/* weak points are interpolated according to their strong */ +/* neighbours */ + typedef struct PSH_ZoneRec_ + { + FT_Fixed scale; + FT_Fixed delta; + FT_Pos min; + FT_Pos max; + } PSH_ZoneRec, *PSH_Zone; + typedef struct PSH_Hint_TableRec_ + { + FT_UInt max_hints; + FT_UInt num_hints; + PSH_Hint hints; + PSH_Hint* sort; + PSH_Hint* sort_global; + FT_UInt num_zones; + PSH_ZoneRec* zones; + PSH_Zone zone; + PS_Mask_Table hint_masks; + PS_Mask_Table counter_masks; + } PSH_Hint_TableRec, *PSH_Hint_Table; + typedef struct PSH_PointRec_* PSH_Point; + typedef struct PSH_ContourRec_* PSH_Contour; + enum + { + PSH_DIR_NONE = 4, + PSH_DIR_UP = -1, + PSH_DIR_DOWN = 1, + PSH_DIR_LEFT = -2, + PSH_DIR_RIGHT = 2 + }; +#define PSH_DIR_HORIZONTAL 2 +#define PSH_DIR_VERTICAL 1 +#define PSH_DIR_COMPARE( d1, d2 ) ( (d1) == (d2) || (d1) == -(d2) ) +#define PSH_DIR_IS_HORIZONTAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_HORIZONTAL ) +#define PSH_DIR_IS_VERTICAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_VERTICAL ) +/* the following bit-flags are computed once by the glyph */ +/* analyzer, for both dimensions */ + enum + { +/* point is off the curve */ + PSH_POINT_OFF = 1, +/* point is smooth */ + PSH_POINT_SMOOTH = 2, +/* point is inflection */ + PSH_POINT_INFLEX = 4 + }; +#define psh_point_is_smooth( p ) ( (p)->flags & PSH_POINT_SMOOTH ) +#define psh_point_is_off( p ) ( (p)->flags & PSH_POINT_OFF ) +#define psh_point_is_inflex( p ) ( (p)->flags & PSH_POINT_INFLEX ) +#define psh_point_set_smooth( p ) (p)->flags |= PSH_POINT_SMOOTH +#define psh_point_set_off( p ) (p)->flags |= PSH_POINT_OFF +#define psh_point_set_inflex( p ) (p)->flags |= PSH_POINT_INFLEX +/* the following bit-flags are re-computed for each dimension */ + enum + { +/* point is strong */ + PSH_POINT_STRONG = 16, +/* point is already fitted */ + PSH_POINT_FITTED = 32, +/* point is local extremum */ + PSH_POINT_EXTREMUM = 64, +/* extremum has positive contour flow */ + PSH_POINT_POSITIVE = 128, +/* extremum has negative contour flow */ + PSH_POINT_NEGATIVE = 256, +/* point is aligned to left/bottom stem edge */ + PSH_POINT_EDGE_MIN = 512, +/* point is aligned to top/right stem edge */ + PSH_POINT_EDGE_MAX = 1024 + }; +#define psh_point_is_strong( p ) ( (p)->flags2 & PSH_POINT_STRONG ) +#define psh_point_is_fitted( p ) ( (p)->flags2 & PSH_POINT_FITTED ) +#define psh_point_is_extremum( p ) ( (p)->flags2 & PSH_POINT_EXTREMUM ) +#define psh_point_is_positive( p ) ( (p)->flags2 & PSH_POINT_POSITIVE ) +#define psh_point_is_negative( p ) ( (p)->flags2 & PSH_POINT_NEGATIVE ) +#define psh_point_is_edge_min( p ) ( (p)->flags2 & PSH_POINT_EDGE_MIN ) +#define psh_point_is_edge_max( p ) ( (p)->flags2 & PSH_POINT_EDGE_MAX ) +#define psh_point_set_strong( p ) (p)->flags2 |= PSH_POINT_STRONG +#define psh_point_set_fitted( p ) (p)->flags2 |= PSH_POINT_FITTED +#define psh_point_set_extremum( p ) (p)->flags2 |= PSH_POINT_EXTREMUM +#define psh_point_set_positive( p ) (p)->flags2 |= PSH_POINT_POSITIVE +#define psh_point_set_negative( p ) (p)->flags2 |= PSH_POINT_NEGATIVE +#define psh_point_set_edge_min( p ) (p)->flags2 |= PSH_POINT_EDGE_MIN +#define psh_point_set_edge_max( p ) (p)->flags2 |= PSH_POINT_EDGE_MAX + typedef struct PSH_PointRec_ + { + PSH_Point prev; + PSH_Point next; + PSH_Contour contour; + FT_UInt flags; + FT_UInt flags2; + FT_Char dir_in; + FT_Char dir_out; + FT_Angle angle_in; + FT_Angle angle_out; + PSH_Hint hint; + FT_Pos org_u; + FT_Pos org_v; + FT_Pos cur_u; +#ifdef DEBUG_HINTER + FT_Pos org_x; + FT_Pos cur_x; + FT_Pos org_y; + FT_Pos cur_y; + FT_UInt flags_x; + FT_UInt flags_y; +#endif + } PSH_PointRec; +#define PSH_POINT_EQUAL_ORG( a, b ) ( (a)->org_u == (b)->org_u && \ + (a)->org_v == (b)->org_v ) +#define PSH_POINT_ANGLE( a, b ) FT_Atan2( (b)->org_u - (a)->org_u, \ + (b)->org_v - (a)->org_v ) + typedef struct PSH_ContourRec_ + { + PSH_Point start; + FT_UInt count; + } PSH_ContourRec; + typedef struct PSH_GlyphRec_ + { + FT_UInt num_points; + FT_UInt num_contours; + PSH_Point points; + PSH_Contour contours; + FT_Memory memory; + FT_Outline* outline; + PSH_Globals globals; + PSH_Hint_TableRec hint_tables[2]; + FT_Bool vertical; + FT_Int major_dir; + FT_Int minor_dir; + FT_Bool do_horz_hints; + FT_Bool do_vert_hints; + FT_Bool do_horz_snapping; + FT_Bool do_vert_snapping; + FT_Bool do_stem_adjust; + } PSH_GlyphRec, *PSH_Glyph; +#ifdef DEBUG_HINTER + extern PSH_Hint_Table ps_debug_hint_table; + typedef void + (*PSH_HintFunc)( PSH_Hint hint, + FT_Bool vertical ); + extern PSH_HintFunc ps_debug_hint_func; + extern PSH_Glyph ps_debug_glyph; +#endif + extern FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ); +FT_END_HEADER +/* END */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_pshrec +#ifdef DEBUG_HINTER + PS_Hints ps_debug_hints = 0; + int ps_debug_no_horz_hints = 0; + int ps_debug_no_vert_hints = 0; +#endif +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PS_HINT MANAGEMENT *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* destroy hints table */ + static void + ps_hint_table_done( PS_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + } +/* ensure that a table can contain "count" elements */ + static FT_Error + ps_hint_table_ensure( PS_Hint_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_hints; + FT_UInt new_max = count; + FT_Error error = PSH_Err_Ok; + if ( new_max > old_max ) + { +/* try to grow the table */ + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) ) + table->max_hints = new_max; + } + return error; + } + static FT_Error + ps_hint_table_alloc( PS_Hint_Table table, + FT_Memory memory, + PS_Hint *ahint ) + { + FT_Error error = PSH_Err_Ok; + FT_UInt count; + PS_Hint hint = 0; + count = table->num_hints; + count++; + if ( count >= table->max_hints ) + { + error = ps_hint_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + hint = table->hints + count - 1; + hint->pos = 0; + hint->len = 0; + hint->flags = 0; + table->num_hints = count; + Exit: + *ahint = hint; + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PS_MASK MANAGEMENT *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* destroy mask */ + static void + ps_mask_done( PS_Mask mask, + FT_Memory memory ) + { + FT_FREE( mask->bytes ); + mask->num_bits = 0; + mask->max_bits = 0; + mask->end_point = 0; + } +/* ensure that a mask can contain "count" bits */ + static FT_Error + ps_mask_ensure( PS_Mask mask, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = ( mask->max_bits + 7 ) >> 3; + FT_UInt new_max = ( count + 7 ) >> 3; + FT_Error error = PSH_Err_Ok; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) + mask->max_bits = new_max * 8; + } + return error; + } +/* test a bit value in a given mask */ + static FT_Int + ps_mask_test_bit( PS_Mask mask, + FT_Int idx ) + { + if ( (FT_UInt)idx >= mask->num_bits ) + return 0; + return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) ); + } +/* clear a given bit */ + static void + ps_mask_clear_bit( PS_Mask mask, + FT_Int idx ) + { + FT_Byte* p; + if ( (FT_UInt)idx >= mask->num_bits ) + return; + p = mask->bytes + ( idx >> 3 ); + p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) ); + } +/* set a given bit, possibly grow the mask */ + static FT_Error + ps_mask_set_bit( PS_Mask mask, + FT_Int idx, + FT_Memory memory ) + { + FT_Error error = PSH_Err_Ok; + FT_Byte* p; + if ( idx < 0 ) + goto Exit; + if ( (FT_UInt)idx >= mask->num_bits ) + { + error = ps_mask_ensure( mask, idx + 1, memory ); + if ( error ) + goto Exit; + mask->num_bits = idx + 1; + } + p = mask->bytes + ( idx >> 3 ); + p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) ); + Exit: + return error; + } +/* destroy mask table */ + static void + ps_mask_table_done( PS_Mask_Table table, + FT_Memory memory ) + { + FT_UInt count = table->max_masks; + PS_Mask mask = table->masks; + for ( ; count > 0; count--, mask++ ) + ps_mask_done( mask, memory ); + FT_FREE( table->masks ); + table->num_masks = 0; + table->max_masks = 0; + } +/* ensure that a mask table can contain "count" masks */ + static FT_Error + ps_mask_table_ensure( PS_Mask_Table table, + FT_UInt count, + FT_Memory memory ) + { + FT_UInt old_max = table->max_masks; + FT_UInt new_max = count; + FT_Error error = PSH_Err_Ok; + if ( new_max > old_max ) + { + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) ) + table->max_masks = new_max; + } + return error; + } +/* allocate a new mask in a table */ + static FT_Error + ps_mask_table_alloc( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_UInt count; + FT_Error error = PSH_Err_Ok; + PS_Mask mask = 0; + count = table->num_masks; + count++; + if ( count > table->max_masks ) + { + error = ps_mask_table_ensure( table, count, memory ); + if ( error ) + goto Exit; + } + mask = table->masks + count - 1; + mask->num_bits = 0; + mask->end_point = 0; + table->num_masks = count; + Exit: + *amask = mask; + return error; + } +/* return last hint mask in a table, create one if the table is empty */ + static FT_Error + ps_mask_table_last( PS_Mask_Table table, + FT_Memory memory, + PS_Mask *amask ) + { + FT_Error error = PSH_Err_Ok; + FT_UInt count; + PS_Mask mask; + count = table->num_masks; + if ( count == 0 ) + { + error = ps_mask_table_alloc( table, memory, &mask ); + if ( error ) + goto Exit; + } + else + mask = table->masks + count - 1; + Exit: + *amask = mask; + return error; + } +/* set a new mask to a given bit range */ + static FT_Error + ps_mask_table_set_bits( PS_Mask_Table table, + const FT_Byte* source, + FT_UInt bit_pos, + FT_UInt bit_count, + FT_Memory memory ) + { + FT_Error error = PSH_Err_Ok; + PS_Mask mask; + error = ps_mask_table_last( table, memory, &mask ); + if ( error ) + goto Exit; + error = ps_mask_ensure( mask, bit_count, memory ); + if ( error ) + goto Exit; + mask->num_bits = bit_count; +/* now, copy bits */ + { + FT_Byte* read = (FT_Byte*)source + ( bit_pos >> 3 ); + FT_Int rmask = 0x80 >> ( bit_pos & 7 ); + FT_Byte* write = mask->bytes; + FT_Int wmask = 0x80; + FT_Int val; + for ( ; bit_count > 0; bit_count-- ) + { + val = write[0] & ~wmask; + if ( read[0] & rmask ) + val |= wmask; + write[0] = (FT_Byte)val; + rmask >>= 1; + if ( rmask == 0 ) + { + read++; + rmask = 0x80; + } + wmask >>= 1; + if ( wmask == 0 ) + { + write++; + wmask = 0x80; + } + } + } + Exit: + return error; + } +/* test whether two masks in a table intersect */ + static FT_Int + ps_mask_table_test_intersect( PS_Mask_Table table, + FT_Int index1, + FT_Int index2 ) + { + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_Byte* p1 = mask1->bytes; + FT_Byte* p2 = mask2->bytes; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_UInt count; + count = ( count1 <= count2 ) ? count1 : count2; + for ( ; count >= 8; count -= 8 ) + { + if ( p1[0] & p2[0] ) + return 1; + p1++; + p2++; + } + if ( count == 0 ) + return 0; + return ( p1[0] & p2[0] ) & ~( 0xFF >> count ); + } +/* merge two masks, used by ps_mask_table_merge_all */ + static FT_Error + ps_mask_table_merge( PS_Mask_Table table, + FT_Int index1, + FT_Int index2, + FT_Memory memory ) + { + FT_UInt temp; + FT_Error error = PSH_Err_Ok; +/* swap index1 and index2 so that index1 < index2 */ + if ( index1 > index2 ) + { + temp = index1; + index1 = index2; + index2 = temp; + } + if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks ) + { +/* we need to merge the bitsets of index1 and index2 with a */ +/* simple union */ + PS_Mask mask1 = table->masks + index1; + PS_Mask mask2 = table->masks + index2; + FT_UInt count1 = mask1->num_bits; + FT_UInt count2 = mask2->num_bits; + FT_Int delta; + if ( count2 > 0 ) + { + FT_UInt pos; + FT_Byte* read; + FT_Byte* write; +/* if "count2" is greater than "count1", we need to grow the */ +/* first bitset, and clear the highest bits */ + if ( count2 > count1 ) + { + error = ps_mask_ensure( mask1, count2, memory ); + if ( error ) + goto Exit; + for ( pos = count1; pos < count2; pos++ ) + ps_mask_clear_bit( mask1, pos ); + } +/* merge (unite) the bitsets */ + read = mask2->bytes; + write = mask1->bytes; + pos = (FT_UInt)( ( count2 + 7 ) >> 3 ); + for ( ; pos > 0; pos-- ) + { + write[0] = (FT_Byte)( write[0] | read[0] ); + write++; + read++; + } + } +/* Now, remove "mask2" from the list. We need to keep the masks */ +/* sorted in order of importance, so move table elements. */ + mask2->num_bits = 0; + mask2->end_point = 0; +/* number of masks to move */ + delta = table->num_masks - 1 - index2; + if ( delta > 0 ) + { +/* move to end of table for reuse */ + PS_MaskRec dummy = *mask2; + ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) ); + mask2[delta] = dummy; + } + table->num_masks--; + } + else + FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", + index1, index2 )); + Exit: + return error; + } +/* Try to merge all masks in a given table. This is used to merge */ +/* all counter masks into independent counter "paths". */ +/* */ + static FT_Error + ps_mask_table_merge_all( PS_Mask_Table table, + FT_Memory memory ) + { + FT_Int index1, index2; + FT_Error error = PSH_Err_Ok; + for ( index1 = table->num_masks - 1; index1 > 0; index1-- ) + { + for ( index2 = index1 - 1; index2 >= 0; index2-- ) + { + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) + { + error = ps_mask_table_merge( table, index2, index1, memory ); + if ( error ) + goto Exit; + break; + } + } + } + Exit: + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PS_DIMENSION MANAGEMENT *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* finalize a given dimension */ + static void + ps_dimension_done( PS_Dimension dimension, + FT_Memory memory ) + { + ps_mask_table_done( &dimension->counters, memory ); + ps_mask_table_done( &dimension->masks, memory ); + ps_hint_table_done( &dimension->hints, memory ); + } +/* initialize a given dimension */ + static void + ps_dimension_init( PS_Dimension dimension ) + { + dimension->hints.num_hints = 0; + dimension->masks.num_masks = 0; + dimension->counters.num_masks = 0; + } +#if 0 +/* set a bit at a given index in the current hint mask */ + static FT_Error + ps_dimension_set_mask_bit( PS_Dimension dim, + FT_UInt idx, + FT_Memory memory ) + { + PS_Mask mask; + FT_Error error = PSH_Err_Ok; +/* get last hint mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + error = ps_mask_set_bit( mask, idx, memory ); + Exit: + return error; + } +#endif +/* set the end point in a mask, called from "End" & "Reset" methods */ + static void + ps_dimension_end_mask( PS_Dimension dim, + FT_UInt end_point ) + { + FT_UInt count = dim->masks.num_masks; + PS_Mask mask; + if ( count > 0 ) + { + mask = dim->masks.masks + count - 1; + mask->end_point = end_point; + } + } +/* set the end point in the current mask, then create a new empty one */ +/* (called by "Reset" method) */ + static FT_Error + ps_dimension_reset_mask( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { + PS_Mask mask; +/* end current mask */ + ps_dimension_end_mask( dim, end_point ); +/* allocate new one */ + return ps_mask_table_alloc( &dim->masks, memory, &mask ); + } +/* set a new mask, called from the "T2Stem" method */ + static FT_Error + ps_dimension_set_mask_bits( PS_Dimension dim, + const FT_Byte* source, + FT_UInt source_pos, + FT_UInt source_bits, + FT_UInt end_point, + FT_Memory memory ) + { + FT_Error error = PSH_Err_Ok; +/* reset current mask, if any */ + error = ps_dimension_reset_mask( dim, end_point, memory ); + if ( error ) + goto Exit; +/* set bits in new mask */ + error = ps_mask_table_set_bits( &dim->masks, source, + source_pos, source_bits, memory ); + Exit: + return error; + } +/* add a new single stem (called from "T1Stem" method) */ + static FT_Error + ps_dimension_add_t1stem( PS_Dimension dim, + FT_Int pos, + FT_Int len, + FT_Memory memory, + FT_Int *aindex ) + { + FT_Error error = PSH_Err_Ok; + FT_UInt flags = 0; +/* detect ghost stem */ + if ( len < 0 ) + { + flags |= PS_HINT_FLAG_GHOST; + if ( len == -21 ) + { + flags |= PS_HINT_FLAG_BOTTOM; + pos += len; + } + len = 0; + } + if ( aindex ) + *aindex = -1; +/* now, lookup stem in the current hints table */ + { + PS_Mask mask; + FT_UInt idx; + FT_UInt max = dim->hints.num_hints; + PS_Hint hint = dim->hints.hints; + for ( idx = 0; idx < max; idx++, hint++ ) + { + if ( hint->pos == pos && hint->len == len ) + break; + } +/* we need to create a new hint in the table */ + if ( idx >= max ) + { + error = ps_hint_table_alloc( &dim->hints, memory, &hint ); + if ( error ) + goto Exit; + hint->pos = pos; + hint->len = len; + hint->flags = flags; + } +/* now, store the hint in the current mask */ + error = ps_mask_table_last( &dim->masks, memory, &mask ); + if ( error ) + goto Exit; + error = ps_mask_set_bit( mask, idx, memory ); + if ( error ) + goto Exit; + if ( aindex ) + *aindex = (FT_Int)idx; + } + Exit: + return error; + } +/* add a "hstem3/vstem3" counter to our dimension table */ + static FT_Error + ps_dimension_add_counter( PS_Dimension dim, + FT_Int hint1, + FT_Int hint2, + FT_Int hint3, + FT_Memory memory ) + { + FT_Error error = PSH_Err_Ok; + FT_UInt count = dim->counters.num_masks; + PS_Mask counter = dim->counters.masks; +/* try to find an existing counter mask that already uses */ +/* one of these stems here */ + for ( ; count > 0; count--, counter++ ) + { + if ( ps_mask_test_bit( counter, hint1 ) || + ps_mask_test_bit( counter, hint2 ) || + ps_mask_test_bit( counter, hint3 ) ) + break; + } +/* create a new counter when needed */ + if ( count == 0 ) + { + error = ps_mask_table_alloc( &dim->counters, memory, &counter ); + if ( error ) + goto Exit; + } +/* now, set the bits for our hints in the counter mask */ + error = ps_mask_set_bit( counter, hint1, memory ); + if ( error ) + goto Exit; + error = ps_mask_set_bit( counter, hint2, memory ); + if ( error ) + goto Exit; + error = ps_mask_set_bit( counter, hint3, memory ); + if ( error ) + goto Exit; + Exit: + return error; + } +/* end of recording session for a given dimension */ + static FT_Error + ps_dimension_end( PS_Dimension dim, + FT_UInt end_point, + FT_Memory memory ) + { +/* end hint mask table */ + ps_dimension_end_mask( dim, end_point ); +/* merge all counter masks into independent "paths" */ + return ps_mask_table_merge_all( &dim->counters, memory ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PS_RECORDER MANAGEMENT *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* destroy hints */ + FT_LOCAL( void ) + ps_hints_done( PS_Hints hints ) + { + FT_Memory memory = hints->memory; + ps_dimension_done( &hints->dimension[0], memory ); + ps_dimension_done( &hints->dimension[1], memory ); + hints->error = PSH_Err_Ok; + hints->memory = 0; + } + FT_LOCAL( FT_Error ) + ps_hints_init( PS_Hints hints, + FT_Memory memory ) + { + FT_MEM_ZERO( hints, sizeof ( *hints ) ); + hints->memory = memory; + return PSH_Err_Ok; + } +/* initialize a hints for a new session */ + static void + ps_hints_open( PS_Hints hints, + PS_Hint_Type hint_type ) + { + switch ( hint_type ) + { + case PS_HINT_TYPE_1: + case PS_HINT_TYPE_2: + hints->error = PSH_Err_Ok; + hints->hint_type = hint_type; + ps_dimension_init( &hints->dimension[0] ); + ps_dimension_init( &hints->dimension[1] ); + break; + default: + hints->error = PSH_Err_Invalid_Argument; + hints->hint_type = hint_type; + FT_TRACE0(( "ps_hints_open: invalid charstring type\n" )); + break; + } + } +/* add one or more stems to the current hints table */ + static void + ps_hints_stem( PS_Hints hints, + FT_Int dimension, + FT_UInt count, + FT_Long* stems ) + { + if ( !hints->error ) + { +/* limit "dimension" to 0..1 */ + if ( dimension < 0 || dimension > 1 ) + { + FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } +/* record the stems in the current hints/masks table */ + switch ( hints->hint_type ) + { +/* Type 1 "hstem" or "vstem" operator */ + case PS_HINT_TYPE_1: +/* Type 2 "hstem" or "vstem" operator */ + case PS_HINT_TYPE_2: + { + PS_Dimension dim = &hints->dimension[dimension]; + for ( ; count > 0; count--, stems += 2 ) + { + FT_Error error; + FT_Memory memory = hints->memory; + error = ps_dimension_add_t1stem( + dim, (FT_Int)stems[0], (FT_Int)stems[1], + memory, NULL ); + if ( error ) + { + FT_ERROR(( "ps_hints_stem: could not add stem" + " (%d,%d) to hints table\n", stems[0], stems[1] )); + hints->error = error; + return; + } + } + break; + } + default: + FT_TRACE0(( "ps_hints_stem: called with invalid hint type (%d)\n", + hints->hint_type )); + break; + } + } + } +/* add one Type1 counter stem to the current hints table */ + static void + ps_hints_t1stem3( PS_Hints hints, + FT_Int dimension, + FT_Fixed* stems ) + { + FT_Error error = PSH_Err_Ok; + if ( !hints->error ) + { + PS_Dimension dim; + FT_Memory memory = hints->memory; + FT_Int count; + FT_Int idx[3]; +/* limit "dimension" to 0..1 */ + if ( dimension < 0 || dimension > 1 ) + { + FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", + dimension )); + dimension = ( dimension != 0 ); + } + dim = &hints->dimension[dimension]; +/* there must be 6 elements in the 'stem' array */ + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { +/* add the three stems to our hints/masks table */ + for ( count = 0; count < 3; count++, stems += 2 ) + { + error = ps_dimension_add_t1stem( dim, + (FT_Int)FIXED_TO_INT( stems[0] ), + (FT_Int)FIXED_TO_INT( stems[1] ), + memory, &idx[count] ); + if ( error ) + goto Fail; + } +/* now, add the hints to the counters table */ + error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2], + memory ); + if ( error ) + goto Fail; + } + else + { + FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type\n" )); + error = PSH_Err_Invalid_Argument; + goto Fail; + } + } + return; + Fail: + FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" )); + hints->error = error; + } +/* reset hints (only with Type 1 hints) */ + static void + ps_hints_t1reset( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error = PSH_Err_Ok; + if ( !hints->error ) + { + FT_Memory memory = hints->memory; + if ( hints->hint_type == PS_HINT_TYPE_1 ) + { + error = ps_dimension_reset_mask( &hints->dimension[0], + end_point, memory ); + if ( error ) + goto Fail; + error = ps_dimension_reset_mask( &hints->dimension[1], + end_point, memory ); + if ( error ) + goto Fail; + } + else + { +/* invalid hint type */ + error = PSH_Err_Invalid_Argument; + goto Fail; + } + } + return; + Fail: + hints->error = error; + } +/* Type2 "hintmask" operator, add a new hintmask to each direction */ + static void + ps_hints_t2mask( PS_Hints hints, + FT_UInt end_point, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + FT_Error error; + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; +/* check bit count; must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_TRACE0(( "ps_hints_t2mask:" + " called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); +/* simply ignore the operator */ + return; + } +/* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, count2, count1, + end_point, memory ); + if ( error ) + goto Fail; + error = ps_dimension_set_mask_bits( &dim[1], bytes, 0, count2, + end_point, memory ); + if ( error ) + goto Fail; + } + return; + Fail: + hints->error = error; + } + static void + ps_hints_t2counter( PS_Hints hints, + FT_UInt bit_count, + const FT_Byte* bytes ) + { + FT_Error error; + if ( !hints->error ) + { + PS_Dimension dim = hints->dimension; + FT_Memory memory = hints->memory; + FT_UInt count1 = dim[0].hints.num_hints; + FT_UInt count2 = dim[1].hints.num_hints; +/* check bit count, must be equal to current total hint count */ + if ( bit_count != count1 + count2 ) + { + FT_TRACE0(( "ps_hints_t2counter:" + " called with invalid bitcount %d (instead of %d)\n", + bit_count, count1 + count2 )); +/* simply ignore the operator */ + return; + } +/* set-up new horizontal and vertical hint mask now */ + error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1, + 0, memory ); + if ( error ) + goto Fail; + error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2, + 0, memory ); + if ( error ) + goto Fail; + } + return; + Fail: + hints->error = error; + } +/* end recording session */ + static FT_Error + ps_hints_close( PS_Hints hints, + FT_UInt end_point ) + { + FT_Error error; + error = hints->error; + if ( !error ) + { + FT_Memory memory = hints->memory; + PS_Dimension dim = hints->dimension; + error = ps_dimension_end( &dim[0], end_point, memory ); + if ( !error ) + { + error = ps_dimension_end( &dim[1], end_point, memory ); + } + } +#ifdef DEBUG_HINTER + if ( !error ) + ps_debug_hints = hints; +#endif + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE 1 HINTS RECORDING INTERFACE *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static void + t1_hints_open( T1_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); + } + static void + t1_hints_stem( T1_Hints hints, + FT_Int dimension, + FT_Fixed* coords ) + { + FT_Pos stems[2]; + stems[0] = FIXED_TO_INT( coords[0] ); + stems[1] = FIXED_TO_INT( coords[1] ); + ps_hints_stem( (PS_Hints)hints, dimension, 1, stems ); + } + FT_LOCAL_DEF( void ) + t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) + { + FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) ); + funcs->open = (T1_Hints_OpenFunc) t1_hints_open; + funcs->close = (T1_Hints_CloseFunc) ps_hints_close; + funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem; + funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3; + funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset; + funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE 2 HINTS RECORDING INTERFACE *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static void + t2_hints_open( T2_Hints hints ) + { + ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 ); + } + static void + t2_hints_stems( T2_Hints hints, + FT_Int dimension, + FT_Int count, + FT_Fixed* coords ) + { + FT_Pos stems[32], y, n; + FT_Int total = count; + y = 0; + while ( total > 0 ) + { +/* determine number of stems to write */ + count = total; + if ( count > 16 ) + count = 16; +/* compute integer stem positions in font units */ + for ( n = 0; n < count * 2; n++ ) + { + y += coords[n]; + stems[n] = FIXED_TO_INT( y ); + } +/* compute lengths */ + for ( n = 0; n < count * 2; n += 2 ) + stems[n + 1] = stems[n + 1] - stems[n]; +/* add them to the current dimension */ + ps_hints_stem( (PS_Hints)hints, dimension, count, stems ); + total -= count; + } + } + FT_LOCAL_DEF( void ) + t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) + { + FT_MEM_ZERO( funcs, sizeof ( *funcs ) ); + funcs->open = (T2_Hints_OpenFunc) t2_hints_open; + funcs->close = (T2_Hints_CloseFunc) ps_hints_close; + funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems; + funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask; + funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter; + funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply; + } +/* END */ +/***************************************************************************/ +/* */ +/* pshglob.c */ +/* */ +/* PostScript hinter global hinting management (body). */ +/* Inspired by the new auto-hinter module. */ +/* */ +/* Copyright 2001-2004, 2006, 2010, 2012 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. */ +/* */ +/***************************************************************************/ +#ifdef DEBUG_HINTER + PSH_Globals ps_debug_globals = 0; +#endif +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** STANDARD WIDTHS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* scale the widths/heights table */ + static void + psh_globals_scale_widths( PSH_Globals globals, + FT_UInt direction ) + { + PSH_Dimension dim = &globals->dimension[direction]; + PSH_Widths stdw = &dim->stdw; + FT_UInt count = stdw->count; + PSH_Width width = stdw->widths; +/* standard width/height */ + PSH_Width stand = width; + FT_Fixed scale = dim->scale_mult; + if ( count > 0 ) + { + width->cur = FT_MulFix( width->org, scale ); + width->fit = FT_PIX_ROUND( width->cur ); + width++; + count--; + for ( ; count > 0; count--, width++ ) + { + FT_Pos w, dist; + w = FT_MulFix( width->org, scale ); + dist = w - stand->cur; + if ( dist < 0 ) + dist = -dist; + if ( dist < 128 ) + w = stand->cur; + width->cur = w; + width->fit = FT_PIX_ROUND( w ); + } + } + } +#if 0 +/* org_width is is font units, result in device pixels, 26.6 format */ + FT_LOCAL_DEF( FT_Pos ) + psh_dimension_snap_width( PSH_Dimension dimension, + FT_Int org_width ) + { + FT_UInt n; + FT_Pos width = FT_MulFix( org_width, dimension->scale_mult ); + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + for ( n = 0; n < dimension->stdw.count; n++ ) + { + FT_Pos w; + FT_Pos dist; + w = dimension->stdw.widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + if ( width >= reference ) + { + width -= 0x21; + if ( width < reference ) + width = reference; + } + else + { + width += 0x21; + if ( width > reference ) + width = reference; + } + return width; + } +/* 0 */ +#endif +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** BLUE ZONES *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static void + psh_blues_set_zones_0( PSH_Blues target, + FT_Bool is_others, + FT_UInt read_count, + FT_Short* read, + PSH_Blue_Table top_table, + PSH_Blue_Table bot_table ) + { + FT_UInt count_top = top_table->count; + FT_UInt count_bot = bot_table->count; + FT_Bool first = 1; + FT_UNUSED( target ); + for ( ; read_count > 1; read_count -= 2 ) + { + FT_Int reference, delta; + FT_UInt count; + PSH_Blue_Zone zones, zone; + FT_Bool top; +/* read blue zone entry, and select target top/bottom zone */ + top = 0; + if ( first || is_others ) + { + reference = read[1]; + delta = read[0] - reference; + zones = bot_table->zones; + count = count_bot; + first = 0; + } + else + { + reference = read[0]; + delta = read[1] - reference; + zones = top_table->zones; + count = count_top; + top = 1; + } +/* insert into sorted table */ + zone = zones; + for ( ; count > 0; count--, zone++ ) + { + if ( reference < zone->org_ref ) + break; + if ( reference == zone->org_ref ) + { + FT_Int delta0 = zone->org_delta; +/* we have two zones on the same reference position -- */ +/* only keep the largest one */ + if ( delta < 0 ) + { + if ( delta < delta0 ) + zone->org_delta = delta; + } + else + { + if ( delta > delta0 ) + zone->org_delta = delta; + } + goto Skip; + } + } + for ( ; count > 0; count-- ) + zone[count] = zone[count-1]; + zone->org_ref = reference; + zone->org_delta = delta; + if ( top ) + count_top++; + else + count_bot++; + Skip: + read += 2; + } + top_table->count = count_top; + bot_table->count = count_bot; + } +/* Re-read blue zones from the original fonts and store them into out */ +/* private structure. This function re-orders, sanitizes and */ +/* fuzz-expands the zones as well. */ + static void + psh_blues_set_zones( PSH_Blues target, + FT_UInt count, + FT_Short* blues, + FT_UInt count_others, + FT_Short* other_blues, + FT_Int fuzz, + FT_Int family ) + { + PSH_Blue_Table top_table, bot_table; + FT_Int count_top, count_bot; + if ( family ) + { + top_table = &target->family_top; + bot_table = &target->family_bottom; + } + else + { + top_table = &target->normal_top; + bot_table = &target->normal_bottom; + } +/* read the input blue zones, and build two sorted tables */ +/* (one for the top zones, the other for the bottom zones) */ + top_table->count = 0; + bot_table->count = 0; +/* first, the blues */ + psh_blues_set_zones_0( target, 0, + count, blues, top_table, bot_table ); + psh_blues_set_zones_0( target, 1, + count_others, other_blues, top_table, bot_table ); + count_top = top_table->count; + count_bot = bot_table->count; +/* sanitize top table */ + if ( count_top > 0 ) + { + PSH_Blue_Zone zone = top_table->zones; + for ( count = count_top; count > 0; count--, zone++ ) + { + FT_Int delta; + if ( count > 1 ) + { + delta = zone[1].org_ref - zone[0].org_ref; + if ( zone->org_delta > delta ) + zone->org_delta = delta; + } + zone->org_bottom = zone->org_ref; + zone->org_top = zone->org_delta + zone->org_ref; + } + } +/* sanitize bottom table */ + if ( count_bot > 0 ) + { + PSH_Blue_Zone zone = bot_table->zones; + for ( count = count_bot; count > 0; count--, zone++ ) + { + FT_Int delta; + if ( count > 1 ) + { + delta = zone[0].org_ref - zone[1].org_ref; + if ( zone->org_delta < delta ) + zone->org_delta = delta; + } + zone->org_top = zone->org_ref; + zone->org_bottom = zone->org_delta + zone->org_ref; + } + } +/* expand top and bottom tables with blue fuzz */ + { + FT_Int dim, top, bot, delta; + PSH_Blue_Zone zone; + zone = top_table->zones; + count = count_top; + for ( dim = 1; dim >= 0; dim-- ) + { + if ( count > 0 ) + { +/* expand the bottom of the lowest zone normally */ + zone->org_bottom -= fuzz; +/* expand the top and bottom of intermediate zones; */ +/* checking that the interval is smaller than the fuzz */ + top = zone->org_top; + for ( count--; count > 0; count-- ) + { + bot = zone[1].org_bottom; + delta = bot - top; + if ( delta < 2 * fuzz ) + zone[0].org_top = zone[1].org_bottom = top + delta / 2; + else + { + zone[0].org_top = top + fuzz; + zone[1].org_bottom = bot - fuzz; + } + zone++; + top = zone->org_top; + } +/* expand the top of the highest zone normally */ + zone->org_top = top + fuzz; + } + zone = bot_table->zones; + count = count_bot; + } + } + } +/* reset the blues table when the device transform changes */ + static void + psh_blues_scale_zones( PSH_Blues blues, + FT_Fixed scale, + FT_Pos delta ) + { + FT_UInt count; + FT_UInt num; + PSH_Blue_Table table = 0; +/* */ +/* Determine whether we need to suppress overshoots or */ +/* not. We simply need to compare the vertical scale */ +/* parameter to the raw bluescale value. Here is why: */ +/* */ +/* We need to suppress overshoots for all pointsizes. */ +/* At 300dpi that satisfies: */ +/* */ +/* pointsize < 240*bluescale + 0.49 */ +/* */ +/* This corresponds to: */ +/* */ +/* pixelsize < 1000*bluescale + 49/24 */ +/* */ +/* scale*EM_Size < 1000*bluescale + 49/24 */ +/* */ +/* However, for normal Type 1 fonts, EM_Size is 1000! */ +/* We thus only check: */ +/* */ +/* scale < bluescale + 49/24000 */ +/* */ +/* which we shorten to */ +/* */ +/* "scale < bluescale" */ +/* */ +/* Note that `blue_scale' is stored 1000 times its real */ +/* value, and that `scale' converts from font units to */ +/* fractional pixels. */ +/* */ +/* 1000 / 64 = 125 / 8 */ + if ( scale >= 0x20C49BAL ) + blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 ); + else + blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 ); +/* */ +/* The blue threshold is the font units distance under */ +/* which overshoots are suppressed due to the BlueShift */ +/* even if the scale is greater than BlueScale. */ +/* */ +/* It is the smallest distance such that */ +/* */ +/* dist <= BlueShift && dist*scale <= 0.5 pixels */ +/* */ + { + FT_Int threshold = blues->blue_shift; + while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 ) + threshold--; + blues->blue_threshold = threshold; + } + for ( num = 0; num < 4; num++ ) + { + PSH_Blue_Zone zone; + switch ( num ) + { + case 0: + table = &blues->normal_top; + break; + case 1: + table = &blues->normal_bottom; + break; + case 2: + table = &blues->family_top; + break; + default: + table = &blues->family_bottom; + break; + } + zone = table->zones; + count = table->count; + for ( ; count > 0; count--, zone++ ) + { + zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta; + zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta; + zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta; + zone->cur_delta = FT_MulFix( zone->org_delta, scale ); +/* round scaled reference position */ + zone->cur_ref = FT_PIX_ROUND( zone->cur_ref ); +#if 0 + if ( zone->cur_ref > zone->cur_top ) + zone->cur_ref -= 64; + else if ( zone->cur_ref < zone->cur_bottom ) + zone->cur_ref += 64; +#endif + } + } +/* process the families now */ + for ( num = 0; num < 2; num++ ) + { + PSH_Blue_Zone zone1, zone2; + FT_UInt count1, count2; + PSH_Blue_Table normal, family; + switch ( num ) + { + case 0: + normal = &blues->normal_top; + family = &blues->family_top; + break; + default: + normal = &blues->normal_bottom; + family = &blues->family_bottom; + } + zone1 = normal->zones; + count1 = normal->count; + for ( ; count1 > 0; count1--, zone1++ ) + { +/* try to find a family zone whose reference position is less */ +/* than 1 pixel far from the current zone */ + zone2 = family->zones; + count2 = family->count; + for ( ; count2 > 0; count2--, zone2++ ) + { + FT_Pos Delta; + Delta = zone1->org_ref - zone2->org_ref; + if ( Delta < 0 ) + Delta = -Delta; + if ( FT_MulFix( Delta, scale ) < 64 ) + { + zone1->cur_top = zone2->cur_top; + zone1->cur_bottom = zone2->cur_bottom; + zone1->cur_ref = zone2->cur_ref; + zone1->cur_delta = zone2->cur_delta; + break; + } + } + } + } + } +/* calculate the maximum height of given blue zones */ + static FT_Short + psh_calc_max_height( FT_UInt num, + const FT_Short* values, + FT_Short cur_max ) + { + FT_UInt count; + for ( count = 0; count < num; count += 2 ) + { + FT_Short cur_height = values[count + 1] - values[count]; + if ( cur_height > cur_max ) + cur_max = cur_height; + } + return cur_max; + } + FT_LOCAL_DEF( void ) + psh_blues_snap_stem( PSH_Blues blues, + FT_Int stem_top, + FT_Int stem_bot, + PSH_Alignment alignment ) + { + PSH_Blue_Table table; + FT_UInt count; + FT_Pos delta; + PSH_Blue_Zone zone; + FT_Int no_shoots; + alignment->align = PSH_BLUE_ALIGN_NONE; + no_shoots = blues->no_overshoots; +/* look up stem top in top zones table */ + table = &blues->normal_top; + count = table->count; + zone = table->zones; + for ( ; count > 0; count--, zone++ ) + { + delta = stem_top - zone->org_bottom; + if ( delta < -blues->blue_fuzz ) + break; + if ( stem_top <= zone->org_top + blues->blue_fuzz ) + { + if ( no_shoots || delta <= blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_TOP; + alignment->align_top = zone->cur_ref; + } + break; + } + } +/* look up stem bottom in bottom zones table */ + table = &blues->normal_bottom; + count = table->count; + zone = table->zones + count-1; + for ( ; count > 0; count--, zone-- ) + { + delta = zone->org_top - stem_bot; + if ( delta < -blues->blue_fuzz ) + break; + if ( stem_bot >= zone->org_bottom - blues->blue_fuzz ) + { + if ( no_shoots || delta < blues->blue_threshold ) + { + alignment->align |= PSH_BLUE_ALIGN_BOT; + alignment->align_bot = zone->cur_ref; + } + break; + } + } + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** GLOBAL HINTS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static void + psh_globals_destroy( PSH_Globals globals ) + { + if ( globals ) + { + FT_Memory memory; + memory = globals->memory; + globals->dimension[0].stdw.count = 0; + globals->dimension[1].stdw.count = 0; + globals->blues.normal_top.count = 0; + globals->blues.normal_bottom.count = 0; + globals->blues.family_top.count = 0; + globals->blues.family_bottom.count = 0; + FT_FREE( globals ); +#ifdef DEBUG_HINTER + ps_debug_globals = 0; +#endif + } + } + static FT_Error + psh_globals_new( FT_Memory memory, + T1_Private* priv, + PSH_Globals *aglobals ) + { + PSH_Globals globals = NULL; + FT_Error error; + if ( !FT_NEW( globals ) ) + { + FT_UInt count; + FT_Short* read; + globals->memory = memory; +/* copy standard widths */ + { + PSH_Dimension dim = &globals->dimension[1]; + PSH_Width write = dim->stdw.widths; + write->org = priv->standard_width[0]; + write++; + read = priv->snap_widths; + for ( count = priv->num_snap_widths; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + dim->stdw.count = priv->num_snap_widths + 1; + } +/* copy standard heights */ + { + PSH_Dimension dim = &globals->dimension[0]; + PSH_Width write = dim->stdw.widths; + write->org = priv->standard_height[0]; + write++; + read = priv->snap_heights; + for ( count = priv->num_snap_heights; count > 0; count-- ) + { + write->org = *read; + write++; + read++; + } + dim->stdw.count = priv->num_snap_heights + 1; + } +/* copy blue zones */ + psh_blues_set_zones( &globals->blues, priv->num_blue_values, + priv->blue_values, priv->num_other_blues, + priv->other_blues, priv->blue_fuzz, 0 ); + psh_blues_set_zones( &globals->blues, priv->num_family_blues, + priv->family_blues, priv->num_family_other_blues, + priv->family_other_blues, priv->blue_fuzz, 1 ); +/* limit the BlueScale value to `1 / max_of_blue_zone_heights' */ + { + FT_Fixed max_scale; + FT_Short max_height = 1; + max_height = psh_calc_max_height( priv->num_blue_values, + priv->blue_values, + max_height ); + max_height = psh_calc_max_height( priv->num_other_blues, + priv->other_blues, + max_height ); + max_height = psh_calc_max_height( priv->num_family_blues, + priv->family_blues, + max_height ); + max_height = psh_calc_max_height( priv->num_family_other_blues, + priv->family_other_blues, + max_height ); +/* BlueScale is scaled 1000 times */ + max_scale = FT_DivFix( 1000, max_height ); + globals->blues.blue_scale = priv->blue_scale < max_scale + ? priv->blue_scale + : max_scale; + } + globals->blues.blue_shift = priv->blue_shift; + globals->blues.blue_fuzz = priv->blue_fuzz; + globals->dimension[0].scale_mult = 0; + globals->dimension[0].scale_delta = 0; + globals->dimension[1].scale_mult = 0; + globals->dimension[1].scale_delta = 0; +#ifdef DEBUG_HINTER + ps_debug_globals = globals; +#endif + } + *aglobals = globals; + return error; + } + FT_LOCAL_DEF( FT_Error ) + psh_globals_set_scale( PSH_Globals globals, + FT_Fixed x_scale, + FT_Fixed y_scale, + FT_Fixed x_delta, + FT_Fixed y_delta ) + { + PSH_Dimension dim = &globals->dimension[0]; + dim = &globals->dimension[0]; + if ( x_scale != dim->scale_mult || + x_delta != dim->scale_delta ) + { + dim->scale_mult = x_scale; + dim->scale_delta = x_delta; + psh_globals_scale_widths( globals, 0 ); + } + dim = &globals->dimension[1]; + if ( y_scale != dim->scale_mult || + y_delta != dim->scale_delta ) + { + dim->scale_mult = y_scale; + dim->scale_delta = y_delta; + psh_globals_scale_widths( globals, 1 ); + psh_blues_scale_zones( &globals->blues, y_scale, y_delta ); + } + return 0; + } + FT_LOCAL_DEF( void ) + psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs ) + { + funcs->create = psh_globals_new; + funcs->set_scale = psh_globals_set_scale; + funcs->destroy = psh_globals_destroy; + } +/* END */ +/***************************************************************************/ +/* */ +/* pshalgo.c */ +/* */ +/* PostScript hinting algorithm (body). */ +/* */ +/* Copyright 2001-2010, 2012 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_COMPONENT +#define FT_COMPONENT trace_pshalgo2 +#ifdef DEBUG_HINTER + PSH_Hint_Table ps_debug_hint_table = 0; + PSH_HintFunc ps_debug_hint_func = 0; + PSH_Glyph ps_debug_glyph = 0; +#endif +/* compute inflection points to optimize `S' */ +#define COMPUTE_INFLEXS +/* and similar glyphs */ +/* slightly increase the contrast of smooth */ +#define STRONGER +/* hinting */ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** BASIC HINTS RECORDINGS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* return true if two stem hints overlap */ + static FT_Int + psh_hint_overlap( PSH_Hint hint1, + PSH_Hint hint2 ) + { + return hint1->org_pos + hint1->org_len >= hint2->org_pos && + hint2->org_pos + hint2->org_len >= hint1->org_pos; + } +/* destroy hints table */ + static void + psh_hint_table_done( PSH_Hint_Table table, + FT_Memory memory ) + { + FT_FREE( table->zones ); + table->num_zones = 0; + table->zone = 0; + FT_FREE( table->sort ); + FT_FREE( table->hints ); + table->num_hints = 0; + table->max_hints = 0; + table->sort_global = 0; + } +/* deactivate all hints in a table */ + static void + psh_hint_table_deactivate( PSH_Hint_Table table ) + { + FT_UInt count = table->max_hints; + PSH_Hint hint = table->hints; + for ( ; count > 0; count--, hint++ ) + { + psh_hint_deactivate( hint ); + hint->order = -1; + } + } +/* internal function to record a new hint */ + static void + psh_hint_table_record( PSH_Hint_Table table, + FT_UInt idx ) + { + PSH_Hint hint = table->hints + idx; + if ( idx >= table->max_hints ) + { + FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx )); + return; + } +/* ignore active hints */ + if ( psh_hint_is_active( hint ) ) + return; + psh_hint_activate( hint ); +/* now scan the current active hint set to check */ +/* whether `hint' overlaps with another hint */ + { + PSH_Hint* sorted = table->sort_global; + FT_UInt count = table->num_hints; + PSH_Hint hint2; + hint->parent = 0; + for ( ; count > 0; count--, sorted++ ) + { + hint2 = sorted[0]; + if ( psh_hint_overlap( hint, hint2 ) ) + { + hint->parent = hint2; + break; + } + } + } + if ( table->num_hints < table->max_hints ) + table->sort_global[table->num_hints++] = hint; + else + FT_TRACE0(( "psh_hint_table_record: too many sorted hints! BUG!\n" )); + } + static void + psh_hint_table_record_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit; + limit = hint_mask->num_bits; + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + if ( val & mask ) + psh_hint_table_record( table, idx ); + mask >>= 1; + } + } +/* create hints table */ + static FT_Error + psh_hint_table_init( PSH_Hint_Table table, + PS_Hint_Table hints, + PS_Mask_Table hint_masks, + PS_Mask_Table counter_masks, + FT_Memory memory ) + { + FT_UInt count; + FT_Error error; + FT_UNUSED( counter_masks ); + count = hints->num_hints; +/* allocate our tables */ + if ( FT_NEW_ARRAY( table->sort, 2 * count ) || + FT_NEW_ARRAY( table->hints, count ) || + FT_NEW_ARRAY( table->zones, 2 * count + 1 ) ) + goto Exit; + table->max_hints = count; + table->sort_global = table->sort + count; + table->num_hints = 0; + table->num_zones = 0; + table->zone = 0; +/* initialize the `table->hints' array */ + { + PSH_Hint write = table->hints; + PS_Hint read = hints->hints; + for ( ; count > 0; count--, write++, read++ ) + { + write->org_pos = read->pos; + write->org_len = read->len; + write->flags = read->flags; + } + } +/* we now need to determine the initial `parent' stems; first */ +/* activate the hints that are given by the initial hint masks */ + if ( hint_masks ) + { + PS_Mask mask = hint_masks->masks; + count = hint_masks->num_masks; + table->hint_masks = hint_masks; + for ( ; count > 0; count--, mask++ ) + psh_hint_table_record_mask( table, mask ); + } +/* finally, do a linear parse in case some hints were left alone */ + if ( table->num_hints != table->max_hints ) + { + FT_UInt idx; + FT_TRACE0(( "psh_hint_table_init: missing/incorrect hint masks\n" )); + count = table->max_hints; + for ( idx = 0; idx < count; idx++ ) + psh_hint_table_record( table, idx ); + } + Exit: + return error; + } + static void + psh_hint_table_activate_mask( PSH_Hint_Table table, + PS_Mask hint_mask ) + { + FT_Int mask = 0, val = 0; + FT_Byte* cursor = hint_mask->bytes; + FT_UInt idx, limit, count; + limit = hint_mask->num_bits; + count = 0; + psh_hint_table_deactivate( table ); + for ( idx = 0; idx < limit; idx++ ) + { + if ( mask == 0 ) + { + val = *cursor++; + mask = 0x80; + } + if ( val & mask ) + { + PSH_Hint hint = &table->hints[idx]; + if ( !psh_hint_is_active( hint ) ) + { + FT_UInt count2; +#if 0 + PSH_Hint* sort = table->sort; + PSH_Hint hint2; + for ( count2 = count; count2 > 0; count2--, sort++ ) + { + hint2 = sort[0]; + if ( psh_hint_overlap( hint, hint2 ) ) + FT_TRACE0(( "psh_hint_table_activate_mask:" + " found overlapping hints\n" )) + } +#else + count2 = 0; +#endif + if ( count2 == 0 ) + { + psh_hint_activate( hint ); + if ( count < table->max_hints ) + table->sort[count++] = hint; + else + FT_TRACE0(( "psh_hint_tableactivate_mask:" + " too many active hints\n" )); + } + } + } + mask >>= 1; + } + table->num_hints = count; +/* now, sort the hints; they are guaranteed to not overlap */ +/* so we can compare their "org_pos" field directly */ + { + FT_Int i1, i2; + PSH_Hint hint1, hint2; + PSH_Hint* sort = table->sort; +/* a simple bubble sort will do, since in 99% of cases, the hints */ +/* will be already sorted -- and the sort will be linear */ + for ( i1 = 1; i1 < (FT_Int)count; i1++ ) + { + hint1 = sort[i1]; + for ( i2 = i1 - 1; i2 >= 0; i2-- ) + { + hint2 = sort[i2]; + if ( hint2->org_pos < hint1->org_pos ) + break; + sort[i2 + 1] = hint2; + sort[i2] = hint1; + } + } + } + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** HINTS GRID-FITTING AND OPTIMIZATION *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#if 1 + static FT_Pos + psh_dimension_quantize_len( PSH_Dimension dim, + FT_Pos len, + FT_Bool do_snapping ) + { + if ( len <= 64 ) + len = 64; + else + { + FT_Pos delta = len - dim->stdw.widths[0].cur; + if ( delta < 0 ) + delta = -delta; + if ( delta < 40 ) + { + len = dim->stdw.widths[0].cur; + if ( len < 48 ) + len = 48; + } + if ( len < 3 * 64 ) + { + delta = ( len & 63 ); + len &= -64; + if ( delta < 10 ) + len += delta; + else if ( delta < 32 ) + len += 10; + else if ( delta < 54 ) + len += 54; + else + len += delta; + } + else + len = FT_PIX_ROUND( len ); + } + if ( do_snapping ) + len = FT_PIX_ROUND( len ); + return len; + } +/* 0 */ +#endif +#ifdef DEBUG_HINTER + static void + ps_simple_scale( PSH_Hint_Table table, + FT_Fixed scale, + FT_Fixed delta, + FT_Int dimension ) + { + PSH_Hint hint; + FT_UInt count; + for ( count = 0; count < table->max_hints; count++ ) + { + hint = table->hints + count; + hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta; + hint->cur_len = FT_MulFix( hint->org_len, scale ); + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); + } + } +/* DEBUG_HINTER */ +#endif + static FT_Fixed + psh_hint_snap_stem_side_delta( FT_Fixed pos, + FT_Fixed len ) + { + FT_Fixed delta1 = FT_PIX_ROUND( pos ) - pos; + FT_Fixed delta2 = FT_PIX_ROUND( pos + len ) - pos - len; + if ( FT_ABS( delta1 ) <= FT_ABS( delta2 ) ) + return delta1; + else + return delta2; + } + static void + psh_hint_align( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + FT_Int do_snapping; + FT_Pos fit_len; + PSH_AlignmentRec align; +/* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + psh_hint_set_fitted( hint ); + return; + } +/* perform stem snapping when requested - this is necessary + * for monochrome and LCD hinting modes only + */ + do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) || + ( dimension == 1 && glyph->do_vert_snapping ); + hint->cur_len = fit_len = len; +/* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + hint->org_pos + hint->org_len, + hint->org_pos, + &align ); + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: +/* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + case PSH_BLUE_ALIGN_BOT: +/* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: +/* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + default: + { + PSH_Hint parent = hint->parent; + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; +/* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align( parent, globals, dimension, glyph ); +/* keep original relation between hints, this is, use the */ +/* scaled distance between the centers of the hints to */ +/* compute the new position */ + par_org_center = parent->org_pos + ( parent->org_len >> 1 ); + par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 ); + cur_org_center = hint->org_pos + ( hint->org_len >> 1 ); + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } + hint->cur_pos = pos; + hint->cur_len = fit_len; +/* Stem adjustment tries to snap stem widths to standard + * ones. This is important to prevent unpleasant rounding + * artefacts. + */ + if ( glyph->do_stem_adjust ) + { + if ( len <= 64 ) + { +/* the stem is less than one pixel; we will center it + * around the nearest pixel center + */ + if ( len >= 32 ) + { +/* This is a special case where we also widen the stem + * and align it to the pixel grid. + * + * stem_center = pos + (len/2) + * nearest_pixel_center = FT_ROUND(stem_center-32)+32 + * new_pos = nearest_pixel_center-32 + * = FT_ROUND(stem_center-32) + * = FT_FLOOR(stem_center-32+32) + * = FT_FLOOR(stem_center) + * new_len = 64 + */ + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ); + len = 64; + } + else if ( len > 0 ) + { +/* This is a very small stem; we simply align it to the + * pixel grid, trying to find the minimum displacement. + * + * left = pos + * right = pos + len + * left_nearest_edge = ROUND(pos) + * right_nearest_edge = ROUND(right) + * + * if ( ABS(left_nearest_edge - left) <= + * ABS(right_nearest_edge - right) ) + * new_pos = left + * else + * new_pos = right + */ + FT_Pos left_nearest = FT_PIX_ROUND( pos ); + FT_Pos right_nearest = FT_PIX_ROUND( pos + len ); + FT_Pos left_disp = left_nearest - pos; + FT_Pos right_disp = right_nearest - ( pos + len ); + if ( left_disp < 0 ) + left_disp = -left_disp; + if ( right_disp < 0 ) + right_disp = -right_disp; + if ( left_disp <= right_disp ) + pos = left_nearest; + else + pos = right_nearest; + } + else + { +/* this is a ghost stem; we simply round it */ + pos = FT_PIX_ROUND( pos ); + } + } + else + { + len = psh_dimension_quantize_len( dim, len, 0 ); + } + } +/* now that we have a good hinted stem width, try to position */ +/* the stem along a pixel grid integer coordinate */ + hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len ); + hint->cur_len = len; + } + } + if ( do_snapping ) + { + pos = hint->cur_pos; + len = hint->cur_len; + if ( len < 64 ) + len = 64; + else + len = FT_PIX_ROUND( len ); + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: + hint->cur_pos = align.align_top - len; + hint->cur_len = len; + break; + case PSH_BLUE_ALIGN_BOT: + hint->cur_len = len; + break; + case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP: +/* don't touch */ + break; + default: + hint->cur_len = len; + if ( len & 64 ) + pos = FT_PIX_FLOOR( pos + ( len >> 1 ) ) + 32; + else + pos = FT_PIX_ROUND( pos + ( len >> 1 ) ); + hint->cur_pos = pos - ( len >> 1 ); + hint->cur_len = len; + } + } + psh_hint_set_fitted( hint ); +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } +/* not used for now, experimental */ +#if 0 +/* + * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT) + * of stems + */ + static void + psh_hint_align_light( PSH_Hint hint, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + if ( !psh_hint_is_fitted( hint ) ) + { + FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta; + FT_Pos len = FT_MulFix( hint->org_len, scale ); + FT_Pos fit_len; + PSH_AlignmentRec align; +/* ignore stem alignments when requested through the hint flags */ + if ( ( dimension == 0 && !glyph->do_horz_hints ) || + ( dimension == 1 && !glyph->do_vert_hints ) ) + { + hint->cur_pos = pos; + hint->cur_len = len; + psh_hint_set_fitted( hint ); + return; + } + fit_len = len; + hint->cur_len = fit_len; +/* check blue zones for horizontal stems */ + align.align = PSH_BLUE_ALIGN_NONE; + align.align_bot = align.align_top = 0; + if ( dimension == 1 ) + psh_blues_snap_stem( &globals->blues, + hint->org_pos + hint->org_len, + hint->org_pos, + &align ); + switch ( align.align ) + { + case PSH_BLUE_ALIGN_TOP: +/* the top of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_top - fit_len; + break; + case PSH_BLUE_ALIGN_BOT: +/* the bottom of the stem is aligned against a blue zone */ + hint->cur_pos = align.align_bot; + break; + case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT: +/* both edges of the stem are aligned against blue zones */ + hint->cur_pos = align.align_bot; + hint->cur_len = align.align_top - align.align_bot; + break; + default: + { + PSH_Hint parent = hint->parent; + if ( parent ) + { + FT_Pos par_org_center, par_cur_center; + FT_Pos cur_org_center, cur_delta; +/* ensure that parent is already fitted */ + if ( !psh_hint_is_fitted( parent ) ) + psh_hint_align_light( parent, globals, dimension, glyph ); + par_org_center = parent->org_pos + ( parent->org_len / 2 ); + par_cur_center = parent->cur_pos + ( parent->cur_len / 2 ); + cur_org_center = hint->org_pos + ( hint->org_len / 2 ); + cur_delta = FT_MulFix( cur_org_center - par_org_center, scale ); + pos = par_cur_center + cur_delta - ( len >> 1 ); + } +/* Stems less than one pixel wide are easy -- we want to + * make them as dark as possible, so they must fall within + * one pixel. If the stem is split between two pixels + * then snap the edge that is nearer to the pixel boundary + * to the pixel boundary. + */ + if ( len <= 64 ) + { + if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 ) + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } +/* Position stems other to minimize the amount of mid-grays. + * There are, in general, two positions that do this, + * illustrated as A) and B) below. + * + * + + + + + * + * A) |--------------------------------| + * B) |--------------------------------| + * C) |--------------------------------| + * + * Position A) (split the excess stem equally) should be better + * for stems of width N + f where f < 0.5. + * + * Position B) (split the deficiency equally) should be better + * for stems of width N + f where f > 0.5. + * + * It turns out though that minimizing the total number of lit + * pixels is also important, so position C), with one edge + * aligned with a pixel boundary is actually preferable + * to A). There are also more possibile positions for C) than + * for A) or B), so it involves less distortion of the overall + * character shape. + */ +/* len > 64 */ + else + { + FT_Fixed frac_len = len & 63; + FT_Fixed center = pos + ( len >> 1 ); + FT_Fixed delta_a, delta_b; + if ( ( len / 64 ) & 1 ) + { + delta_a = FT_PIX_FLOOR( center ) + 32 - center; + delta_b = FT_PIX_ROUND( center ) - center; + } + else + { + delta_a = FT_PIX_ROUND( center ) - center; + delta_b = FT_PIX_FLOOR( center ) + 32 - center; + } +/* We choose between B) and C) above based on the amount + * of fractinal stem width; for small amounts, choose + * C) always, for large amounts, B) always, and inbetween, + * pick whichever one involves less stem movement. + */ + if ( frac_len < 32 ) + { + pos += psh_hint_snap_stem_side_delta ( pos, len ); + } + else if ( frac_len < 48 ) + { + FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos, + len ); + if ( FT_ABS( side_delta ) < FT_ABS( delta_b ) ) + pos += side_delta; + else + pos += delta_b; + } + else + { + pos += delta_b; + } + } + hint->cur_pos = pos; + } +/* switch */ + } + psh_hint_set_fitted( hint ); +#ifdef DEBUG_HINTER + if ( ps_debug_hint_func ) + ps_debug_hint_func( hint, dimension ); +#endif + } + } +/* 0 */ +#endif + static void + psh_hint_table_align_hints( PSH_Hint_Table table, + PSH_Globals globals, + FT_Int dimension, + PSH_Glyph glyph ) + { + PSH_Hint hint; + FT_UInt count; +#ifdef DEBUG_HINTER + PSH_Dimension dim = &globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + if ( ps_debug_no_vert_hints && dimension == 0 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } + if ( ps_debug_no_horz_hints && dimension == 1 ) + { + ps_simple_scale( table, scale, delta, dimension ); + return; + } +/* DEBUG_HINTER*/ +#endif + hint = table->hints; + count = table->max_hints; + for ( ; count > 0; count--, hint++ ) + psh_hint_align( hint, globals, dimension, glyph ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** POINTS INTERPOLATION ROUTINES *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#define PSH_ZONE_MIN -3200000L +#define PSH_ZONE_MAX +3200000L +#define xxDEBUG_ZONES +#ifdef DEBUG_ZONES + static void + psh_print_zone( PSH_Zone zone ) + { + printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n", + zone->scale / 65536.0, + zone->delta / 64.0, + zone->min, + zone->max ); + } +#else +#define psh_print_zone( x ) do { } while ( 0 ) +/* DEBUG_ZONES */ +#endif +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** HINTER GLYPH MANAGEMENT *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#if 1 +#define psh_corner_is_flat ft_corner_is_flat +#define psh_corner_orientation ft_corner_orientation +#else + FT_LOCAL_DEF( FT_Int ) + psh_corner_is_flat( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ) + { + FT_Pos ax = x_in; + FT_Pos ay = y_in; + FT_Pos d_in, d_out, d_corner; + if ( ax < 0 ) + ax = -ax; + if ( ay < 0 ) + ay = -ay; + d_in = ax + ay; + ax = x_out; + if ( ax < 0 ) + ax = -ax; + ay = y_out; + if ( ay < 0 ) + ay = -ay; + d_out = ax + ay; + ax = x_out + x_in; + if ( ax < 0 ) + ax = -ax; + ay = y_out + y_in; + if ( ay < 0 ) + ay = -ay; + d_corner = ax + ay; + return ( d_in + d_out - d_corner ) < ( d_corner >> 4 ); + } + static FT_Int + psh_corner_orientation( FT_Pos in_x, + FT_Pos in_y, + FT_Pos out_x, + FT_Pos out_y ) + { + FT_Int result; +/* deal with the trivial cases quickly */ + if ( in_y == 0 ) + { + if ( in_x >= 0 ) + result = out_y; + else + result = -out_y; + } + else if ( in_x == 0 ) + { + if ( in_y >= 0 ) + result = -out_x; + else + result = out_x; + } + else if ( out_y == 0 ) + { + if ( out_x >= 0 ) + result = in_y; + else + result = -in_y; + } + else if ( out_x == 0 ) + { + if ( out_y >= 0 ) + result = -in_x; + else + result = in_x; + } +/* general case */ + else + { + long long delta = (long long)in_x * out_y - (long long)in_y * out_x; + if ( delta == 0 ) + result = 0; + else + result = 1 - 2 * ( delta < 0 ); + } + return result; + } +/* !1 */ +#endif +#ifdef COMPUTE_INFLEXS +/* compute all inflex points in a given glyph */ + static void + psh_glyph_compute_inflections( PSH_Glyph glyph ) + { + FT_UInt n; + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first, start, end, before, after; + FT_Pos in_x, in_y, out_x, out_y; + FT_Int orient_prev, orient_cur; + FT_Int finished = 0; +/* we need at least 4 points to create an inflection point */ + if ( glyph->contours[n].count < 4 ) + continue; +/* compute first segment in contour */ + first = glyph->contours[n].start; + start = end = first; + do + { + end = end->next; + if ( end == first ) + goto Skip; + in_x = end->org_u - start->org_u; + in_y = end->org_v - start->org_v; + } while ( in_x == 0 && in_y == 0 ); +/* extend the segment start whenever possible */ + before = start; + do + { + do + { + start = before; + before = before->prev; + if ( before == first ) + goto Skip; + out_x = start->org_u - before->org_u; + out_y = start->org_v - before->org_v; + } while ( out_x == 0 && out_y == 0 ); + orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y ); + } while ( orient_prev == 0 ); + first = start; + in_x = out_x; + in_y = out_y; +/* now, process all segments in the contour */ + do + { +/* first, extend current segment's end whenever possible */ + after = end; + do + { + do + { + end = after; + after = after->next; + if ( after == first ) + finished = 1; + out_x = after->org_u - end->org_u; + out_y = after->org_v - end->org_v; + } while ( out_x == 0 && out_y == 0 ); + orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y ); + } while ( orient_cur == 0 ); + if ( ( orient_cur ^ orient_prev ) < 0 ) + { + do + { + psh_point_set_inflex( start ); + start = start->next; + } + while ( start != end ); + psh_point_set_inflex( start ); + } + start = end; + end = after; + orient_prev = orient_cur; + in_x = out_x; + in_y = out_y; + } while ( !finished ); + Skip: + ; + } + } +/* COMPUTE_INFLEXS */ +#endif + static void + psh_glyph_done( PSH_Glyph glyph ) + { + FT_Memory memory = glyph->memory; + psh_hint_table_done( &glyph->hint_tables[1], memory ); + psh_hint_table_done( &glyph->hint_tables[0], memory ); + FT_FREE( glyph->points ); + FT_FREE( glyph->contours ); + glyph->num_points = 0; + glyph->num_contours = 0; + glyph->memory = 0; + } + static int + psh_compute_dir( FT_Pos dx, + FT_Pos dy ) + { + FT_Pos ax, ay; + int result = PSH_DIR_NONE; + ax = ( dx >= 0 ) ? dx : -dx; + ay = ( dy >= 0 ) ? dy : -dy; + if ( ay * 12 < ax ) + { +/* |dy| <<< |dx| means a near-horizontal segment */ + result = ( dx >= 0 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT; + } + else if ( ax * 12 < ay ) + { +/* |dx| <<< |dy| means a near-vertical segment */ + result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN; + } + return result; + } +/* load outline point coordinates into hinter glyph */ + static void + psh_glyph_load_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_Vector* vec = glyph->outline->points; + PSH_Point point = glyph->points; + FT_UInt count = glyph->num_points; + for ( ; count > 0; count--, point++, vec++ ) + { + point->flags2 = 0; + point->hint = NULL; + if ( dimension == 0 ) + { + point->org_u = vec->x; + point->org_v = vec->y; + } + else + { + point->org_u = vec->y; + point->org_v = vec->x; + } +#ifdef DEBUG_HINTER + point->org_x = vec->x; + point->org_y = vec->y; +#endif + } + } +/* save hinted point coordinates back to outline */ + static void + psh_glyph_save_points( PSH_Glyph glyph, + FT_Int dimension ) + { + FT_UInt n; + PSH_Point point = glyph->points; + FT_Vector* vec = glyph->outline->points; + char* tags = glyph->outline->tags; + for ( n = 0; n < glyph->num_points; n++ ) + { + if ( dimension == 0 ) + vec[n].x = point->cur_u; + else + vec[n].y = point->cur_u; + if ( psh_point_is_strong( point ) ) + tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 ); +#ifdef DEBUG_HINTER + if ( dimension == 0 ) + { + point->cur_x = point->cur_u; + point->flags_x = point->flags2 | point->flags; + } + else + { + point->cur_y = point->cur_u; + point->flags_y = point->flags2 | point->flags; + } +#endif + point++; + } + } + static FT_Error + psh_glyph_init( PSH_Glyph glyph, + FT_Outline* outline, + PS_Hints ps_hints, + PSH_Globals globals ) + { + FT_Error error; + FT_Memory memory; +/* clear all fields */ + FT_MEM_ZERO( glyph, sizeof ( *glyph ) ); + memory = glyph->memory = globals->memory; +/* allocate and setup points + contours arrays */ + if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) || + FT_NEW_ARRAY( glyph->contours, outline->n_contours ) ) + goto Exit; + glyph->num_points = outline->n_points; + glyph->num_contours = outline->n_contours; + { + FT_UInt first = 0, next, n; + PSH_Point points = glyph->points; + PSH_Contour contour = glyph->contours; + for ( n = 0; n < glyph->num_contours; n++ ) + { + FT_Int count; + PSH_Point point; + next = outline->contours[n] + 1; + count = next - first; + contour->start = points + first; + contour->count = (FT_UInt)count; + if ( count > 0 ) + { + point = points + first; + point->prev = points + next - 1; + point->contour = contour; + for ( ; count > 1; count-- ) + { + point[0].next = point + 1; + point[1].prev = point; + point++; + point->contour = contour; + } + point->next = points + first; + } + contour++; + first = next; + } + } + { + PSH_Point points = glyph->points; + PSH_Point point = points; + FT_Vector* vec = outline->points; + FT_UInt n; + for ( n = 0; n < glyph->num_points; n++, point++ ) + { + FT_Int n_prev = (FT_Int)( point->prev - points ); + FT_Int n_next = (FT_Int)( point->next - points ); + FT_Pos dxi, dyi, dxo, dyo; + if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) + point->flags = PSH_POINT_OFF; + dxi = vec[n].x - vec[n_prev].x; + dyi = vec[n].y - vec[n_prev].y; + point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi ); + dxo = vec[n_next].x - vec[n].x; + dyo = vec[n_next].y - vec[n].y; + point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo ); +/* detect smooth points */ + if ( point->flags & PSH_POINT_OFF ) + point->flags |= PSH_POINT_SMOOTH; + else if ( point->dir_in == point->dir_out ) + { + if ( point->dir_out != PSH_DIR_NONE || + psh_corner_is_flat( dxi, dyi, dxo, dyo ) ) + point->flags |= PSH_POINT_SMOOTH; + } + } + } + glyph->outline = outline; + glyph->globals = globals; +#ifdef COMPUTE_INFLEXS + psh_glyph_load_points( glyph, 0 ); + psh_glyph_compute_inflections( glyph ); +/* COMPUTE_INFLEXS */ +#endif +/* now deal with hints tables */ + error = psh_hint_table_init( &glyph->hint_tables [0], + &ps_hints->dimension[0].hints, + &ps_hints->dimension[0].masks, + &ps_hints->dimension[0].counters, + memory ); + if ( error ) + goto Exit; + error = psh_hint_table_init( &glyph->hint_tables [1], + &ps_hints->dimension[1].hints, + &ps_hints->dimension[1].masks, + &ps_hints->dimension[1].counters, + memory ); + if ( error ) + goto Exit; + Exit: + return error; + } +/* compute all extrema in a glyph for a given dimension */ + static void + psh_glyph_compute_extrema( PSH_Glyph glyph ) + { + FT_UInt n; +/* first of all, compute all local extrema */ + for ( n = 0; n < glyph->num_contours; n++ ) + { + PSH_Point first = glyph->contours[n].start; + PSH_Point point, before, after; + if ( glyph->contours[n].count == 0 ) + continue; + point = first; + before = point; + after = point; + do + { + before = before->prev; + if ( before == first ) + goto Skip; + } while ( before->org_u == point->org_u ); + first = point = before->next; + for (;;) + { + after = point; + do + { + after = after->next; + if ( after == first ) + goto Next; + } while ( after->org_u == point->org_u ); + if ( before->org_u < point->org_u ) + { + if ( after->org_u < point->org_u ) + { +/* local maximum */ + goto Extremum; + } + } +/* before->org_u > point->org_u */ + else + { + if ( after->org_u > point->org_u ) + { +/* local minimum */ + Extremum: + do + { + psh_point_set_extremum( point ); + point = point->next; + } while ( point != after ); + } + } + before = after->prev; + point = after; +/* for */ + } + Next: + ; + } +/* for each extremum, determine its direction along the */ +/* orthogonal axis */ + for ( n = 0; n < glyph->num_points; n++ ) + { + PSH_Point point, before, after; + point = &glyph->points[n]; + before = point; + after = point; + if ( psh_point_is_extremum( point ) ) + { + do + { + before = before->prev; + if ( before == point ) + goto Skip; + } while ( before->org_v == point->org_v ); + do + { + after = after->next; + if ( after == point ) + goto Skip; + } while ( after->org_v == point->org_v ); + } + if ( before->org_v < point->org_v && + after->org_v > point->org_v ) + { + psh_point_set_positive( point ); + } + else if ( before->org_v > point->org_v && + after->org_v < point->org_v ) + { + psh_point_set_negative( point ); + } + Skip: + ; + } + } +/* major_dir is the direction for points on the bottom/left of the stem; */ +/* Points on the top/right of the stem will have a direction of */ +/* -major_dir. */ + static void + psh_hint_table_find_strong_points( PSH_Hint_Table table, + PSH_Point point, + FT_UInt count, + FT_Int threshold, + FT_Int major_dir ) + { + PSH_Hint* sort = table->sort; + FT_UInt num_hints = table->num_hints; + for ( ; count > 0; count--, point++ ) + { + FT_Int point_dir = 0; + FT_Pos org_u = point->org_u; + if ( psh_point_is_strong( point ) ) + continue; + if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) ) + point_dir = point->dir_in; + else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) ) + point_dir = point->dir_out; + if ( point_dir ) + { + if ( point_dir == major_dir ) + { + FT_UInt nn; + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + break; + } + } + } + else if ( point_dir == -major_dir ) + { + FT_UInt nn; + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + if ( d < threshold && -d < threshold ) + { + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + break; + } + } + } + } +#if 1 + else if ( psh_point_is_extremum( point ) ) + { +/* treat extrema as special cases for stem edge alignment */ + FT_UInt nn, min_flag, max_flag; + if ( major_dir == PSH_DIR_HORIZONTAL ) + { + min_flag = PSH_POINT_POSITIVE; + max_flag = PSH_POINT_NEGATIVE; + } + else + { + min_flag = PSH_POINT_NEGATIVE; + max_flag = PSH_POINT_POSITIVE; + } + if ( point->flags2 & min_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + else if ( point->flags2 & max_flag ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; + if ( d < threshold && -d < threshold ) + { + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + psh_point_set_strong( point ); + break; + } + } + } + if ( point->hint == NULL ) + { + for ( nn = 0; nn < num_hints; nn++ ) + { + PSH_Hint hint = sort[nn]; + if ( org_u >= hint->org_pos && + org_u <= hint->org_pos + hint->org_len ) + { + point->hint = hint; + break; + } + } + } + } +/* 1 */ +#endif + } + } +/* the accepted shift for strong points in fractional pixels */ +#define PSH_STRONG_THRESHOLD 32 +/* the maximum shift value in font units */ +#define PSH_STRONG_THRESHOLD_MAXIMUM 30 +/* find strong points in a glyph */ + static void + psh_glyph_find_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { +/* a point is `strong' if it is located on a stem edge and */ +/* has an `in' or `out' tangent parallel to the hint's direction */ + PSH_Hint_Table table = &glyph->hint_tables[dimension]; + PS_Mask mask = table->hint_masks->masks; + FT_UInt num_masks = table->hint_masks->num_masks; + FT_UInt first = 0; + FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL + : PSH_DIR_HORIZONTAL; + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Int threshold; + threshold = (FT_Int)FT_DivFix( PSH_STRONG_THRESHOLD, scale ); + if ( threshold > PSH_STRONG_THRESHOLD_MAXIMUM ) + threshold = PSH_STRONG_THRESHOLD_MAXIMUM; +/* process secondary hints to `selected' points */ + if ( num_masks > 1 && glyph->num_points > 0 ) + { +/* the `endchar' op can reduce the number of points */ + first = mask->end_point > glyph->num_points + ? glyph->num_points + : mask->end_point; + mask++; + for ( ; num_masks > 1; num_masks--, mask++ ) + { + FT_UInt next; + FT_Int count; + next = mask->end_point > glyph->num_points + ? glyph->num_points + : mask->end_point; + count = next - first; + if ( count > 0 ) + { + PSH_Point point = glyph->points + first; + psh_hint_table_activate_mask( table, mask ); + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } + first = next; + } + } +/* process primary hints for all points */ + if ( num_masks == 1 ) + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + psh_hint_table_activate_mask( table, table->hint_masks->masks ); + psh_hint_table_find_strong_points( table, point, count, + threshold, major_dir ); + } +/* now, certain points may have been attached to a hint and */ +/* not marked as strong; update their flags then */ + { + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + for ( ; count > 0; count--, point++ ) + if ( point->hint && !psh_point_is_strong( point ) ) + psh_point_set_strong( point ); + } + } +/* find points in a glyph which are in a blue zone and have `in' or */ +/* `out' tangents parallel to the horizontal axis */ + static void + psh_glyph_find_blue_points( PSH_Blues blues, + PSH_Glyph glyph ) + { + PSH_Blue_Table table; + PSH_Blue_Zone zone; + FT_UInt glyph_count = glyph->num_points; + FT_UInt blue_count; + PSH_Point point = glyph->points; + for ( ; glyph_count > 0; glyph_count--, point++ ) + { + FT_Pos y; +/* check tangents */ + if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) && + !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) ) + continue; +/* skip strong points */ + if ( psh_point_is_strong( point ) ) + continue; + y = point->org_u; +/* look up top zones */ + table = &blues->normal_top; + blue_count = table->count; + zone = table->zones; + for ( ; blue_count > 0; blue_count--, zone++ ) + { + FT_Pos delta = y - zone->org_bottom; + if ( delta < -blues->blue_fuzz ) + break; + if ( y <= zone->org_top + blues->blue_fuzz ) + if ( blues->no_overshoots || delta <= blues->blue_threshold ) + { + point->cur_u = zone->cur_bottom; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } +/* look up bottom zones */ + table = &blues->normal_bottom; + blue_count = table->count; + zone = table->zones + blue_count - 1; + for ( ; blue_count > 0; blue_count--, zone-- ) + { + FT_Pos delta = zone->org_top - y; + if ( delta < -blues->blue_fuzz ) + break; + if ( y >= zone->org_bottom - blues->blue_fuzz ) + if ( blues->no_overshoots || delta < blues->blue_threshold ) + { + point->cur_u = zone->cur_top; + psh_point_set_strong( point ); + psh_point_set_fitted( point ); + } + } + } + } +/* interpolate strong points with the help of hinted coordinates */ + static void + psh_glyph_interpolate_strong_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_UInt count = glyph->num_points; + PSH_Point point = glyph->points; + for ( ; count > 0; count--, point++ ) + { + PSH_Hint hint = point->hint; + if ( hint ) + { + FT_Pos delta; + if ( psh_point_is_edge_min( point ) ) + point->cur_u = hint->cur_pos; + else if ( psh_point_is_edge_max( point ) ) + point->cur_u = hint->cur_pos + hint->cur_len; + else + { + delta = point->org_u - hint->org_pos; + if ( delta <= 0 ) + point->cur_u = hint->cur_pos + FT_MulFix( delta, scale ); + else if ( delta >= hint->org_len ) + point->cur_u = hint->cur_pos + hint->cur_len + + FT_MulFix( delta - hint->org_len, scale ); +/* hint->org_len > 0 */ + else + point->cur_u = hint->cur_pos + + FT_MulDiv( delta, hint->cur_len, + hint->org_len ); + } + psh_point_set_fitted( point ); + } + } + } +#define PSH_MAX_STRONG_INTERNAL 16 + static void + psh_glyph_interpolate_normal_points( PSH_Glyph glyph, + FT_Int dimension ) + { +#if 1 +/* first technique: a point is strong if it is a local extremum */ + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Memory memory = glyph->memory; + PSH_Point* strongs = NULL; + PSH_Point strongs_0[PSH_MAX_STRONG_INTERNAL]; + FT_UInt num_strongs = 0; + PSH_Point points = glyph->points; + PSH_Point points_end = points + glyph->num_points; + PSH_Point point; +/* first count the number of strong points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + num_strongs++; + } +/* nothing to do here */ + if ( num_strongs == 0 ) + return; +/* allocate an array to store a list of points, */ +/* stored in increasing org_u order */ + if ( num_strongs <= PSH_MAX_STRONG_INTERNAL ) + strongs = strongs_0; + else + { + FT_Error error; + if ( FT_NEW_ARRAY( strongs, num_strongs ) ) + return; + } + num_strongs = 0; + for ( point = points; point < points_end; point++ ) + { + PSH_Point* insert; + if ( !psh_point_is_strong( point ) ) + continue; + for ( insert = strongs + num_strongs; insert > strongs; insert-- ) + { + if ( insert[-1]->org_u <= point->org_u ) + break; + insert[0] = insert[-1]; + } + insert[0] = point; + num_strongs++; + } +/* now try to interpolate all normal points */ + for ( point = points; point < points_end; point++ ) + { + if ( psh_point_is_strong( point ) ) + continue; +/* sometimes, some local extrema are smooth points */ + if ( psh_point_is_smooth( point ) ) + { + if ( point->dir_in == PSH_DIR_NONE || + point->dir_in != point->dir_out ) + continue; + if ( !psh_point_is_extremum( point ) && + !psh_point_is_inflex( point ) ) + continue; + point->flags &= ~PSH_POINT_SMOOTH; + } +/* find best enclosing point coordinates then interpolate */ + { + PSH_Point before, after; + FT_UInt nn; + for ( nn = 0; nn < num_strongs; nn++ ) + if ( strongs[nn]->org_u > point->org_u ) + break; +/* point before the first strong point */ + if ( nn == 0 ) + { + after = strongs[0]; + point->cur_u = after->cur_u + + FT_MulFix( point->org_u - after->org_u, + scale ); + } + else + { + before = strongs[nn - 1]; + for ( nn = num_strongs; nn > 0; nn-- ) + if ( strongs[nn - 1]->org_u < point->org_u ) + break; +/* point is after last strong point */ + if ( nn == num_strongs ) + { + before = strongs[nn - 1]; + point->cur_u = before->cur_u + + FT_MulFix( point->org_u - before->org_u, + scale ); + } + else + { + FT_Pos u; + after = strongs[nn]; +/* now interpolate point between before and after */ + u = point->org_u; + if ( u == before->org_u ) + point->cur_u = before->cur_u; + else if ( u == after->org_u ) + point->cur_u = after->cur_u; + else + point->cur_u = before->cur_u + + FT_MulDiv( u - before->org_u, + after->cur_u - before->cur_u, + after->org_u - before->org_u ); + } + } + psh_point_set_fitted( point ); + } + } + if ( strongs != strongs_0 ) + FT_FREE( strongs ); +/* 1 */ +#endif + } +/* interpolate other points */ + static void + psh_glyph_interpolate_other_points( PSH_Glyph glyph, + FT_Int dimension ) + { + PSH_Dimension dim = &glyph->globals->dimension[dimension]; + FT_Fixed scale = dim->scale_mult; + FT_Fixed delta = dim->scale_delta; + PSH_Contour contour = glyph->contours; + FT_UInt num_contours = glyph->num_contours; + for ( ; num_contours > 0; num_contours--, contour++ ) + { + PSH_Point start = contour->start; + PSH_Point first, next, point; + FT_UInt fit_count; +/* count the number of strong points in this contour */ + next = start + contour->count; + fit_count = 0; + first = 0; + for ( point = start; point < next; point++ ) + if ( psh_point_is_fitted( point ) ) + { + if ( !first ) + first = point; + fit_count++; + } +/* if there are less than 2 fitted points in the contour, we */ +/* simply scale and eventually translate the contour points */ + if ( fit_count < 2 ) + { + if ( fit_count == 1 ) + delta = first->cur_u - FT_MulFix( first->org_u, scale ); + for ( point = start; point < next; point++ ) + if ( point != first ) + point->cur_u = FT_MulFix( point->org_u, scale ) + delta; + goto Next_Contour; + } +/* there are more than 2 strong points in this contour; we */ +/* need to interpolate weak points between them */ + start = first; + do + { + point = first; +/* skip consecutive fitted points */ + for (;;) + { + next = first->next; + if ( next == start ) + goto Next_Contour; + if ( !psh_point_is_fitted( next ) ) + break; + first = next; + } +/* find next fitted point after unfitted one */ + for (;;) + { + next = next->next; + if ( psh_point_is_fitted( next ) ) + break; + } +/* now interpolate between them */ + { + FT_Pos org_a, org_ab, cur_a, cur_ab; + FT_Pos org_c, org_ac, cur_c; + FT_Fixed scale_ab; + if ( first->org_u <= next->org_u ) + { + org_a = first->org_u; + cur_a = first->cur_u; + org_ab = next->org_u - org_a; + cur_ab = next->cur_u - cur_a; + } + else + { + org_a = next->org_u; + cur_a = next->cur_u; + org_ab = first->org_u - org_a; + cur_ab = first->cur_u - cur_a; + } + scale_ab = 0x10000L; + if ( org_ab > 0 ) + scale_ab = FT_DivFix( cur_ab, org_ab ); + point = first->next; + do + { + org_c = point->org_u; + org_ac = org_c - org_a; + if ( org_ac <= 0 ) + { +/* on the left of the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale ); + } + else if ( org_ac >= org_ab ) + { +/* on the right on the interpolation zone */ + cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale ); + } + else + { +/* within the interpolation zone */ + cur_c = cur_a + FT_MulFix( org_ac, scale_ab ); + } + point->cur_u = cur_c; + point = point->next; + } while ( point != next ); + } +/* keep going until all points in the contours have been processed */ + first = next; + } while ( first != start ); + Next_Contour: + ; + } + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** HIGH-LEVEL INTERFACE *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_Error + ps_hints_apply( PS_Hints ps_hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + PSH_GlyphRec glyphrec; + PSH_Glyph glyph = &glyphrec; + FT_Error error; +#ifdef DEBUG_HINTER + FT_Memory memory; +#endif + FT_Int dimension; +/* something to do? */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return PSH_Err_Ok; +#ifdef DEBUG_HINTER + memory = globals->memory; + if ( ps_debug_glyph ) + { + psh_glyph_done( ps_debug_glyph ); + FT_FREE( ps_debug_glyph ); + } + if ( FT_NEW( glyph ) ) + return error; + ps_debug_glyph = glyph; +/* DEBUG_HINTER */ +#endif + error = psh_glyph_init( glyph, outline, ps_hints, globals ); + if ( error ) + goto Exit; +/* try to optimize the y_scale so that the top of non-capital letters + * is aligned on a pixel boundary whenever possible + */ + { + PSH_Dimension dim_x = &glyph->globals->dimension[0]; + PSH_Dimension dim_y = &glyph->globals->dimension[1]; + FT_Fixed x_scale = dim_x->scale_mult; + FT_Fixed y_scale = dim_y->scale_mult; + FT_Fixed old_x_scale = x_scale; + FT_Fixed old_y_scale = y_scale; + FT_Fixed scaled; + FT_Fixed fitted; + FT_Bool rescale = FALSE; + scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); + fitted = FT_PIX_ROUND( scaled ); + if ( fitted != 0 && scaled != fitted ) + { + rescale = TRUE; + y_scale = FT_MulDiv( y_scale, fitted, scaled ); + if ( fitted < scaled ) + x_scale -= x_scale / 50; + psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 ); + } + glyph->do_horz_hints = 1; + glyph->do_vert_hints = 1; + glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD ); + glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO || + hint_mode == FT_RENDER_MODE_LCD_V ); + glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT ); + for ( dimension = 0; dimension < 2; dimension++ ) + { +/* load outline coordinates into glyph */ + psh_glyph_load_points( glyph, dimension ); +/* compute local extrema */ + psh_glyph_compute_extrema( glyph ); +/* compute aligned stem/hints positions */ + psh_hint_table_align_hints( &glyph->hint_tables[dimension], + glyph->globals, + dimension, + glyph ); +/* find strong points, align them, then interpolate others */ + psh_glyph_find_strong_points( glyph, dimension ); + if ( dimension == 1 ) + psh_glyph_find_blue_points( &globals->blues, glyph ); + psh_glyph_interpolate_strong_points( glyph, dimension ); + psh_glyph_interpolate_normal_points( glyph, dimension ); + psh_glyph_interpolate_other_points( glyph, dimension ); +/* save hinted coordinates back to outline */ + psh_glyph_save_points( glyph, dimension ); + if ( rescale ) + psh_globals_set_scale( glyph->globals, + old_x_scale, old_y_scale, 0, 0 ); + } + } + Exit: +#ifndef DEBUG_HINTER + psh_glyph_done( glyph ); +#endif + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* pshmod.c */ +/* */ +/* FreeType PostScript hinter module implementation (body). */ +/* */ +/* Copyright 2001, 2002, 2007, 2009, 2012 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 Postscript Hinter module structure */ + typedef struct PS_Hinter_Module_Rec_ + { + FT_ModuleRec root; + PS_HintsRec ps_hints; + PSH_Globals_FuncsRec globals_funcs; + T1_Hints_FuncsRec t1_funcs; + T2_Hints_FuncsRec t2_funcs; + } PS_Hinter_ModuleRec, *PS_Hinter_Module; +/* finalize module */ + FT_CALLBACK_DEF( void ) + ps_hinter_done( PS_Hinter_Module module ) + { + module->t1_funcs.hints = NULL; + module->t2_funcs.hints = NULL; + ps_hints_done( &module->ps_hints ); + } +/* initialize module, create hints recorder and the interface */ + FT_CALLBACK_DEF( FT_Error ) + ps_hinter_init( PS_Hinter_Module module ) + { + FT_Memory memory = module->root.memory; + void* ph = &module->ps_hints; + ps_hints_init( &module->ps_hints, memory ); + psh_globals_funcs_init( &module->globals_funcs ); + t1_hints_funcs_init( &module->t1_funcs ); + module->t1_funcs.hints = (T1_Hints)ph; + t2_hints_funcs_init( &module->t2_funcs ); + module->t2_funcs.hints = (T2_Hints)ph; + return 0; + } +/* returns global hints interface */ + FT_CALLBACK_DEF( PSH_Globals_Funcs ) + pshinter_get_globals_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->globals_funcs; + } +/* return Type 1 hints interface */ + FT_CALLBACK_DEF( T1_Hints_Funcs ) + pshinter_get_t1_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t1_funcs; + } +/* return Type 2 hints interface */ + FT_CALLBACK_DEF( T2_Hints_Funcs ) + pshinter_get_t2_funcs( FT_Module module ) + { + return &((PS_Hinter_Module)module)->t2_funcs; + } + FT_DEFINE_PSHINTER_INTERFACE( + pshinter_interface, + pshinter_get_globals_funcs, + pshinter_get_t1_funcs, + pshinter_get_t2_funcs ) + FT_DEFINE_MODULE( + pshinter_module_class, + 0, + sizeof ( PS_Hinter_ModuleRec ), + "pshinter", + 0x10000L, + 0x20000L, +/* module-specific interface */ + &PSHINTER_INTERFACE_GET, + (FT_Module_Constructor)ps_hinter_init, + (FT_Module_Destructor) ps_hinter_done, +/* no additional interface for now */ + (FT_Module_Requester) NULL ) +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* psnames.c */ +/* */ +/* FreeType PSNames module component (body only). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* pspic.c */ +/* */ +/* The FreeType position independent code services for psnames module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pspic.h */ +/* */ +/* The FreeType position independent code services for psnames module. */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __PSPIC_H__ +FT_BEGIN_HEADER +#define PSCMAPS_SERVICES_GET pscmaps_services +#define PSCMAPS_INTERFACE_GET pscmaps_interface +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* psnamerr.h */ +/* */ +/* PS names module error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 PS names module error enumeration */ +/* constants. */ +/* */ +/*************************************************************************/ +#define __PSNAMERR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSnames_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSnames +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* psmodule.c */ +/* */ +/* PSNames module implementation (body). */ +/* */ +/* Copyright 1996-2003, 2005-2008, 2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* psmodule.h */ +/* */ +/* High-level PSNames module interface (specification). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define __PSMODULE_H__ +FT_BEGIN_HEADER + FT_DECLARE_MODULE( psnames_module_class ) +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* pstables.h */ +/* */ +/* PostScript glyph names. */ +/* */ +/* Copyright 2005, 2008, 2011 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 has been generated automatically -- do not edit! */ + static const char ft_standard_glyph_names[3696] = + { + '.','n','u','l','l', 0, + 'n','o','n','m','a','r','k','i','n','g','r','e','t','u','r','n', 0, + 'n','o','t','e','q','u','a','l', 0, + 'i','n','f','i','n','i','t','y', 0, + 'l','e','s','s','e','q','u','a','l', 0, + 'g','r','e','a','t','e','r','e','q','u','a','l', 0, + 'p','a','r','t','i','a','l','d','i','f','f', 0, + 's','u','m','m','a','t','i','o','n', 0, + 'p','r','o','d','u','c','t', 0, + 'p','i', 0, + 'i','n','t','e','g','r','a','l', 0, + 'O','m','e','g','a', 0, + 'r','a','d','i','c','a','l', 0, + 'a','p','p','r','o','x','e','q','u','a','l', 0, + 'D','e','l','t','a', 0, + 'n','o','n','b','r','e','a','k','i','n','g','s','p','a','c','e', 0, + 'l','o','z','e','n','g','e', 0, + 'a','p','p','l','e', 0, + 'f','r','a','n','c', 0, + 'G','b','r','e','v','e', 0, + 'g','b','r','e','v','e', 0, + 'I','d','o','t','a','c','c','e','n','t', 0, + 'S','c','e','d','i','l','l','a', 0, + 's','c','e','d','i','l','l','a', 0, + 'C','a','c','u','t','e', 0, + 'c','a','c','u','t','e', 0, + 'C','c','a','r','o','n', 0, + 'c','c','a','r','o','n', 0, + 'd','c','r','o','a','t', 0, + '.','n','o','t','d','e','f', 0, + 's','p','a','c','e', 0, + 'e','x','c','l','a','m', 0, + 'q','u','o','t','e','d','b','l', 0, + 'n','u','m','b','e','r','s','i','g','n', 0, + 'd','o','l','l','a','r', 0, + 'p','e','r','c','e','n','t', 0, + 'a','m','p','e','r','s','a','n','d', 0, + 'q','u','o','t','e','r','i','g','h','t', 0, + 'p','a','r','e','n','l','e','f','t', 0, + 'p','a','r','e','n','r','i','g','h','t', 0, + 'a','s','t','e','r','i','s','k', 0, + 'p','l','u','s', 0, + 'c','o','m','m','a', 0, + 'h','y','p','h','e','n', 0, + 'p','e','r','i','o','d', 0, + 's','l','a','s','h', 0, + 'z','e','r','o', 0, + 'o','n','e', 0, + 't','w','o', 0, + 't','h','r','e','e', 0, + 'f','o','u','r', 0, + 'f','i','v','e', 0, + 's','i','x', 0, + 's','e','v','e','n', 0, + 'e','i','g','h','t', 0, + 'n','i','n','e', 0, + 'c','o','l','o','n', 0, + 's','e','m','i','c','o','l','o','n', 0, + 'l','e','s','s', 0, + 'e','q','u','a','l', 0, + 'g','r','e','a','t','e','r', 0, + 'q','u','e','s','t','i','o','n', 0, + 'a','t', 0, + 'A', 0, + 'B', 0, + 'C', 0, + 'D', 0, + 'E', 0, + 'F', 0, + 'G', 0, + 'H', 0, + 'I', 0, + 'J', 0, + 'K', 0, + 'L', 0, + 'M', 0, + 'N', 0, + 'O', 0, + 'P', 0, + 'Q', 0, + 'R', 0, + 'S', 0, + 'T', 0, + 'U', 0, + 'V', 0, + 'W', 0, + 'X', 0, + 'Y', 0, + 'Z', 0, + 'b','r','a','c','k','e','t','l','e','f','t', 0, + 'b','a','c','k','s','l','a','s','h', 0, + 'b','r','a','c','k','e','t','r','i','g','h','t', 0, + 'a','s','c','i','i','c','i','r','c','u','m', 0, + 'u','n','d','e','r','s','c','o','r','e', 0, + 'q','u','o','t','e','l','e','f','t', 0, + 'a', 0, + 'b', 0, + 'c', 0, + 'd', 0, + 'e', 0, + 'f', 0, + 'g', 0, + 'h', 0, + 'i', 0, + 'j', 0, + 'k', 0, + 'l', 0, + 'm', 0, + 'n', 0, + 'o', 0, + 'p', 0, + 'q', 0, + 'r', 0, + 's', 0, + 't', 0, + 'u', 0, + 'v', 0, + 'w', 0, + 'x', 0, + 'y', 0, + 'z', 0, + 'b','r','a','c','e','l','e','f','t', 0, + 'b','a','r', 0, + 'b','r','a','c','e','r','i','g','h','t', 0, + 'a','s','c','i','i','t','i','l','d','e', 0, + 'e','x','c','l','a','m','d','o','w','n', 0, + 'c','e','n','t', 0, + 's','t','e','r','l','i','n','g', 0, + 'f','r','a','c','t','i','o','n', 0, + 'y','e','n', 0, + 'f','l','o','r','i','n', 0, + 's','e','c','t','i','o','n', 0, + 'c','u','r','r','e','n','c','y', 0, + 'q','u','o','t','e','s','i','n','g','l','e', 0, + 'q','u','o','t','e','d','b','l','l','e','f','t', 0, + 'g','u','i','l','l','e','m','o','t','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','l','e','f','t', 0, + 'g','u','i','l','s','i','n','g','l','r','i','g','h','t', 0, + 'f','i', 0, + 'f','l', 0, + 'e','n','d','a','s','h', 0, + 'd','a','g','g','e','r', 0, + 'd','a','g','g','e','r','d','b','l', 0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d', 0, + 'p','a','r','a','g','r','a','p','h', 0, + 'b','u','l','l','e','t', 0, + 'q','u','o','t','e','s','i','n','g','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','b','a','s','e', 0, + 'q','u','o','t','e','d','b','l','r','i','g','h','t', 0, + 'g','u','i','l','l','e','m','o','t','r','i','g','h','t', 0, + 'e','l','l','i','p','s','i','s', 0, + 'p','e','r','t','h','o','u','s','a','n','d', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n', 0, + 'g','r','a','v','e', 0, + 'a','c','u','t','e', 0, + 'c','i','r','c','u','m','f','l','e','x', 0, + 't','i','l','d','e', 0, + 'm','a','c','r','o','n', 0, + 'b','r','e','v','e', 0, + 'd','o','t','a','c','c','e','n','t', 0, + 'd','i','e','r','e','s','i','s', 0, + 'r','i','n','g', 0, + 'c','e','d','i','l','l','a', 0, + 'h','u','n','g','a','r','u','m','l','a','u','t', 0, + 'o','g','o','n','e','k', 0, + 'c','a','r','o','n', 0, + 'e','m','d','a','s','h', 0, + 'A','E', 0, + 'o','r','d','f','e','m','i','n','i','n','e', 0, + 'L','s','l','a','s','h', 0, + 'O','s','l','a','s','h', 0, + 'O','E', 0, + 'o','r','d','m','a','s','c','u','l','i','n','e', 0, + 'a','e', 0, + 'd','o','t','l','e','s','s','i', 0, + 'l','s','l','a','s','h', 0, + 'o','s','l','a','s','h', 0, + 'o','e', 0, + 'g','e','r','m','a','n','d','b','l','s', 0, + 'o','n','e','s','u','p','e','r','i','o','r', 0, + 'l','o','g','i','c','a','l','n','o','t', 0, + 'm','u', 0, + 't','r','a','d','e','m','a','r','k', 0, + 'E','t','h', 0, + 'o','n','e','h','a','l','f', 0, + 'p','l','u','s','m','i','n','u','s', 0, + 'T','h','o','r','n', 0, + 'o','n','e','q','u','a','r','t','e','r', 0, + 'd','i','v','i','d','e', 0, + 'b','r','o','k','e','n','b','a','r', 0, + 'd','e','g','r','e','e', 0, + 't','h','o','r','n', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s', 0, + 't','w','o','s','u','p','e','r','i','o','r', 0, + 'r','e','g','i','s','t','e','r','e','d', 0, + 'm','i','n','u','s', 0, + 'e','t','h', 0, + 'm','u','l','t','i','p','l','y', 0, + 't','h','r','e','e','s','u','p','e','r','i','o','r', 0, + 'c','o','p','y','r','i','g','h','t', 0, + 'A','a','c','u','t','e', 0, + 'A','c','i','r','c','u','m','f','l','e','x', 0, + 'A','d','i','e','r','e','s','i','s', 0, + 'A','g','r','a','v','e', 0, + 'A','r','i','n','g', 0, + 'A','t','i','l','d','e', 0, + 'C','c','e','d','i','l','l','a', 0, + 'E','a','c','u','t','e', 0, + 'E','c','i','r','c','u','m','f','l','e','x', 0, + 'E','d','i','e','r','e','s','i','s', 0, + 'E','g','r','a','v','e', 0, + 'I','a','c','u','t','e', 0, + 'I','c','i','r','c','u','m','f','l','e','x', 0, + 'I','d','i','e','r','e','s','i','s', 0, + 'I','g','r','a','v','e', 0, + 'N','t','i','l','d','e', 0, + 'O','a','c','u','t','e', 0, + 'O','c','i','r','c','u','m','f','l','e','x', 0, + 'O','d','i','e','r','e','s','i','s', 0, + 'O','g','r','a','v','e', 0, + 'O','t','i','l','d','e', 0, + 'S','c','a','r','o','n', 0, + 'U','a','c','u','t','e', 0, + 'U','c','i','r','c','u','m','f','l','e','x', 0, + 'U','d','i','e','r','e','s','i','s', 0, + 'U','g','r','a','v','e', 0, + 'Y','a','c','u','t','e', 0, + 'Y','d','i','e','r','e','s','i','s', 0, + 'Z','c','a','r','o','n', 0, + 'a','a','c','u','t','e', 0, + 'a','c','i','r','c','u','m','f','l','e','x', 0, + 'a','d','i','e','r','e','s','i','s', 0, + 'a','g','r','a','v','e', 0, + 'a','r','i','n','g', 0, + 'a','t','i','l','d','e', 0, + 'c','c','e','d','i','l','l','a', 0, + 'e','a','c','u','t','e', 0, + 'e','c','i','r','c','u','m','f','l','e','x', 0, + 'e','d','i','e','r','e','s','i','s', 0, + 'e','g','r','a','v','e', 0, + 'i','a','c','u','t','e', 0, + 'i','c','i','r','c','u','m','f','l','e','x', 0, + 'i','d','i','e','r','e','s','i','s', 0, + 'i','g','r','a','v','e', 0, + 'n','t','i','l','d','e', 0, + 'o','a','c','u','t','e', 0, + 'o','c','i','r','c','u','m','f','l','e','x', 0, + 'o','d','i','e','r','e','s','i','s', 0, + 'o','g','r','a','v','e', 0, + 'o','t','i','l','d','e', 0, + 's','c','a','r','o','n', 0, + 'u','a','c','u','t','e', 0, + 'u','c','i','r','c','u','m','f','l','e','x', 0, + 'u','d','i','e','r','e','s','i','s', 0, + 'u','g','r','a','v','e', 0, + 'y','a','c','u','t','e', 0, + 'y','d','i','e','r','e','s','i','s', 0, + 'z','c','a','r','o','n', 0, + 'e','x','c','l','a','m','s','m','a','l','l', 0, + 'H','u','n','g','a','r','u','m','l','a','u','t','s','m','a','l','l', 0, + 'd','o','l','l','a','r','o','l','d','s','t','y','l','e', 0, + 'd','o','l','l','a','r','s','u','p','e','r','i','o','r', 0, + 'a','m','p','e','r','s','a','n','d','s','m','a','l','l', 0, + 'A','c','u','t','e','s','m','a','l','l', 0, + 'p','a','r','e','n','l','e','f','t','s','u','p','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 't','w','o','d','o','t','e','n','l','e','a','d','e','r', 0, + 'o','n','e','d','o','t','e','n','l','e','a','d','e','r', 0, + 'z','e','r','o','o','l','d','s','t','y','l','e', 0, + 'o','n','e','o','l','d','s','t','y','l','e', 0, + 't','w','o','o','l','d','s','t','y','l','e', 0, + 't','h','r','e','e','o','l','d','s','t','y','l','e', 0, + 'f','o','u','r','o','l','d','s','t','y','l','e', 0, + 'f','i','v','e','o','l','d','s','t','y','l','e', 0, + 's','i','x','o','l','d','s','t','y','l','e', 0, + 's','e','v','e','n','o','l','d','s','t','y','l','e', 0, + 'e','i','g','h','t','o','l','d','s','t','y','l','e', 0, + 'n','i','n','e','o','l','d','s','t','y','l','e', 0, + 'c','o','m','m','a','s','u','p','e','r','i','o','r', 0, + 't','h','r','e','e','q','u','a','r','t','e','r','s','e','m','d','a','s','h', 0, + 'p','e','r','i','o','d','s','u','p','e','r','i','o','r', 0, + 'q','u','e','s','t','i','o','n','s','m','a','l','l', 0, + 'a','s','u','p','e','r','i','o','r', 0, + 'b','s','u','p','e','r','i','o','r', 0, + 'c','e','n','t','s','u','p','e','r','i','o','r', 0, + 'd','s','u','p','e','r','i','o','r', 0, + 'e','s','u','p','e','r','i','o','r', 0, + 'i','s','u','p','e','r','i','o','r', 0, + 'l','s','u','p','e','r','i','o','r', 0, + 'm','s','u','p','e','r','i','o','r', 0, + 'n','s','u','p','e','r','i','o','r', 0, + 'o','s','u','p','e','r','i','o','r', 0, + 'r','s','u','p','e','r','i','o','r', 0, + 's','s','u','p','e','r','i','o','r', 0, + 't','s','u','p','e','r','i','o','r', 0, + 'f','f', 0, + 'f','f','i', 0, + 'f','f','l', 0, + 'p','a','r','e','n','l','e','f','t','i','n','f','e','r','i','o','r', 0, + 'p','a','r','e','n','r','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'C','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'h','y','p','h','e','n','s','u','p','e','r','i','o','r', 0, + 'G','r','a','v','e','s','m','a','l','l', 0, + 'A','s','m','a','l','l', 0, + 'B','s','m','a','l','l', 0, + 'C','s','m','a','l','l', 0, + 'D','s','m','a','l','l', 0, + 'E','s','m','a','l','l', 0, + 'F','s','m','a','l','l', 0, + 'G','s','m','a','l','l', 0, + 'H','s','m','a','l','l', 0, + 'I','s','m','a','l','l', 0, + 'J','s','m','a','l','l', 0, + 'K','s','m','a','l','l', 0, + 'L','s','m','a','l','l', 0, + 'M','s','m','a','l','l', 0, + 'N','s','m','a','l','l', 0, + 'O','s','m','a','l','l', 0, + 'P','s','m','a','l','l', 0, + 'Q','s','m','a','l','l', 0, + 'R','s','m','a','l','l', 0, + 'S','s','m','a','l','l', 0, + 'T','s','m','a','l','l', 0, + 'U','s','m','a','l','l', 0, + 'V','s','m','a','l','l', 0, + 'W','s','m','a','l','l', 0, + 'X','s','m','a','l','l', 0, + 'Y','s','m','a','l','l', 0, + 'Z','s','m','a','l','l', 0, + 'c','o','l','o','n','m','o','n','e','t','a','r','y', 0, + 'o','n','e','f','i','t','t','e','d', 0, + 'r','u','p','i','a','h', 0, + 'T','i','l','d','e','s','m','a','l','l', 0, + 'e','x','c','l','a','m','d','o','w','n','s','m','a','l','l', 0, + 'c','e','n','t','o','l','d','s','t','y','l','e', 0, + 'L','s','l','a','s','h','s','m','a','l','l', 0, + 'S','c','a','r','o','n','s','m','a','l','l', 0, + 'Z','c','a','r','o','n','s','m','a','l','l', 0, + 'D','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'B','r','e','v','e','s','m','a','l','l', 0, + 'C','a','r','o','n','s','m','a','l','l', 0, + 'D','o','t','a','c','c','e','n','t','s','m','a','l','l', 0, + 'M','a','c','r','o','n','s','m','a','l','l', 0, + 'f','i','g','u','r','e','d','a','s','h', 0, + 'h','y','p','h','e','n','i','n','f','e','r','i','o','r', 0, + 'O','g','o','n','e','k','s','m','a','l','l', 0, + 'R','i','n','g','s','m','a','l','l', 0, + 'C','e','d','i','l','l','a','s','m','a','l','l', 0, + 'q','u','e','s','t','i','o','n','d','o','w','n','s','m','a','l','l', 0, + 'o','n','e','e','i','g','h','t','h', 0, + 't','h','r','e','e','e','i','g','h','t','h','s', 0, + 'f','i','v','e','e','i','g','h','t','h','s', 0, + 's','e','v','e','n','e','i','g','h','t','h','s', 0, + 'o','n','e','t','h','i','r','d', 0, + 't','w','o','t','h','i','r','d','s', 0, + 'z','e','r','o','s','u','p','e','r','i','o','r', 0, + 'f','o','u','r','s','u','p','e','r','i','o','r', 0, + 'f','i','v','e','s','u','p','e','r','i','o','r', 0, + 's','i','x','s','u','p','e','r','i','o','r', 0, + 's','e','v','e','n','s','u','p','e','r','i','o','r', 0, + 'e','i','g','h','t','s','u','p','e','r','i','o','r', 0, + 'n','i','n','e','s','u','p','e','r','i','o','r', 0, + 'z','e','r','o','i','n','f','e','r','i','o','r', 0, + 'o','n','e','i','n','f','e','r','i','o','r', 0, + 't','w','o','i','n','f','e','r','i','o','r', 0, + 't','h','r','e','e','i','n','f','e','r','i','o','r', 0, + 'f','o','u','r','i','n','f','e','r','i','o','r', 0, + 'f','i','v','e','i','n','f','e','r','i','o','r', 0, + 's','i','x','i','n','f','e','r','i','o','r', 0, + 's','e','v','e','n','i','n','f','e','r','i','o','r', 0, + 'e','i','g','h','t','i','n','f','e','r','i','o','r', 0, + 'n','i','n','e','i','n','f','e','r','i','o','r', 0, + 'c','e','n','t','i','n','f','e','r','i','o','r', 0, + 'd','o','l','l','a','r','i','n','f','e','r','i','o','r', 0, + 'p','e','r','i','o','d','i','n','f','e','r','i','o','r', 0, + 'c','o','m','m','a','i','n','f','e','r','i','o','r', 0, + 'A','g','r','a','v','e','s','m','a','l','l', 0, + 'A','a','c','u','t','e','s','m','a','l','l', 0, + 'A','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'A','t','i','l','d','e','s','m','a','l','l', 0, + 'A','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'A','r','i','n','g','s','m','a','l','l', 0, + 'A','E','s','m','a','l','l', 0, + 'C','c','e','d','i','l','l','a','s','m','a','l','l', 0, + 'E','g','r','a','v','e','s','m','a','l','l', 0, + 'E','a','c','u','t','e','s','m','a','l','l', 0, + 'E','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'E','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'I','g','r','a','v','e','s','m','a','l','l', 0, + 'I','a','c','u','t','e','s','m','a','l','l', 0, + 'I','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'I','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'E','t','h','s','m','a','l','l', 0, + 'N','t','i','l','d','e','s','m','a','l','l', 0, + 'O','g','r','a','v','e','s','m','a','l','l', 0, + 'O','a','c','u','t','e','s','m','a','l','l', 0, + 'O','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'O','t','i','l','d','e','s','m','a','l','l', 0, + 'O','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'O','E','s','m','a','l','l', 0, + 'O','s','l','a','s','h','s','m','a','l','l', 0, + 'U','g','r','a','v','e','s','m','a','l','l', 0, + 'U','a','c','u','t','e','s','m','a','l','l', 0, + 'U','c','i','r','c','u','m','f','l','e','x','s','m','a','l','l', 0, + 'U','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + 'Y','a','c','u','t','e','s','m','a','l','l', 0, + 'T','h','o','r','n','s','m','a','l','l', 0, + 'Y','d','i','e','r','e','s','i','s','s','m','a','l','l', 0, + '0','0','1','.','0','0','0', 0, + '0','0','1','.','0','0','1', 0, + '0','0','1','.','0','0','2', 0, + '0','0','1','.','0','0','3', 0, + 'B','l','a','c','k', 0, + 'B','o','l','d', 0, + 'B','o','o','k', 0, + 'L','i','g','h','t', 0, + 'M','e','d','i','u','m', 0, + 'R','e','g','u','l','a','r', 0, + 'R','o','m','a','n', 0, + 'S','e','m','i','b','o','l','d', 0, + }; +#define FT_NUM_MAC_NAMES 258 +/* Values are offsets into the `ft_standard_glyph_names' table */ + static const short ft_mac_names[FT_NUM_MAC_NAMES] = + { + 253, 0, 6, 261, 267, 274, 283, 294, 301, 309, 758, 330, 340, 351, + 360, 365, 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, + 436, 441, 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, + 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, + 528, 530, 532, 534, 536, 538, 540, 552, 562, 575, 587, 979, 608, 610, + 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, + 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, + 1375,1392,1405,1414,1486,1512,1562,1603,1632,1610,1622,1645,1639,1652, + 1661,1690,1668,1680,1697,1726,1704,1716,1733,1740,1769,1747,1759,1776, + 1790,1819,1797,1809, 839,1263, 707, 712, 741, 881, 871,1160,1302,1346, + 1197, 985,1031, 23,1086,1108, 32,1219, 41, 51, 730,1194, 64, 76, + 86, 94, 97,1089,1118, 106,1131,1150, 966, 696,1183, 112, 734, 120, + 132, 783, 930, 945, 138,1385,1398,1529,1115,1157, 832,1079, 770, 916, + 598, 319,1246, 155,1833,1586, 721, 749, 797, 811, 826, 829, 846, 856, + 888, 903, 954,1363,1421,1356,1433,1443,1450,1457,1469,1479,1493,1500, + 163,1522,1543,1550,1572,1134, 991,1002,1008,1015,1021,1040,1045,1053, + 1066,1073,1101,1143,1536,1783,1596,1843,1253,1207,1319,1579,1826,1229, + 1270,1313,1323,1171,1290,1332,1211,1235,1276, 169, 175, 182, 189, 200, + 209, 218, 225, 232, 239, 246 + }; +#define FT_NUM_SID_NAMES 391 +/* Values are offsets into the `ft_standard_glyph_names' table */ + static const short ft_sid_names[FT_NUM_SID_NAMES] = + { + 253, 261, 267, 274, 283, 294, 301, 309, 319, 330, 340, 351, 360, 365, + 371, 378, 385, 391, 396, 400, 404, 410, 415, 420, 424, 430, 436, 441, + 447, 457, 462, 468, 476, 485, 488, 490, 492, 494, 496, 498, 500, 502, + 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, + 532, 534, 536, 538, 540, 552, 562, 575, 587, 598, 608, 610, 612, 614, + 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, + 644, 646, 648, 650, 652, 654, 656, 658, 660, 670, 674, 685, 696, 707, + 712, 721, 730, 734, 741, 749, 758, 770, 783, 797, 811, 826, 829, 832, + 839, 846, 856, 871, 881, 888, 903, 916, 930, 945, 954, 966, 979, 985, + 991,1002,1008,1015,1021,1031,1040,1045,1053,1066,1073,1079,1086,1089, + 1101,1108,1115,1118,1131,1134,1143,1150,1157,1160,1171,1183,1194,1197, + 1207,1211,1219,1229,1235,1246,1253,1263,1270,1276,1290,1302,1313,1319, + 1323,1332,1346,1356,1363,1375,1385,1392,1398,1405,1414,1421,1433,1443, + 1450,1457,1469,1479,1486,1493,1500,1512,1522,1529,1536,1543,1550,1562, + 1572,1579,1586,1596,1603,1610,1622,1632,1639,1645,1652,1661,1668,1680, + 1690,1697,1704,1716,1726,1733,1740,1747,1759,1769,1776,1783,1790,1797, + 1809,1819,1826,1833,1843,1850,1862,1880,1895,1910,1925,1936,1954,1973, + 1988,2003,2016,2028,2040,2054,2067,2080,2092,2106,2120,2133,2147,2167, + 2182,2196,2206,2216,2229,2239,2249,2259,2269,2279,2289,2299,2309,2319, + 2329,2332,2336,2340,2358,2377,2393,2408,2419,2426,2433,2440,2447,2454, + 2461,2468,2475,2482,2489,2496,2503,2510,2517,2524,2531,2538,2545,2552, + 2559,2566,2573,2580,2587,2594,2601,2615,2625,2632,2643,2659,2672,2684, + 2696,2708,2722,2733,2744,2759,2771,2782,2797,2809,2819,2832,2850,2860, + 2873,2885,2898,2907,2917,2930,2943,2956,2968,2982,2996,3009,3022,3034, + 3046,3060,3073,3086,3098,3112,3126,3139,3152,3167,3182,3196,3208,3220, + 3237,3249,3264,3275,3283,3297,3309,3321,3338,3353,3365,3377,3394,3409, + 3418,3430,3442,3454,3471,3483,3498,3506,3518,3530,3542,3559,3574,3586, + 3597,3612,3620,3628,3636,3644,3650,3655,3660,3666,3673,3681,3687 + }; +/* the following are indices into the SID name table */ + static const unsigned short t1_standard_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110, + 0,111,112,113,114, 0,115,116,117,118,119,120,121,122, 0,123, + 0,124,125,126,127,128,129,130,131, 0,132,133, 0,134,135,136, + 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,138, 0,139, 0, 0, 0, 0,140,141,142,143, 0, 0, 0, 0, + 0,144, 0, 0, 0,145, 0, 0,146,147,148,149, 0, 0, 0, 0 + }; +/* the following are indices into the SID name table */ + static const unsigned short t1_expert_encoding[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1,229,230, 0,231,232,233,234,235,236,237,238, 13, 14, 15, 99, + 239,240,241,242,243,244,245,246,247,248, 27, 28,249,250,251,252, + 0,253,254,255,256,257, 0, 0, 0,258, 0, 0,259,260,261,262, + 0, 0,263,264,265, 0,266,109,110,267,268,269, 0,270,271,272, + 273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288, + 289,290,291,292,293,294,295,296,297,298,299,300,301,302,303, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,304,305,306, 0, 0,307,308,309,310,311, 0,312, 0, 0,313, + 0, 0,314,315, 0, 0,316,317,318, 0, 0, 0,158,155,163,319, + 320,321,322,323,324,325, 0, 0,326,150,164,169,327,328,329,330, + 331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346, + 347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362, + 363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378 + }; +/* + * This table is a compressed version of the Adobe Glyph List (AGL), + * optimized for efficient searching. It has been generated by the + * `glnames.py' python script located in the `src/tools' directory. + * + * The lookup function to get the Unicode value for a given string + * is defined below the table. + */ + static const unsigned char ft_adobe_glyph_list[55997L] = + { + 0, 52, 0,106, 2,167, 3, 63, 4,220, 6,125, 9,143, 10, 23, + 11,137, 12,199, 14,246, 15, 87, 16,233, 17,219, 18,104, 19, 88, + 22,110, 23, 32, 23, 71, 24, 77, 27,156, 29, 73, 31,247, 32,107, + 32,222, 33, 55, 34,154, 35,218, 58, 10, 64,122, 72,188, 80,109, + 88,104, 93, 61, 98,168,106, 91,114,111,115,237,122,180,127,255, + 135,164,143,132,149,213,158,108,161,115,168,175,183,147,197,199, + 202, 25,204,166,208,209,209, 81,215, 26, 65,143, 0, 65, 0,140, + 0,175, 0,193, 1, 15, 1,147, 1,233, 1,251, 2, 7, 2, 40, + 2, 57, 2, 82, 2, 91, 2,128, 2,136, 2,154, 69,131, 0,198, + 0,150, 0,158, 0,167,225,227,245,244,101,128, 1,252,237,225, + 227,242,239,110,128, 1,226,243,237,225,236,108,128,247,230,225, + 227,245,244,101,129, 0,193, 0,185,243,237,225,236,108,128,247, + 225,226,242,229,246,101,134, 1, 2, 0,213, 0,221, 0,232, 0, + 243, 0,251, 1, 7,225,227,245,244,101,128, 30,174,227,249,242, + 233,236,236,233, 99,128, 4,208,228,239,244,226,229,236,239,119, + 128, 30,182,231,242,225,246,101,128, 30,176,232,239,239,235,225, + 226,239,246,101,128, 30,178,244,233,236,228,101,128, 30,180, 99, + 4, 1, 25, 1, 32, 1,121, 1,137,225,242,239,110,128, 1,205, + 233,242, 99, 2, 1, 40, 1, 45,236,101,128, 36,182,245,237,230, + 236,229,120,134, 0,194, 1, 66, 1, 74, 1, 85, 1, 93, 1,105, + 1,113,225,227,245,244,101,128, 30,164,228,239,244,226,229,236, + 239,119,128, 30,172,231,242,225,246,101,128, 30,166,232,239,239, + 235,225,226,239,246,101,128, 30,168,243,237,225,236,108,128,247, + 226,244,233,236,228,101,128, 30,170,245,244,101,129,246,201, 1, + 129,243,237,225,236,108,128,247,180,249,242,233,236,236,233, 99, + 128, 4, 16,100, 3, 1,155, 1,165, 1,209,226,236,231,242,225, + 246,101,128, 2, 0,233,229,242,229,243,233,115,131, 0,196, 1, + 181, 1,192, 1,201,227,249,242,233,236,236,233, 99,128, 4,210, + 237,225,227,242,239,110,128, 1,222,243,237,225,236,108,128,247, + 228,239,116, 2, 1,216, 1,224,226,229,236,239,119,128, 30,160, + 237,225,227,242,239,110,128, 1,224,231,242,225,246,101,129, 0, + 192, 1,243,243,237,225,236,108,128,247,224,232,239,239,235,225, + 226,239,246,101,128, 30,162,105, 2, 2, 13, 2, 25,229,227,249, + 242,233,236,236,233, 99,128, 4,212,238,246,229,242,244,229,228, + 226,242,229,246,101,128, 2, 2,236,240,232, 97,129, 3,145, 2, + 49,244,239,238,239,115,128, 3,134,109, 2, 2, 63, 2, 71,225, + 227,242,239,110,128, 1, 0,239,238,239,243,240,225,227,101,128, + 255, 33,239,231,239,238,229,107,128, 1, 4,242,233,238,103,131, + 0,197, 2,104, 2,112, 2,120,225,227,245,244,101,128, 1,250, + 226,229,236,239,119,128, 30, 0,243,237,225,236,108,128,247,229, + 243,237,225,236,108,128,247, 97,244,233,236,228,101,129, 0,195, + 2,146,243,237,225,236,108,128,247,227,249,226,225,242,237,229, + 238,233,225,110,128, 5, 49, 66,137, 0, 66, 2,189, 2,198, 2, + 223, 3, 3, 3, 10, 3, 22, 3, 34, 3, 46, 3, 54,227,233,242, + 227,236,101,128, 36,183,228,239,116, 2, 2,206, 2,215,225,227, + 227,229,238,116,128, 30, 2,226,229,236,239,119,128, 30, 4,101, + 3, 2,231, 2,242, 2,254,227,249,242,233,236,236,233, 99,128, + 4, 17,238,225,242,237,229,238,233,225,110,128, 5, 50,244, 97, + 128, 3,146,232,239,239,107,128, 1,129,236,233,238,229,226,229, + 236,239,119,128, 30, 6,237,239,238,239,243,240,225,227,101,128, + 255, 34,242,229,246,229,243,237,225,236,108,128,246,244,243,237, + 225,236,108,128,247, 98,244,239,240,226,225,114,128, 1,130, 67, + 137, 0, 67, 3, 85, 3,127, 3,193, 3,210, 3,224, 4,171, 4, + 188, 4,200, 4,212, 97, 3, 3, 93, 3,104, 3,111,225,242,237, + 229,238,233,225,110,128, 5, 62,227,245,244,101,128, 1, 6,242, + 239,110,129,246,202, 3,119,243,237,225,236,108,128,246,245, 99, + 3, 3,135, 3,142, 3,171,225,242,239,110,128, 1, 12,229,228, + 233,236,236, 97,130, 0,199, 3,155, 3,163,225,227,245,244,101, + 128, 30, 8,243,237,225,236,108,128,247,231,233,242, 99, 2, 3, + 179, 3,184,236,101,128, 36,184,245,237,230,236,229,120,128, 1, + 8,228,239,116,129, 1, 10, 3,201,225,227,227,229,238,116,128, + 1, 10,229,228,233,236,236,225,243,237,225,236,108,128,247,184, + 104, 4, 3,234, 3,246, 4,161, 4,165,225,225,242,237,229,238, + 233,225,110,128, 5, 73,101, 6, 4, 4, 4, 24, 4, 35, 4,103, + 4,115, 4,136,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,188,227,249,242,233,236,236,233, 99, + 128, 4, 39,100, 2, 4, 41, 4, 85,229,243,227,229,238,228,229, + 114, 2, 4, 54, 4, 74,225,226,235,232,225,243,233,225,238,227, + 249,242,233,236,236,233, 99,128, 4,190,227,249,242,233,236,236, + 233, 99,128, 4,182,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,244,232,225,242,237,229,238,233,225,110, + 128, 5, 67,235,232,225,235,225,243,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,203,246,229,242,244,233,227,225,236, + 243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4, + 184,105,128, 3,167,239,239,107,128, 1,135,233,242,227,245,237, + 230,236,229,248,243,237,225,236,108,128,246,246,237,239,238,239, + 243,240,225,227,101,128,255, 35,239,225,242,237,229,238,233,225, + 110,128, 5, 81,243,237,225,236,108,128,247, 99, 68,142, 0, 68, + 4,252, 5, 10, 5, 36, 5, 96, 5,121, 5,166, 5,173, 5,231, + 5,244, 6, 0, 6, 12, 6, 28, 6, 48, 6, 57, 90,129, 1,241, + 5, 2,227,225,242,239,110,128, 1,196, 97, 2, 5, 16, 5, 27, + 225,242,237,229,238,233,225,110,128, 5, 52,230,242,233,227,225, + 110,128, 1,137, 99, 4, 5, 46, 5, 53, 5, 62, 5, 89,225,242, + 239,110,128, 1, 14,229,228,233,236,236, 97,128, 30, 16,233,242, + 99, 2, 5, 70, 5, 75,236,101,128, 36,185,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 18,242,239,225,116,128, 1, 16, + 228,239,116, 2, 5,104, 5,113,225,227,227,229,238,116,128, 30, + 10,226,229,236,239,119,128, 30, 12,101, 3, 5,129, 5,140, 5, + 150,227,249,242,233,236,236,233, 99,128, 4, 20,233,227,239,240, + 244,233, 99,128, 3,238,236,244, 97,129, 34, 6, 5,158,231,242, + 229,229,107,128, 3,148,232,239,239,107,128, 1,138,105, 2, 5, + 179, 5,218,229,242,229,243,233,115,131,246,203, 5,194, 5,202, + 5,210,193,227,245,244,101,128,246,204,199,242,225,246,101,128, + 246,205,243,237,225,236,108,128,247,168,231,225,237,237,225,231, + 242,229,229,107,128, 3,220,234,229,227,249,242,233,236,236,233, + 99,128, 4, 2,236,233,238,229,226,229,236,239,119,128, 30, 14, + 237,239,238,239,243,240,225,227,101,128,255, 36,239,244,225,227, + 227,229,238,244,243,237,225,236,108,128,246,247,115, 2, 6, 34, + 6, 41,236,225,243,104,128, 1, 16,237,225,236,108,128,247,100, + 244,239,240,226,225,114,128, 1,139,122,131, 1,242, 6, 67, 6, + 75, 6,112,227,225,242,239,110,128, 1,197,101, 2, 6, 81, 6, + 101,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,224,227,249,242,233,236,236,233, 99,128, 4, 5, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 15, 69,146, 0, + 69, 6,165, 6,183, 6,191, 7, 89, 7,153, 7,165, 7,183, 7, + 211, 8, 7, 8, 36, 8, 94, 8,169, 8,189, 8,208, 8,248, 9, + 44, 9,109, 9,115,225,227,245,244,101,129, 0,201, 6,175,243, + 237,225,236,108,128,247,233,226,242,229,246,101,128, 1, 20, 99, + 5, 6,203, 6,210, 6,224, 6,236, 7, 79,225,242,239,110,128, + 1, 26,229,228,233,236,236,225,226,242,229,246,101,128, 30, 28, + 232,225,242,237,229,238,233,225,110,128, 5, 53,233,242, 99, 2, + 6,244, 6,249,236,101,128, 36,186,245,237,230,236,229,120,135, + 0,202, 7, 16, 7, 24, 7, 32, 7, 43, 7, 51, 7, 63, 7, 71, + 225,227,245,244,101,128, 30,190,226,229,236,239,119,128, 30, 24, + 228,239,244,226,229,236,239,119,128, 30,198,231,242,225,246,101, + 128, 30,192,232,239,239,235,225,226,239,246,101,128, 30,194,243, + 237,225,236,108,128,247,234,244,233,236,228,101,128, 30,196,249, + 242,233,236,236,233, 99,128, 4, 4,100, 3, 7, 97, 7,107, 7, + 127,226,236,231,242,225,246,101,128, 2, 4,233,229,242,229,243, + 233,115,129, 0,203, 7,119,243,237,225,236,108,128,247,235,239, + 116,130, 1, 22, 7,136, 7,145,225,227,227,229,238,116,128, 1, + 22,226,229,236,239,119,128, 30,184,230,227,249,242,233,236,236, + 233, 99,128, 4, 36,231,242,225,246,101,129, 0,200, 7,175,243, + 237,225,236,108,128,247,232,104, 2, 7,189, 7,200,225,242,237, + 229,238,233,225,110,128, 5, 55,239,239,235,225,226,239,246,101, + 128, 30,186,105, 3, 7,219, 7,230, 7,245,231,232,244,242,239, + 237,225,110,128, 33,103,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 6,239,244,233,230,233,229,228,227,249,242,233, + 236,236,233, 99,128, 4,100,108, 2, 8, 13, 8, 24,227,249,242, + 233,236,236,233, 99,128, 4, 27,229,246,229,238,242,239,237,225, + 110,128, 33,106,109, 3, 8, 44, 8, 72, 8, 83,225,227,242,239, + 110,130, 1, 18, 8, 56, 8, 64,225,227,245,244,101,128, 30, 22, + 231,242,225,246,101,128, 30, 20,227,249,242,233,236,236,233, 99, + 128, 4, 28,239,238,239,243,240,225,227,101,128,255, 37,110, 4, + 8,104, 8,115, 8,135, 8,154,227,249,242,233,236,236,233, 99, + 128, 4, 29,228,229,243,227,229,238,228,229,242,227,249,242,233, + 236,236,233, 99,128, 4,162,103,129, 1, 74, 8,141,232,229,227, + 249,242,233,236,236,233, 99,128, 4,164,232,239,239,235,227,249, + 242,233,236,236,233, 99,128, 4,199,111, 2, 8,175, 8,183,231, + 239,238,229,107,128, 1, 24,240,229,110,128, 1,144,240,243,233, + 236,239,110,129, 3,149, 8,200,244,239,238,239,115,128, 3,136, + 114, 2, 8,214, 8,225,227,249,242,233,236,236,233, 99,128, 4, + 32,229,246,229,242,243,229,100,129, 1,142, 8,237,227,249,242, + 233,236,236,233, 99,128, 4, 45,115, 4, 9, 2, 9, 13, 9, 33, + 9, 37,227,249,242,233,236,236,233, 99,128, 4, 33,228,229,243, + 227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4, + 170,104,128, 1,169,237,225,236,108,128,247,101,116, 3, 9, 52, + 9, 78, 9, 92, 97,130, 3,151, 9, 60, 9, 70,242,237,229,238, + 233,225,110,128, 5, 56,244,239,238,239,115,128, 3,137,104,129, + 0,208, 9, 84,243,237,225,236,108,128,247,240,233,236,228,101, + 129, 30,188, 9,101,226,229,236,239,119,128, 30, 26,245,242,111, + 128, 32,172,250,104,130, 1,183, 9,124, 9,132,227,225,242,239, + 110,128, 1,238,242,229,246,229,242,243,229,100,128, 1,184, 70, + 136, 0, 70, 9,163, 9,172, 9,184, 9,212, 9,219, 9,248, 10, + 4, 10, 15,227,233,242,227,236,101,128, 36,187,228,239,244,225, + 227,227,229,238,116,128, 30, 30,101, 2, 9,190, 9,202,232,225, + 242,237,229,238,233,225,110,128, 5, 86,233,227,239,240,244,233, + 99,128, 3,228,232,239,239,107,128, 1,145,105, 2, 9,225, 9, + 238,244,225,227,249,242,233,236,236,233, 99,128, 4,114,246,229, + 242,239,237,225,110,128, 33,100,237,239,238,239,243,240,225,227, + 101,128,255, 38,239,245,242,242,239,237,225,110,128, 33, 99,243, + 237,225,236,108,128,247,102, 71,140, 0, 71, 10, 51, 10, 61, 10, + 107, 10,115, 10,176, 10,193, 10,205, 11, 39, 11, 52, 11, 65, 11, + 90, 11,107,194,243,241,245,225,242,101,128, 51,135, 97, 3, 10, + 69, 10, 76, 10, 94,227,245,244,101,128, 1,244,237,237, 97,129, + 3,147, 10, 84,225,230,242,233,227,225,110,128, 1,148,238,231, + 233,225,227,239,240,244,233, 99,128, 3,234,226,242,229,246,101, + 128, 1, 30, 99, 4, 10,125, 10,132, 10,141, 10,163,225,242,239, + 110,128, 1,230,229,228,233,236,236, 97,128, 1, 34,233,242, 99, + 2, 10,149, 10,154,236,101,128, 36,188,245,237,230,236,229,120, + 128, 1, 28,239,237,237,225,225,227,227,229,238,116,128, 1, 34, + 228,239,116,129, 1, 32, 10,184,225,227,227,229,238,116,128, 1, + 32,229,227,249,242,233,236,236,233, 99,128, 4, 19,104, 3, 10, + 213, 10,226, 11, 33,225,228,225,242,237,229,238,233,225,110,128, + 5, 66,101, 3, 10,234, 10,255, 11, 16,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,148,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,146, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 144,239,239,107,128, 1,147,233,237,225,242,237,229,238,233,225, + 110,128, 5, 51,234,229,227,249,242,233,236,236,233, 99,128, 4, + 3,109, 2, 11, 71, 11, 79,225,227,242,239,110,128, 30, 32,239, + 238,239,243,240,225,227,101,128,255, 39,242,225,246,101,129,246, + 206, 11, 99,243,237,225,236,108,128,247, 96,115, 2, 11,113, 11, + 129,237,225,236,108,129,247,103, 11,122,232,239,239,107,128, 2, + 155,244,242,239,235,101,128, 1,228, 72,140, 0, 72, 11,165, 11, + 190, 11,198, 11,208, 12, 17, 12, 40, 12, 77, 12,117, 12,129, 12, + 157, 12,165, 12,189,177,184, 53, 3, 11,175, 11,180, 11,185,179, + 51,128, 37,207,180, 51,128, 37,170,181, 49,128, 37,171,178,178, + 176,183, 51,128, 37,161,208,243,241,245,225,242,101,128, 51,203, + 97, 3, 11,216, 11,236, 12, 0,225,226,235,232,225,243,233,225, + 238,227,249,242,233,236,236,233, 99,128, 4,168,228,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,178, + 242,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, 4, + 42, 98, 2, 12, 23, 12, 28,225,114,128, 1, 38,242,229,246,229, + 226,229,236,239,119,128, 30, 42, 99, 2, 12, 46, 12, 55,229,228, + 233,236,236, 97,128, 30, 40,233,242, 99, 2, 12, 63, 12, 68,236, + 101,128, 36,189,245,237,230,236,229,120,128, 1, 36,100, 2, 12, + 83, 12, 93,233,229,242,229,243,233,115,128, 30, 38,239,116, 2, + 12,100, 12,109,225,227,227,229,238,116,128, 30, 34,226,229,236, + 239,119,128, 30, 36,237,239,238,239,243,240,225,227,101,128,255, + 40,111, 2, 12,135, 12,146,225,242,237,229,238,233,225,110,128, + 5, 64,242,233,227,239,240,244,233, 99,128, 3,232,243,237,225, + 236,108,128,247,104,245,238,231,225,242,245,237,236,225,245,116, + 129,246,207, 12,181,243,237,225,236,108,128,246,248,250,243,241, + 245,225,242,101,128, 51,144, 73,146, 0, 73, 12,239, 12,251, 12, + 255, 13, 11, 13, 29, 13, 37, 13, 94, 13,181, 13,214, 13,224, 13, + 242, 13,254, 14, 48, 14, 86, 14, 99, 14,166, 14,187, 14,205,193, + 227,249,242,233,236,236,233, 99,128, 4, 47, 74,128, 1, 50,213, + 227,249,242,233,236,236,233, 99,128, 4, 46,225,227,245,244,101, + 129, 0,205, 13, 21,243,237,225,236,108,128,247,237,226,242,229, + 246,101,128, 1, 44, 99, 3, 13, 45, 13, 52, 13, 84,225,242,239, + 110,128, 1,207,233,242, 99, 2, 13, 60, 13, 65,236,101,128, 36, + 190,245,237,230,236,229,120,129, 0,206, 13, 76,243,237,225,236, + 108,128,247,238,249,242,233,236,236,233, 99,128, 4, 6,100, 3, + 13,102, 13,112, 13,155,226,236,231,242,225,246,101,128, 2, 8, + 233,229,242,229,243,233,115,131, 0,207, 13,128, 13,136, 13,147, + 225,227,245,244,101,128, 30, 46,227,249,242,233,236,236,233, 99, + 128, 4,228,243,237,225,236,108,128,247,239,239,116,130, 1, 48, + 13,164, 13,173,225,227,227,229,238,116,128, 1, 48,226,229,236, + 239,119,128, 30,202,101, 2, 13,187, 13,203,226,242,229,246,229, + 227,249,242,233,236,236,233, 99,128, 4,214,227,249,242,233,236, + 236,233, 99,128, 4, 21,230,242,225,235,244,245,114,128, 33, 17, + 231,242,225,246,101,129, 0,204, 13,234,243,237,225,236,108,128, + 247,236,232,239,239,235,225,226,239,246,101,128, 30,200,105, 3, + 14, 6, 14, 17, 14, 32,227,249,242,233,236,236,233, 99,128, 4, + 24,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 10, + 243,232,239,242,244,227,249,242,233,236,236,233, 99,128, 4, 25, + 109, 2, 14, 54, 14, 75,225,227,242,239,110,129, 1, 42, 14, 64, + 227,249,242,233,236,236,233, 99,128, 4,226,239,238,239,243,240, + 225,227,101,128,255, 41,238,233,225,242,237,229,238,233,225,110, + 128, 5, 59,111, 3, 14,107, 14,118, 14,126,227,249,242,233,236, + 236,233, 99,128, 4, 1,231,239,238,229,107,128, 1, 46,244, 97, + 131, 3,153, 14,137, 14,147, 14,158,225,230,242,233,227,225,110, + 128, 1,150,228,233,229,242,229,243,233,115,128, 3,170,244,239, + 238,239,115,128, 3,138,115, 2, 14,172, 14,179,237,225,236,108, + 128,247,105,244,242,239,235,101,128, 1,151,244,233,236,228,101, + 129, 1, 40, 14,197,226,229,236,239,119,128, 30, 44,250,232,233, + 244,243, 97, 2, 14,216, 14,227,227,249,242,233,236,236,233, 99, + 128, 4,116,228,226,236,231,242,225,246,229,227,249,242,233,236, + 236,233, 99,128, 4,118, 74,134, 0, 74, 15, 6, 15, 18, 15, 41, + 15, 53, 15, 67, 15, 79,225,225,242,237,229,238,233,225,110,128, + 5, 65,227,233,242, 99, 2, 15, 27, 15, 32,236,101,128, 36,191, + 245,237,230,236,229,120,128, 1, 52,229,227,249,242,233,236,236, + 233, 99,128, 4, 8,232,229,232,225,242,237,229,238,233,225,110, + 128, 5, 75,237,239,238,239,243,240,225,227,101,128,255, 42,243, + 237,225,236,108,128,247,106, 75,140, 0, 75, 15,115, 15,125, 15, + 135, 16, 18, 16, 65, 16, 76, 16,106, 16,143, 16,156, 16,168, 16, + 180, 16,208,194,243,241,245,225,242,101,128, 51,133,203,243,241, + 245,225,242,101,128, 51,205, 97, 7, 15,151, 15,169, 15,191, 15, + 211, 15,226, 15,232, 15,249,226,225,243,232,235,233,242,227,249, + 242,233,236,236,233, 99,128, 4,160, 99, 2, 15,175, 15,181,245, + 244,101,128, 30, 48,249,242,233,236,236,233, 99,128, 4, 26,228, + 229,243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99, + 128, 4,154,232,239,239,235,227,249,242,233,236,236,233, 99,128, + 4,195,240,240, 97,128, 3,154,243,244,242,239,235,229,227,249, + 242,233,236,236,233, 99,128, 4,158,246,229,242,244,233,227,225, + 236,243,244,242,239,235,229,227,249,242,233,236,236,233, 99,128, + 4,156, 99, 4, 16, 28, 16, 35, 16, 44, 16, 52,225,242,239,110, + 128, 1,232,229,228,233,236,236, 97,128, 1, 54,233,242,227,236, + 101,128, 36,192,239,237,237,225,225,227,227,229,238,116,128, 1, + 54,228,239,244,226,229,236,239,119,128, 30, 50,101, 2, 16, 82, + 16, 94,232,225,242,237,229,238,233,225,110,128, 5, 84,238,225, + 242,237,229,238,233,225,110,128, 5, 63,104, 3, 16,114, 16,126, + 16,137,225,227,249,242,233,236,236,233, 99,128, 4, 37,229,233, + 227,239,240,244,233, 99,128, 3,230,239,239,107,128, 1,152,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 12,236,233,238,229, + 226,229,236,239,119,128, 30, 52,237,239,238,239,243,240,225,227, + 101,128,255, 43,239,240,240, 97, 2, 16,189, 16,200,227,249,242, + 233,236,236,233, 99,128, 4,128,231,242,229,229,107,128, 3,222, + 115, 2, 16,214, 16,226,233,227,249,242,233,236,236,233, 99,128, + 4,110,237,225,236,108,128,247,107, 76,138, 0, 76, 17, 1, 17, + 5, 17, 9, 17, 29, 17, 95, 17,133, 17,147, 17,165, 17,177, 17, + 189, 74,128, 1,199, 76,128,246,191, 97, 2, 17, 15, 17, 22,227, + 245,244,101,128, 1, 57,237,226,228, 97,128, 3,155, 99, 4, 17, + 39, 17, 46, 17, 55, 17, 82,225,242,239,110,128, 1, 61,229,228, + 233,236,236, 97,128, 1, 59,233,242, 99, 2, 17, 63, 17, 68,236, + 101,128, 36,193,245,237,230,236,229,248,226,229,236,239,119,128, + 30, 60,239,237,237,225,225,227,227,229,238,116,128, 1, 59,228, + 239,116,130, 1, 63, 17,105, 17,114,225,227,227,229,238,116,128, + 1, 63,226,229,236,239,119,129, 30, 54, 17,124,237,225,227,242, + 239,110,128, 30, 56,233,247,238,225,242,237,229,238,233,225,110, + 128, 5, 60,106,129, 1,200, 17,153,229,227,249,242,233,236,236, + 233, 99,128, 4, 9,236,233,238,229,226,229,236,239,119,128, 30, + 58,237,239,238,239,243,240,225,227,101,128,255, 44,115, 2, 17, + 195, 17,212,236,225,243,104,129, 1, 65, 17,204,243,237,225,236, + 108,128,246,249,237,225,236,108,128,247,108, 77,137, 0, 77, 17, + 241, 17,251, 18, 24, 18, 33, 18, 58, 18, 71, 18, 83, 18, 91, 18, + 100,194,243,241,245,225,242,101,128, 51,134,225, 99, 2, 18, 2, + 18, 18,242,239,110,129,246,208, 18, 10,243,237,225,236,108,128, + 247,175,245,244,101,128, 30, 62,227,233,242,227,236,101,128, 36, + 194,228,239,116, 2, 18, 41, 18, 50,225,227,227,229,238,116,128, + 30, 64,226,229,236,239,119,128, 30, 66,229,238,225,242,237,229, + 238,233,225,110,128, 5, 68,237,239,238,239,243,240,225,227,101, + 128,255, 45,243,237,225,236,108,128,247,109,244,245,242,238,229, + 100,128, 1,156,117,128, 3,156, 78,141, 0, 78, 18,134, 18,138, + 18,146, 18,212, 18,237, 18,248, 19, 3, 19, 21, 19, 33, 19, 45, + 19, 58, 19, 66, 19, 84, 74,128, 1,202,225,227,245,244,101,128, + 1, 67, 99, 4, 18,156, 18,163, 18,172, 18,199,225,242,239,110, + 128, 1, 71,229,228,233,236,236, 97,128, 1, 69,233,242, 99, 2, + 18,180, 18,185,236,101,128, 36,195,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 74,239,237,237,225,225,227,227,229,238, + 116,128, 1, 69,228,239,116, 2, 18,220, 18,229,225,227,227,229, + 238,116,128, 30, 68,226,229,236,239,119,128, 30, 70,232,239,239, + 235,236,229,230,116,128, 1,157,233,238,229,242,239,237,225,110, + 128, 33,104,106,129, 1,203, 19, 9,229,227,249,242,233,236,236, + 233, 99,128, 4, 10,236,233,238,229,226,229,236,239,119,128, 30, + 72,237,239,238,239,243,240,225,227,101,128,255, 46,239,247,225, + 242,237,229,238,233,225,110,128, 5, 70,243,237,225,236,108,128, + 247,110,244,233,236,228,101,129, 0,209, 19, 76,243,237,225,236, + 108,128,247,241,117,128, 3,157, 79,141, 0, 79, 19,118, 19,132, + 19,150, 19,203, 20, 78, 20,152, 20,187, 21, 48, 21, 69, 21,213, + 21,223, 21,254, 22, 53, 69,129, 1, 82, 19,124,243,237,225,236, + 108,128,246,250,225,227,245,244,101,129, 0,211, 19,142,243,237, + 225,236,108,128,247,243, 98, 2, 19,156, 19,196,225,242,242,229, + 100, 2, 19,166, 19,177,227,249,242,233,236,236,233, 99,128, 4, + 232,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,234,242,229,246,101,128, 1, 78, 99, 4, 19,213, 19, + 220, 19,235, 20, 68,225,242,239,110,128, 1,209,229,238,244,229, + 242,229,228,244,233,236,228,101,128, 1,159,233,242, 99, 2, 19, + 243, 19,248,236,101,128, 36,196,245,237,230,236,229,120,134, 0, + 212, 20, 13, 20, 21, 20, 32, 20, 40, 20, 52, 20, 60,225,227,245, + 244,101,128, 30,208,228,239,244,226,229,236,239,119,128, 30,216, + 231,242,225,246,101,128, 30,210,232,239,239,235,225,226,239,246, + 101,128, 30,212,243,237,225,236,108,128,247,244,244,233,236,228, + 101,128, 30,214,249,242,233,236,236,233, 99,128, 4, 30,100, 3, + 20, 86, 20,109, 20,142,226,108, 2, 20, 93, 20,101,225,227,245, + 244,101,128, 1, 80,231,242,225,246,101,128, 2, 12,233,229,242, + 229,243,233,115,130, 0,214, 20,123, 20,134,227,249,242,233,236, + 236,233, 99,128, 4,230,243,237,225,236,108,128,247,246,239,244, + 226,229,236,239,119,128, 30,204,103, 2, 20,158, 20,170,239,238, + 229,235,243,237,225,236,108,128,246,251,242,225,246,101,129, 0, + 210, 20,179,243,237,225,236,108,128,247,242,104, 4, 20,197, 20, + 208, 20,212, 21, 34,225,242,237,229,238,233,225,110,128, 5, 85, + 109,128, 33, 38,111, 2, 20,218, 20,228,239,235,225,226,239,246, + 101,128, 30,206,242,110,133, 1,160, 20,243, 20,251, 21, 6, 21, + 14, 21, 26,225,227,245,244,101,128, 30,218,228,239,244,226,229, + 236,239,119,128, 30,226,231,242,225,246,101,128, 30,220,232,239, + 239,235,225,226,239,246,101,128, 30,222,244,233,236,228,101,128, + 30,224,245,238,231,225,242,245,237,236,225,245,116,128, 1, 80, + 105,129, 1,162, 21, 54,238,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 14,109, 4, 21, 79, 21,107, 21,184, 21,202,225, + 227,242,239,110,130, 1, 76, 21, 91, 21, 99,225,227,245,244,101, + 128, 30, 82,231,242,225,246,101,128, 30, 80,229,231, 97,132, 33, + 38, 21,121, 21,132, 21,140, 21,156,227,249,242,233,236,236,233, + 99,128, 4, 96,231,242,229,229,107,128, 3,169,242,239,245,238, + 228,227,249,242,233,236,236,233, 99,128, 4,122,116, 2, 21,162, + 21,177,233,244,236,239,227,249,242,233,236,236,233, 99,128, 4, + 124,239,238,239,115,128, 3,143,233,227,242,239,110,129, 3,159, + 21,194,244,239,238,239,115,128, 3,140,239,238,239,243,240,225, + 227,101,128,255, 47,238,229,242,239,237,225,110,128, 33, 96,111, + 2, 21,229, 21,248,231,239,238,229,107,129, 1,234, 21,239,237, + 225,227,242,239,110,128, 1,236,240,229,110,128, 1,134,115, 3, + 22, 6, 22, 33, 22, 40,236,225,243,104,130, 0,216, 22, 17, 22, + 25,225,227,245,244,101,128, 1,254,243,237,225,236,108,128,247, + 248,237,225,236,108,128,247,111,244,242,239,235,229,225,227,245, + 244,101,128, 1,254,116, 2, 22, 59, 22, 70,227,249,242,233,236, + 236,233, 99,128, 4,126,233,236,228,101,131, 0,213, 22, 83, 22, + 91, 22,102,225,227,245,244,101,128, 30, 76,228,233,229,242,229, + 243,233,115,128, 30, 78,243,237,225,236,108,128,247,245, 80,136, + 0, 80, 22,130, 22,138, 22,147, 22,159, 22,211, 22,227, 22,246, + 23, 2,225,227,245,244,101,128, 30, 84,227,233,242,227,236,101, + 128, 36,197,228,239,244,225,227,227,229,238,116,128, 30, 86,101, + 3, 22,167, 22,178, 22,190,227,249,242,233,236,236,233, 99,128, + 4, 31,232,225,242,237,229,238,233,225,110,128, 5, 74,237,233, + 228,228,236,229,232,239,239,235,227,249,242,233,236,236,233, 99, + 128, 4,166,104, 2, 22,217, 22,221,105,128, 3,166,239,239,107, + 128, 1,164,105,129, 3,160, 22,233,247,242,225,242,237,229,238, + 233,225,110,128, 5, 83,237,239,238,239,243,240,225,227,101,128, + 255, 48,115, 2, 23, 8, 23, 25,105,129, 3,168, 23, 14,227,249, + 242,233,236,236,233, 99,128, 4,112,237,225,236,108,128,247,112, + 81,131, 0, 81, 23, 42, 23, 51, 23, 63,227,233,242,227,236,101, + 128, 36,198,237,239,238,239,243,240,225,227,101,128,255, 49,243, + 237,225,236,108,128,247,113, 82,138, 0, 82, 23, 95, 23,119, 23, + 166, 23,217, 23,230, 23,240, 23,245, 24, 19, 24, 31, 24, 43, 97, + 2, 23,101, 23,112,225,242,237,229,238,233,225,110,128, 5, 76, + 227,245,244,101,128, 1, 84, 99, 4, 23,129, 23,136, 23,145, 23, + 153,225,242,239,110,128, 1, 88,229,228,233,236,236, 97,128, 1, + 86,233,242,227,236,101,128, 36,199,239,237,237,225,225,227,227, + 229,238,116,128, 1, 86,100, 2, 23,172, 23,182,226,236,231,242, + 225,246,101,128, 2, 16,239,116, 2, 23,189, 23,198,225,227,227, + 229,238,116,128, 30, 88,226,229,236,239,119,129, 30, 90, 23,208, + 237,225,227,242,239,110,128, 30, 92,229,232,225,242,237,229,238, + 233,225,110,128, 5, 80,230,242,225,235,244,245,114,128, 33, 28, + 232,111,128, 3,161,233,110, 2, 23,252, 24, 5,231,243,237,225, + 236,108,128,246,252,246,229,242,244,229,228,226,242,229,246,101, + 128, 2, 18,236,233,238,229,226,229,236,239,119,128, 30, 94,237, + 239,238,239,243,240,225,227,101,128,255, 50,243,237,225,236,108, + 129,247,114, 24, 53,233,238,246,229,242,244,229,100,129, 2,129, + 24, 66,243,245,240,229,242,233,239,114,128, 2,182, 83,139, 0, + 83, 24,103, 26, 17, 26, 55, 26,182, 26,221, 26,250, 27, 84, 27, + 105, 27,117, 27,135, 27,143, 70, 6, 24,117, 24,209, 24,241, 25, + 77, 25,119, 25,221, 48, 9, 24,137, 24,145, 24,153, 24,161, 24, + 169, 24,177, 24,185, 24,193, 24,201,177,176,176,176, 48,128, 37, + 12,178,176,176,176, 48,128, 37, 20,179,176,176,176, 48,128, 37, + 16,180,176,176,176, 48,128, 37, 24,181,176,176,176, 48,128, 37, + 60,182,176,176,176, 48,128, 37, 44,183,176,176,176, 48,128, 37, + 52,184,176,176,176, 48,128, 37, 28,185,176,176,176, 48,128, 37, + 36, 49, 3, 24,217, 24,225, 24,233,176,176,176,176, 48,128, 37, + 0,177,176,176,176, 48,128, 37, 2,185,176,176,176, 48,128, 37, + 97, 50, 9, 25, 5, 25, 13, 25, 21, 25, 29, 25, 37, 25, 45, 25, + 53, 25, 61, 25, 69,176,176,176,176, 48,128, 37, 98,177,176,176, + 176, 48,128, 37, 86,178,176,176,176, 48,128, 37, 85,179,176,176, + 176, 48,128, 37, 99,180,176,176,176, 48,128, 37, 81,181,176,176, + 176, 48,128, 37, 87,182,176,176,176, 48,128, 37, 93,183,176,176, + 176, 48,128, 37, 92,184,176,176,176, 48,128, 37, 91, 51, 4, 25, + 87, 25, 95, 25,103, 25,111,182,176,176,176, 48,128, 37, 94,183, + 176,176,176, 48,128, 37, 95,184,176,176,176, 48,128, 37, 90,185, + 176,176,176, 48,128, 37, 84, 52, 10, 25,141, 25,149, 25,157, 25, + 165, 25,173, 25,181, 25,189, 25,197, 25,205, 25,213,176,176,176, + 176, 48,128, 37,105,177,176,176,176, 48,128, 37,102,178,176,176, + 176, 48,128, 37, 96,179,176,176,176, 48,128, 37, 80,180,176,176, + 176, 48,128, 37,108,181,176,176,176, 48,128, 37,103,182,176,176, + 176, 48,128, 37,104,183,176,176,176, 48,128, 37,100,184,176,176, + 176, 48,128, 37,101,185,176,176,176, 48,128, 37, 89, 53, 5, 25, + 233, 25,241, 25,249, 26, 1, 26, 9,176,176,176,176, 48,128, 37, + 88,177,176,176,176, 48,128, 37, 82,178,176,176,176, 48,128, 37, + 83,179,176,176,176, 48,128, 37,107,180,176,176,176, 48,128, 37, + 106, 97, 2, 26, 23, 26, 44,227,245,244,101,129, 1, 90, 26, 32, + 228,239,244,225,227,227,229,238,116,128, 30,100,237,240,233,231, + 242,229,229,107,128, 3,224, 99, 5, 26, 67, 26, 98, 26,107, 26, + 147, 26,169,225,242,239,110,130, 1, 96, 26, 78, 26, 90,228,239, + 244,225,227,227,229,238,116,128, 30,102,243,237,225,236,108,128, + 246,253,229,228,233,236,236, 97,128, 1, 94,232,247, 97,130, 1, + 143, 26,117, 26,128,227,249,242,233,236,236,233, 99,128, 4,216, + 228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99, + 128, 4,218,233,242, 99, 2, 26,155, 26,160,236,101,128, 36,200, + 245,237,230,236,229,120,128, 1, 92,239,237,237,225,225,227,227, + 229,238,116,128, 2, 24,228,239,116, 2, 26,190, 26,199,225,227, + 227,229,238,116,128, 30, 96,226,229,236,239,119,129, 30, 98, 26, + 209,228,239,244,225,227,227,229,238,116,128, 30,104,101, 2, 26, + 227, 26,239,232,225,242,237,229,238,233,225,110,128, 5, 77,246, + 229,238,242,239,237,225,110,128, 33,102,104, 5, 27, 6, 27, 34, + 27, 48, 27, 59, 27, 72, 97, 2, 27, 12, 27, 23,225,242,237,229, + 238,233,225,110,128, 5, 71,227,249,242,233,236,236,233, 99,128, + 4, 40,227,232,225,227,249,242,233,236,236,233, 99,128, 4, 41, + 229,233,227,239,240,244,233, 99,128, 3,226,232,225,227,249,242, + 233,236,236,233, 99,128, 4,186,233,237,225,227,239,240,244,233, + 99,128, 3,236,105, 2, 27, 90, 27, 96,231,237, 97,128, 3,163, + 248,242,239,237,225,110,128, 33,101,237,239,238,239,243,240,225, + 227,101,128,255, 51,239,230,244,243,233,231,238,227,249,242,233, + 236,236,233, 99,128, 4, 44,243,237,225,236,108,128,247,115,244, + 233,231,237,225,231,242,229,229,107,128, 3,218, 84,141, 0, 84, + 27,186, 27,191, 27,197, 28, 7, 28, 32, 28, 96, 28,147, 28,177, + 28,189, 28,201, 28,246, 29, 6, 29, 46,225,117,128, 3,164,226, + 225,114,128, 1,102, 99, 4, 27,207, 27,214, 27,223, 27,250,225, + 242,239,110,128, 1,100,229,228,233,236,236, 97,128, 1, 98,233, + 242, 99, 2, 27,231, 27,236,236,101,128, 36,201,245,237,230,236, + 229,248,226,229,236,239,119,128, 30,112,239,237,237,225,225,227, + 227,229,238,116,128, 1, 98,228,239,116, 2, 28, 15, 28, 24,225, + 227,227,229,238,116,128, 30,106,226,229,236,239,119,128, 30,108, + 101, 4, 28, 42, 28, 53, 28, 73, 28, 82,227,249,242,233,236,236, + 233, 99,128, 4, 34,228,229,243,227,229,238,228,229,242,227,249, + 242,233,236,236,233, 99,128, 4,172,238,242,239,237,225,110,128, + 33,105,244,243,229,227,249,242,233,236,236,233, 99,128, 4,180, + 104, 3, 28,104, 28,110, 28,136,229,244, 97,128, 3,152,111, 2, + 28,116, 28,121,239,107,128, 1,172,242,110,129, 0,222, 28,128, + 243,237,225,236,108,128,247,254,242,229,229,242,239,237,225,110, + 128, 33, 98,105, 2, 28,153, 28,164,236,228,229,243,237,225,236, + 108,128,246,254,247,238,225,242,237,229,238,233,225,110,128, 5, + 79,236,233,238,229,226,229,236,239,119,128, 30,110,237,239,238, + 239,243,240,225,227,101,128,255, 52,111, 2, 28,207, 28,218,225, + 242,237,229,238,233,225,110,128, 5, 57,238,101, 3, 28,227, 28, + 234, 28,240,230,233,246,101,128, 1,188,243,233,120,128, 1,132, + 244,247,111,128, 1,167,242,229,244,242,239,230,236,229,248,232, + 239,239,107,128, 1,174,115, 3, 29, 14, 29, 26, 29, 39,229,227, + 249,242,233,236,236,233, 99,128, 4, 38,232,229,227,249,242,233, + 236,236,233, 99,128, 4, 11,237,225,236,108,128,247,116,119, 2, + 29, 52, 29, 64,229,236,246,229,242,239,237,225,110,128, 33,107, + 239,242,239,237,225,110,128, 33, 97, 85,142, 0, 85, 29,105, 29, + 123, 29,131, 29,198, 30, 69, 30, 87, 30,198, 30,214, 30,226, 31, + 21, 31, 30, 31,142, 31,149, 31,219,225,227,245,244,101,129, 0, + 218, 29,115,243,237,225,236,108,128,247,250,226,242,229,246,101, + 128, 1,108, 99, 3, 29,139, 29,146, 29,188,225,242,239,110,128, + 1,211,233,242, 99, 2, 29,154, 29,159,236,101,128, 36,202,245, + 237,230,236,229,120,130, 0,219, 29,172, 29,180,226,229,236,239, + 119,128, 30,118,243,237,225,236,108,128,247,251,249,242,233,236, + 236,233, 99,128, 4, 35,100, 3, 29,206, 29,229, 30, 59,226,108, + 2, 29,213, 29,221,225,227,245,244,101,128, 1,112,231,242,225, + 246,101,128, 2, 20,233,229,242,229,243,233,115,134, 0,220, 29, + 251, 30, 3, 30, 11, 30, 34, 30, 42, 30, 51,225,227,245,244,101, + 128, 1,215,226,229,236,239,119,128, 30,114, 99, 2, 30, 17, 30, + 24,225,242,239,110,128, 1,217,249,242,233,236,236,233, 99,128, + 4,240,231,242,225,246,101,128, 1,219,237,225,227,242,239,110, + 128, 1,213,243,237,225,236,108,128,247,252,239,244,226,229,236, + 239,119,128, 30,228,231,242,225,246,101,129, 0,217, 30, 79,243, + 237,225,236,108,128,247,249,104, 2, 30, 93, 30,171,111, 2, 30, + 99, 30,109,239,235,225,226,239,246,101,128, 30,230,242,110,133, + 1,175, 30,124, 30,132, 30,143, 30,151, 30,163,225,227,245,244, + 101,128, 30,232,228,239,244,226,229,236,239,119,128, 30,240,231, + 242,225,246,101,128, 30,234,232,239,239,235,225,226,239,246,101, + 128, 30,236,244,233,236,228,101,128, 30,238,245,238,231,225,242, + 245,237,236,225,245,116,129, 1,112, 30,187,227,249,242,233,236, + 236,233, 99,128, 4,242,233,238,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 22,235,227,249,242,233,236,236,233, 99,128, + 4,120,109, 2, 30,232, 31, 10,225,227,242,239,110,130, 1,106, + 30,244, 30,255,227,249,242,233,236,236,233, 99,128, 4,238,228, + 233,229,242,229,243,233,115,128, 30,122,239,238,239,243,240,225, + 227,101,128,255, 53,239,231,239,238,229,107,128, 1,114,240,243, + 233,236,239,110,133, 3,165, 31, 49, 31, 53, 31, 90, 31,121, 31, + 134, 49,128, 3,210, 97, 2, 31, 59, 31, 81,227,245,244,229,232, + 239,239,235,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 211,230,242,233,227,225,110,128, 1,177,228,233,229,242,229,243, + 233,115,129, 3,171, 31,103,232,239,239,235,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,212,232,239,239,235,243,249,237, + 226,239,108,128, 3,210,244,239,238,239,115,128, 3,142,242,233, + 238,103,128, 1,110,115, 3, 31,157, 31,172, 31,179,232,239,242, + 244,227,249,242,233,236,236,233, 99,128, 4, 14,237,225,236,108, + 128,247,117,244,242,225,233,231,232,116, 2, 31,191, 31,202,227, + 249,242,233,236,236,233, 99,128, 4,174,243,244,242,239,235,229, + 227,249,242,233,236,236,233, 99,128, 4,176,244,233,236,228,101, + 130, 1,104, 31,231, 31,239,225,227,245,244,101,128, 30,120,226, + 229,236,239,119,128, 30,116, 86,136, 0, 86, 32, 11, 32, 20, 32, + 31, 32, 60, 32, 67, 32, 79, 32, 91, 32, 99,227,233,242,227,236, + 101,128, 36,203,228,239,244,226,229,236,239,119,128, 30,126,101, + 2, 32, 37, 32, 48,227,249,242,233,236,236,233, 99,128, 4, 18, + 247,225,242,237,229,238,233,225,110,128, 5, 78,232,239,239,107, + 128, 1,178,237,239,238,239,243,240,225,227,101,128,255, 54,239, + 225,242,237,229,238,233,225,110,128, 5, 72,243,237,225,236,108, + 128,247,118,244,233,236,228,101,128, 30,124, 87,134, 0, 87, 32, + 123, 32,131, 32,154, 32,194, 32,202, 32,214,225,227,245,244,101, + 128, 30,130,227,233,242, 99, 2, 32,140, 32,145,236,101,128, 36, + 204,245,237,230,236,229,120,128, 1,116,100, 2, 32,160, 32,170, + 233,229,242,229,243,233,115,128, 30,132,239,116, 2, 32,177, 32, + 186,225,227,227,229,238,116,128, 30,134,226,229,236,239,119,128, + 30,136,231,242,225,246,101,128, 30,128,237,239,238,239,243,240, + 225,227,101,128,255, 55,243,237,225,236,108,128,247,119, 88,134, + 0, 88, 32,238, 32,247, 33, 18, 33, 31, 33, 35, 33, 47,227,233, + 242,227,236,101,128, 36,205,100, 2, 32,253, 33, 7,233,229,242, + 229,243,233,115,128, 30,140,239,244,225,227,227,229,238,116,128, + 30,138,229,232,225,242,237,229,238,233,225,110,128, 5, 61,105, + 128, 3,158,237,239,238,239,243,240,225,227,101,128,255, 56,243, + 237,225,236,108,128,247,120, 89,139, 0, 89, 33, 81, 33,116, 33, + 139, 33,189, 33,228, 33,236, 33,253, 34, 40, 34, 52, 34, 60, 34, + 68, 97, 2, 33, 87, 33,104,227,245,244,101,129, 0,221, 33, 96, + 243,237,225,236,108,128,247,253,244,227,249,242,233,236,236,233, + 99,128, 4, 98,227,233,242, 99, 2, 33,125, 33,130,236,101,128, + 36,206,245,237,230,236,229,120,128, 1,118,100, 2, 33,145, 33, + 165,233,229,242,229,243,233,115,129, 1,120, 33,157,243,237,225, + 236,108,128,247,255,239,116, 2, 33,172, 33,181,225,227,227,229, + 238,116,128, 30,142,226,229,236,239,119,128, 30,244,229,114, 2, + 33,196, 33,208,233,227,249,242,233,236,236,233, 99,128, 4, 43, + 245,228,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,248,231,242,225,246,101,128, 30,242,232,239,239,107, + 129, 1,179, 33,245,225,226,239,246,101,128, 30,246,105, 3, 34, + 5, 34, 16, 34, 27,225,242,237,229,238,233,225,110,128, 5, 69, + 227,249,242,233,236,236,233, 99,128, 4, 7,247,238,225,242,237, + 229,238,233,225,110,128, 5, 82,237,239,238,239,243,240,225,227, + 101,128,255, 57,243,237,225,236,108,128,247,121,244,233,236,228, + 101,128, 30,248,245,115, 2, 34, 75, 34,113,226,233,103, 2, 34, + 83, 34, 94,227,249,242,233,236,236,233, 99,128, 4,106,233,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 108,236,233,244,244,236,101, 2, 34,124, 34,135,227,249,242,233, + 236,236,233, 99,128, 4,102,233,239,244,233,230,233,229,228,227, + 249,242,233,236,236,233, 99,128, 4,104, 90,136, 0, 90, 34,174, + 34,198, 34,243, 35, 14, 35, 81, 35,173, 35,185, 35,197, 97, 2, + 34,180, 34,191,225,242,237,229,238,233,225,110,128, 5, 54,227, + 245,244,101,128, 1,121, 99, 2, 34,204, 34,221,225,242,239,110, + 129, 1,125, 34,213,243,237,225,236,108,128,246,255,233,242, 99, + 2, 34,229, 34,234,236,101,128, 36,207,245,237,230,236,229,120, + 128, 30,144,228,239,116,130, 1,123, 34,253, 35, 6,225,227,227, + 229,238,116,128, 1,123,226,229,236,239,119,128, 30,146,101, 3, + 35, 22, 35, 33, 35, 76,227,249,242,233,236,236,233, 99,128, 4, + 23,100, 2, 35, 39, 35, 58,229,243,227,229,238,228,229,242,227, + 249,242,233,236,236,233, 99,128, 4,152,233,229,242,229,243,233, + 243,227,249,242,233,236,236,233, 99,128, 4,222,244, 97,128, 3, + 150,232,101, 4, 35, 92, 35,103, 35,119, 35,130,225,242,237,229, + 238,233,225,110,128, 5, 58,226,242,229,246,229,227,249,242,233, + 236,236,233, 99,128, 4,193,227,249,242,233,236,236,233, 99,128, + 4, 22,100, 2, 35,136, 35,155,229,243,227,229,238,228,229,242, + 227,249,242,233,236,236,233, 99,128, 4,150,233,229,242,229,243, + 233,243,227,249,242,233,236,236,233, 99,128, 4,220,236,233,238, + 229,226,229,236,239,119,128, 30,148,237,239,238,239,243,240,225, + 227,101,128,255, 58,115, 2, 35,203, 35,210,237,225,236,108,128, + 247,122,244,242,239,235,101,128, 1,181, 97,158, 0, 97, 36, 26, + 38,154, 39, 4, 39, 68, 39,132, 39,196, 40, 4, 40, 68, 40,126, + 40,190, 41, 70, 41,217, 42,137, 42,237, 43, 17, 49,192, 49,229, + 50, 0, 50,225, 51, 7, 52, 96, 52,168, 53,123, 53,132, 54, 5, + 56, 13, 57, 3, 57, 50, 57,201, 57,215, 49,138, 39, 1, 36, 50, + 36,114, 36,154, 36,218, 37, 26, 37, 90, 37,154, 37,218, 38, 26, + 38, 90, 48,138, 39, 33, 36, 74, 36, 78, 36, 82, 36, 86, 36, 90, + 36, 94, 36, 98, 36,102, 36,106, 36,110, 48,128, 39, 94, 49,128, + 39, 97, 50,128, 39, 98, 51,128, 39, 99, 52,128, 39,100, 53,128, + 39, 16, 54,128, 39,101, 55,128, 39,102, 56,128, 39,103, 57,128, + 38, 96, 49,134, 38, 27, 36,130, 36,134, 36,138, 36,142, 36,146, + 36,150, 48,128, 38,101, 49,128, 38,102, 50,128, 38, 99, 55,128, + 39, 9, 56,128, 39, 8, 57,128, 39, 7, 50,138, 38, 30, 36,178, + 36,182, 36,186, 36,190, 36,194, 36,198, 36,202, 36,206, 36,210, + 36,214, 48,128, 36, 96, 49,128, 36, 97, 50,128, 36, 98, 51,128, + 36, 99, 52,128, 36,100, 53,128, 36,101, 54,128, 36,102, 55,128, + 36,103, 56,128, 36,104, 57,128, 36,105, 51,138, 39, 12, 36,242, + 36,246, 36,250, 36,254, 37, 2, 37, 6, 37, 10, 37, 14, 37, 18, + 37, 22, 48,128, 39,118, 49,128, 39,119, 50,128, 39,120, 51,128, + 39,121, 52,128, 39,122, 53,128, 39,123, 54,128, 39,124, 55,128, + 39,125, 56,128, 39,126, 57,128, 39,127, 52,138, 39, 13, 37, 50, + 37, 54, 37, 58, 37, 62, 37, 66, 37, 70, 37, 74, 37, 78, 37, 82, + 37, 86, 48,128, 39,128, 49,128, 39,129, 50,128, 39,130, 51,128, + 39,131, 52,128, 39,132, 53,128, 39,133, 54,128, 39,134, 55,128, + 39,135, 56,128, 39,136, 57,128, 39,137, 53,138, 39, 14, 37,114, + 37,118, 37,122, 37,126, 37,130, 37,134, 37,138, 37,142, 37,146, + 37,150, 48,128, 39,138, 49,128, 39,139, 50,128, 39,140, 51,128, + 39,141, 52,128, 39,142, 53,128, 39,143, 54,128, 39,144, 55,128, + 39,145, 56,128, 39,146, 57,128, 39,147, 54,138, 39, 15, 37,178, + 37,182, 37,186, 37,190, 37,194, 37,198, 37,202, 37,206, 37,210, + 37,214, 48,128, 39,148, 49,128, 33,146, 50,128, 39,163, 51,128, + 33,148, 52,128, 33,149, 53,128, 39,153, 54,128, 39,155, 55,128, + 39,156, 56,128, 39,157, 57,128, 39,158, 55,138, 39, 17, 37,242, + 37,246, 37,250, 37,254, 38, 2, 38, 6, 38, 10, 38, 14, 38, 18, + 38, 22, 48,128, 39,159, 49,128, 39,160, 50,128, 39,161, 51,128, + 39,162, 52,128, 39,164, 53,128, 39,165, 54,128, 39,166, 55,128, + 39,167, 56,128, 39,168, 57,128, 39,169, 56,138, 39, 18, 38, 50, + 38, 54, 38, 58, 38, 62, 38, 66, 38, 70, 38, 74, 38, 78, 38, 82, + 38, 86, 48,128, 39,171, 49,128, 39,173, 50,128, 39,175, 51,128, + 39,178, 52,128, 39,179, 53,128, 39,181, 54,128, 39,184, 55,128, + 39,186, 56,128, 39,187, 57,128, 39,188, 57,138, 39, 19, 38,114, + 38,118, 38,122, 38,126, 38,130, 38,134, 38,138, 38,142, 38,146, + 38,150, 48,128, 39,189, 49,128, 39,190, 50,128, 39,154, 51,128, + 39,170, 52,128, 39,182, 53,128, 39,185, 54,128, 39,152, 55,128, + 39,180, 56,128, 39,183, 57,128, 39,172, 50,138, 39, 2, 38,178, + 38,224, 38,228, 38,232, 38,236, 38,240, 38,244, 38,248, 38,252, + 39, 0, 48,135, 39, 20, 38,196, 38,200, 38,204, 38,208, 38,212, + 38,216, 38,220, 48,128, 39,174, 49,128, 39,177, 50,128, 39, 3, + 51,128, 39, 80, 52,128, 39, 82, 53,128, 39,110, 54,128, 39,112, + 49,128, 39, 21, 50,128, 39, 22, 51,128, 39, 23, 52,128, 39, 24, + 53,128, 39, 25, 54,128, 39, 26, 55,128, 39, 27, 56,128, 39, 28, + 57,128, 39, 34, 51,138, 39, 4, 39, 28, 39, 32, 39, 36, 39, 40, + 39, 44, 39, 48, 39, 52, 39, 56, 39, 60, 39, 64, 48,128, 39, 35, + 49,128, 39, 36, 50,128, 39, 37, 51,128, 39, 38, 52,128, 39, 39, + 53,128, 38, 5, 54,128, 39, 41, 55,128, 39, 42, 56,128, 39, 43, + 57,128, 39, 44, 52,138, 38, 14, 39, 92, 39, 96, 39,100, 39,104, + 39,108, 39,112, 39,116, 39,120, 39,124, 39,128, 48,128, 39, 45, + 49,128, 39, 46, 50,128, 39, 47, 51,128, 39, 48, 52,128, 39, 49, + 53,128, 39, 50, 54,128, 39, 51, 55,128, 39, 52, 56,128, 39, 53, + 57,128, 39, 54, 53,138, 39, 6, 39,156, 39,160, 39,164, 39,168, + 39,172, 39,176, 39,180, 39,184, 39,188, 39,192, 48,128, 39, 55, + 49,128, 39, 56, 50,128, 39, 57, 51,128, 39, 58, 52,128, 39, 59, + 53,128, 39, 60, 54,128, 39, 61, 55,128, 39, 62, 56,128, 39, 63, + 57,128, 39, 64, 54,138, 39, 29, 39,220, 39,224, 39,228, 39,232, + 39,236, 39,240, 39,244, 39,248, 39,252, 40, 0, 48,128, 39, 65, + 49,128, 39, 66, 50,128, 39, 67, 51,128, 39, 68, 52,128, 39, 69, + 53,128, 39, 70, 54,128, 39, 71, 55,128, 39, 72, 56,128, 39, 73, + 57,128, 39, 74, 55,138, 39, 30, 40, 28, 40, 32, 40, 36, 40, 40, + 40, 44, 40, 48, 40, 52, 40, 56, 40, 60, 40, 64, 48,128, 39, 75, + 49,128, 37,207, 50,128, 39, 77, 51,128, 37,160, 52,128, 39, 79, + 53,128, 39, 81, 54,128, 37,178, 55,128, 37,188, 56,128, 37,198, + 57,128, 39, 86, 56,137, 39, 31, 40, 90, 40, 94, 40, 98, 40,102, + 40,106, 40,110, 40,114, 40,118, 40,122, 49,128, 37,215, 50,128, + 39, 88, 51,128, 39, 89, 52,128, 39, 90, 53,128, 39,111, 54,128, + 39,113, 55,128, 39,114, 56,128, 39,115, 57,128, 39,104, 57,138, + 39, 32, 40,150, 40,154, 40,158, 40,162, 40,166, 40,170, 40,174, + 40,178, 40,182, 40,186, 48,128, 39,105, 49,128, 39,108, 50,128, + 39,109, 51,128, 39,106, 52,128, 39,107, 53,128, 39,116, 54,128, + 39,117, 55,128, 39, 91, 56,128, 39, 92, 57,128, 39, 93, 97, 7, + 40,206, 40,216, 40,223, 40,230, 40,255, 41, 15, 41, 26,226,229, + 238,231,225,236,105,128, 9,134,227,245,244,101,128, 0,225,228, + 229,246, 97,128, 9, 6,231,117, 2, 40,237, 40,246,234,225,242, + 225,244,105,128, 10,134,242,237,245,235,232,105,128, 10, 6,237, + 225,244,242,225,231,245,242,237,245,235,232,105,128, 10, 62,242, + 245,243,241,245,225,242,101,128, 51, 3,246,239,247,229,236,243, + 233,231,110, 3, 41, 42, 41, 52, 41, 59,226,229,238,231,225,236, + 105,128, 9,190,228,229,246, 97,128, 9, 62,231,245,234,225,242, + 225,244,105,128, 10,190, 98, 4, 41, 80, 41,121, 41,130, 41,140, + 226,242,229,246,233,225,244,233,239,110, 2, 41, 95, 41,110,237, + 225,242,235,225,242,237,229,238,233,225,110,128, 5, 95,243,233, + 231,238,228,229,246, 97,128, 9,112,229,238,231,225,236,105,128, + 9,133,239,240,239,237,239,230,111,128, 49, 26,242,229,246,101, + 134, 1, 3, 41,159, 41,167, 41,178, 41,189, 41,197, 41,209,225, + 227,245,244,101,128, 30,175,227,249,242,233,236,236,233, 99,128, + 4,209,228,239,244,226,229,236,239,119,128, 30,183,231,242,225, + 246,101,128, 30,177,232,239,239,235,225,226,239,246,101,128, 30, + 179,244,233,236,228,101,128, 30,181, 99, 4, 41,227, 41,234, 42, + 57, 42,127,225,242,239,110,128, 1,206,233,242, 99, 2, 41,242, + 41,247,236,101,128, 36,208,245,237,230,236,229,120,133, 0,226, + 42, 10, 42, 18, 42, 29, 42, 37, 42, 49,225,227,245,244,101,128, + 30,165,228,239,244,226,229,236,239,119,128, 30,173,231,242,225, + 246,101,128, 30,167,232,239,239,235,225,226,239,246,101,128, 30, + 169,244,233,236,228,101,128, 30,171,245,244,101,133, 0,180, 42, + 73, 42, 84, 42,101, 42,108, 42,117,226,229,236,239,247,227,237, + 98,128, 3, 23, 99, 2, 42, 90, 42, 95,237, 98,128, 3, 1,239, + 237, 98,128, 3, 1,228,229,246, 97,128, 9, 84,236,239,247,237, + 239,100,128, 2,207,244,239,238,229,227,237, 98,128, 3, 65,249, + 242,233,236,236,233, 99,128, 4, 48,100, 5, 42,149, 42,159, 42, + 173, 42,179, 42,213,226,236,231,242,225,246,101,128, 2, 1,228, + 225,235,231,245,242,237,245,235,232,105,128, 10,113,229,246, 97, + 128, 9, 5,233,229,242,229,243,233,115,130, 0,228, 42,193, 42, + 204,227,249,242,233,236,236,233, 99,128, 4,211,237,225,227,242, + 239,110,128, 1,223,239,116, 2, 42,220, 42,228,226,229,236,239, + 119,128, 30,161,237,225,227,242,239,110,128, 1,225,101,131, 0, + 230, 42,247, 42,255, 43, 8,225,227,245,244,101,128, 1,253,235, + 239,242,229,225,110,128, 49, 80,237,225,227,242,239,110,128, 1, + 227,230,233,105, 6, 43, 33, 43, 53, 45,246, 45,252, 46, 11, 49, + 111, 48, 2, 43, 39, 43, 46,176,178,176, 56,128, 32, 21,184,185, + 180, 49,128, 32,164,177, 48, 3, 43, 62, 45, 86, 45,221, 48, 9, + 43, 82, 43,102, 43,164, 43,226, 44, 32, 44, 94, 44,156, 44,218, + 45, 24, 49, 3, 43, 90, 43, 94, 43, 98, 55,128, 4, 16, 56,128, + 4, 17, 57,128, 4, 18, 50, 10, 43,124, 43,128, 43,132, 43,136, + 43,140, 43,144, 43,148, 43,152, 43,156, 43,160, 48,128, 4, 19, + 49,128, 4, 20, 50,128, 4, 21, 51,128, 4, 1, 52,128, 4, 22, + 53,128, 4, 23, 54,128, 4, 24, 55,128, 4, 25, 56,128, 4, 26, + 57,128, 4, 27, 51, 10, 43,186, 43,190, 43,194, 43,198, 43,202, + 43,206, 43,210, 43,214, 43,218, 43,222, 48,128, 4, 28, 49,128, + 4, 29, 50,128, 4, 30, 51,128, 4, 31, 52,128, 4, 32, 53,128, + 4, 33, 54,128, 4, 34, 55,128, 4, 35, 56,128, 4, 36, 57,128, + 4, 37, 52, 10, 43,248, 43,252, 44, 0, 44, 4, 44, 8, 44, 12, + 44, 16, 44, 20, 44, 24, 44, 28, 48,128, 4, 38, 49,128, 4, 39, + 50,128, 4, 40, 51,128, 4, 41, 52,128, 4, 42, 53,128, 4, 43, + 54,128, 4, 44, 55,128, 4, 45, 56,128, 4, 46, 57,128, 4, 47, + 53, 10, 44, 54, 44, 58, 44, 62, 44, 66, 44, 70, 44, 74, 44, 78, + 44, 82, 44, 86, 44, 90, 48,128, 4,144, 49,128, 4, 2, 50,128, + 4, 3, 51,128, 4, 4, 52,128, 4, 5, 53,128, 4, 6, 54,128, + 4, 7, 55,128, 4, 8, 56,128, 4, 9, 57,128, 4, 10, 54, 10, + 44,116, 44,120, 44,124, 44,128, 44,132, 44,136, 44,140, 44,144, + 44,148, 44,152, 48,128, 4, 11, 49,128, 4, 12, 50,128, 4, 14, + 51,128,246,196, 52,128,246,197, 53,128, 4, 48, 54,128, 4, 49, + 55,128, 4, 50, 56,128, 4, 51, 57,128, 4, 52, 55, 10, 44,178, + 44,182, 44,186, 44,190, 44,194, 44,198, 44,202, 44,206, 44,210, + 44,214, 48,128, 4, 53, 49,128, 4, 81, 50,128, 4, 54, 51,128, + 4, 55, 52,128, 4, 56, 53,128, 4, 57, 54,128, 4, 58, 55,128, + 4, 59, 56,128, 4, 60, 57,128, 4, 61, 56, 10, 44,240, 44,244, + 44,248, 44,252, 45, 0, 45, 4, 45, 8, 45, 12, 45, 16, 45, 20, + 48,128, 4, 62, 49,128, 4, 63, 50,128, 4, 64, 51,128, 4, 65, + 52,128, 4, 66, 53,128, 4, 67, 54,128, 4, 68, 55,128, 4, 69, + 56,128, 4, 70, 57,128, 4, 71, 57, 10, 45, 46, 45, 50, 45, 54, + 45, 58, 45, 62, 45, 66, 45, 70, 45, 74, 45, 78, 45, 82, 48,128, + 4, 72, 49,128, 4, 73, 50,128, 4, 74, 51,128, 4, 75, 52,128, + 4, 76, 53,128, 4, 77, 54,128, 4, 78, 55,128, 4, 79, 56,128, + 4,145, 57,128, 4, 82, 49, 4, 45, 96, 45,158, 45,163, 45,189, + 48, 10, 45,118, 45,122, 45,126, 45,130, 45,134, 45,138, 45,142, + 45,146, 45,150, 45,154, 48,128, 4, 83, 49,128, 4, 84, 50,128, + 4, 85, 51,128, 4, 86, 52,128, 4, 87, 53,128, 4, 88, 54,128, + 4, 89, 55,128, 4, 90, 56,128, 4, 91, 57,128, 4, 92,177, 48, + 128, 4, 94, 52, 4, 45,173, 45,177, 45,181, 45,185, 53,128, 4, + 15, 54,128, 4, 98, 55,128, 4,114, 56,128, 4,116, 57, 5, 45, + 201, 45,205, 45,209, 45,213, 45,217, 50,128,246,198, 51,128, 4, + 95, 52,128, 4, 99, 53,128, 4,115, 54,128, 4,117, 56, 2, 45, + 227, 45,241, 51, 2, 45,233, 45,237, 49,128,246,199, 50,128,246, + 200,180, 54,128, 4,217,178,185, 57,128, 32, 14,179, 48, 2, 46, + 3, 46, 7, 48,128, 32, 15, 49,128, 32, 13,181, 55, 7, 46, 28, + 46, 98, 47,163, 47,240, 48,197, 49, 34, 49,105, 51, 2, 46, 34, + 46, 48, 56, 2, 46, 40, 46, 44, 49,128, 6,106, 56,128, 6, 12, + 57, 8, 46, 66, 46, 70, 46, 74, 46, 78, 46, 82, 46, 86, 46, 90, + 46, 94, 50,128, 6, 96, 51,128, 6, 97, 52,128, 6, 98, 53,128, + 6, 99, 54,128, 6,100, 55,128, 6,101, 56,128, 6,102, 57,128, + 6,103, 52, 7, 46,114, 46,146, 46,208, 47, 14, 47, 46, 47,102, + 47,158, 48, 5, 46,126, 46,130, 46,134, 46,138, 46,142, 48,128, + 6,104, 49,128, 6,105, 51,128, 6, 27, 55,128, 6, 31, 57,128, + 6, 33, 49, 10, 46,168, 46,172, 46,176, 46,180, 46,184, 46,188, + 46,192, 46,196, 46,200, 46,204, 48,128, 6, 34, 49,128, 6, 35, + 50,128, 6, 36, 51,128, 6, 37, 52,128, 6, 38, 53,128, 6, 39, + 54,128, 6, 40, 55,128, 6, 41, 56,128, 6, 42, 57,128, 6, 43, + 50, 10, 46,230, 46,234, 46,238, 46,242, 46,246, 46,250, 46,254, + 47, 2, 47, 6, 47, 10, 48,128, 6, 44, 49,128, 6, 45, 50,128, + 6, 46, 51,128, 6, 47, 52,128, 6, 48, 53,128, 6, 49, 54,128, + 6, 50, 55,128, 6, 51, 56,128, 6, 52, 57,128, 6, 53, 51, 5, + 47, 26, 47, 30, 47, 34, 47, 38, 47, 42, 48,128, 6, 54, 49,128, + 6, 55, 50,128, 6, 56, 51,128, 6, 57, 52,128, 6, 58, 52, 9, + 47, 66, 47, 70, 47, 74, 47, 78, 47, 82, 47, 86, 47, 90, 47, 94, + 47, 98, 48,128, 6, 64, 49,128, 6, 65, 50,128, 6, 66, 51,128, + 6, 67, 52,128, 6, 68, 53,128, 6, 69, 54,128, 6, 70, 56,128, + 6, 72, 57,128, 6, 73, 53, 9, 47,122, 47,126, 47,130, 47,134, + 47,138, 47,142, 47,146, 47,150, 47,154, 48,128, 6, 74, 49,128, + 6, 75, 50,128, 6, 76, 51,128, 6, 77, 52,128, 6, 78, 53,128, + 6, 79, 54,128, 6, 80, 55,128, 6, 81, 56,128, 6, 82,183, 48, + 128, 6, 71, 53, 3, 47,171, 47,203, 47,235, 48, 5, 47,183, 47, + 187, 47,191, 47,195, 47,199, 53,128, 6,164, 54,128, 6,126, 55, + 128, 6,134, 56,128, 6,152, 57,128, 6,175, 49, 5, 47,215, 47, + 219, 47,223, 47,227, 47,231, 49,128, 6,121, 50,128, 6,136, 51, + 128, 6,145, 52,128, 6,186, 57,128, 6,210,179, 52,128, 6,213, + 54, 7, 48, 0, 48, 5, 48, 10, 48, 15, 48, 53, 48,115, 48,177, + 179, 54,128, 32,170,180, 53,128, 5,190,181, 56,128, 5,195, 54, + 6, 48, 29, 48, 33, 48, 37, 48, 41, 48, 45, 48, 49, 52,128, 5, + 208, 53,128, 5,209, 54,128, 5,210, 55,128, 5,211, 56,128, 5, + 212, 57,128, 5,213, 55, 10, 48, 75, 48, 79, 48, 83, 48, 87, 48, + 91, 48, 95, 48, 99, 48,103, 48,107, 48,111, 48,128, 5,214, 49, + 128, 5,215, 50,128, 5,216, 51,128, 5,217, 52,128, 5,218, 53, + 128, 5,219, 54,128, 5,220, 55,128, 5,221, 56,128, 5,222, 57, + 128, 5,223, 56, 10, 48,137, 48,141, 48,145, 48,149, 48,153, 48, + 157, 48,161, 48,165, 48,169, 48,173, 48,128, 5,224, 49,128, 5, + 225, 50,128, 5,226, 51,128, 5,227, 52,128, 5,228, 53,128, 5, + 229, 54,128, 5,230, 55,128, 5,231, 56,128, 5,232, 57,128, 5, + 233, 57, 3, 48,185, 48,189, 48,193, 48,128, 5,234, 52,128,251, + 42, 53,128,251, 43, 55, 4, 48,207, 48,221, 48,241, 48,246, 48, + 2, 48,213, 48,217, 48,128,251, 75, 53,128,251, 31, 49, 3, 48, + 229, 48,233, 48,237, 54,128, 5,240, 55,128, 5,241, 56,128, 5, + 242,178, 51,128,251, 53, 57, 7, 49, 6, 49, 10, 49, 14, 49, 18, + 49, 22, 49, 26, 49, 30, 51,128, 5,180, 52,128, 5,181, 53,128, + 5,182, 54,128, 5,187, 55,128, 5,184, 56,128, 5,183, 57,128, + 5,176, 56, 3, 49, 42, 49, 86, 49, 91, 48, 7, 49, 58, 49, 62, + 49, 66, 49, 70, 49, 74, 49, 78, 49, 82, 48,128, 5,178, 49,128, + 5,177, 50,128, 5,179, 51,128, 5,194, 52,128, 5,193, 54,128, + 5,185, 55,128, 5,188,179, 57,128, 5,189, 52, 2, 49, 97, 49, + 101, 49,128, 5,191, 50,128, 5,192,185,178, 57,128, 2,188, 54, + 3, 49,119, 49,178, 49,185, 49, 4, 49,129, 49,145, 49,151, 49, + 172, 50, 2, 49,135, 49,140,180, 56,128, 33, 5,184, 57,128, 33, + 19,179,181, 50,128, 33, 22,181, 55, 3, 49,160, 49,164, 49,168, + 51,128, 32, 44, 52,128, 32, 45, 53,128, 32, 46,182,182, 52,128, + 32, 12,179,177,182, 55,128, 6,109,180,185,179, 55,128, 2,189, + 103, 2, 49,198, 49,205,242,225,246,101,128, 0,224,117, 2, 49, + 211, 49,220,234,225,242,225,244,105,128, 10,133,242,237,245,235, + 232,105,128, 10, 5,104, 2, 49,235, 49,245,233,242,225,231,225, + 238, 97,128, 48, 66,239,239,235,225,226,239,246,101,128, 30,163, + 105, 7, 50, 16, 50, 41, 50, 48, 50, 60, 50, 85, 50,101, 50,181, + 98, 2, 50, 22, 50, 31,229,238,231,225,236,105,128, 9,144,239, + 240,239,237,239,230,111,128, 49, 30,228,229,246, 97,128, 9, 16, + 229,227,249,242,233,236,236,233, 99,128, 4,213,231,117, 2, 50, + 67, 50, 76,234,225,242,225,244,105,128, 10,144,242,237,245,235, + 232,105,128, 10, 16,237,225,244,242,225,231,245,242,237,245,235, + 232,105,128, 10, 72,110, 5, 50,113, 50,122, 50,136, 50,152, 50, + 167,225,242,225,226,233, 99,128, 6, 57,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,202,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,203,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,204,246,229,242,244,229,228,226,242,229, + 246,101,128, 2, 3,246,239,247,229,236,243,233,231,110, 3, 50, + 197, 50,207, 50,214,226,229,238,231,225,236,105,128, 9,200,228, + 229,246, 97,128, 9, 72,231,245,234,225,242,225,244,105,128, 10, + 200,107, 2, 50,231, 50,255,225,244,225,235,225,238, 97,129, 48, + 162, 50,243,232,225,236,230,247,233,228,244,104,128,255,113,239, + 242,229,225,110,128, 49, 79,108, 3, 51, 15, 52, 71, 52, 80,101, + 2, 51, 21, 52, 66,102,136, 5,208, 51, 41, 51, 50, 51, 65, 51, + 79, 51,168, 51,182, 52, 37, 52, 51,225,242,225,226,233, 99,128, + 6, 39,228,225,231,229,243,232,232,229,226,242,229,119,128,251, + 48,230,233,238,225,236,225,242,225,226,233, 99,128,254,142,104, + 2, 51, 85, 51,160,225,237,250, 97, 2, 51, 94, 51,127,225,226, + 239,246,101, 2, 51,104, 51,113,225,242,225,226,233, 99,128, 6, + 35,230,233,238,225,236,225,242,225,226,233, 99,128,254,132,226, + 229,236,239,119, 2, 51,137, 51,146,225,242,225,226,233, 99,128, + 6, 37,230,233,238,225,236,225,242,225,226,233, 99,128,254,136, + 229,226,242,229,119,128, 5,208,236,225,237,229,228,232,229,226, + 242,229,119,128,251, 79,237, 97, 2, 51,189, 51,225,228,228,225, + 225,226,239,246,101, 2, 51,202, 51,211,225,242,225,226,233, 99, + 128, 6, 34,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 130,235,243,245,242, 97, 4, 51,239, 51,248, 52, 6, 52, 22,225, + 242,225,226,233, 99,128, 6, 73,230,233,238,225,236,225,242,225, + 226,233, 99,128,254,240,233,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,254,243,237,229,228,233,225,236,225,242,225,226, + 233, 99,128,254,244,240,225,244,225,232,232,229,226,242,229,119, + 128,251, 46,241,225,237,225,244,243,232,229,226,242,229,119,128, + 251, 47,240,104,128, 33, 53,236,229,241,245,225,108,128, 34, 76, + 240,232, 97,129, 3,177, 52, 88,244,239,238,239,115,128, 3,172, + 109, 4, 52,106, 52,114, 52,125, 52,159,225,227,242,239,110,128, + 1, 1,239,238,239,243,240,225,227,101,128,255, 65,240,229,242, + 243,225,238,100,130, 0, 38, 52,139, 52,151,237,239,238,239,243, + 240,225,227,101,128,255, 6,243,237,225,236,108,128,247, 38,243, + 241,245,225,242,101,128, 51,194,110, 4, 52,178, 52,189, 53, 55, + 53, 65,226,239,240,239,237,239,230,111,128, 49, 34,103, 4, 52, + 199, 52,210, 52,224, 53, 47,226,239,240,239,237,239,230,111,128, + 49, 36,235,232,225,238,235,232,245,244,232,225,105,128, 14, 90, + 236,101,131, 34, 32, 52,235, 53, 32, 53, 39,226,242,225,227,235, + 229,116, 2, 52,247, 53, 11,236,229,230,116,129, 48, 8, 53, 0, + 246,229,242,244,233,227,225,108,128,254, 63,242,233,231,232,116, + 129, 48, 9, 53, 21,246,229,242,244,233,227,225,108,128,254, 64, + 236,229,230,116,128, 35, 41,242,233,231,232,116,128, 35, 42,243, + 244,242,239,109,128, 33, 43,239,244,229,236,229,233, 97,128, 3, + 135,117, 2, 53, 71, 53, 83,228,225,244,244,225,228,229,246, 97, + 128, 9, 82,243,246,225,242, 97, 3, 53, 95, 53,105, 53,112,226, + 229,238,231,225,236,105,128, 9,130,228,229,246, 97,128, 9, 2, + 231,245,234,225,242,225,244,105,128, 10,130,239,231,239,238,229, + 107,128, 1, 5,112, 3, 53,140, 53,164, 53,194, 97, 2, 53,146, + 53,158,225,244,239,243,241,245,225,242,101,128, 51, 0,242,229, + 110,128, 36,156,239,243,244,242,239,240,232,101, 2, 53,177, 53, + 188,225,242,237,229,238,233,225,110,128, 5, 90,237,239,100,128, + 2,188,112, 2, 53,200, 53,205,236,101,128,248,255,242,111, 2, + 53,212, 53,220,225,227,232,229,115,128, 34, 80,120, 2, 53,226, + 53,246,229,241,245,225,108,129, 34, 72, 53,236,239,242,233,237, + 225,231,101,128, 34, 82,233,237,225,244,229,236,249,229,241,245, + 225,108,128, 34, 69,114, 4, 54, 15, 54, 42, 54, 46, 54, 91,225, + 229, 97, 2, 54, 23, 54, 33,229,235,239,242,229,225,110,128, 49, + 142,235,239,242,229,225,110,128, 49,141, 99,128, 35, 18,105, 2, + 54, 52, 54, 66,231,232,244,232,225,236,230,242,233,238,103,128, + 30,154,238,103,130, 0,229, 54, 75, 54, 83,225,227,245,244,101, + 128, 1,251,226,229,236,239,119,128, 30, 1,242,239,119, 8, 54, + 111, 54,118, 54,247, 55, 57, 55,107, 55,162, 55,185, 56, 4,226, + 239,244,104,128, 33,148,100, 3, 54,126, 54,165, 54,212,225,243, + 104, 4, 54,138, 54,145, 54,152, 54,160,228,239,247,110,128, 33, + 227,236,229,230,116,128, 33,224,242,233,231,232,116,128, 33,226, + 245,112,128, 33,225,226,108, 5, 54,178, 54,185, 54,192, 54,199, + 54,207,226,239,244,104,128, 33,212,228,239,247,110,128, 33,211, + 236,229,230,116,128, 33,208,242,233,231,232,116,128, 33,210,245, + 112,128, 33,209,239,247,110,131, 33,147, 54,224, 54,231, 54,239, + 236,229,230,116,128, 33,153,242,233,231,232,116,128, 33,152,247, + 232,233,244,101,128, 33,233,104, 2, 54,253, 55, 48,229,225,100, + 4, 55, 9, 55, 19, 55, 29, 55, 40,228,239,247,238,237,239,100, + 128, 2,197,236,229,230,244,237,239,100,128, 2,194,242,233,231, + 232,244,237,239,100,128, 2,195,245,240,237,239,100,128, 2,196, + 239,242,233,250,229,120,128,248,231,236,229,230,116,131, 33,144, + 55, 70, 55, 87, 55, 99,228,226,108,129, 33,208, 55, 78,243,244, + 242,239,235,101,128, 33,205,239,246,229,242,242,233,231,232,116, + 128, 33,198,247,232,233,244,101,128, 33,230,242,233,231,232,116, + 132, 33,146, 55,123, 55,135, 55,143, 55,154,228,226,236,243,244, + 242,239,235,101,128, 33,207,232,229,225,246,121,128, 39,158,239, + 246,229,242,236,229,230,116,128, 33,196,247,232,233,244,101,128, + 33,232,244,225, 98, 2, 55,170, 55,177,236,229,230,116,128, 33, + 228,242,233,231,232,116,128, 33,229,245,112,132, 33,145, 55,198, + 55,226, 55,244, 55,252,100, 2, 55,204, 55,216,110,129, 33,149, + 55,210,226,243,101,128, 33,168,239,247,238,226,225,243,101,128, + 33,168,236,229,230,116,129, 33,150, 55,235,239,230,228,239,247, + 110,128, 33,197,242,233,231,232,116,128, 33,151,247,232,233,244, + 101,128, 33,231,246,229,242,244,229,120,128,248,230,115, 5, 56, + 25, 56,101, 56,146, 56,229, 56,239, 99, 2, 56, 31, 56, 83,233, + 105, 2, 56, 38, 56, 61,227,233,242,227,245,109,129, 0, 94, 56, + 49,237,239,238,239,243,240,225,227,101,128,255, 62,244,233,236, + 228,101,129, 0,126, 56, 71,237,239,238,239,243,240,225,227,101, + 128,255, 94,242,233,240,116,129, 2, 81, 56, 92,244,245,242,238, + 229,100,128, 2, 82,237,225,236,108, 2, 56,110, 56,121,232,233, + 242,225,231,225,238, 97,128, 48, 65,235,225,244,225,235,225,238, + 97,129, 48,161, 56,134,232,225,236,230,247,233,228,244,104,128, + 255,103,244,229,242,233,115, 2, 56,156, 56,225,107,131, 0, 42, + 56,166, 56,194, 56,217, 97, 2, 56,172, 56,186,236,244,239,238, + 229,225,242,225,226,233, 99,128, 6,109,242,225,226,233, 99,128, + 6,109,109, 2, 56,200, 56,206,225,244,104,128, 34, 23,239,238, + 239,243,240,225,227,101,128,255, 10,243,237,225,236,108,128,254, + 97,109,128, 32, 66,245,240,229,242,233,239,114,128,246,233,249, + 237,240,244,239,244,233,227,225,236,236,249,229,241,245,225,108, + 128, 34, 67,116,132, 0, 64, 57, 15, 57, 22, 57, 34, 57, 42,233, + 236,228,101,128, 0,227,237,239,238,239,243,240,225,227,101,128, + 255, 32,243,237,225,236,108,128,254,107,245,242,238,229,100,128, + 2, 80,117, 6, 57, 64, 57, 89, 57, 96, 57,121, 57,141, 57,157, + 98, 2, 57, 70, 57, 79,229,238,231,225,236,105,128, 9,148,239, + 240,239,237,239,230,111,128, 49, 32,228,229,246, 97,128, 9, 20, + 231,117, 2, 57,103, 57,112,234,225,242,225,244,105,128, 10,148, + 242,237,245,235,232,105,128, 10, 20,236,229,238,231,244,232,237, + 225,242,235,226,229,238,231,225,236,105,128, 9,215,237,225,244, + 242,225,231,245,242,237,245,235,232,105,128, 10, 76,246,239,247, + 229,236,243,233,231,110, 3, 57,173, 57,183, 57,190,226,229,238, + 231,225,236,105,128, 9,204,228,229,246, 97,128, 9, 76,231,245, + 234,225,242,225,244,105,128, 10,204,246,225,231,242,225,232,225, + 228,229,246, 97,128, 9, 61,121, 2, 57,221, 57,233,226,225,242, + 237,229,238,233,225,110,128, 5, 97,233,110,130, 5,226, 57,242, + 58, 1,225,236,244,239,238,229,232,229,226,242,229,119,128,251, + 32,232,229,226,242,229,119,128, 5,226, 98,144, 0, 98, 58, 46, + 58,181, 58,192, 58,201, 58,226, 60, 11, 60, 73, 60,146, 62, 72, + 62, 84, 62,127, 62,135, 62,145, 64, 15, 64, 39, 64, 48, 97, 7, + 58, 62, 58, 72, 58, 96, 58,103, 58,128, 58,152, 58,163,226,229, + 238,231,225,236,105,128, 9,172,227,235,243,236,225,243,104,129, + 0, 92, 58, 84,237,239,238,239,243,240,225,227,101,128,255, 60, + 228,229,246, 97,128, 9, 44,231,117, 2, 58,110, 58,119,234,225, + 242,225,244,105,128, 10,172,242,237,245,235,232,105,128, 10, 44, + 104, 2, 58,134, 58,144,233,242,225,231,225,238, 97,128, 48,112, + 244,244,232,225,105,128, 14, 63,235,225,244,225,235,225,238, 97, + 128, 48,208,114,129, 0,124, 58,169,237,239,238,239,243,240,225, + 227,101,128,255, 92,226,239,240,239,237,239,230,111,128, 49, 5, + 227,233,242,227,236,101,128, 36,209,228,239,116, 2, 58,209, 58, + 218,225,227,227,229,238,116,128, 30, 3,226,229,236,239,119,128, + 30, 5,101, 6, 58,240, 59, 5, 59, 28, 59,170, 59,181, 59,193, + 225,237,229,228,243,233,248,244,229,229,238,244,232,238,239,244, + 229,115,128, 38,108, 99, 2, 59, 11, 59, 18,225,245,243,101,128, + 34, 53,249,242,233,236,236,233, 99,128, 4, 49,104, 5, 59, 40, + 59, 49, 59, 63, 59, 93, 59,152,225,242,225,226,233, 99,128, 6, + 40,230,233,238,225,236,225,242,225,226,233, 99,128,254,144,105, + 2, 59, 69, 59, 84,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,145,242,225,231,225,238, 97,128, 48,121,237,101, 2, + 59,100, 59,113,228,233,225,236,225,242,225,226,233, 99,128,254, + 146,229,237,105, 2, 59,121, 59,136,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,159,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 8,238,239,239,238,230,233,238,225, + 236,225,242,225,226,233, 99,128,252,109,235,225,244,225,235,225, + 238, 97,128, 48,217,238,225,242,237,229,238,233,225,110,128, 5, + 98,116,132, 5,209, 59,205, 59,225, 59,245, 59,254, 97,129, 3, + 178, 59,211,243,249,237,226,239,236,231,242,229,229,107,128, 3, + 208,228,225,231,229,243,104,129,251, 49, 59,236,232,229,226,242, + 229,119,128,251, 49,232,229,226,242,229,119,128, 5,209,242,225, + 230,229,232,229,226,242,229,119,128,251, 76,104, 2, 60, 17, 60, + 67, 97, 3, 60, 25, 60, 35, 60, 42,226,229,238,231,225,236,105, + 128, 9,173,228,229,246, 97,128, 9, 45,231,117, 2, 60, 49, 60, + 58,234,225,242,225,244,105,128, 10,173,242,237,245,235,232,105, + 128, 10, 45,239,239,107,128, 2, 83,105, 5, 60, 85, 60, 96, 60, + 107, 60,121, 60,135,232,233,242,225,231,225,238, 97,128, 48,115, + 235,225,244,225,235,225,238, 97,128, 48,211,236,225,226,233,225, + 236,227,236,233,227,107,128, 2,152,238,228,233,231,245,242,237, + 245,235,232,105,128, 10, 2,242,245,243,241,245,225,242,101,128, + 51, 49,108, 3, 60,154, 62, 55, 62, 66, 97, 2, 60,160, 62, 50, + 227,107, 6, 60,175, 60,184, 60,221, 61,114, 61,169, 61,221,227, + 233,242,227,236,101,128, 37,207,100, 2, 60,190, 60,199,233,225, + 237,239,238,100,128, 37,198,239,247,238,240,239,233,238,244,233, + 238,231,244,242,233,225,238,231,236,101,128, 37,188,108, 2, 60, + 227, 61, 74,101, 2, 60,233, 61, 13,230,244,240,239,233,238,244, + 233,238,103, 2, 60,248, 61, 2,240,239,233,238,244,229,114,128, + 37,196,244,242,233,225,238,231,236,101,128, 37,192,238,244,233, + 227,245,236,225,242,226,242,225,227,235,229,116, 2, 61, 33, 61, + 53,236,229,230,116,129, 48, 16, 61, 42,246,229,242,244,233,227, + 225,108,128,254, 59,242,233,231,232,116,129, 48, 17, 61, 63,246, + 229,242,244,233,227,225,108,128,254, 60,239,247,229,114, 2, 61, + 83, 61, 98,236,229,230,244,244,242,233,225,238,231,236,101,128, + 37,227,242,233,231,232,244,244,242,233,225,238,231,236,101,128, + 37,226,114, 2, 61,120, 61,131,229,227,244,225,238,231,236,101, + 128, 37,172,233,231,232,244,240,239,233,238,244,233,238,103, 2, + 61,148, 61,158,240,239,233,238,244,229,114,128, 37,186,244,242, + 233,225,238,231,236,101,128, 37,182,115, 3, 61,177, 61,207, 61, + 215,109, 2, 61,183, 61,195,225,236,236,243,241,245,225,242,101, + 128, 37,170,233,236,233,238,231,230,225,227,101,128, 38, 59,241, + 245,225,242,101,128, 37,160,244,225,114,128, 38, 5,245,240,112, + 2, 61,229, 62, 11,229,114, 2, 61,236, 61,251,236,229,230,244, + 244,242,233,225,238,231,236,101,128, 37,228,242,233,231,232,244, + 244,242,233,225,238,231,236,101,128, 37,229,239,233,238,244,233, + 238,103, 2, 62, 23, 62, 39,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,180,244,242,233,225,238,231,236,101,128, + 37,178,238,107,128, 36, 35,233,238,229,226,229,236,239,119,128, + 30, 7,239,227,107,128, 37,136,237,239,238,239,243,240,225,227, + 101,128,255, 66,111, 3, 62, 92, 62,105, 62,116,226,225,233,237, + 225,233,244,232,225,105,128, 14, 26,232,233,242,225,231,225,238, + 97,128, 48,124,235,225,244,225,235,225,238, 97,128, 48,220,240, + 225,242,229,110,128, 36,157,241,243,241,245,225,242,101,128, 51, + 195,114, 4, 62,155, 63,149, 63,222, 64, 5,225, 99, 2, 62,162, + 63, 56,101, 3, 62,170, 62,175, 62,243,229,120,128,248,244,236, + 229,230,116,133, 0,123, 62,192, 62,197, 62,219, 62,227, 62,232, + 226,116,128,248,243,109, 2, 62,203, 62,208,233,100,128,248,242, + 239,238,239,243,240,225,227,101,128,255, 91,243,237,225,236,108, + 128,254, 91,244,112,128,248,241,246,229,242,244,233,227,225,108, + 128,254, 55,242,233,231,232,116,133, 0,125, 63, 5, 63, 10, 63, + 32, 63, 40, 63, 45,226,116,128,248,254,109, 2, 63, 16, 63, 21, + 233,100,128,248,253,239,238,239,243,240,225,227,101,128,255, 93, + 243,237,225,236,108,128,254, 92,244,112,128,248,252,246,229,242, + 244,233,227,225,108,128,254, 56,235,229,116, 2, 63, 64, 63,106, + 236,229,230,116,132, 0, 91, 63, 79, 63, 84, 63, 89, 63,101,226, + 116,128,248,240,229,120,128,248,239,237,239,238,239,243,240,225, + 227,101,128,255, 59,244,112,128,248,238,242,233,231,232,116,132, + 0, 93, 63,122, 63,127, 63,132, 63,144,226,116,128,248,251,229, + 120,128,248,250,237,239,238,239,243,240,225,227,101,128,255, 61, + 244,112,128,248,249,229,246,101,131, 2,216, 63,161, 63,172, 63, + 178,226,229,236,239,247,227,237, 98,128, 3, 46,227,237, 98,128, + 3, 6,233,238,246,229,242,244,229,100, 3, 63,193, 63,204, 63, + 210,226,229,236,239,247,227,237, 98,128, 3, 47,227,237, 98,128, + 3, 17,228,239,245,226,236,229,227,237, 98,128, 3, 97,233,228, + 231,101, 2, 63,231, 63,242,226,229,236,239,247,227,237, 98,128, + 3, 42,233,238,246,229,242,244,229,228,226,229,236,239,247,227, + 237, 98,128, 3, 58,239,235,229,238,226,225,114,128, 0,166,115, + 2, 64, 21, 64, 29,244,242,239,235,101,128, 1,128,245,240,229, + 242,233,239,114,128,246,234,244,239,240,226,225,114,128, 1,131, + 117, 3, 64, 56, 64, 67, 64, 78,232,233,242,225,231,225,238, 97, + 128, 48,118,235,225,244,225,235,225,238, 97,128, 48,214,236,108, + 2, 64, 85, 64,115,229,116,130, 32, 34, 64, 94, 64,104,233,238, + 246,229,242,243,101,128, 37,216,239,240,229,242,225,244,239,114, + 128, 34, 25,243,229,249,101,128, 37,206, 99,143, 0, 99, 64,156, + 65,105, 65,116, 65,180, 65,211, 66, 48, 67,215, 68,199, 69, 43, + 69, 92, 72, 84, 72, 92, 72,102, 72,114, 72,147, 97, 9, 64,176, + 64,187, 64,197, 64,204, 64,211, 64,236, 64,246, 65, 42, 65, 51, + 225,242,237,229,238,233,225,110,128, 5,110,226,229,238,231,225, + 236,105,128, 9,154,227,245,244,101,128, 1, 7,228,229,246, 97, + 128, 9, 26,231,117, 2, 64,218, 64,227,234,225,242,225,244,105, + 128, 10,154,242,237,245,235,232,105,128, 10, 26,236,243,241,245, + 225,242,101,128, 51,136,238,228,242,225,226,233,238,228,117, 4, + 65, 8, 65, 18, 65, 24, 65, 31,226,229,238,231,225,236,105,128, + 9,129,227,237, 98,128, 3, 16,228,229,246, 97,128, 9, 1,231, + 245,234,225,242,225,244,105,128, 10,129,240,243,236,239,227,107, + 128, 33,234,114, 3, 65, 59, 65, 65, 65, 91,229,239,102,128, 33, + 5,239,110,130, 2,199, 65, 74, 65, 85,226,229,236,239,247,227, + 237, 98,128, 3, 44,227,237, 98,128, 3, 12,242,233,225,231,229, + 242,229,244,245,242,110,128, 33,181,226,239,240,239,237,239,230, + 111,128, 49, 24, 99, 4, 65,126, 65,133, 65,152, 65,174,225,242, + 239,110,128, 1, 13,229,228,233,236,236, 97,129, 0,231, 65,144, + 225,227,245,244,101,128, 30, 9,233,242, 99, 2, 65,160, 65,165, + 236,101,128, 36,210,245,237,230,236,229,120,128, 1, 9,245,242, + 108,128, 2, 85,100, 2, 65,186, 65,202,239,116,129, 1, 11, 65, + 193,225,227,227,229,238,116,128, 1, 11,243,241,245,225,242,101, + 128, 51,197,101, 2, 65,217, 65,233,228,233,236,236, 97,129, 0, + 184, 65,227,227,237, 98,128, 3, 39,238,116,132, 0,162, 65,246, + 66, 14, 66, 26, 66, 37,105, 2, 65,252, 66, 4,231,242,225,228, + 101,128, 33, 3,238,230,229,242,233,239,114,128,246,223,237,239, + 238,239,243,240,225,227,101,128,255,224,239,236,228,243,244,249, + 236,101,128,247,162,243,245,240,229,242,233,239,114,128,246,224, + 104, 5, 66, 60, 66,123, 66,134, 67, 62, 67,154, 97, 4, 66, 70, + 66, 81, 66, 91, 66, 98,225,242,237,229,238,233,225,110,128, 5, + 121,226,229,238,231,225,236,105,128, 9,155,228,229,246, 97,128, + 9, 27,231,117, 2, 66,105, 66,114,234,225,242,225,244,105,128, + 10,155,242,237,245,235,232,105,128, 10, 27,226,239,240,239,237, + 239,230,111,128, 49, 20,101, 6, 66,148, 66,168, 66,192, 67, 4, + 67, 16, 67, 37,225,226,235,232,225,243,233,225,238,227,249,242, + 233,236,236,233, 99,128, 4,189, 99, 2, 66,174, 66,182,235,237, + 225,242,107,128, 39, 19,249,242,233,236,236,233, 99,128, 4, 71, + 100, 2, 66,198, 66,242,229,243,227,229,238,228,229,114, 2, 66, + 211, 66,231,225,226,235,232,225,243,233,225,238,227,249,242,233, + 236,236,233, 99,128, 4,191,227,249,242,233,236,236,233, 99,128, + 4,183,233,229,242,229,243,233,243,227,249,242,233,236,236,233, + 99,128, 4,245,232,225,242,237,229,238,233,225,110,128, 5,115, + 235,232,225,235,225,243,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,204,246,229,242,244,233,227,225,236,243,244,242, + 239,235,229,227,249,242,233,236,236,233, 99,128, 4,185,105,129, + 3,199, 67, 68,229,245,227,104, 4, 67, 81, 67,116, 67,131, 67, + 140, 97, 2, 67, 87, 67,102,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,119,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 23,227,233,242,227,236,229,235,239,242,229,225,110, + 128, 50,105,235,239,242,229,225,110,128, 49, 74,240,225,242,229, + 238,235,239,242,229,225,110,128, 50, 9,111, 2, 67,160, 67,210, + 227,104, 3, 67,169, 67,191, 67,201,225,110, 2, 67,176, 67,184, + 231,244,232,225,105,128, 14, 10,244,232,225,105,128, 14, 8,233, + 238,231,244,232,225,105,128, 14, 9,239,229,244,232,225,105,128, + 14, 12,239,107,128, 1,136,105, 2, 67,221, 68, 67,229,245, 99, + 5, 67,235, 68, 14, 68, 29, 68, 38, 68, 52, 97, 2, 67,241, 68, + 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,118, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 22,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,104,235,239,242, + 229,225,110,128, 49, 72,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 8,245,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 28,242, 99, 2, 68, 74, 68,169,236,101,132, 37,203, 68, + 87, 68, 98, 68,103, 68,127,237,245,236,244,233,240,236,121,128, + 34,151,239,116,128, 34,153,112, 2, 68,109, 68,115,236,245,115, + 128, 34,149,239,243,244,225,236,237,225,242,107,128, 48, 54,247, + 233,244,104, 2, 68,136, 68,152,236,229,230,244,232,225,236,230, + 226,236,225,227,107,128, 37,208,242,233,231,232,244,232,225,236, + 230,226,236,225,227,107,128, 37,209,245,237,230,236,229,120,130, + 2,198, 68,182, 68,193,226,229,236,239,247,227,237, 98,128, 3, + 45,227,237, 98,128, 3, 2,108, 3, 68,207, 68,213, 69, 11,229, + 225,114,128, 35, 39,233,227,107, 4, 68,225, 68,236, 68,245, 68, + 255,225,236,246,229,239,236,225,114,128, 1,194,228,229,238,244, + 225,108,128, 1,192,236,225,244,229,242,225,108,128, 1,193,242, + 229,244,242,239,230,236,229,120,128, 1,195,245, 98,129, 38, 99, + 69, 18,243,245,233,116, 2, 69, 27, 69, 35,226,236,225,227,107, + 128, 38, 99,247,232,233,244,101,128, 38,103,109, 3, 69, 51, 69, + 65, 69, 76,227,245,226,229,228,243,241,245,225,242,101,128, 51, + 164,239,238,239,243,240,225,227,101,128,255, 67,243,241,245,225, + 242,229,228,243,241,245,225,242,101,128, 51,160,111, 8, 69,110, + 69,121, 69,208, 70,150, 71,179, 71,210, 72, 61, 72, 70,225,242, + 237,229,238,233,225,110,128, 5,129,236,239,110,131, 0, 58, 69, + 133, 69,158, 69,177,237,239,110, 2, 69,141, 69,149,229,244,225, + 242,121,128, 32,161,239,243,240,225,227,101,128,255, 26,115, 2, + 69,164, 69,170,233,231,110,128, 32,161,237,225,236,108,128,254, + 85,244,242,233,225,238,231,245,236,225,114, 2, 69,192, 69,202, + 232,225,236,230,237,239,100,128, 2,209,237,239,100,128, 2,208, + 109, 2, 69,214, 70,143,237, 97,134, 0, 44, 69,231, 70, 39, 70, + 50, 70, 62, 70, 92, 70,115, 97, 3, 69,239, 70, 9, 70, 17,226, + 239,246,101, 2, 69,248, 69,254,227,237, 98,128, 3, 19,242,233, + 231,232,244,227,237, 98,128, 3, 21,227,227,229,238,116,128,246, + 195,114, 2, 70, 23, 70, 30,225,226,233, 99,128, 6, 12,237,229, + 238,233,225,110,128, 5, 93,233,238,230,229,242,233,239,114,128, + 246,225,237,239,238,239,243,240,225,227,101,128,255, 12,242,229, + 246,229,242,243,229,100, 2, 70, 75, 70, 86,225,226,239,246,229, + 227,237, 98,128, 3, 20,237,239,100,128, 2,189,115, 2, 70, 98, + 70,105,237,225,236,108,128,254, 80,245,240,229,242,233,239,114, + 128,246,226,244,245,242,238,229,100, 2, 70,126, 70,137,225,226, + 239,246,229,227,237, 98,128, 3, 18,237,239,100,128, 2,187,240, + 225,243,115,128, 38, 60,110, 2, 70,156, 70,165,231,242,245,229, + 238,116,128, 34, 69,116, 2, 70,171, 70,185,239,245,242,233,238, + 244,229,231,242,225,108,128, 34, 46,242,239,108,142, 35, 3, 70, + 219, 70,225, 70,240, 70,255, 71, 43, 71, 88, 71,102, 71,107, 71, + 112, 71,117, 71,123, 71,128, 71,169, 71,174,193,195, 75,128, 0, + 6, 66, 2, 70,231, 70,236,197, 76,128, 0, 7, 83,128, 0, 8, + 67, 2, 70,246, 70,251,193, 78,128, 0, 24, 82,128, 0, 13, 68, + 3, 71, 7, 71, 33, 71, 38, 67, 4, 71, 17, 71, 21, 71, 25, 71, + 29, 49,128, 0, 17, 50,128, 0, 18, 51,128, 0, 19, 52,128, 0, + 20,197, 76,128, 0,127,204, 69,128, 0, 16, 69, 5, 71, 55, 71, + 59, 71, 64, 71, 69, 71, 74, 77,128, 0, 25,206, 81,128, 0, 5, + 207, 84,128, 0, 4,211, 67,128, 0, 27, 84, 2, 71, 80, 71, 84, + 66,128, 0, 23, 88,128, 0, 3, 70, 2, 71, 94, 71, 98, 70,128, + 0, 12, 83,128, 0, 28,199, 83,128, 0, 29,200, 84,128, 0, 9, + 204, 70,128, 0, 10,206,193, 75,128, 0, 21,210, 83,128, 0, 30, + 83, 5, 71,140, 71,144, 71,154, 71,159, 71,164, 73,128, 0, 15, + 79,129, 0, 14, 71,150, 84,128, 0, 2,212, 88,128, 0, 1,213, + 66,128, 0, 26,217, 78,128, 0, 22,213, 83,128, 0, 31,214, 84, + 128, 0, 11,240,249,242,233,231,232,116,129, 0,169, 71,191,115, + 2, 71,197, 71,203,225,238,115,128,248,233,229,242,233,102,128, + 246,217,114, 2, 71,216, 72, 44,238,229,242,226,242,225,227,235, + 229,116, 2, 71,231, 72, 9,236,229,230,116,130, 48, 12, 71,242, + 71,254,232,225,236,230,247,233,228,244,104,128,255, 98,246,229, + 242,244,233,227,225,108,128,254, 65,242,233,231,232,116,130, 48, + 13, 72, 21, 72, 33,232,225,236,230,247,233,228,244,104,128,255, + 99,246,229,242,244,233,227,225,108,128,254, 66,240,239,242,225, + 244,233,239,238,243,241,245,225,242,101,128, 51,127,243,241,245, + 225,242,101,128, 51,199,246,229,242,235,231,243,241,245,225,242, + 101,128, 51,198,240,225,242,229,110,128, 36,158,242,245,250,229, + 233,242,111,128, 32,162,243,244,242,229,244,227,232,229,100,128, + 2,151,245,114, 2, 72,121, 72,139,236,121, 2, 72,128, 72,134, + 225,238,100,128, 34,207,239,114,128, 34,206,242,229,238,227,121, + 128, 0,164,249,114, 4, 72,158, 72,166, 72,173, 72,181,194,242, + 229,246,101,128,246,209,198,236,229,120,128,246,210,226,242,229, + 246,101,128,246,212,230,236,229,120,128,246,213,100,146, 0,100, + 72,228, 74,110, 75,134, 75,194, 76,114, 77, 68, 77,130, 78, 59, + 78, 72, 78, 81, 78,107, 78,132, 78,141, 79,208, 79,216, 79,227, + 79,247, 80, 19, 97, 11, 72,252, 73, 7, 73, 17, 73, 89, 73,152, + 73,163, 73,174, 73,243, 74, 49, 74, 55, 74, 85,225,242,237,229, + 238,233,225,110,128, 5,100,226,229,238,231,225,236,105,128, 9, + 166,100, 5, 73, 29, 73, 38, 73, 44, 73, 58, 73, 74,225,242,225, + 226,233, 99,128, 6, 54,229,246, 97,128, 9, 38,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,190,233,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,191,237,229,228,233,225,236, + 225,242,225,226,233, 99,128,254,192,103, 3, 73, 97, 73,114, 73, + 128,229,243,104,129, 5,188, 73,105,232,229,226,242,229,119,128, + 5,188,231,229,114,129, 32, 32, 73,122,228,226,108,128, 32, 33, + 117, 2, 73,134, 73,143,234,225,242,225,244,105,128, 10,166,242, + 237,245,235,232,105,128, 10, 38,232,233,242,225,231,225,238, 97, + 128, 48, 96,235,225,244,225,235,225,238, 97,128, 48,192,108, 3, + 73,182, 73,191, 73,229,225,242,225,226,233, 99,128, 6, 47,229, + 116,130, 5,211, 73,200, 73,220,228,225,231,229,243,104,129,251, + 51, 73,211,232,229,226,242,229,119,128,251, 51,232,229,226,242, + 229,119,128, 5,211,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,170,237,237, 97, 3, 73,253, 74, 6, 74, 18,225,242,225, + 226,233, 99,128, 6, 79,236,239,247,225,242,225,226,233, 99,128, + 6, 79,244,225,238, 97, 2, 74, 27, 74, 41,236,244,239,238,229, + 225,242,225,226,233, 99,128, 6, 76,242,225,226,233, 99,128, 6, + 76,238,228, 97,128, 9,100,242,231, 97, 2, 74, 63, 74, 72,232, + 229,226,242,229,119,128, 5,167,236,229,230,244,232,229,226,242, + 229,119,128, 5,167,243,233,225,240,238,229,245,237,225,244,225, + 227,249,242,233,236,236,233,227,227,237, 98,128, 4,133, 98, 3, + 74,118, 75,115, 75,125,108, 9, 74,138, 74,146, 75, 3, 75, 11, + 75, 27, 75, 38, 75, 56, 75, 70, 75, 81,199,242,225,246,101,128, + 246,211, 97, 2, 74,152, 74,209,238,231,236,229,226,242,225,227, + 235,229,116, 2, 74,168, 74,188,236,229,230,116,129, 48, 10, 74, + 177,246,229,242,244,233,227,225,108,128,254, 61,242,233,231,232, + 116,129, 48, 11, 74,198,246,229,242,244,233,227,225,108,128,254, + 62,114, 2, 74,215, 74,236,227,232,233,238,246,229,242,244,229, + 228,226,229,236,239,247,227,237, 98,128, 3, 43,242,239,119, 2, + 74,244, 74,251,236,229,230,116,128, 33,212,242,233,231,232,116, + 128, 33,210,228,225,238,228, 97,128, 9,101,231,242,225,246,101, + 129,246,214, 75, 21,227,237, 98,128, 3, 15,233,238,244,229,231, + 242,225,108,128, 34, 44,236,239,247,236,233,238,101,129, 32, 23, + 75, 50,227,237, 98,128, 3, 51,239,246,229,242,236,233,238,229, + 227,237, 98,128, 3, 63,240,242,233,237,229,237,239,100,128, 2, + 186,246,229,242,244,233,227,225,108, 2, 75, 94, 75,100,226,225, + 114,128, 32, 22,236,233,238,229,225,226,239,246,229,227,237, 98, + 128, 3, 14,239,240,239,237,239,230,111,128, 49, 9,243,241,245, + 225,242,101,128, 51,200, 99, 4, 75,144, 75,151, 75,160, 75,187, + 225,242,239,110,128, 1, 15,229,228,233,236,236, 97,128, 30, 17, + 233,242, 99, 2, 75,168, 75,173,236,101,128, 36,211,245,237,230, + 236,229,248,226,229,236,239,119,128, 30, 19,242,239,225,116,128, + 1, 17,100, 4, 75,204, 76, 29, 76, 39, 76, 90, 97, 4, 75,214, + 75,224, 75,231, 76, 0,226,229,238,231,225,236,105,128, 9,161, + 228,229,246, 97,128, 9, 33,231,117, 2, 75,238, 75,247,234,225, + 242,225,244,105,128, 10,161,242,237,245,235,232,105,128, 10, 33, + 108, 2, 76, 6, 76, 15,225,242,225,226,233, 99,128, 6,136,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,137,228,232,225, + 228,229,246, 97,128, 9, 92,232, 97, 3, 76, 48, 76, 58, 76, 65, + 226,229,238,231,225,236,105,128, 9,162,228,229,246, 97,128, 9, + 34,231,117, 2, 76, 72, 76, 81,234,225,242,225,244,105,128, 10, + 162,242,237,245,235,232,105,128, 10, 34,239,116, 2, 76, 97, 76, + 106,225,227,227,229,238,116,128, 30, 11,226,229,236,239,119,128, + 30, 13,101, 8, 76,132, 76,185, 76,192, 76,217, 76,227, 76,238, + 77, 27, 77, 63, 99, 2, 76,138, 76,175,233,237,225,236,243,229, + 240,225,242,225,244,239,114, 2, 76,156, 76,165,225,242,225,226, + 233, 99,128, 6,107,240,229,242,243,233,225,110,128, 6,107,249, + 242,233,236,236,233, 99,128, 4, 52,231,242,229,101,128, 0,176, + 232,105, 2, 76,199, 76,208,232,229,226,242,229,119,128, 5,173, + 242,225,231,225,238, 97,128, 48,103,233,227,239,240,244,233, 99, + 128, 3,239,235,225,244,225,235,225,238, 97,128, 48,199,108, 2, + 76,244, 77, 11,229,244,101, 2, 76,252, 77, 3,236,229,230,116, + 128, 35, 43,242,233,231,232,116,128, 35, 38,244, 97,129, 3,180, + 77, 18,244,245,242,238,229,100,128, 1,141,238,239,237,233,238, + 225,244,239,242,237,233,238,245,243,239,238,229,238,245,237,229, + 242,225,244,239,242,226,229,238,231,225,236,105,128, 9,248,250, + 104,128, 2,164,104, 2, 77, 74, 77,124, 97, 3, 77, 82, 77, 92, + 77, 99,226,229,238,231,225,236,105,128, 9,167,228,229,246, 97, + 128, 9, 39,231,117, 2, 77,106, 77,115,234,225,242,225,244,105, + 128, 10,167,242,237,245,235,232,105,128, 10, 39,239,239,107,128, + 2, 87,105, 6, 77,144, 77,193, 77,253, 78, 8, 78, 19, 78, 29, + 97, 2, 77,150, 77,172,236,249,244,233,235,225,244,239,238,239, + 115,129, 3,133, 77,166,227,237, 98,128, 3, 68,237,239,238,100, + 129, 38,102, 77,181,243,245,233,244,247,232,233,244,101,128, 38, + 98,229,242,229,243,233,115,133, 0,168, 77,212, 77,220, 77,231, + 77,237, 77,245,225,227,245,244,101,128,246,215,226,229,236,239, + 247,227,237, 98,128, 3, 36,227,237, 98,128, 3, 8,231,242,225, + 246,101,128,246,216,244,239,238,239,115,128, 3,133,232,233,242, + 225,231,225,238, 97,128, 48, 98,235,225,244,225,235,225,238, 97, + 128, 48,194,244,244,239,237,225,242,107,128, 48, 3,246,105, 2, + 78, 36, 78, 47,228,101,129, 0,247, 78, 43,115,128, 34, 35,243, + 233,239,238,243,236,225,243,104,128, 34, 21,234,229,227,249,242, + 233,236,236,233, 99,128, 4, 82,235,243,232,225,228,101,128, 37, + 147,108, 2, 78, 87, 78, 98,233,238,229,226,229,236,239,119,128, + 30, 15,243,241,245,225,242,101,128, 51,151,109, 2, 78,113, 78, + 121,225,227,242,239,110,128, 1, 17,239,238,239,243,240,225,227, + 101,128,255, 68,238,226,236,239,227,107,128, 37,132,111, 10, 78, + 163, 78,175, 78,185, 78,196, 78,207, 79, 23, 79, 28, 79, 39, 79, + 154, 79,180,227,232,225,228,225,244,232,225,105,128, 14, 14,228, + 229,235,244,232,225,105,128, 14, 20,232,233,242,225,231,225,238, + 97,128, 48,105,235,225,244,225,235,225,238, 97,128, 48,201,236, + 236,225,114,132, 0, 36, 78,222, 78,233, 78,245, 79, 0,233,238, + 230,229,242,233,239,114,128,246,227,237,239,238,239,243,240,225, + 227,101,128,255, 4,239,236,228,243,244,249,236,101,128,247, 36, + 115, 2, 79, 6, 79, 13,237,225,236,108,128,254,105,245,240,229, + 242,233,239,114,128,246,228,238,103,128, 32,171,242,245,243,241, + 245,225,242,101,128, 51, 38,116, 6, 79, 53, 79, 70, 79, 92, 79, + 103, 79,135, 79,142,225,227,227,229,238,116,129, 2,217, 79, 64, + 227,237, 98,128, 3, 7,226,229,236,239,247, 99, 2, 79, 81, 79, + 86,237, 98,128, 3, 35,239,237, 98,128, 3, 35,235,225,244,225, + 235,225,238, 97,128, 48,251,236,229,243,115, 2, 79,112, 79,116, + 105,128, 1, 49,106,129,246,190, 79,122,243,244,242,239,235,229, + 232,239,239,107,128, 2,132,237,225,244,104,128, 34,197,244,229, + 228,227,233,242,227,236,101,128, 37,204,245,226,236,229,249,239, + 228,240,225,244,225,104,129,251, 31, 79,171,232,229,226,242,229, + 119,128,251, 31,247,238,244,225,227,107, 2, 79,191, 79,202,226, + 229,236,239,247,227,237, 98,128, 3, 30,237,239,100,128, 2,213, + 240,225,242,229,110,128, 36,159,243,245,240,229,242,233,239,114, + 128,246,235,116, 2, 79,233, 79,239,225,233,108,128, 2, 86,239, + 240,226,225,114,128, 1,140,117, 2, 79,253, 80, 8,232,233,242, + 225,231,225,238, 97,128, 48,101,235,225,244,225,235,225,238, 97, + 128, 48,197,122,132, 1,243, 80, 31, 80, 40, 80, 59, 80, 96,225, + 236,244,239,238,101,128, 2,163, 99, 2, 80, 46, 80, 53,225,242, + 239,110,128, 1,198,245,242,108,128, 2,165,101, 2, 80, 65, 80, + 85,225,226,235,232,225,243,233,225,238,227,249,242,233,236,236, + 233, 99,128, 4,225,227,249,242,233,236,236,233, 99,128, 4, 85, + 232,229,227,249,242,233,236,236,233, 99,128, 4, 95,101,151, 0, + 101, 80,159, 80,178, 80,212, 81,186, 81,248, 82, 25, 82, 37, 82, + 60, 82,113, 83,225, 84, 27, 84,129, 84,245, 85,124, 85,199, 85, + 230, 86, 36, 86, 89, 87, 24, 87,157, 87,177, 87,221, 88, 56, 97, + 2, 80,165, 80,172,227,245,244,101,128, 0,233,242,244,104,128, + 38, 65, 98, 3, 80,186, 80,195, 80,205,229,238,231,225,236,105, + 128, 9,143,239,240,239,237,239,230,111,128, 49, 28,242,229,246, + 101,128, 1, 21, 99, 5, 80,224, 81, 41, 81, 55, 81, 87, 81,176, + 97, 2, 80,230, 81, 35,238,228,242, 97, 3, 80,241, 80,248, 81, + 3,228,229,246, 97,128, 9, 13,231,245,234,225,242,225,244,105, + 128, 10,141,246,239,247,229,236,243,233,231,110, 2, 81, 17, 81, + 24,228,229,246, 97,128, 9, 69,231,245,234,225,242,225,244,105, + 128, 10,197,242,239,110,128, 1, 27,229,228,233,236,236,225,226, + 242,229,246,101,128, 30, 29,104, 2, 81, 61, 81, 72,225,242,237, + 229,238,233,225,110,128, 5,101,249,233,247,238,225,242,237,229, + 238,233,225,110,128, 5,135,233,242, 99, 2, 81, 95, 81,100,236, + 101,128, 36,212,245,237,230,236,229,120,134, 0,234, 81,121, 81, + 129, 81,137, 81,148, 81,156, 81,168,225,227,245,244,101,128, 30, + 191,226,229,236,239,119,128, 30, 25,228,239,244,226,229,236,239, + 119,128, 30,199,231,242,225,246,101,128, 30,193,232,239,239,235, + 225,226,239,246,101,128, 30,195,244,233,236,228,101,128, 30,197, + 249,242,233,236,236,233, 99,128, 4, 84,100, 4, 81,196, 81,206, + 81,212, 81,222,226,236,231,242,225,246,101,128, 2, 5,229,246, + 97,128, 9, 15,233,229,242,229,243,233,115,128, 0,235,239,116, + 130, 1, 23, 81,231, 81,240,225,227,227,229,238,116,128, 1, 23, + 226,229,236,239,119,128, 30,185,101, 2, 81,254, 82, 9,231,245, + 242,237,245,235,232,105,128, 10, 15,237,225,244,242,225,231,245, + 242,237,245,235,232,105,128, 10, 71,230,227,249,242,233,236,236, + 233, 99,128, 4, 68,103, 2, 82, 43, 82, 50,242,225,246,101,128, + 0,232,245,234,225,242,225,244,105,128, 10,143,104, 4, 82, 70, + 82, 81, 82, 92, 82,102,225,242,237,229,238,233,225,110,128, 5, + 103,226,239,240,239,237,239,230,111,128, 49, 29,233,242,225,231, + 225,238, 97,128, 48, 72,239,239,235,225,226,239,246,101,128, 30, + 187,105, 4, 82,123, 82,134, 83,192, 83,207,226,239,240,239,237, + 239,230,111,128, 49, 31,231,232,116,142, 0, 56, 82,168, 82,177, + 82,187, 82,217, 82,224, 83, 6, 83, 31, 83, 76, 83,110, 83,122, + 83,133, 83,166, 83,174, 83,185,225,242,225,226,233, 99,128, 6, + 104,226,229,238,231,225,236,105,128, 9,238,227,233,242,227,236, + 101,129, 36,103, 82,198,233,238,246,229,242,243,229,243,225,238, + 243,243,229,242,233,102,128, 39,145,228,229,246, 97,128, 9,110, + 229,229,110, 2, 82,232, 82,241,227,233,242,227,236,101,128, 36, + 113,112, 2, 82,247, 82,254,225,242,229,110,128, 36,133,229,242, + 233,239,100,128, 36,153,231,117, 2, 83, 13, 83, 22,234,225,242, + 225,244,105,128, 10,238,242,237,245,235,232,105,128, 10,110,104, + 2, 83, 37, 83, 63, 97, 2, 83, 43, 83, 54,227,235,225,242,225, + 226,233, 99,128, 6,104,238,231,250,232,239,117,128, 48, 40,238, + 239,244,229,226,229,225,237,229,100,128, 38,107,105, 2, 83, 82, + 83,100,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 39,238,230,229,242,233,239,114,128, 32,136,237,239, + 238,239,243,240,225,227,101,128,255, 24,239,236,228,243,244,249, + 236,101,128,247, 56,112, 2, 83,139, 83,146,225,242,229,110,128, + 36,123,229,114, 2, 83,153, 83,159,233,239,100,128, 36,143,243, + 233,225,110,128, 6,248,242,239,237,225,110,128, 33,119,243,245, + 240,229,242,233,239,114,128, 32,120,244,232,225,105,128, 14, 88, + 238,246,229,242,244,229,228,226,242,229,246,101,128, 2, 7,239, + 244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, 4, + 101,107, 2, 83,231, 83,255,225,244,225,235,225,238, 97,129, 48, + 168, 83,243,232,225,236,230,247,233,228,244,104,128,255,116,111, + 2, 84, 5, 84, 20,238,235,225,242,231,245,242,237,245,235,232, + 105,128, 10,116,242,229,225,110,128, 49, 84,108, 3, 84, 35, 84, + 46, 84,107,227,249,242,233,236,236,233, 99,128, 4, 59,101, 2, + 84, 52, 84, 59,237,229,238,116,128, 34, 8,246,229,110, 3, 84, + 69, 84, 78, 84, 99,227,233,242,227,236,101,128, 36,106,112, 2, + 84, 84, 84, 91,225,242,229,110,128, 36,126,229,242,233,239,100, + 128, 36,146,242,239,237,225,110,128, 33,122,236,233,240,243,233, + 115,129, 32, 38, 84,118,246,229,242,244,233,227,225,108,128, 34, + 238,109, 5, 84,141, 84,169, 84,180, 84,200, 84,211,225,227,242, + 239,110,130, 1, 19, 84,153, 84,161,225,227,245,244,101,128, 30, + 23,231,242,225,246,101,128, 30, 21,227,249,242,233,236,236,233, + 99,128, 4, 60,228,225,243,104,129, 32, 20, 84,189,246,229,242, + 244,233,227,225,108,128,254, 49,239,238,239,243,240,225,227,101, + 128,255, 69,112, 2, 84,217, 84,237,232,225,243,233,243,237,225, + 242,235,225,242,237,229,238,233,225,110,128, 5, 91,244,249,243, + 229,116,128, 34, 5,110, 6, 85, 3, 85, 14, 85, 25, 85, 69, 85, + 101, 85,116,226,239,240,239,237,239,230,111,128, 49, 35,227,249, + 242,233,236,236,233, 99,128, 4, 61,100, 2, 85, 31, 85, 50,225, + 243,104,129, 32, 19, 85, 39,246,229,242,244,233,227,225,108,128, + 254, 50,229,243,227,229,238,228,229,242,227,249,242,233,236,236, + 233, 99,128, 4,163,103,130, 1, 75, 85, 77, 85, 88,226,239,240, + 239,237,239,230,111,128, 49, 37,232,229,227,249,242,233,236,236, + 233, 99,128, 4,165,232,239,239,235,227,249,242,233,236,236,233, + 99,128, 4,200,243,240,225,227,101,128, 32, 2,111, 3, 85,132, + 85,140, 85,149,231,239,238,229,107,128, 1, 25,235,239,242,229, + 225,110,128, 49, 83,240,229,110,130, 2, 91, 85,159, 85,168,227, + 236,239,243,229,100,128, 2,154,242,229,246,229,242,243,229,100, + 130, 2, 92, 85,183, 85,192,227,236,239,243,229,100,128, 2, 94, + 232,239,239,107,128, 2, 93,112, 2, 85,205, 85,212,225,242,229, + 110,128, 36,160,243,233,236,239,110,129, 3,181, 85,222,244,239, + 238,239,115,128, 3,173,241,117, 2, 85,237, 86, 25,225,108,130, + 0, 61, 85,246, 86, 2,237,239,238,239,243,240,225,227,101,128, + 255, 29,115, 2, 86, 8, 86, 15,237,225,236,108,128,254,102,245, + 240,229,242,233,239,114,128, 32,124,233,246,225,236,229,238,227, + 101,128, 34, 97,114, 3, 86, 44, 86, 55, 86, 66,226,239,240,239, + 237,239,230,111,128, 49, 38,227,249,242,233,236,236,233, 99,128, + 4, 64,229,246,229,242,243,229,100,129, 2, 88, 86, 78,227,249, + 242,233,236,236,233, 99,128, 4, 77,115, 6, 86,103, 86,114, 86, + 134, 86,215, 87, 4, 87, 14,227,249,242,233,236,236,233, 99,128, + 4, 65,228,229,243,227,229,238,228,229,242,227,249,242,233,236, + 236,233, 99,128, 4,171,104,132, 2,131, 86,146, 86,153, 86,184, + 86,199,227,245,242,108,128, 2,134,239,242,116, 2, 86,161, 86, + 168,228,229,246, 97,128, 9, 14,246,239,247,229,236,243,233,231, + 238,228,229,246, 97,128, 9, 70,242,229,246,229,242,243,229,228, + 236,239,239,112,128, 1,170,243,241,245,225,244,242,229,246,229, + 242,243,229,100,128, 2,133,237,225,236,108, 2, 86,224, 86,235, + 232,233,242,225,231,225,238, 97,128, 48, 71,235,225,244,225,235, + 225,238, 97,129, 48,167, 86,248,232,225,236,230,247,233,228,244, + 104,128,255,106,244,233,237,225,244,229,100,128, 33, 46,245,240, + 229,242,233,239,114,128,246,236,116, 5, 87, 36, 87, 62, 87, 66, + 87, 83, 87,149, 97,130, 3,183, 87, 44, 87, 54,242,237,229,238, + 233,225,110,128, 5,104,244,239,238,239,115,128, 3,174,104,128, + 0,240,233,236,228,101,129, 30,189, 87, 75,226,229,236,239,119, + 128, 30, 27,238,225,232,244, 97, 3, 87, 95, 87,127, 87,136,230, + 239,245,235,104, 2, 87,105, 87,114,232,229,226,242,229,119,128, + 5,145,236,229,230,244,232,229,226,242,229,119,128, 5,145,232, + 229,226,242,229,119,128, 5,145,236,229,230,244,232,229,226,242, + 229,119,128, 5,145,245,242,238,229,100,128, 1,221,117, 2, 87, + 163, 87,172,235,239,242,229,225,110,128, 49, 97,242,111,128, 32, + 172,246,239,247,229,236,243,233,231,110, 3, 87,193, 87,203, 87, + 210,226,229,238,231,225,236,105,128, 9,199,228,229,246, 97,128, + 9, 71,231,245,234,225,242,225,244,105,128, 10,199,120, 2, 87, + 227, 88, 44,227,236,225,109,132, 0, 33, 87,242, 87,253, 88, 24, + 88, 36,225,242,237,229,238,233,225,110,128, 5, 92,100, 2, 88, + 3, 88, 8,226,108,128, 32, 60,239,247,110,129, 0,161, 88, 16, + 243,237,225,236,108,128,247,161,237,239,238,239,243,240,225,227, + 101,128,255, 1,243,237,225,236,108,128,247, 33,233,243,244,229, + 238,244,233,225,108,128, 34, 3,250,104,131, 2,146, 88, 67, 88, + 86, 88, 97, 99, 2, 88, 73, 88, 80,225,242,239,110,128, 1,239, + 245,242,108,128, 2,147,242,229,246,229,242,243,229,100,128, 1, + 185,244,225,233,108,128, 1,186,102,140, 0,102, 88,132, 88,214, + 88,225, 88,234, 88,246, 89, 93, 89,109, 91,117, 91,130, 91,156, + 93, 33, 93, 41, 97, 4, 88,142, 88,149, 88,160, 88,171,228,229, + 246, 97,128, 9, 94,231,245,242,237,245,235,232,105,128, 10, 94, + 232,242,229,238,232,229,233,116,128, 33, 9,244,232, 97, 3, 88, + 181, 88,190, 88,202,225,242,225,226,233, 99,128, 6, 78,236,239, + 247,225,242,225,226,233, 99,128, 6, 78,244,225,238,225,242,225, + 226,233, 99,128, 6, 75,226,239,240,239,237,239,230,111,128, 49, + 8,227,233,242,227,236,101,128, 36,213,228,239,244,225,227,227, + 229,238,116,128, 30, 31,101, 3, 88,254, 89, 76, 89, 86,104, 4, + 89, 8, 89, 31, 89, 45, 89, 61,225,114, 2, 89, 15, 89, 22,225, + 226,233, 99,128, 6, 65,237,229,238,233,225,110,128, 5,134,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,210,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,211,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,254,212,233,227,239,240, + 244,233, 99,128, 3,229,237,225,236,101,128, 38, 64,102,130,251, + 0, 89,101, 89,105,105,128,251, 3,108,128,251, 4,105,136,251, + 1, 89,129, 89,169, 89,180, 89,202, 90, 68, 90, 85, 90, 93, 90, + 106,230,244,229,229,110, 2, 89,139, 89,148,227,233,242,227,236, + 101,128, 36,110,112, 2, 89,154, 89,161,225,242,229,110,128, 36, + 130,229,242,233,239,100,128, 36,150,231,245,242,229,228,225,243, + 104,128, 32, 18,236,236,229,100, 2, 89,189, 89,195,226,239,120, + 128, 37,160,242,229,227,116,128, 37,172,238,225,108, 5, 89,216, + 89,255, 90, 16, 90, 33, 90, 49,235,225,102,130, 5,218, 89,226, + 89,246,228,225,231,229,243,104,129,251, 58, 89,237,232,229,226, + 242,229,119,128,251, 58,232,229,226,242,229,119,128, 5,218,237, + 229,109,129, 5,221, 90, 7,232,229,226,242,229,119,128, 5,221, + 238,245,110,129, 5,223, 90, 24,232,229,226,242,229,119,128, 5, + 223,240,101,129, 5,227, 90, 40,232,229,226,242,229,119,128, 5, + 227,244,243,225,228,105,129, 5,229, 90, 59,232,229,226,242,229, + 119,128, 5,229,242,243,244,244,239,238,229,227,232,233,238,229, + 243,101,128, 2,201,243,232,229,249,101,128, 37,201,244,225,227, + 249,242,233,236,236,233, 99,128, 4,115,246,101,142, 0, 53, 90, + 139, 90,148, 90,158, 90,188, 90,195, 90,205, 90,230, 91, 1, 91, + 35, 91, 47, 91, 58, 91, 91, 91, 99, 91,110,225,242,225,226,233, + 99,128, 6,101,226,229,238,231,225,236,105,128, 9,235,227,233, + 242,227,236,101,129, 36,100, 90,169,233,238,246,229,242,243,229, + 243,225,238,243,243,229,242,233,102,128, 39,142,228,229,246, 97, + 128, 9,107,229,233,231,232,244,232,115,128, 33, 93,231,117, 2, + 90,212, 90,221,234,225,242,225,244,105,128, 10,235,242,237,245, + 235,232,105,128, 10,107,232, 97, 2, 90,237, 90,248,227,235,225, + 242,225,226,233, 99,128, 6,101,238,231,250,232,239,117,128, 48, + 37,105, 2, 91, 7, 91, 25,228,229,239,231,242,225,240,232,233, + 227,240,225,242,229,110,128, 50, 36,238,230,229,242,233,239,114, + 128, 32,133,237,239,238,239,243,240,225,227,101,128,255, 21,239, + 236,228,243,244,249,236,101,128,247, 53,112, 2, 91, 64, 91, 71, + 225,242,229,110,128, 36,120,229,114, 2, 91, 78, 91, 84,233,239, + 100,128, 36,140,243,233,225,110,128, 6,245,242,239,237,225,110, + 128, 33,116,243,245,240,229,242,233,239,114,128, 32,117,244,232, + 225,105,128, 14, 85,108,129,251, 2, 91,123,239,242,233,110,128, + 1,146,109, 2, 91,136, 91,147,239,238,239,243,240,225,227,101, + 128,255, 70,243,241,245,225,242,101,128, 51,153,111, 4, 91,166, + 91,188, 91,200, 91,207,230, 97, 2, 91,173, 91,181,238,244,232, + 225,105,128, 14, 31,244,232,225,105,128, 14, 29,238,231,237,225, + 238,244,232,225,105,128, 14, 79,242,225,236,108,128, 34, 0,245, + 114,142, 0, 52, 91,240, 91,249, 92, 3, 92, 33, 92, 40, 92, 65, + 92, 92, 92,126, 92,138, 92,157, 92,168, 92,201, 92,209, 92,220, + 225,242,225,226,233, 99,128, 6,100,226,229,238,231,225,236,105, + 128, 9,234,227,233,242,227,236,101,129, 36, 99, 92, 14,233,238, + 246,229,242,243,229,243,225,238,243,243,229,242,233,102,128, 39, + 141,228,229,246, 97,128, 9,106,231,117, 2, 92, 47, 92, 56,234, + 225,242,225,244,105,128, 10,234,242,237,245,235,232,105,128, 10, + 106,232, 97, 2, 92, 72, 92, 83,227,235,225,242,225,226,233, 99, + 128, 6,100,238,231,250,232,239,117,128, 48, 36,105, 2, 92, 98, + 92,116,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 35,238,230,229,242,233,239,114,128, 32,132,237,239, + 238,239,243,240,225,227,101,128,255, 20,238,245,237,229,242,225, + 244,239,242,226,229,238,231,225,236,105,128, 9,247,239,236,228, + 243,244,249,236,101,128,247, 52,112, 2, 92,174, 92,181,225,242, + 229,110,128, 36,119,229,114, 2, 92,188, 92,194,233,239,100,128, + 36,139,243,233,225,110,128, 6,244,242,239,237,225,110,128, 33, + 115,243,245,240,229,242,233,239,114,128, 32,116,116, 2, 92,226, + 93, 8,229,229,110, 2, 92,234, 92,243,227,233,242,227,236,101, + 128, 36,109,112, 2, 92,249, 93, 0,225,242,229,110,128, 36,129, + 229,242,233,239,100,128, 36,149,104, 2, 93, 14, 93, 19,225,105, + 128, 14, 84,244,239,238,229,227,232,233,238,229,243,101,128, 2, + 203,240,225,242,229,110,128, 36,161,242, 97, 2, 93, 48, 93, 56, + 227,244,233,239,110,128, 32, 68,238, 99,128, 32,163,103,144, 0, + 103, 93, 97, 94, 43, 94, 66, 94,127, 94,144, 95, 65, 96, 58, 96, + 143, 96,156, 97, 14, 97, 39, 97, 67, 97, 89, 98, 34, 98, 56, 98, + 158, 97, 9, 93,117, 93,127, 93,134, 93,141, 93,205, 93,230, 93, + 241, 93,252, 94, 30,226,229,238,231,225,236,105,128, 9,151,227, + 245,244,101,128, 1,245,228,229,246, 97,128, 9, 23,102, 4, 93, + 151, 93,160, 93,174, 93,190,225,242,225,226,233, 99,128, 6,175, + 230,233,238,225,236,225,242,225,226,233, 99,128,251,147,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,251,148,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,251,149,231,117, 2, + 93,212, 93,221,234,225,242,225,244,105,128, 10,151,242,237,245, + 235,232,105,128, 10, 23,232,233,242,225,231,225,238, 97,128, 48, + 76,235,225,244,225,235,225,238, 97,128, 48,172,237,237, 97,130, + 3,179, 94, 6, 94, 19,236,225,244,233,238,243,237,225,236,108, + 128, 2, 99,243,245,240,229,242,233,239,114,128, 2,224,238,231, + 233,225,227,239,240,244,233, 99,128, 3,235, 98, 2, 94, 49, 94, + 59,239,240,239,237,239,230,111,128, 49, 13,242,229,246,101,128, + 1, 31, 99, 4, 94, 76, 94, 83, 94, 92, 94,114,225,242,239,110, + 128, 1,231,229,228,233,236,236, 97,128, 1, 35,233,242, 99, 2, + 94,100, 94,105,236,101,128, 36,214,245,237,230,236,229,120,128, + 1, 29,239,237,237,225,225,227,227,229,238,116,128, 1, 35,228, + 239,116,129, 1, 33, 94,135,225,227,227,229,238,116,128, 1, 33, + 101, 6, 94,158, 94,169, 94,180, 94,191, 94,210, 95, 56,227,249, + 242,233,236,236,233, 99,128, 4, 51,232,233,242,225,231,225,238, + 97,128, 48, 82,235,225,244,225,235,225,238, 97,128, 48,178,239, + 237,229,244,242,233,227,225,236,236,249,229,241,245,225,108,128, + 34, 81,114, 3, 94,218, 95, 11, 95, 21,229,243,104, 3, 94,228, + 94,243, 94,252,225,227,227,229,238,244,232,229,226,242,229,119, + 128, 5,156,232,229,226,242,229,119,128, 5,243,237,245,241,228, + 225,237,232,229,226,242,229,119,128, 5,157,237,225,238,228,226, + 236,115,128, 0,223,243,232,225,249,233,109, 2, 95, 32, 95, 47, + 225,227,227,229,238,244,232,229,226,242,229,119,128, 5,158,232, + 229,226,242,229,119,128, 5,244,244,225,237,225,242,107,128, 48, + 19,104, 5, 95, 77, 95,210, 96, 17, 96, 42, 96, 48, 97, 4, 95, + 87, 95, 97, 95,120, 95,145,226,229,238,231,225,236,105,128, 9, + 152,100, 2, 95,103, 95,114,225,242,237,229,238,233,225,110,128, + 5,114,229,246, 97,128, 9, 24,231,117, 2, 95,127, 95,136,234, + 225,242,225,244,105,128, 10,152,242,237,245,235,232,105,128, 10, + 24,233,110, 4, 95,156, 95,165, 95,179, 95,195,225,242,225,226, + 233, 99,128, 6, 58,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,206,233,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,207,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,208,101, 3, 95,218, 95,239, 96, 0,237,233,228,228,236,229, + 232,239,239,235,227,249,242,233,236,236,233, 99,128, 4,149,243, + 244,242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,147, + 245,240,244,245,242,238,227,249,242,233,236,236,233, 99,128, 4, + 145,232, 97, 2, 96, 24, 96, 31,228,229,246, 97,128, 9, 90,231, + 245,242,237,245,235,232,105,128, 10, 90,239,239,107,128, 2, 96, + 250,243,241,245,225,242,101,128, 51,147,105, 3, 96, 66, 96, 77, + 96, 88,232,233,242,225,231,225,238, 97,128, 48, 78,235,225,244, + 225,235,225,238, 97,128, 48,174,109, 2, 96, 94, 96,105,225,242, + 237,229,238,233,225,110,128, 5, 99,229,108,130, 5,210, 96,114, + 96,134,228,225,231,229,243,104,129,251, 50, 96,125,232,229,226, + 242,229,119,128,251, 50,232,229,226,242,229,119,128, 5,210,234, + 229,227,249,242,233,236,236,233, 99,128, 4, 83,236,239,244,244, + 225,108, 2, 96,167, 96,184,233,238,246,229,242,244,229,228,243, + 244,242,239,235,101,128, 1,190,243,244,239,112,132, 2,148, 96, + 199, 96,210, 96,216, 96,248,233,238,246,229,242,244,229,100,128, + 2,150,237,239,100,128, 2,192,242,229,246,229,242,243,229,100, + 130, 2,149, 96,231, 96,237,237,239,100,128, 2,193,243,245,240, + 229,242,233,239,114,128, 2,228,243,244,242,239,235,101,129, 2, + 161, 97, 3,242,229,246,229,242,243,229,100,128, 2,162,109, 2, + 97, 20, 97, 28,225,227,242,239,110,128, 30, 33,239,238,239,243, + 240,225,227,101,128,255, 71,111, 2, 97, 45, 97, 56,232,233,242, + 225,231,225,238, 97,128, 48, 84,235,225,244,225,235,225,238, 97, + 128, 48,180,240, 97, 2, 97, 74, 97, 80,242,229,110,128, 36,162, + 243,241,245,225,242,101,128, 51,172,114, 2, 97, 95, 97,192, 97, + 2, 97,101, 97,109,228,233,229,238,116,128, 34, 7,246,101,134, + 0, 96, 97,126, 97,137, 97,154, 97,161, 97,170, 97,182,226,229, + 236,239,247,227,237, 98,128, 3, 22, 99, 2, 97,143, 97,148,237, + 98,128, 3, 0,239,237, 98,128, 3, 0,228,229,246, 97,128, 9, + 83,236,239,247,237,239,100,128, 2,206,237,239,238,239,243,240, + 225,227,101,128,255, 64,244,239,238,229,227,237, 98,128, 3, 64, + 229,225,244,229,114,132, 0, 62, 97,208, 97,227, 97,239, 98, 26, + 229,241,245,225,108,129, 34,101, 97,218,239,242,236,229,243,115, + 128, 34,219,237,239,238,239,243,240,225,227,101,128,255, 30,111, + 2, 97,245, 98, 15,114, 2, 97,251, 98, 8,229,241,245,233,246, + 225,236,229,238,116,128, 34,115,236,229,243,115,128, 34,119,246, + 229,242,229,241,245,225,108,128, 34,103,243,237,225,236,108,128, + 254,101,115, 2, 98, 40, 98, 48,227,242,233,240,116,128, 2, 97, + 244,242,239,235,101,128, 1,229,117, 4, 98, 66, 98, 77, 98,134, + 98,145,232,233,242,225,231,225,238, 97,128, 48, 80,233,108, 2, + 98, 84, 98,109,236,229,237,239,116, 2, 98, 94, 98,101,236,229, + 230,116,128, 0,171,242,233,231,232,116,128, 0,187,243,233,238, + 231,108, 2, 98,119, 98,126,236,229,230,116,128, 32, 57,242,233, + 231,232,116,128, 32, 58,235,225,244,225,235,225,238, 97,128, 48, + 176,242,225,237,245,243,241,245,225,242,101,128, 51, 24,249,243, + 241,245,225,242,101,128, 51,201,104,144, 0,104, 98,204,101, 90, + 101,125,101,162,101,202,103, 90,103,110,104, 75,104, 87,104, 99, + 105,167,105,175,105,186,105,195,106, 19,106, 23, 97, 13, 98,232, + 99, 15, 99, 25, 99, 55, 99, 80, 99,158, 99,170, 99,195, 99,210, + 99,239, 99,252,100, 54,100, 63, 97, 2, 98,238, 99, 1,226,235, + 232,225,243,233,225,238,227,249,242,233,236,236,233, 99,128, 4, + 169,236,244,239,238,229,225,242,225,226,233, 99,128, 6,193,226, + 229,238,231,225,236,105,128, 9,185,228,101, 2, 99, 32, 99, 50, + 243,227,229,238,228,229,242,227,249,242,233,236,236,233, 99,128, + 4,179,246, 97,128, 9, 57,231,117, 2, 99, 62, 99, 71,234,225, + 242,225,244,105,128, 10,185,242,237,245,235,232,105,128, 10, 57, + 104, 4, 99, 90, 99, 99, 99,113, 99,143,225,242,225,226,233, 99, + 128, 6, 45,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 162,105, 2, 99,119, 99,134,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,254,163,242,225,231,225,238, 97,128, 48,111,237, + 229,228,233,225,236,225,242,225,226,233, 99,128,254,164,233,244, + 245,243,241,245,225,242,101,128, 51, 42,235,225,244,225,235,225, + 238, 97,129, 48,207, 99,183,232,225,236,230,247,233,228,244,104, + 128,255,138,236,225,238,244,231,245,242,237,245,235,232,105,128, + 10, 77,237,250, 97, 2, 99,218, 99,227,225,242,225,226,233, 99, + 128, 6, 33,236,239,247,225,242,225,226,233, 99,128, 6, 33,238, + 231,245,236,230,233,236,236,229,114,128, 49,100,114, 2,100, 2, + 100, 18,228,243,233,231,238,227,249,242,233,236,236,233, 99,128, + 4, 74,240,239,239,110, 2,100, 27,100, 40,236,229,230,244,226, + 225,242,226,245,112,128, 33,188,242,233,231,232,244,226,225,242, + 226,245,112,128, 33,192,243,241,245,225,242,101,128, 51,202,244, + 225,102, 3,100, 73,100,165,101, 0,240,225,244,225,104,134, 5, + 178,100, 93,100, 98,100,112,100,121,100,136,100,152,177, 54,128, + 5,178, 50, 2,100,104,100,108, 51,128, 5,178,102,128, 5,178, + 232,229,226,242,229,119,128, 5,178,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,178,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,178,247,233,228,229,232,229,226,242, + 229,119,128, 5,178,241,225,237,225,244,115,135, 5,179,100,188, + 100,193,100,198,100,203,100,212,100,227,100,243,177, 98,128, 5, + 179,178, 56,128, 5,179,179, 52,128, 5,179,232,229,226,242,229, + 119,128, 5,179,238,225,242,242,239,247,232,229,226,242,229,119, + 128, 5,179,241,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,179,247,233,228,229,232,229,226,242,229,119,128, 5,179, + 243,229,231,239,108,135, 5,177,101, 22,101, 27,101, 32,101, 37, + 101, 46,101, 61,101, 77,177, 55,128, 5,177,178, 52,128, 5,177, + 179, 48,128, 5,177,232,229,226,242,229,119,128, 5,177,238,225, + 242,242,239,247,232,229,226,242,229,119,128, 5,177,241,245,225, + 242,244,229,242,232,229,226,242,229,119,128, 5,177,247,233,228, + 229,232,229,226,242,229,119,128, 5,177, 98, 3,101, 98,101,103, + 101,113,225,114,128, 1, 39,239,240,239,237,239,230,111,128, 49, + 15,242,229,246,229,226,229,236,239,119,128, 30, 43, 99, 2,101, + 131,101,140,229,228,233,236,236, 97,128, 30, 41,233,242, 99, 2, + 101,148,101,153,236,101,128, 36,215,245,237,230,236,229,120,128, + 1, 37,100, 2,101,168,101,178,233,229,242,229,243,233,115,128, + 30, 39,239,116, 2,101,185,101,194,225,227,227,229,238,116,128, + 30, 35,226,229,236,239,119,128, 30, 37,101,136, 5,212,101,222, + 101,255,102, 19,102,248,103, 8,103, 53,103, 62,103, 75,225,242, + 116,129, 38,101,101,230,243,245,233,116, 2,101,239,101,247,226, + 236,225,227,107,128, 38,101,247,232,233,244,101,128, 38, 97,228, + 225,231,229,243,104,129,251, 52,102, 10,232,229,226,242,229,119, + 128,251, 52,104, 6,102, 33,102, 61,102, 69,102,119,102,165,102, + 214, 97, 2,102, 39,102, 53,236,244,239,238,229,225,242,225,226, + 233, 99,128, 6,193,242,225,226,233, 99,128, 6, 71,229,226,242, + 229,119,128, 5,212,230,233,238,225,236, 97, 2,102, 80,102,111, + 236,116, 2,102, 87,102, 99,239,238,229,225,242,225,226,233, 99, + 128,251,167,244,247,239,225,242,225,226,233, 99,128,254,234,242, + 225,226,233, 99,128,254,234,232,225,237,250,225,225,226,239,246, + 101, 2,102,134,102,148,230,233,238,225,236,225,242,225,226,233, + 99,128,251,165,233,243,239,236,225,244,229,228,225,242,225,226, + 233, 99,128,251,164,105, 2,102,171,102,205,238,233,244,233,225, + 236, 97, 2,102,183,102,197,236,244,239,238,229,225,242,225,226, + 233, 99,128,251,168,242,225,226,233, 99,128,254,235,242,225,231, + 225,238, 97,128, 48,120,237,229,228,233,225,236, 97, 2,102,226, + 102,240,236,244,239,238,229,225,242,225,226,233, 99,128,251,169, + 242,225,226,233, 99,128,254,236,233,243,229,233,229,242,225,243, + 241,245,225,242,101,128, 51,123,107, 2,103, 14,103, 38,225,244, + 225,235,225,238, 97,129, 48,216,103, 26,232,225,236,230,247,233, + 228,244,104,128,255,141,245,244,225,225,242,245,243,241,245,225, + 242,101,128, 51, 54,238,231,232,239,239,107,128, 2,103,242,245, + 244,245,243,241,245,225,242,101,128, 51, 57,116,129, 5,215,103, + 81,232,229,226,242,229,119,128, 5,215,232,239,239,107,129, 2, + 102,103, 99,243,245,240,229,242,233,239,114,128, 2,177,105, 4, + 103,120,103,205,103,216,103,241,229,245,104, 4,103,132,103,167, + 103,182,103,191, 97, 2,103,138,103,153,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,123,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 27,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50,109,235,239,242,229,225,110,128, 49, 78,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 13,232,233,242, + 225,231,225,238, 97,128, 48,114,235,225,244,225,235,225,238, 97, + 129, 48,210,103,229,232,225,236,230,247,233,228,244,104,128,255, + 139,242,233,113,134, 5,180,104, 3,104, 8,104, 22,104, 31,104, + 46,104, 62,177, 52,128, 5,180, 50, 2,104, 14,104, 18, 49,128, + 5,180,100,128, 5,180,232,229,226,242,229,119,128, 5,180,238, + 225,242,242,239,247,232,229,226,242,229,119,128, 5,180,241,245, + 225,242,244,229,242,232,229,226,242,229,119,128, 5,180,247,233, + 228,229,232,229,226,242,229,119,128, 5,180,236,233,238,229,226, + 229,236,239,119,128, 30,150,237,239,238,239,243,240,225,227,101, + 128,255, 72,111, 9,104,119,104,130,104,154,104,179,105, 11,105, + 24,105,110,105,150,105,161,225,242,237,229,238,233,225,110,128, + 5,112,232,105, 2,104,137,104,145,240,244,232,225,105,128, 14, + 43,242,225,231,225,238, 97,128, 48,123,235,225,244,225,235,225, + 238, 97,129, 48,219,104,167,232,225,236,230,247,233,228,244,104, + 128,255,142,236,225,109,135, 5,185,104,199,104,204,104,209,104, + 214,104,223,104,238,104,254,177, 57,128, 5,185,178, 54,128, 5, + 185,179, 50,128, 5,185,232,229,226,242,229,119,128, 5,185,238, + 225,242,242,239,247,232,229,226,242,229,119,128, 5,185,241,245, + 225,242,244,229,242,232,229,226,242,229,119,128, 5,185,247,233, + 228,229,232,229,226,242,229,119,128, 5,185,238,239,235,232,245, + 235,244,232,225,105,128, 14, 46,111, 2,105, 30,105,100,107, 4, + 105, 40,105, 52,105, 58,105, 80,225,226,239,246,229,227,239,237, + 98,128, 3, 9,227,237, 98,128, 3, 9,240,225,236,225,244,225, + 236,233,250,229,228,226,229,236,239,247,227,237, 98,128, 3, 33, + 242,229,244,242,239,230,236,229,248,226,229,236,239,247,227,237, + 98,128, 3, 34,238,243,241,245,225,242,101,128, 51, 66,114, 2, + 105,116,105,143,105, 2,105,122,105,131,227,239,240,244,233, 99, + 128, 3,233,250,239,238,244,225,236,226,225,114,128, 32, 21,238, + 227,237, 98,128, 3, 27,244,243,240,242,233,238,231,115,128, 38, + 104,245,243,101,128, 35, 2,240,225,242,229,110,128, 36,163,243, + 245,240,229,242,233,239,114,128, 2,176,244,245,242,238,229,100, + 128, 2,101,117, 4,105,205,105,216,105,229,105,254,232,233,242, + 225,231,225,238, 97,128, 48,117,233,233,244,239,243,241,245,225, + 242,101,128, 51, 51,235,225,244,225,235,225,238, 97,129, 48,213, + 105,242,232,225,236,230,247,233,228,244,104,128,255,140,238,231, + 225,242,245,237,236,225,245,116,129, 2,221,106, 13,227,237, 98, + 128, 3, 11,118,128, 1,149,249,240,232,229,110,132, 0, 45,106, + 39,106, 50,106, 62,106, 85,233,238,230,229,242,233,239,114,128, + 246,229,237,239,238,239,243,240,225,227,101,128,255, 13,115, 2, + 106, 68,106, 75,237,225,236,108,128,254, 99,245,240,229,242,233, + 239,114,128,246,230,244,247,111,128, 32, 16,105,149, 0,105,106, + 137,106,160,106,194,106,241,110,123,110,243,111, 24,111, 51,111, + 213,111,217,111,255,112, 21,112,105,113, 14,113, 89,113, 97,113, + 110,113,197,113,254,114, 26,114, 70,225, 99, 2,106,144,106,150, + 245,244,101,128, 0,237,249,242,233,236,236,233, 99,128, 4, 79, + 98, 3,106,168,106,177,106,187,229,238,231,225,236,105,128, 9, + 135,239,240,239,237,239,230,111,128, 49, 39,242,229,246,101,128, + 1, 45, 99, 3,106,202,106,209,106,231,225,242,239,110,128, 1, + 208,233,242, 99, 2,106,217,106,222,236,101,128, 36,216,245,237, + 230,236,229,120,128, 0,238,249,242,233,236,236,233, 99,128, 4, + 86,100, 4,106,251,107, 5,110, 80,110,113,226,236,231,242,225, + 246,101,128, 2, 9,101, 2,107, 11,110, 75,239,231,242,225,240, + 104, 7,107, 32,107, 46,107, 59,109,244,110, 19,110, 32,110, 44, + 229,225,242,244,232,227,233,242,227,236,101,128, 50,143,230,233, + 242,229,227,233,242,227,236,101,128, 50,139,233, 99, 14,107, 90, + 107,106,107,205,108, 3,108, 69,108, 98,108,114,108,171,108,220, + 108,232,109, 3,109, 70,109,208,109,237,225,236,236,233,225,238, + 227,229,240,225,242,229,110,128, 50, 63, 99, 4,107,116,107,127, + 107,141,107,148,225,236,236,240,225,242,229,110,128, 50, 58,229, + 238,244,242,229,227,233,242,227,236,101,128, 50,165,236,239,243, + 101,128, 48, 6,111, 3,107,156,107,171,107,191,237,237, 97,129, + 48, 1,107,164,236,229,230,116,128,255,100,238,231,242,225,244, + 245,236,225,244,233,239,238,240,225,242,229,110,128, 50, 55,242, + 242,229,227,244,227,233,242,227,236,101,128, 50,163,101, 3,107, + 213,107,225,107,242,225,242,244,232,240,225,242,229,110,128, 50, + 47,238,244,229,242,240,242,233,243,229,240,225,242,229,110,128, + 50, 61,248,227,229,236,236,229,238,244,227,233,242,227,236,101, + 128, 50,157,102, 2,108, 9,108, 24,229,243,244,233,246,225,236, + 240,225,242,229,110,128, 50, 64,105, 2,108, 30,108, 59,238,225, + 238,227,233,225,108, 2,108, 42,108, 51,227,233,242,227,236,101, + 128, 50,150,240,225,242,229,110,128, 50, 54,242,229,240,225,242, + 229,110,128, 50, 43,104, 2,108, 75,108, 86,225,246,229,240,225, + 242,229,110,128, 50, 50,233,231,232,227,233,242,227,236,101,128, + 50,164,233,244,229,242,225,244,233,239,238,237,225,242,107,128, + 48, 5,108, 3,108,122,108,148,108,160,225,226,239,114, 2,108, + 131,108,140,227,233,242,227,236,101,128, 50,152,240,225,242,229, + 110,128, 50, 56,229,230,244,227,233,242,227,236,101,128, 50,167, + 239,247,227,233,242,227,236,101,128, 50,166,109, 2,108,177,108, + 209,101, 2,108,183,108,198,228,233,227,233,238,229,227,233,242, + 227,236,101,128, 50,169,244,225,236,240,225,242,229,110,128, 50, + 46,239,239,238,240,225,242,229,110,128, 50, 42,238,225,237,229, + 240,225,242,229,110,128, 50, 52,112, 2,108,238,108,246,229,242, + 233,239,100,128, 48, 2,242,233,238,244,227,233,242,227,236,101, + 128, 50,158,114, 2,109, 9,109, 57,101, 3,109, 17,109, 28,109, + 43,225,227,232,240,225,242,229,110,128, 50, 67,240,242,229,243, + 229,238,244,240,225,242,229,110,128, 50, 57,243,239,245,242,227, + 229,240,225,242,229,110,128, 50, 62,233,231,232,244,227,233,242, + 227,236,101,128, 50,168,115, 5,109, 82,109,111,109,125,109,150, + 109,178,101, 2,109, 88,109,101,227,242,229,244,227,233,242,227, + 236,101,128, 50,153,236,230,240,225,242,229,110,128, 50, 66,239, + 227,233,229,244,249,240,225,242,229,110,128, 50, 51,112, 2,109, + 131,109,137,225,227,101,128, 48, 0,229,227,233,225,236,240,225, + 242,229,110,128, 50, 53,116, 2,109,156,109,167,239,227,235,240, + 225,242,229,110,128, 50, 49,245,228,249,240,225,242,229,110,128, + 50, 59,117, 2,109,184,109,193,238,240,225,242,229,110,128, 50, + 48,240,229,242,246,233,243,229,240,225,242,229,110,128, 50, 60, + 119, 2,109,214,109,226,225,244,229,242,240,225,242,229,110,128, + 50, 44,239,239,228,240,225,242,229,110,128, 50, 45,250,229,242, + 111,128, 48, 7,109, 2,109,250,110, 7,229,244,225,236,227,233, + 242,227,236,101,128, 50,142,239,239,238,227,233,242,227,236,101, + 128, 50,138,238,225,237,229,227,233,242,227,236,101,128, 50,148, + 243,245,238,227,233,242,227,236,101,128, 50,144,119, 2,110, 50, + 110, 63,225,244,229,242,227,233,242,227,236,101,128, 50,140,239, + 239,228,227,233,242,227,236,101,128, 50,141,246, 97,128, 9, 7, + 233,229,242,229,243,233,115,130, 0,239,110, 94,110,102,225,227, + 245,244,101,128, 30, 47,227,249,242,233,236,236,233, 99,128, 4, + 229,239,244,226,229,236,239,119,128, 30,203,101, 3,110,131,110, + 147,110,158,226,242,229,246,229,227,249,242,233,236,236,233, 99, + 128, 4,215,227,249,242,233,236,236,233, 99,128, 4, 53,245,238, + 103, 4,110,170,110,205,110,220,110,229, 97, 2,110,176,110,191, + 227,233,242,227,236,229,235,239,242,229,225,110,128, 50,117,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 21,227,233,242, + 227,236,229,235,239,242,229,225,110,128, 50,103,235,239,242,229, + 225,110,128, 49, 71,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 7,103, 2,110,249,111, 0,242,225,246,101,128, 0,236, + 117, 2,111, 6,111, 15,234,225,242,225,244,105,128, 10,135,242, + 237,245,235,232,105,128, 10, 7,104, 2,111, 30,111, 40,233,242, + 225,231,225,238, 97,128, 48, 68,239,239,235,225,226,239,246,101, + 128, 30,201,105, 8,111, 69,111, 79,111, 90,111, 97,111,122,111, + 138,111,153,111,169,226,229,238,231,225,236,105,128, 9,136,227, + 249,242,233,236,236,233, 99,128, 4, 56,228,229,246, 97,128, 9, + 8,231,117, 2,111,104,111,113,234,225,242,225,244,105,128, 10, + 136,242,237,245,235,232,105,128, 10, 8,237,225,244,242,225,231, + 245,242,237,245,235,232,105,128, 10, 64,238,246,229,242,244,229, + 228,226,242,229,246,101,128, 2, 11,243,232,239,242,244,227,249, + 242,233,236,236,233, 99,128, 4, 57,246,239,247,229,236,243,233, + 231,110, 3,111,185,111,195,111,202,226,229,238,231,225,236,105, + 128, 9,192,228,229,246, 97,128, 9, 64,231,245,234,225,242,225, + 244,105,128, 10,192,106,128, 1, 51,107, 2,111,223,111,247,225, + 244,225,235,225,238, 97,129, 48,164,111,235,232,225,236,230,247, + 233,228,244,104,128,255,114,239,242,229,225,110,128, 49, 99,108, + 2,112, 5,112, 10,228,101,128, 2,220,245,249,232,229,226,242, + 229,119,128, 5,172,109, 2,112, 27,112, 94, 97, 3,112, 35,112, + 55,112, 80,227,242,239,110,129, 1, 43,112, 44,227,249,242,233, + 236,236,233, 99,128, 4,227,231,229,239,242,225,240,240,242,239, + 248,233,237,225,244,229,236,249,229,241,245,225,108,128, 34, 83, + 244,242,225,231,245,242,237,245,235,232,105,128, 10, 63,239,238, + 239,243,240,225,227,101,128,255, 73,110, 5,112,117,112,127,112, + 136,112,148,112,232,227,242,229,237,229,238,116,128, 34, 6,230, + 233,238,233,244,121,128, 34, 30,233,225,242,237,229,238,233,225, + 110,128, 5,107,116, 2,112,154,112,222,101, 2,112,160,112,211, + 231,242,225,108,131, 34, 43,112,173,112,191,112,196, 98, 2,112, + 179,112,187,239,244,244,239,109,128, 35, 33,116,128, 35, 33,229, + 120,128,248,245,116, 2,112,202,112,207,239,112,128, 35, 32,112, + 128, 35, 32,242,243,229,227,244,233,239,110,128, 34, 41,233,243, + 241,245,225,242,101,128, 51, 5,118, 3,112,240,112,249,113, 2, + 226,245,236,236,229,116,128, 37,216,227,233,242,227,236,101,128, + 37,217,243,237,233,236,229,230,225,227,101,128, 38, 59,111, 3, + 113, 22,113, 33,113, 41,227,249,242,233,236,236,233, 99,128, 4, + 81,231,239,238,229,107,128, 1, 47,244, 97,131, 3,185,113, 52, + 113, 73,113, 81,228,233,229,242,229,243,233,115,129, 3,202,113, + 65,244,239,238,239,115,128, 3,144,236,225,244,233,110,128, 2, + 105,244,239,238,239,115,128, 3,175,240,225,242,229,110,128, 36, + 164,242,233,231,245,242,237,245,235,232,105,128, 10,114,115, 4, + 113,120,113,165,113,179,113,187,237,225,236,108, 2,113,129,113, + 140,232,233,242,225,231,225,238, 97,128, 48, 67,235,225,244,225, + 235,225,238, 97,129, 48,163,113,153,232,225,236,230,247,233,228, + 244,104,128,255,104,243,232,225,242,226,229,238,231,225,236,105, + 128, 9,250,244,242,239,235,101,128, 2,104,245,240,229,242,233, + 239,114,128,246,237,116, 2,113,203,113,237,229,242,225,244,233, + 239,110, 2,113,215,113,226,232,233,242,225,231,225,238, 97,128, + 48,157,235,225,244,225,235,225,238, 97,128, 48,253,233,236,228, + 101,129, 1, 41,113,246,226,229,236,239,119,128, 30, 45,117, 2, + 114, 4,114, 15,226,239,240,239,237,239,230,111,128, 49, 41,227, + 249,242,233,236,236,233, 99,128, 4, 78,246,239,247,229,236,243, + 233,231,110, 3,114, 42,114, 52,114, 59,226,229,238,231,225,236, + 105,128, 9,191,228,229,246, 97,128, 9, 63,231,245,234,225,242, + 225,244,105,128, 10,191,250,232,233,244,243, 97, 2,114, 81,114, + 92,227,249,242,233,236,236,233, 99,128, 4,117,228,226,236,231, + 242,225,246,229,227,249,242,233,236,236,233, 99,128, 4,119,106, + 138, 0,106,114,135,114,198,114,209,115, 3,115, 19,115,132,115, + 201,115,206,115,218,115,226, 97, 4,114,145,114,156,114,166,114, + 173,225,242,237,229,238,233,225,110,128, 5,113,226,229,238,231, + 225,236,105,128, 9,156,228,229,246, 97,128, 9, 28,231,117, 2, + 114,180,114,189,234,225,242,225,244,105,128, 10,156,242,237,245, + 235,232,105,128, 10, 28,226,239,240,239,237,239,230,111,128, 49, + 16, 99, 3,114,217,114,224,114,246,225,242,239,110,128, 1,240, + 233,242, 99, 2,114,232,114,237,236,101,128, 36,217,245,237,230, + 236,229,120,128, 1, 53,242,239,243,243,229,228,244,225,233,108, + 128, 2,157,228,239,244,236,229,243,243,243,244,242,239,235,101, + 128, 2, 95,101, 3,115, 27,115, 38,115,103,227,249,242,233,236, + 236,233, 99,128, 4, 88,229,109, 4,115, 49,115, 58,115, 72,115, + 88,225,242,225,226,233, 99,128, 6, 44,230,233,238,225,236,225, + 242,225,226,233, 99,128,254,158,233,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,254,159,237,229,228,233,225,236,225,242, + 225,226,233, 99,128,254,160,104, 2,115,109,115,118,225,242,225, + 226,233, 99,128, 6,152,230,233,238,225,236,225,242,225,226,233, + 99,128,251,139,104, 2,115,138,115,188, 97, 3,115,146,115,156, + 115,163,226,229,238,231,225,236,105,128, 9,157,228,229,246, 97, + 128, 9, 29,231,117, 2,115,170,115,179,234,225,242,225,244,105, + 128, 10,157,242,237,245,235,232,105,128, 10, 29,229,232,225,242, + 237,229,238,233,225,110,128, 5,123,233,115,128, 48, 4,237,239, + 238,239,243,240,225,227,101,128,255, 74,240,225,242,229,110,128, + 36,165,243,245,240,229,242,233,239,114,128, 2,178,107,146, 0, + 107,116, 21,118,110,118,121,118,183,118,194,119, 28,119, 42,120, + 150,121, 90,121,103,121,129,121,178,122, 60,122, 82,122, 95,122, + 118,122,160,122,170, 97, 12,116, 47,116, 79,116,101,116,131,116, + 245,117, 14,117, 44,117, 69,117,175,117,189,118, 56,118, 85, 98, + 2,116, 53,116, 70,225,243,232,235,233,242,227,249,242,233,236, + 236,233, 99,128, 4,161,229,238,231,225,236,105,128, 9,149, 99, + 2,116, 85,116, 91,245,244,101,128, 30, 49,249,242,233,236,236, + 233, 99,128, 4, 58,228,101, 2,116,108,116,126,243,227,229,238, + 228,229,242,227,249,242,233,236,236,233, 99,128, 4,155,246, 97, + 128, 9, 21,102,135, 5,219,116,149,116,158,116,178,116,192,116, + 201,116,217,116,232,225,242,225,226,233, 99,128, 6, 67,228,225, + 231,229,243,104,129,251, 59,116,169,232,229,226,242,229,119,128, + 251, 59,230,233,238,225,236,225,242,225,226,233, 99,128,254,218, + 232,229,226,242,229,119,128, 5,219,233,238,233,244,233,225,236, + 225,242,225,226,233, 99,128,254,219,237,229,228,233,225,236,225, + 242,225,226,233, 99,128,254,220,242,225,230,229,232,229,226,242, + 229,119,128,251, 77,231,117, 2,116,252,117, 5,234,225,242,225, + 244,105,128, 10,149,242,237,245,235,232,105,128, 10, 21,104, 2, + 117, 20,117, 30,233,242,225,231,225,238, 97,128, 48, 75,239,239, + 235,227,249,242,233,236,236,233, 99,128, 4,196,235,225,244,225, + 235,225,238, 97,129, 48,171,117, 57,232,225,236,230,247,233,228, + 244,104,128,255,118,112, 2,117, 75,117, 96,240, 97,129, 3,186, + 117, 82,243,249,237,226,239,236,231,242,229,229,107,128, 3,240, + 249,229,239,245,110, 3,117,108,117,122,117,156,237,233,229,245, + 237,235,239,242,229,225,110,128, 49,113,112, 2,117,128,117,143, + 232,233,229,245,240,232,235,239,242,229,225,110,128, 49,132,233, + 229,245,240,235,239,242,229,225,110,128, 49,120,243,243,225,238, + 231,240,233,229,245,240,235,239,242,229,225,110,128, 49,121,242, + 239,242,233,233,243,241,245,225,242,101,128, 51, 13,115, 5,117, + 201,117,245,118, 4,118, 12,118, 40,232,233,228,225,225,245,244, + 111, 2,117,214,117,223,225,242,225,226,233, 99,128, 6, 64,238, + 239,243,233,228,229,226,229,225,242,233,238,231,225,242,225,226, + 233, 99,128, 6, 64,237,225,236,236,235,225,244,225,235,225,238, + 97,128, 48,245,241,245,225,242,101,128, 51,132,242, 97, 2,118, + 19,118, 28,225,242,225,226,233, 99,128, 6, 80,244,225,238,225, + 242,225,226,233, 99,128, 6, 77,244,242,239,235,229,227,249,242, + 233,236,236,233, 99,128, 4,159,244,225,232,233,242,225,240,242, + 239,236,239,238,231,237,225,242,235,232,225,236,230,247,233,228, + 244,104,128,255,112,246,229,242,244,233,227,225,236,243,244,242, + 239,235,229,227,249,242,233,236,236,233, 99,128, 4,157,226,239, + 240,239,237,239,230,111,128, 49, 14, 99, 4,118,131,118,153,118, + 162,118,170, 97, 2,118,137,118,147,236,243,241,245,225,242,101, + 128, 51,137,242,239,110,128, 1,233,229,228,233,236,236, 97,128, + 1, 55,233,242,227,236,101,128, 36,218,239,237,237,225,225,227, + 227,229,238,116,128, 1, 55,228,239,244,226,229,236,239,119,128, + 30, 51,101, 4,118,204,118,231,119, 0,119, 12,104, 2,118,210, + 118,221,225,242,237,229,238,233,225,110,128, 5,132,233,242,225, + 231,225,238, 97,128, 48, 81,235,225,244,225,235,225,238, 97,129, + 48,177,118,244,232,225,236,230,247,233,228,244,104,128,255,121, + 238,225,242,237,229,238,233,225,110,128, 5,111,243,237,225,236, + 236,235,225,244,225,235,225,238, 97,128, 48,246,231,242,229,229, + 238,236,225,238,228,233, 99,128, 1, 56,104, 6,119, 56,119,185, + 119,196,119,221,120, 52,120,140, 97, 5,119, 68,119, 78,119, 89, + 119, 96,119,121,226,229,238,231,225,236,105,128, 9,150,227,249, + 242,233,236,236,233, 99,128, 4, 69,228,229,246, 97,128, 9, 22, + 231,117, 2,119,103,119,112,234,225,242,225,244,105,128, 10,150, + 242,237,245,235,232,105,128, 10, 22,104, 4,119,131,119,140,119, + 154,119,170,225,242,225,226,233, 99,128, 6, 46,230,233,238,225, + 236,225,242,225,226,233, 99,128,254,166,233,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,167,237,229,228,233,225,236, + 225,242,225,226,233, 99,128,254,168,229,233,227,239,240,244,233, + 99,128, 3,231,232, 97, 2,119,203,119,210,228,229,246, 97,128, + 9, 89,231,245,242,237,245,235,232,105,128, 10, 89,233,229,245, + 235,104, 4,119,235,120, 14,120, 29,120, 38, 97, 2,119,241,120, + 0,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,120, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 24,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50,106,235,239,242, + 229,225,110,128, 49, 75,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 10,111, 4,120, 62,120,111,120,121,120,126,235,104, + 4,120, 73,120, 82,120, 91,120,101,225,233,244,232,225,105,128, + 14, 2,239,238,244,232,225,105,128, 14, 5,245,225,244,244,232, + 225,105,128, 14, 3,247,225,233,244,232,225,105,128, 14, 4,237, + 245,244,244,232,225,105,128, 14, 91,239,107,128, 1,153,242,225, + 235,232,225,238,231,244,232,225,105,128, 14, 6,250,243,241,245, + 225,242,101,128, 51,145,105, 4,120,160,120,171,120,196,120,245, + 232,233,242,225,231,225,238, 97,128, 48, 77,235,225,244,225,235, + 225,238, 97,129, 48,173,120,184,232,225,236,230,247,233,228,244, + 104,128,255,119,242,111, 3,120,205,120,220,120,236,231,245,242, + 225,237,245,243,241,245,225,242,101,128, 51, 21,237,229,229,244, + 239,242,245,243,241,245,225,242,101,128, 51, 22,243,241,245,225, + 242,101,128, 51, 20,249,229,239,107, 5,121, 4,121, 39,121, 54, + 121, 63,121, 77, 97, 2,121, 10,121, 25,227,233,242,227,236,229, + 235,239,242,229,225,110,128, 50,110,240,225,242,229,238,235,239, + 242,229,225,110,128, 50, 14,227,233,242,227,236,229,235,239,242, + 229,225,110,128, 50, 96,235,239,242,229,225,110,128, 49, 49,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 0,243,233,239, + 243,235,239,242,229,225,110,128, 49, 51,234,229,227,249,242,233, + 236,236,233, 99,128, 4, 92,108, 2,121,109,121,120,233,238,229, + 226,229,236,239,119,128, 30, 53,243,241,245,225,242,101,128, 51, + 152,109, 3,121,137,121,151,121,162,227,245,226,229,228,243,241, + 245,225,242,101,128, 51,166,239,238,239,243,240,225,227,101,128, + 255, 75,243,241,245,225,242,229,228,243,241,245,225,242,101,128, + 51,162,111, 5,121,190,121,216,121,254,122, 10,122, 24,104, 2, + 121,196,121,206,233,242,225,231,225,238, 97,128, 48, 83,237,243, + 241,245,225,242,101,128, 51,192,235, 97, 2,121,223,121,231,233, + 244,232,225,105,128, 14, 1,244,225,235,225,238, 97,129, 48,179, + 121,242,232,225,236,230,247,233,228,244,104,128,255,122,239,240, + 239,243,241,245,225,242,101,128, 51, 30,240,240,225,227,249,242, + 233,236,236,233, 99,128, 4,129,114, 2,122, 30,122, 50,229,225, + 238,243,244,225,238,228,225,242,228,243,249,237,226,239,108,128, + 50,127,239,238,233,243,227,237, 98,128, 3, 67,240, 97, 2,122, + 67,122, 73,242,229,110,128, 36,166,243,241,245,225,242,101,128, + 51,170,243,233,227,249,242,233,236,236,233, 99,128, 4,111,116, + 2,122,101,122,110,243,241,245,225,242,101,128, 51,207,245,242, + 238,229,100,128, 2,158,117, 2,122,124,122,135,232,233,242,225, + 231,225,238, 97,128, 48, 79,235,225,244,225,235,225,238, 97,129, + 48,175,122,148,232,225,236,230,247,233,228,244,104,128,255,120, + 246,243,241,245,225,242,101,128, 51,184,247,243,241,245,225,242, + 101,128, 51,190,108,146, 0,108,122,220,124,247,125, 20,125, 86, + 125,124,126, 20,126, 29,126, 45,126, 69,126, 87,126,205,126,246, + 127,125,127,133,127,166,127,175,127,183,127,245, 97, 7,122,236, + 122,246,122,253,123, 4,123, 29,123, 45,124,235,226,229,238,231, + 225,236,105,128, 9,178,227,245,244,101,128, 1, 58,228,229,246, + 97,128, 9, 50,231,117, 2,123, 11,123, 20,234,225,242,225,244, + 105,128, 10,178,242,237,245,235,232,105,128, 10, 50,235,235,232, + 225,238,231,249,225,239,244,232,225,105,128, 14, 69,109, 10,123, + 67,124, 6,124, 23,124, 61,124, 75,124, 94,124,110,124,130,124, + 150,124,173, 97, 2,123, 73,123,254,236,229,102, 4,123, 85,123, + 99,123,191,123,208,230,233,238,225,236,225,242,225,226,233, 99, + 128,254,252,232,225,237,250, 97, 2,123,109,123,150,225,226,239, + 246,101, 2,123,119,123,133,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,248,233,243,239,236,225,244,229,228,225,242,225, + 226,233, 99,128,254,247,226,229,236,239,119, 2,123,160,123,174, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,250,233,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,254,249,233, + 243,239,236,225,244,229,228,225,242,225,226,233, 99,128,254,251, + 237,225,228,228,225,225,226,239,246,101, 2,123,223,123,237,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,246,233,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,254,245,242,225, + 226,233, 99,128, 6, 68,226,228, 97,129, 3,187,124, 14,243,244, + 242,239,235,101,128, 1,155,229,100,130, 5,220,124, 32,124, 52, + 228,225,231,229,243,104,129,251, 60,124, 43,232,229,226,242,229, + 119,128,251, 60,232,229,226,242,229,119,128, 5,220,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,222,232,225,232,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,202,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,223,234,229, + 229,237,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 252,201,235,232,225,232,233,238,233,244,233,225,236,225,242,225, + 226,233, 99,128,252,203,236,225,237,232,229,232,233,243,239,236, + 225,244,229,228,225,242,225,226,233, 99,128,253,242,237,101, 2, + 124,180,124,193,228,233,225,236,225,242,225,226,233, 99,128,254, + 224,229,109, 2,124,200,124,219,232,225,232,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,253,136,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,252,204,242,231,229,227,233, + 242,227,236,101,128, 37,239, 98, 3,124,255,125, 4,125, 10,225, + 114,128, 1,154,229,236,116,128, 2,108,239,240,239,237,239,230, + 111,128, 49, 12, 99, 4,125, 30,125, 37,125, 46,125, 73,225,242, + 239,110,128, 1, 62,229,228,233,236,236, 97,128, 1, 60,233,242, + 99, 2,125, 54,125, 59,236,101,128, 36,219,245,237,230,236,229, + 248,226,229,236,239,119,128, 30, 61,239,237,237,225,225,227,227, + 229,238,116,128, 1, 60,228,239,116,130, 1, 64,125, 96,125,105, + 225,227,227,229,238,116,128, 1, 64,226,229,236,239,119,129, 30, + 55,125,115,237,225,227,242,239,110,128, 30, 57,101, 3,125,132, + 125,170,126, 15,230,116, 2,125,139,125,155,225,238,231,236,229, + 225,226,239,246,229,227,237, 98,128, 3, 26,244,225,227,235,226, + 229,236,239,247,227,237, 98,128, 3, 24,243,115,132, 0, 60,125, + 183,125,205,125,217,126, 7,229,241,245,225,108,129, 34,100,125, + 193,239,242,231,242,229,225,244,229,114,128, 34,218,237,239,238, + 239,243,240,225,227,101,128,255, 28,111, 2,125,223,125,252,114, + 2,125,229,125,242,229,241,245,233,246,225,236,229,238,116,128, + 34,114,231,242,229,225,244,229,114,128, 34,118,246,229,242,229, + 241,245,225,108,128, 34,102,243,237,225,236,108,128,254,100,250, + 104,128, 2,110,230,226,236,239,227,107,128, 37,140,232,239,239, + 235,242,229,244,242,239,230,236,229,120,128, 2,109,105, 2,126, + 51,126, 56,242, 97,128, 32,164,247,238,225,242,237,229,238,233, + 225,110,128, 5,108,106,129, 1,201,126, 75,229,227,249,242,233, + 236,236,233, 99,128, 4, 89,108,132,246,192,126, 99,126,123,126, + 134,126,143, 97, 2,126,105,126,112,228,229,246, 97,128, 9, 51, + 231,245,234,225,242,225,244,105,128, 10,179,233,238,229,226,229, + 236,239,119,128, 30, 59,236,225,228,229,246, 97,128, 9, 52,246, + 239,227,225,236,233, 99, 3,126,157,126,167,126,174,226,229,238, + 231,225,236,105,128, 9,225,228,229,246, 97,128, 9, 97,246,239, + 247,229,236,243,233,231,110, 2,126,188,126,198,226,229,238,231, + 225,236,105,128, 9,227,228,229,246, 97,128, 9, 99,109, 3,126, + 213,126,226,126,237,233,228,228,236,229,244,233,236,228,101,128, + 2,107,239,238,239,243,240,225,227,101,128,255, 76,243,241,245, + 225,242,101,128, 51,208,111, 6,127, 4,127, 16,127, 58,127, 69, + 127, 75,127,117,227,232,245,236,225,244,232,225,105,128, 14, 44, + 231,233,227,225,108, 3,127, 28,127, 34,127, 53,225,238,100,128, + 34, 39,238,239,116,129, 0,172,127, 42,242,229,246,229,242,243, + 229,100,128, 35, 16,239,114,128, 34, 40,236,233,238,231,244,232, + 225,105,128, 14, 37,238,231,115,128, 1,127,247,236,233,238,101, + 2,127, 85,127,108, 99, 2,127, 91,127,103,229,238,244,229,242, + 236,233,238,101,128,254, 78,237, 98,128, 3, 50,228,225,243,232, + 229,100,128,254, 77,250,229,238,231,101,128, 37,202,240,225,242, + 229,110,128, 36,167,115, 3,127,141,127,148,127,156,236,225,243, + 104,128, 1, 66,241,245,225,242,101,128, 33, 19,245,240,229,242, + 233,239,114,128,246,238,244,243,232,225,228,101,128, 37,145,245, + 244,232,225,105,128, 14, 38,246,239,227,225,236,233, 99, 3,127, + 197,127,207,127,214,226,229,238,231,225,236,105,128, 9,140,228, + 229,246, 97,128, 9, 12,246,239,247,229,236,243,233,231,110, 2, + 127,228,127,238,226,229,238,231,225,236,105,128, 9,226,228,229, + 246, 97,128, 9, 98,248,243,241,245,225,242,101,128, 51,211,109, + 144, 0,109,128, 35,130,144,130,169,130,196,130,221,132, 18,132, + 40,133, 95,133,125,133,174,134, 25,134, 47,134, 72,134, 81,135, + 108,135,136, 97, 12,128, 61,128, 71,128,135,128,142,128,167,128, + 215,130, 51,130, 76,130, 81,130, 95,130,107,130,112,226,229,238, + 231,225,236,105,128, 9,174, 99, 2,128, 77,128,129,242,239,110, + 132, 0,175,128, 91,128,102,128,108,128,117,226,229,236,239,247, + 227,237, 98,128, 3, 49,227,237, 98,128, 3, 4,236,239,247,237, + 239,100,128, 2,205,237,239,238,239,243,240,225,227,101,128,255, + 227,245,244,101,128, 30, 63,228,229,246, 97,128, 9, 46,231,117, + 2,128,149,128,158,234,225,242,225,244,105,128, 10,174,242,237, + 245,235,232,105,128, 10, 46,104, 2,128,173,128,205,225,240,225, + 235,104, 2,128,183,128,192,232,229,226,242,229,119,128, 5,164, + 236,229,230,244,232,229,226,242,229,119,128, 5,164,233,242,225, + 231,225,238, 97,128, 48,126,105, 5,128,227,129, 40,129,103,129, + 133,130, 39,227,232,225,244,244,225,247, 97, 3,128,242,129, 17, + 129, 24,236,239,119, 2,128,250,129, 5,236,229,230,244,244,232, + 225,105,128,248,149,242,233,231,232,244,244,232,225,105,128,248, + 148,244,232,225,105,128, 14, 75,245,240,240,229,242,236,229,230, + 244,244,232,225,105,128,248,147,229,107, 3,129, 49,129, 80,129, + 87,236,239,119, 2,129, 57,129, 68,236,229,230,244,244,232,225, + 105,128,248,140,242,233,231,232,244,244,232,225,105,128,248,139, + 244,232,225,105,128, 14, 72,245,240,240,229,242,236,229,230,244, + 244,232,225,105,128,248,138,232,225,238,225,235,225,116, 2,129, + 115,129,126,236,229,230,244,244,232,225,105,128,248,132,244,232, + 225,105,128, 14, 49,116, 3,129,141,129,169,129,232,225,233,235, + 232,117, 2,129,151,129,162,236,229,230,244,244,232,225,105,128, + 248,137,244,232,225,105,128, 14, 71,232,111, 3,129,178,129,209, + 129,216,236,239,119, 2,129,186,129,197,236,229,230,244,244,232, + 225,105,128,248,143,242,233,231,232,244,244,232,225,105,128,248, + 142,244,232,225,105,128, 14, 73,245,240,240,229,242,236,229,230, + 244,244,232,225,105,128,248,141,242,105, 3,129,241,130, 16,130, + 23,236,239,119, 2,129,249,130, 4,236,229,230,244,244,232,225, + 105,128,248,146,242,233,231,232,244,244,232,225,105,128,248,145, + 244,232,225,105,128, 14, 74,245,240,240,229,242,236,229,230,244, + 244,232,225,105,128,248,144,249,225,237,239,235,244,232,225,105, + 128, 14, 70,235,225,244,225,235,225,238, 97,129, 48,222,130, 64, + 232,225,236,230,247,233,228,244,104,128,255,143,236,101,128, 38, + 66,238,243,249,239,238,243,241,245,225,242,101,128, 51, 71,241, + 225,230,232,229,226,242,229,119,128, 5,190,242,115,128, 38, 66, + 115, 2,130,118,130,136,239,242,225,227,233,242,227,236,229,232, + 229,226,242,229,119,128, 5,175,241,245,225,242,101,128, 51,131, + 98, 2,130,150,130,160,239,240,239,237,239,230,111,128, 49, 7, + 243,241,245,225,242,101,128, 51,212, 99, 2,130,175,130,183,233, + 242,227,236,101,128, 36,220,245,226,229,228,243,241,245,225,242, + 101,128, 51,165,228,239,116, 2,130,204,130,213,225,227,227,229, + 238,116,128, 30, 65,226,229,236,239,119,128, 30, 67,101, 7,130, + 237,131,108,131,119,131,134,131,159,131,196,131,208,101, 2,130, + 243,131, 95,109, 4,130,253,131, 6,131, 20,131, 36,225,242,225, + 226,233, 99,128, 6, 69,230,233,238,225,236,225,242,225,226,233, + 99,128,254,226,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,227,237,101, 2,131, 43,131, 56,228,233,225,236,225, + 242,225,226,233, 99,128,254,228,229,237,105, 2,131, 64,131, 79, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,209,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 72,244, + 239,242,245,243,241,245,225,242,101,128, 51, 77,232,233,242,225, + 231,225,238, 97,128, 48,129,233,250,233,229,242,225,243,241,245, + 225,242,101,128, 51,126,235,225,244,225,235,225,238, 97,129, 48, + 225,131,147,232,225,236,230,247,233,228,244,104,128,255,146,109, + 130, 5,222,131,167,131,187,228,225,231,229,243,104,129,251, 62, + 131,178,232,229,226,242,229,119,128,251, 62,232,229,226,242,229, + 119,128, 5,222,238,225,242,237,229,238,233,225,110,128, 5,116, + 242,235,232, 97, 3,131,219,131,228,132, 5,232,229,226,242,229, + 119,128, 5,165,235,229,230,245,236, 97, 2,131,239,131,248,232, + 229,226,242,229,119,128, 5,166,236,229,230,244,232,229,226,242, + 229,119,128, 5,166,236,229,230,244,232,229,226,242,229,119,128, + 5,165,104, 2,132, 24,132, 30,239,239,107,128, 2,113,250,243, + 241,245,225,242,101,128, 51,146,105, 6,132, 54,132, 91,132,228, + 132,239,133, 8,133, 65,228,100, 2,132, 61,132, 86,236,229,228, + 239,244,235,225,244,225,235,225,238,225,232,225,236,230,247,233, + 228,244,104,128,255,101,239,116,128, 0,183,229,245,109, 5,132, + 105,132,140,132,155,132,164,132,215, 97, 2,132,111,132,126,227, + 233,242,227,236,229,235,239,242,229,225,110,128, 50,114,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 18,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,100,235,239,242,229,225, + 110,128, 49, 65,112, 2,132,170,132,202, 97, 2,132,176,132,190, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,112,242,229, + 238,235,239,242,229,225,110,128, 50, 4,233,229,245,240,235,239, + 242,229,225,110,128, 49,110,243,233,239,243,235,239,242,229,225, + 110,128, 49,111,232,233,242,225,231,225,238, 97,128, 48,127,235, + 225,244,225,235,225,238, 97,129, 48,223,132,252,232,225,236,230, + 247,233,228,244,104,128,255,144,238,117, 2,133, 15,133, 60,115, + 132, 34, 18,133, 27,133, 38,133, 47,133, 53,226,229,236,239,247, + 227,237, 98,128, 3, 32,227,233,242,227,236,101,128, 34,150,237, + 239,100,128, 2,215,240,236,245,115,128, 34, 19,244,101,128, 32, + 50,242,105, 2,133, 72,133, 86,226,225,225,242,245,243,241,245, + 225,242,101,128, 51, 74,243,241,245,225,242,101,128, 51, 73,108, + 2,133,101,133,116,239,238,231,236,229,231,244,245,242,238,229, + 100,128, 2,112,243,241,245,225,242,101,128, 51,150,109, 3,133, + 133,133,147,133,158,227,245,226,229,228,243,241,245,225,242,101, + 128, 51,163,239,238,239,243,240,225,227,101,128,255, 77,243,241, + 245,225,242,229,228,243,241,245,225,242,101,128, 51,159,111, 5, + 133,186,133,212,133,237,133,247,134, 0,104, 2,133,192,133,202, + 233,242,225,231,225,238, 97,128, 48,130,237,243,241,245,225,242, + 101,128, 51,193,235,225,244,225,235,225,238, 97,129, 48,226,133, + 225,232,225,236,230,247,233,228,244,104,128,255,147,236,243,241, + 245,225,242,101,128, 51,214,237,225,244,232,225,105,128, 14, 33, + 246,229,242,243,243,241,245,225,242,101,129, 51,167,134, 15,228, + 243,241,245,225,242,101,128, 51,168,240, 97, 2,134, 32,134, 38, + 242,229,110,128, 36,168,243,241,245,225,242,101,128, 51,171,115, + 2,134, 53,134, 62,243,241,245,225,242,101,128, 51,179,245,240, + 229,242,233,239,114,128,246,239,244,245,242,238,229,100,128, 2, + 111,117,141, 0,181,134,111,134,115,134,125,134,149,134,159,134, + 181,134,192,134,217,134,240,134,250,135, 24,135, 88,135, 98, 49, + 128, 0,181,225,243,241,245,225,242,101,128, 51,130,227,104, 2, + 134,132,134,142,231,242,229,225,244,229,114,128, 34,107,236,229, + 243,115,128, 34,106,230,243,241,245,225,242,101,128, 51,140,103, + 2,134,165,134,172,242,229,229,107,128, 3,188,243,241,245,225, + 242,101,128, 51,141,232,233,242,225,231,225,238, 97,128, 48,128, + 235,225,244,225,235,225,238, 97,129, 48,224,134,205,232,225,236, + 230,247,233,228,244,104,128,255,145,108, 2,134,223,134,232,243, + 241,245,225,242,101,128, 51,149,244,233,240,236,121,128, 0,215, + 237,243,241,245,225,242,101,128, 51,155,238,225,104, 2,135, 2, + 135, 11,232,229,226,242,229,119,128, 5,163,236,229,230,244,232, + 229,226,242,229,119,128, 5,163,115, 2,135, 30,135, 79,233, 99, + 3,135, 39,135, 56,135, 67,225,236,238,239,244,101,129, 38,106, + 135, 50,228,226,108,128, 38,107,230,236,225,244,243,233,231,110, + 128, 38,109,243,232,225,242,240,243,233,231,110,128, 38,111,243, + 241,245,225,242,101,128, 51,178,246,243,241,245,225,242,101,128, + 51,182,247,243,241,245,225,242,101,128, 51,188,118, 2,135,114, + 135,127,237,229,231,225,243,241,245,225,242,101,128, 51,185,243, + 241,245,225,242,101,128, 51,183,119, 2,135,142,135,155,237,229, + 231,225,243,241,245,225,242,101,128, 51,191,243,241,245,225,242, + 101,128, 51,189,110,150, 0,110,135,212,136, 90,136,114,136,180, + 136,205,137, 7,137, 17,137, 84,137,127,139,161,139,179,139,204, + 139,235,140, 5,140, 70,142, 52,142, 60,142, 85,142, 93,143, 61, + 143, 71,143, 81, 97, 8,135,230,135,250,136, 1,136, 8,136, 33, + 136, 44,136, 69,136, 81, 98, 2,135,236,135,245,229,238,231,225, + 236,105,128, 9,168,236, 97,128, 34, 7,227,245,244,101,128, 1, + 68,228,229,246, 97,128, 9, 40,231,117, 2,136, 15,136, 24,234, + 225,242,225,244,105,128, 10,168,242,237,245,235,232,105,128, 10, + 40,232,233,242,225,231,225,238, 97,128, 48,106,235,225,244,225, + 235,225,238, 97,129, 48,202,136, 57,232,225,236,230,247,233,228, + 244,104,128,255,133,240,239,243,244,242,239,240,232,101,128, 1, + 73,243,241,245,225,242,101,128, 51,129, 98, 2,136, 96,136,106, + 239,240,239,237,239,230,111,128, 49, 11,243,240,225,227,101,128, + 0,160, 99, 4,136,124,136,131,136,140,136,167,225,242,239,110, + 128, 1, 72,229,228,233,236,236, 97,128, 1, 70,233,242, 99, 2, + 136,148,136,153,236,101,128, 36,221,245,237,230,236,229,248,226, + 229,236,239,119,128, 30, 75,239,237,237,225,225,227,227,229,238, + 116,128, 1, 70,228,239,116, 2,136,188,136,197,225,227,227,229, + 238,116,128, 30, 69,226,229,236,239,119,128, 30, 71,101, 3,136, + 213,136,224,136,249,232,233,242,225,231,225,238, 97,128, 48,109, + 235,225,244,225,235,225,238, 97,129, 48,205,136,237,232,225,236, + 230,247,233,228,244,104,128,255,136,247,243,232,229,241,229,236, + 243,233,231,110,128, 32,170,230,243,241,245,225,242,101,128, 51, + 139,103, 2,137, 23,137, 73, 97, 3,137, 31,137, 41,137, 48,226, + 229,238,231,225,236,105,128, 9,153,228,229,246, 97,128, 9, 25, + 231,117, 2,137, 55,137, 64,234,225,242,225,244,105,128, 10,153, + 242,237,245,235,232,105,128, 10, 25,239,238,231,245,244,232,225, + 105,128, 14, 7,104, 2,137, 90,137,100,233,242,225,231,225,238, + 97,128, 48,147,239,239,107, 2,137,108,137,115,236,229,230,116, + 128, 2,114,242,229,244,242,239,230,236,229,120,128, 2,115,105, + 4,137,137,138, 50,138, 61,138,119,229,245,110, 7,137,155,137, + 190,137,222,137,236,137,245,138, 22,138, 35, 97, 2,137,161,137, + 176,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,111, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 15,227,105, + 2,137,197,137,209,229,245,227,235,239,242,229,225,110,128, 49, + 53,242,227,236,229,235,239,242,229,225,110,128, 50, 97,232,233, + 229,245,232,235,239,242,229,225,110,128, 49, 54,235,239,242,229, + 225,110,128, 49, 52,240, 97, 2,137,252,138, 10,238,243,233,239, + 243,235,239,242,229,225,110,128, 49,104,242,229,238,235,239,242, + 229,225,110,128, 50, 1,243,233,239,243,235,239,242,229,225,110, + 128, 49,103,244,233,235,229,245,244,235,239,242,229,225,110,128, + 49,102,232,233,242,225,231,225,238, 97,128, 48,107,107, 2,138, + 67,138, 91,225,244,225,235,225,238, 97,129, 48,203,138, 79,232, + 225,236,230,247,233,228,244,104,128,255,134,232,225,232,233,116, + 2,138,101,138,112,236,229,230,244,244,232,225,105,128,248,153, + 244,232,225,105,128, 14, 77,238,101,141, 0, 57,138,150,138,159, + 138,169,138,199,138,206,138,231,139, 2,139, 36,139, 48,139, 59, + 139, 92,139,100,139,111,225,242,225,226,233, 99,128, 6,105,226, + 229,238,231,225,236,105,128, 9,239,227,233,242,227,236,101,129, + 36,104,138,180,233,238,246,229,242,243,229,243,225,238,243,243, + 229,242,233,102,128, 39,146,228,229,246, 97,128, 9,111,231,117, + 2,138,213,138,222,234,225,242,225,244,105,128, 10,239,242,237, + 245,235,232,105,128, 10,111,232, 97, 2,138,238,138,249,227,235, + 225,242,225,226,233, 99,128, 6,105,238,231,250,232,239,117,128, + 48, 41,105, 2,139, 8,139, 26,228,229,239,231,242,225,240,232, + 233,227,240,225,242,229,110,128, 50, 40,238,230,229,242,233,239, + 114,128, 32,137,237,239,238,239,243,240,225,227,101,128,255, 25, + 239,236,228,243,244,249,236,101,128,247, 57,112, 2,139, 65,139, + 72,225,242,229,110,128, 36,124,229,114, 2,139, 79,139, 85,233, + 239,100,128, 36,144,243,233,225,110,128, 6,249,242,239,237,225, + 110,128, 33,120,243,245,240,229,242,233,239,114,128, 32,121,116, + 2,139,117,139,155,229,229,110, 2,139,125,139,134,227,233,242, + 227,236,101,128, 36,114,112, 2,139,140,139,147,225,242,229,110, + 128, 36,134,229,242,233,239,100,128, 36,154,232,225,105,128, 14, + 89,106,129, 1,204,139,167,229,227,249,242,233,236,236,233, 99, + 128, 4, 90,235,225,244,225,235,225,238, 97,129, 48,243,139,192, + 232,225,236,230,247,233,228,244,104,128,255,157,108, 2,139,210, + 139,224,229,231,242,233,231,232,244,236,239,238,103,128, 1,158, + 233,238,229,226,229,236,239,119,128, 30, 73,109, 2,139,241,139, + 252,239,238,239,243,240,225,227,101,128,255, 78,243,241,245,225, + 242,101,128, 51,154,110, 2,140, 11,140, 61, 97, 3,140, 19,140, + 29,140, 36,226,229,238,231,225,236,105,128, 9,163,228,229,246, + 97,128, 9, 35,231,117, 2,140, 43,140, 52,234,225,242,225,244, + 105,128, 10,163,242,237,245,235,232,105,128, 10, 35,238,225,228, + 229,246, 97,128, 9, 41,111, 6,140, 84,140, 95,140,120,140,161, + 141,113,142, 40,232,233,242,225,231,225,238, 97,128, 48,110,235, + 225,244,225,235,225,238, 97,129, 48,206,140,108,232,225,236,230, + 247,233,228,244,104,128,255,137,110, 3,140,128,140,144,140,153, + 226,242,229,225,235,233,238,231,243,240,225,227,101,128, 0,160, + 229,238,244,232,225,105,128, 14, 19,245,244,232,225,105,128, 14, + 25,239,110, 7,140,178,140,187,140,201,140,235,140,251,141, 36, + 141, 95,225,242,225,226,233, 99,128, 6, 70,230,233,238,225,236, + 225,242,225,226,233, 99,128,254,230,231,232,245,238,238, 97, 2, + 140,212,140,221,225,242,225,226,233, 99,128, 6,186,230,233,238, + 225,236,225,242,225,226,233, 99,128,251,159,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,254,231,234,229,229,237,105, + 2,141, 5,141, 20,238,233,244,233,225,236,225,242,225,226,233, + 99,128,252,210,243,239,236,225,244,229,228,225,242,225,226,233, + 99,128,252, 75,237,101, 2,141, 43,141, 56,228,233,225,236,225, + 242,225,226,233, 99,128,254,232,229,237,105, 2,141, 64,141, 79, + 238,233,244,233,225,236,225,242,225,226,233, 99,128,252,213,243, + 239,236,225,244,229,228,225,242,225,226,233, 99,128,252, 78,238, + 239,239,238,230,233,238,225,236,225,242,225,226,233, 99,128,252, + 141,116, 7,141,129,141,140,141,169,141,204,141,216,141,236,142, + 6,227,239,238,244,225,233,238,115,128, 34, 12,101, 2,141,146, + 141,162,236,229,237,229,238,116,129, 34, 9,141,157,239,102,128, + 34, 9,241,245,225,108,128, 34, 96,231,242,229,225,244,229,114, + 129, 34,111,141,181,238,239,114, 2,141,189,141,197,229,241,245, + 225,108,128, 34,113,236,229,243,115,128, 34,121,233,228,229,238, + 244,233,227,225,108,128, 34, 98,236,229,243,115,129, 34,110,141, + 225,238,239,242,229,241,245,225,108,128, 34,112,112, 2,141,242, + 141,252,225,242,225,236,236,229,108,128, 34, 38,242,229,227,229, + 228,229,115,128, 34,128,243,117, 3,142, 15,142, 22,142, 31,226, + 243,229,116,128, 34,132,227,227,229,229,228,115,128, 34,129,240, + 229,242,243,229,116,128, 34,133,247,225,242,237,229,238,233,225, + 110,128, 5,118,240,225,242,229,110,128, 36,169,115, 2,142, 66, + 142, 75,243,241,245,225,242,101,128, 51,177,245,240,229,242,233, + 239,114,128, 32,127,244,233,236,228,101,128, 0,241,117,132, 3, + 189,142,105,142,116,142,197,143, 24,232,233,242,225,231,225,238, + 97,128, 48,108,107, 2,142,122,142,146,225,244,225,235,225,238, + 97,129, 48,204,142,134,232,225,236,230,247,233,228,244,104,128, + 255,135,244, 97, 3,142,155,142,165,142,172,226,229,238,231,225, + 236,105,128, 9,188,228,229,246, 97,128, 9, 60,231,117, 2,142, + 179,142,188,234,225,242,225,244,105,128, 10,188,242,237,245,235, + 232,105,128, 10, 60,109, 2,142,203,142,237,226,229,242,243,233, + 231,110,130, 0, 35,142,217,142,229,237,239,238,239,243,240,225, + 227,101,128,255, 3,243,237,225,236,108,128,254, 95,229,114, 2, + 142,244,143, 20,225,236,243,233,231,110, 2,142,255,143, 7,231, + 242,229,229,107,128, 3,116,236,239,247,229,242,231,242,229,229, + 107,128, 3,117,111,128, 33, 22,110,130, 5,224,143, 32,143, 52, + 228,225,231,229,243,104,129,251, 64,143, 43,232,229,226,242,229, + 119,128,251, 64,232,229,226,242,229,119,128, 5,224,246,243,241, + 245,225,242,101,128, 51,181,247,243,241,245,225,242,101,128, 51, + 187,249, 97, 3,143, 90,143,100,143,107,226,229,238,231,225,236, + 105,128, 9,158,228,229,246, 97,128, 9, 30,231,117, 2,143,114, + 143,123,234,225,242,225,244,105,128, 10,158,242,237,245,235,232, + 105,128, 10, 30,111,147, 0,111,143,174,143,196,144, 18,144,188, + 145, 4,145, 19,145, 59,145,182,145,203,145,241,145,252,146,174, + 148, 8,148, 72,148,105,148,151,149, 24,149, 71,149, 83, 97, 2, + 143,180,143,187,227,245,244,101,128, 0,243,238,231,244,232,225, + 105,128, 14, 45, 98, 4,143,206,143,248,144, 1,144, 11,225,242, + 242,229,100,130, 2,117,143,218,143,229,227,249,242,233,236,236, + 233, 99,128, 4,233,228,233,229,242,229,243,233,243,227,249,242, + 233,236,236,233, 99,128, 4,235,229,238,231,225,236,105,128, 9, + 147,239,240,239,237,239,230,111,128, 49, 27,242,229,246,101,128, + 1, 79, 99, 3,144, 26,144, 99,144,178, 97, 2,144, 32,144, 93, + 238,228,242, 97, 3,144, 43,144, 50,144, 61,228,229,246, 97,128, + 9, 17,231,245,234,225,242,225,244,105,128, 10,145,246,239,247, + 229,236,243,233,231,110, 2,144, 75,144, 82,228,229,246, 97,128, + 9, 73,231,245,234,225,242,225,244,105,128, 10,201,242,239,110, + 128, 1,210,233,242, 99, 2,144,107,144,112,236,101,128, 36,222, + 245,237,230,236,229,120,133, 0,244,144,131,144,139,144,150,144, + 158,144,170,225,227,245,244,101,128, 30,209,228,239,244,226,229, + 236,239,119,128, 30,217,231,242,225,246,101,128, 30,211,232,239, + 239,235,225,226,239,246,101,128, 30,213,244,233,236,228,101,128, + 30,215,249,242,233,236,236,233, 99,128, 4, 62,100, 4,144,198, + 144,221,144,227,144,250,226,108, 2,144,205,144,213,225,227,245, + 244,101,128, 1, 81,231,242,225,246,101,128, 2, 13,229,246, 97, + 128, 9, 19,233,229,242,229,243,233,115,129, 0,246,144,239,227, + 249,242,233,236,236,233, 99,128, 4,231,239,244,226,229,236,239, + 119,128, 30,205,101,129, 1, 83,145, 10,235,239,242,229,225,110, + 128, 49, 90,103, 3,145, 27,145, 42,145, 49,239,238,229,107,129, + 2,219,145, 36,227,237, 98,128, 3, 40,242,225,246,101,128, 0, + 242,245,234,225,242,225,244,105,128, 10,147,104, 4,145, 69,145, + 80,145, 90,145,168,225,242,237,229,238,233,225,110,128, 5,133, + 233,242,225,231,225,238, 97,128, 48, 74,111, 2,145, 96,145,106, + 239,235,225,226,239,246,101,128, 30,207,242,110,133, 1,161,145, + 121,145,129,145,140,145,148,145,160,225,227,245,244,101,128, 30, + 219,228,239,244,226,229,236,239,119,128, 30,227,231,242,225,246, + 101,128, 30,221,232,239,239,235,225,226,239,246,101,128, 30,223, + 244,233,236,228,101,128, 30,225,245,238,231,225,242,245,237,236, + 225,245,116,128, 1, 81,105,129, 1,163,145,188,238,246,229,242, + 244,229,228,226,242,229,246,101,128, 2, 15,107, 2,145,209,145, + 233,225,244,225,235,225,238, 97,129, 48,170,145,221,232,225,236, + 230,247,233,228,244,104,128,255,117,239,242,229,225,110,128, 49, + 87,236,229,232,229,226,242,229,119,128, 5,171,109, 6,146, 10, + 146, 38,146, 45,146,134,146,145,146,163,225,227,242,239,110,130, + 1, 77,146, 22,146, 30,225,227,245,244,101,128, 30, 83,231,242, + 225,246,101,128, 30, 81,228,229,246, 97,128, 9, 80,229,231, 97, + 133, 3,201,146, 61,146, 65,146, 76,146, 90,146,106, 49,128, 3, + 214,227,249,242,233,236,236,233, 99,128, 4, 97,236,225,244,233, + 238,227,236,239,243,229,100,128, 2,119,242,239,245,238,228,227, + 249,242,233,236,236,233, 99,128, 4,123,116, 2,146,112,146,127, + 233,244,236,239,227,249,242,233,236,236,233, 99,128, 4,125,239, + 238,239,115,128, 3,206,231,245,234,225,242,225,244,105,128, 10, + 208,233,227,242,239,110,129, 3,191,146,155,244,239,238,239,115, + 128, 3,204,239,238,239,243,240,225,227,101,128,255, 79,238,101, + 145, 0, 49,146,213,146,222,146,232,147, 6,147, 31,147, 40,147, + 49,147, 74,147,108,147,142,147,154,147,173,147,184,147,217,147, + 227,147,235,147,246,225,242,225,226,233, 99,128, 6, 97,226,229, + 238,231,225,236,105,128, 9,231,227,233,242,227,236,101,129, 36, + 96,146,243,233,238,246,229,242,243,229,243,225,238,243,243,229, + 242,233,102,128, 39,138,100, 2,147, 12,147, 18,229,246, 97,128, + 9,103,239,244,229,238,236,229,225,228,229,114,128, 32, 36,229, + 233,231,232,244,104,128, 33, 91,230,233,244,244,229,100,128,246, + 220,231,117, 2,147, 56,147, 65,234,225,242,225,244,105,128, 10, + 231,242,237,245,235,232,105,128, 10,103,232, 97, 3,147, 83,147, + 94,147, 99,227,235,225,242,225,226,233, 99,128, 6, 97,236,102, + 128, 0,189,238,231,250,232,239,117,128, 48, 33,105, 2,147,114, + 147,132,228,229,239,231,242,225,240,232,233,227,240,225,242,229, + 110,128, 50, 32,238,230,229,242,233,239,114,128, 32,129,237,239, + 238,239,243,240,225,227,101,128,255, 17,238,245,237,229,242,225, + 244,239,242,226,229,238,231,225,236,105,128, 9,244,239,236,228, + 243,244,249,236,101,128,247, 49,112, 2,147,190,147,197,225,242, + 229,110,128, 36,116,229,114, 2,147,204,147,210,233,239,100,128, + 36,136,243,233,225,110,128, 6,241,241,245,225,242,244,229,114, + 128, 0,188,242,239,237,225,110,128, 33,112,243,245,240,229,242, + 233,239,114,128, 0,185,244,104, 2,147,253,148, 2,225,105,128, + 14, 81,233,242,100,128, 33, 83,111, 3,148, 16,148, 50,148, 66, + 103, 2,148, 22,148, 40,239,238,229,107,129, 1,235,148, 31,237, + 225,227,242,239,110,128, 1,237,245,242,237,245,235,232,105,128, + 10, 19,237,225,244,242,225,231,245,242,237,245,235,232,105,128, + 10, 75,240,229,110,128, 2, 84,112, 3,148, 80,148, 87,148, 98, + 225,242,229,110,128, 36,170,229,238,226,245,236,236,229,116,128, + 37,230,244,233,239,110,128, 35, 37,114, 2,148,111,148,140,100, + 2,148,117,148,128,230,229,237,233,238,233,238,101,128, 0,170, + 237,225,243,227,245,236,233,238,101,128, 0,186,244,232,239,231, + 239,238,225,108,128, 34, 31,115, 5,148,163,148,195,148,212,149, + 1,149, 14,232,239,242,116, 2,148,172,148,179,228,229,246, 97, + 128, 9, 18,246,239,247,229,236,243,233,231,238,228,229,246, 97, + 128, 9, 74,236,225,243,104,129, 0,248,148,204,225,227,245,244, + 101,128, 1,255,237,225,236,108, 2,148,221,148,232,232,233,242, + 225,231,225,238, 97,128, 48, 73,235,225,244,225,235,225,238, 97, + 129, 48,169,148,245,232,225,236,230,247,233,228,244,104,128,255, + 107,244,242,239,235,229,225,227,245,244,101,128, 1,255,245,240, + 229,242,233,239,114,128,246,240,116, 2,149, 30,149, 41,227,249, + 242,233,236,236,233, 99,128, 4,127,233,236,228,101,130, 0,245, + 149, 52,149, 60,225,227,245,244,101,128, 30, 77,228,233,229,242, + 229,243,233,115,128, 30, 79,245,226,239,240,239,237,239,230,111, + 128, 49, 33,118, 2,149, 89,149,170,229,114, 2,149, 96,149,162, + 236,233,238,101,131, 32, 62,149,109,149,132,149,155, 99, 2,149, + 115,149,127,229,238,244,229,242,236,233,238,101,128,254, 74,237, + 98,128, 3, 5,100, 2,149,138,149,146,225,243,232,229,100,128, + 254, 73,226,236,247,225,246,121,128,254, 76,247,225,246,121,128, + 254, 75,243,227,239,242,101,128, 0,175,239,247,229,236,243,233, + 231,110, 3,149,185,149,195,149,202,226,229,238,231,225,236,105, + 128, 9,203,228,229,246, 97,128, 9, 75,231,245,234,225,242,225, + 244,105,128, 10,203,112,145, 0,112,149,251,152,123,152,134,152, + 143,152,155,154, 80,154, 90,155, 82,156,101,156,191,156,217,157, + 92,157,100,158, 2,158, 60,158, 88,158, 98, 97, 14,150, 25,150, + 57,150, 67,150, 74,150, 81,150,129,150,140,150,154,150,165,150, + 212,150,226,151,238,152, 21,152,111, 97, 2,150, 31,150, 43,237, + 240,243,243,241,245,225,242,101,128, 51,128,243,229,238,244,239, + 243,241,245,225,242,101,128, 51, 43,226,229,238,231,225,236,105, + 128, 9,170,227,245,244,101,128, 30, 85,228,229,246, 97,128, 9, + 42,103, 2,150, 87,150,105,101, 2,150, 93,150,100,228,239,247, + 110,128, 33,223,245,112,128, 33,222,117, 2,150,111,150,120,234, + 225,242,225,244,105,128, 10,170,242,237,245,235,232,105,128, 10, + 42,232,233,242,225,231,225,238, 97,128, 48,113,233,249,225,238, + 238,239,233,244,232,225,105,128, 14, 47,235,225,244,225,235,225, + 238, 97,128, 48,209,108, 2,150,171,150,196,225,244,225,236,233, + 250,225,244,233,239,238,227,249,242,233,236,236,233,227,227,237, + 98,128, 4,132,239,227,232,235,225,227,249,242,233,236,236,233, + 99,128, 4,192,238,243,233,239,243,235,239,242,229,225,110,128, + 49,127,114, 3,150,234,150,255,151,227, 97, 2,150,240,150,248, + 231,242,225,240,104,128, 0,182,236,236,229,108,128, 34, 37,229, + 110, 2,151, 6,151,116,236,229,230,116,136, 0, 40,151, 29,151, + 44,151, 49,151, 54,151, 65,151, 77,151,100,151,105,225,236,244, + 239,238,229,225,242,225,226,233, 99,128,253, 62,226,116,128,248, + 237,229,120,128,248,236,233,238,230,229,242,233,239,114,128, 32, + 141,237,239,238,239,243,240,225,227,101,128,255, 8,115, 2,151, + 83,151, 90,237,225,236,108,128,254, 89,245,240,229,242,233,239, + 114,128, 32,125,244,112,128,248,235,246,229,242,244,233,227,225, + 108,128,254, 53,242,233,231,232,116,136, 0, 41,151,140,151,155, + 151,160,151,165,151,176,151,188,151,211,151,216,225,236,244,239, + 238,229,225,242,225,226,233, 99,128,253, 63,226,116,128,248,248, + 229,120,128,248,247,233,238,230,229,242,233,239,114,128, 32,142, + 237,239,238,239,243,240,225,227,101,128,255, 9,115, 2,151,194, + 151,201,237,225,236,108,128,254, 90,245,240,229,242,233,239,114, + 128, 32,126,244,112,128,248,246,246,229,242,244,233,227,225,108, + 128,254, 54,244,233,225,236,228,233,230,102,128, 34, 2,115, 3, + 151,246,152, 1,152, 13,229,241,232,229,226,242,229,119,128, 5, + 192,232,244,225,232,229,226,242,229,119,128, 5,153,241,245,225, + 242,101,128, 51,169,244,225,104,134, 5,183,152, 39,152, 53,152, + 58,152, 67,152, 82,152, 98, 49, 2,152, 45,152, 49, 49,128, 5, + 183,100,128, 5,183,178, 97,128, 5,183,232,229,226,242,229,119, + 128, 5,183,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,183,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,183,247,233,228,229,232,229,226,242,229,119,128, 5,183,250, + 229,242,232,229,226,242,229,119,128, 5,161,226,239,240,239,237, + 239,230,111,128, 49, 6,227,233,242,227,236,101,128, 36,223,228, + 239,244,225,227,227,229,238,116,128, 30, 87,101,137, 5,228,152, + 177,152,188,152,208,152,220,152,240,153, 86,153, 97,153,118,154, + 73,227,249,242,233,236,236,233, 99,128, 4, 63,228,225,231,229, + 243,104,129,251, 68,152,199,232,229,226,242,229,119,128,251, 68, + 229,250,233,243,241,245,225,242,101,128, 51, 59,230,233,238,225, + 236,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 67, + 104, 5,152,252,153, 19,153, 27,153, 41,153, 71,225,114, 2,153, + 3,153, 10,225,226,233, 99,128, 6,126,237,229,238,233,225,110, + 128, 5,122,229,226,242,229,119,128, 5,228,230,233,238,225,236, + 225,242,225,226,233, 99,128,251, 87,105, 2,153, 47,153, 62,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,251, 88,242,225, + 231,225,238, 97,128, 48,122,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,251, 89,235,225,244,225,235,225,238, 97,128, 48, + 218,237,233,228,228,236,229,232,239,239,235,227,249,242,233,236, + 236,233, 99,128, 4,167,114, 5,153,130,153,142,153,184,154, 49, + 154, 62,225,230,229,232,229,226,242,229,119,128,251, 78,227,229, + 238,116,131, 0, 37,153,155,153,164,153,176,225,242,225,226,233, + 99,128, 6,106,237,239,238,239,243,240,225,227,101,128,255, 5, + 243,237,225,236,108,128,254,106,105, 2,153,190,154, 31,239,100, + 134, 0, 46,153,207,153,218,153,229,153,241,153,252,154, 8,225, + 242,237,229,238,233,225,110,128, 5,137,227,229,238,244,229,242, + 229,100,128, 0,183,232,225,236,230,247,233,228,244,104,128,255, + 97,233,238,230,229,242,233,239,114,128,246,231,237,239,238,239, + 243,240,225,227,101,128,255, 14,115, 2,154, 14,154, 21,237,225, + 236,108,128,254, 82,245,240,229,242,233,239,114,128,246,232,243, + 240,239,237,229,238,233,231,242,229,229,235,227,237, 98,128, 3, + 66,240,229,238,228,233,227,245,236,225,114,128, 34,165,244,232, + 239,245,243,225,238,100,128, 32, 48,243,229,244, 97,128, 32,167, + 230,243,241,245,225,242,101,128, 51,138,104, 3,154, 98,154,148, + 155, 29, 97, 3,154,106,154,116,154,123,226,229,238,231,225,236, + 105,128, 9,171,228,229,246, 97,128, 9, 43,231,117, 2,154,130, + 154,139,234,225,242,225,244,105,128, 10,171,242,237,245,235,232, + 105,128, 10, 43,105,133, 3,198,154,162,154,166,154,252,155, 4, + 155, 15, 49,128, 3,213,229,245,240,104, 4,154,179,154,214,154, + 229,154,238, 97, 2,154,185,154,200,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50,122,240,225,242,229,238,235,239,242, + 229,225,110,128, 50, 26,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,108,235,239,242,229,225,110,128, 49, 77,240,225, + 242,229,238,235,239,242,229,225,110,128, 50, 12,236,225,244,233, + 110,128, 2,120,238,244,232,245,244,232,225,105,128, 14, 58,243, + 249,237,226,239,236,231,242,229,229,107,128, 3,213,111, 3,155, + 37,155, 42,155, 68,239,107,128, 1,165,240,104, 2,155, 49,155, + 58,225,238,244,232,225,105,128, 14, 30,245,238,231,244,232,225, + 105,128, 14, 28,243,225,237,240,232,225,239,244,232,225,105,128, + 14, 32,105,133, 3,192,155, 96,156, 52,156, 63,156, 74,156, 88, + 229,245,112, 6,155,112,155,147,155,179,155,207,155,221,156, 17, + 97, 2,155,118,155,133,227,233,242,227,236,229,235,239,242,229, + 225,110,128, 50,115,240,225,242,229,238,235,239,242,229,225,110, + 128, 50, 19,227,105, 2,155,154,155,166,229,245,227,235,239,242, + 229,225,110,128, 49,118,242,227,236,229,235,239,242,229,225,110, + 128, 50,101,107, 2,155,185,155,199,233,249,229,239,235,235,239, + 242,229,225,110,128, 49,114,239,242,229,225,110,128, 49, 66,240, + 225,242,229,238,235,239,242,229,225,110,128, 50, 5,243,233,239, + 115, 2,155,230,156, 2,107, 2,155,236,155,250,233,249,229,239, + 235,235,239,242,229,225,110,128, 49,116,239,242,229,225,110,128, + 49, 68,244,233,235,229,245,244,235,239,242,229,225,110,128, 49, + 117,116, 2,156, 23,156, 38,232,233,229,245,244,232,235,239,242, + 229,225,110,128, 49,119,233,235,229,245,244,235,239,242,229,225, + 110,128, 49,115,232,233,242,225,231,225,238, 97,128, 48,116,235, + 225,244,225,235,225,238, 97,128, 48,212,243,249,237,226,239,236, + 231,242,229,229,107,128, 3,214,247,242,225,242,237,229,238,233, + 225,110,128, 5,131,236,245,115,132, 0, 43,156,115,156,126,156, + 135,156,168,226,229,236,239,247,227,237, 98,128, 3, 31,227,233, + 242,227,236,101,128, 34,149,109, 2,156,141,156,148,233,238,245, + 115,128, 0,177,111, 2,156,154,156,158,100,128, 2,214,238,239, + 243,240,225,227,101,128,255, 11,115, 2,156,174,156,181,237,225, + 236,108,128,254, 98,245,240,229,242,233,239,114,128, 32,122,109, + 2,156,197,156,208,239,238,239,243,240,225,227,101,128,255, 80, + 243,241,245,225,242,101,128, 51,216,111, 5,156,229,156,240,157, + 51,157, 62,157, 72,232,233,242,225,231,225,238, 97,128, 48,125, + 233,238,244,233,238,231,233,238,228,229,120, 4,157, 4,157, 16, + 157, 28,157, 41,228,239,247,238,247,232,233,244,101,128, 38, 31, + 236,229,230,244,247,232,233,244,101,128, 38, 28,242,233,231,232, + 244,247,232,233,244,101,128, 38, 30,245,240,247,232,233,244,101, + 128, 38, 29,235,225,244,225,235,225,238, 97,128, 48,221,240,236, + 225,244,232,225,105,128, 14, 27,243,244,225,236,237,225,242,107, + 129, 48, 18,157, 85,230,225,227,101,128, 48, 32,240,225,242,229, + 110,128, 36,171,114, 3,157,108,157,134,157,159,101, 2,157,114, + 157,122,227,229,228,229,115,128, 34,122,243,227,242,233,240,244, + 233,239,110,128, 33, 30,233,237,101, 2,157,142,157,148,237,239, + 100,128, 2,185,242,229,246,229,242,243,229,100,128, 32, 53,111, + 4,157,169,157,176,157,186,157,199,228,245,227,116,128, 34, 15, + 234,229,227,244,233,246,101,128, 35, 5,236,239,238,231,229,228, + 235,225,238, 97,128, 48,252,112, 2,157,205,157,242,101, 2,157, + 211,157,218,236,236,239,114,128, 35, 24,242,243,117, 2,157,226, + 157,233,226,243,229,116,128, 34,130,240,229,242,243,229,116,128, + 34,131,239,242,244,233,239,110,129, 34, 55,157,253,225,108,128, + 34, 29,115, 2,158, 8,158, 51,105,130, 3,200,158, 16,158, 27, + 227,249,242,233,236,236,233, 99,128, 4,113,236,233,240,238,229, + 245,237,225,244,225,227,249,242,233,236,236,233,227,227,237, 98, + 128, 4,134,243,241,245,225,242,101,128, 51,176,117, 2,158, 66, + 158, 77,232,233,242,225,231,225,238, 97,128, 48,119,235,225,244, + 225,235,225,238, 97,128, 48,215,246,243,241,245,225,242,101,128, + 51,180,247,243,241,245,225,242,101,128, 51,186,113,136, 0,113, + 158,128,159,177,159,188,159,197,159,204,159,216,159,254,160, 6, + 97, 4,158,138,158,161,158,225,159,160,100, 2,158,144,158,150, + 229,246, 97,128, 9, 88,237,225,232,229,226,242,229,119,128, 5, + 168,102, 4,158,171,158,180,158,194,158,210,225,242,225,226,233, + 99,128, 6, 66,230,233,238,225,236,225,242,225,226,233, 99,128, + 254,214,233,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,215,237,229,228,233,225,236,225,242,225,226,233, 99,128,254, + 216,237,225,244,115,136, 5,184,158,248,159, 12,159, 26,159, 31, + 159, 36,159, 45,159, 60,159,147, 49, 3,159, 0,159, 4,159, 8, + 48,128, 5,184, 97,128, 5,184, 99,128, 5,184, 50, 2,159, 18, + 159, 22, 55,128, 5,184, 57,128, 5,184,179, 51,128, 5,184,228, + 101,128, 5,184,232,229,226,242,229,119,128, 5,184,238,225,242, + 242,239,247,232,229,226,242,229,119,128, 5,184,113, 2,159, 66, + 159,132,225,244,225,110, 4,159, 79,159, 88,159,103,159,119,232, + 229,226,242,229,119,128, 5,184,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,184,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,184,247,233,228,229,232,229,226,242,229, + 119,128, 5,184,245,225,242,244,229,242,232,229,226,242,229,119, + 128, 5,184,247,233,228,229,232,229,226,242,229,119,128, 5,184, + 242,238,229,249,240,225,242,225,232,229,226,242,229,119,128, 5, + 159,226,239,240,239,237,239,230,111,128, 49, 17,227,233,242,227, + 236,101,128, 36,224,232,239,239,107,128, 2,160,237,239,238,239, + 243,240,225,227,101,128,255, 81,239,102,130, 5,231,159,225,159, + 245,228,225,231,229,243,104,129,251, 71,159,236,232,229,226,242, + 229,119,128,251, 71,232,229,226,242,229,119,128, 5,231,240,225, + 242,229,110,128, 36,172,117, 4,160, 16,160, 28,160,117,160,204, + 225,242,244,229,242,238,239,244,101,128, 38,105,226,245,244,115, + 135, 5,187,160, 49,160, 54,160, 59,160, 64,160, 73,160, 88,160, + 104,177, 56,128, 5,187,178, 53,128, 5,187,179, 49,128, 5,187, + 232,229,226,242,229,119,128, 5,187,238,225,242,242,239,247,232, + 229,226,242,229,119,128, 5,187,241,245,225,242,244,229,242,232, + 229,226,242,229,119,128, 5,187,247,233,228,229,232,229,226,242, + 229,119,128, 5,187,229,243,244,233,239,110,133, 0, 63,160,136, + 160,159,160,176,160,184,160,196,225,114, 2,160,143,160,150,225, + 226,233, 99,128, 6, 31,237,229,238,233,225,110,128, 5, 94,228, + 239,247,110,129, 0,191,160,168,243,237,225,236,108,128,247,191, + 231,242,229,229,107,128, 3,126,237,239,238,239,243,240,225,227, + 101,128,255, 31,243,237,225,236,108,128,247, 63,239,244,101, 4, + 160,216,161, 31,161, 51,161, 80,228,226,108,133, 0, 34,160,232, + 160,239,160,246,161, 2,161, 23,226,225,243,101,128, 32, 30,236, + 229,230,116,128, 32, 28,237,239,238,239,243,240,225,227,101,128, + 255, 2,240,242,233,237,101,129, 48, 30,161, 12,242,229,246,229, + 242,243,229,100,128, 48, 29,242,233,231,232,116,128, 32, 29,236, + 229,230,116,129, 32, 24,161, 40,242,229,246,229,242,243,229,100, + 128, 32, 27,114, 2,161, 57,161, 67,229,246,229,242,243,229,100, + 128, 32, 27,233,231,232,116,129, 32, 25,161, 76,110,128, 1, 73, + 243,233,238,231,108, 2,161, 90,161, 97,226,225,243,101,128, 32, + 26,101,129, 0, 39,161,103,237,239,238,239,243,240,225,227,101, + 128,255, 7,114,145, 0,114,161,153,162,157,162,168,162,215,163, + 10,164, 27,164, 51,164,146,166,180,166,217,166,229,167, 27,167, + 35,167,197,167,208,167,243,168, 87, 97, 11,161,177,161,188,161, + 198,161,205,162, 14,162, 30,162, 55,162, 66,162, 91,162,114,162, + 151,225,242,237,229,238,233,225,110,128, 5,124,226,229,238,231, + 225,236,105,128, 9,176,227,245,244,101,128, 1, 85,100, 4,161, + 215,161,221,161,235,162, 5,229,246, 97,128, 9, 48,233,227,225, + 108,129, 34, 26,161,230,229,120,128,248,229,239,246,229,242,243, + 243,241,245,225,242,101,129, 51,174,161,251,228,243,241,245,225, + 242,101,128, 51,175,243,241,245,225,242,101,128, 51,173,230,101, + 129, 5,191,162, 21,232,229,226,242,229,119,128, 5,191,231,117, + 2,162, 37,162, 46,234,225,242,225,244,105,128, 10,176,242,237, + 245,235,232,105,128, 10, 48,232,233,242,225,231,225,238, 97,128, + 48,137,235,225,244,225,235,225,238, 97,129, 48,233,162, 79,232, + 225,236,230,247,233,228,244,104,128,255,151,236,239,247,229,242, + 228,233,225,231,239,238,225,236,226,229,238,231,225,236,105,128, + 9,241,109, 2,162,120,162,143,233,228,228,236,229,228,233,225, + 231,239,238,225,236,226,229,238,231,225,236,105,128, 9,240,243, + 232,239,242,110,128, 2,100,244,233,111,128, 34, 54,226,239,240, + 239,237,239,230,111,128, 49, 22, 99, 4,162,178,162,185,162,194, + 162,202,225,242,239,110,128, 1, 89,229,228,233,236,236, 97,128, + 1, 87,233,242,227,236,101,128, 36,225,239,237,237,225,225,227, + 227,229,238,116,128, 1, 87,100, 2,162,221,162,231,226,236,231, + 242,225,246,101,128, 2, 17,239,116, 2,162,238,162,247,225,227, + 227,229,238,116,128, 30, 89,226,229,236,239,119,129, 30, 91,163, + 1,237,225,227,242,239,110,128, 30, 93,101, 6,163, 24,163, 69, + 163,104,163,159,163,184,163,217,102, 2,163, 30,163, 43,229,242, + 229,238,227,229,237,225,242,107,128, 32, 59,236,229,248,243,117, + 2,163, 53,163, 60,226,243,229,116,128, 34,134,240,229,242,243, + 229,116,128, 34,135,231,233,243,244,229,114, 2,163, 80,163, 85, + 229,100,128, 0,174,115, 2,163, 91,163, 97,225,238,115,128,248, + 232,229,242,233,102,128,246,218,104, 3,163,112,163,135,163,149, + 225,114, 2,163,119,163,126,225,226,233, 99,128, 6, 49,237,229, + 238,233,225,110,128, 5,128,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,174,233,242,225,231,225,238, 97,128, 48,140,235, + 225,244,225,235,225,238, 97,129, 48,236,163,172,232,225,236,230, + 247,233,228,244,104,128,255,154,243,104,130, 5,232,163,193,163, + 208,228,225,231,229,243,232,232,229,226,242,229,119,128,251, 72, + 232,229,226,242,229,119,128, 5,232,118, 3,163,225,163,238,164, + 14,229,242,243,229,228,244,233,236,228,101,128, 34, 61,233, 97, + 2,163,245,163,254,232,229,226,242,229,119,128, 5,151,237,245, + 231,242,225,243,232,232,229,226,242,229,119,128, 5,151,236,239, + 231,233,227,225,236,238,239,116,128, 35, 16,230,233,243,232,232, + 239,239,107,129, 2,126,164, 40,242,229,246,229,242,243,229,100, + 128, 2,127,104, 2,164, 57,164, 80, 97, 2,164, 63,164, 73,226, + 229,238,231,225,236,105,128, 9,221,228,229,246, 97,128, 9, 93, + 111,131, 3,193,164, 90,164,119,164,133,239,107,129, 2,125,164, + 97,244,245,242,238,229,100,129, 2,123,164,108,243,245,240,229, + 242,233,239,114,128, 2,181,243,249,237,226,239,236,231,242,229, + 229,107,128, 3,241,244,233,227,232,239,239,235,237,239,100,128, + 2,222,105, 6,164,160,165,204,165,250,166, 5,166, 30,166,166, + 229,245,108, 9,164,182,164,217,164,232,164,246,165, 36,165, 50, + 165,136,165,149,165,184, 97, 2,164,188,164,203,227,233,242,227, + 236,229,235,239,242,229,225,110,128, 50,113,240,225,242,229,238, + 235,239,242,229,225,110,128, 50, 17,227,233,242,227,236,229,235, + 239,242,229,225,110,128, 50, 99,232,233,229,245,232,235,239,242, + 229,225,110,128, 49, 64,107, 2,164,252,165, 28,233,249,229,239, + 107, 2,165, 6,165, 15,235,239,242,229,225,110,128, 49, 58,243, + 233,239,243,235,239,242,229,225,110,128, 49,105,239,242,229,225, + 110,128, 49, 57,237,233,229,245,237,235,239,242,229,225,110,128, + 49, 59,112, 3,165, 58,165, 90,165,105, 97, 2,165, 64,165, 78, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,108,242,229, + 238,235,239,242,229,225,110,128, 50, 3,232,233,229,245,240,232, + 235,239,242,229,225,110,128, 49, 63,233,229,245,112, 2,165,114, + 165,123,235,239,242,229,225,110,128, 49, 60,243,233,239,243,235, + 239,242,229,225,110,128, 49,107,243,233,239,243,235,239,242,229, + 225,110,128, 49, 61,116, 2,165,155,165,170,232,233,229,245,244, + 232,235,239,242,229,225,110,128, 49, 62,233,235,229,245,244,235, + 239,242,229,225,110,128, 49,106,249,229,239,242,233,238,232,233, + 229,245,232,235,239,242,229,225,110,128, 49,109,231,232,116, 2, + 165,212,165,220,225,238,231,236,101,128, 34, 31,116, 2,165,226, + 165,240,225,227,235,226,229,236,239,247,227,237, 98,128, 3, 25, + 242,233,225,238,231,236,101,128, 34,191,232,233,242,225,231,225, + 238, 97,128, 48,138,235,225,244,225,235,225,238, 97,129, 48,234, + 166, 18,232,225,236,230,247,233,228,244,104,128,255,152,110, 2, + 166, 36,166,152,103,131, 2,218,166, 46,166, 57,166, 63,226,229, + 236,239,247,227,237, 98,128, 3, 37,227,237, 98,128, 3, 10,232, + 225,236,102, 2,166, 72,166,118,236,229,230,116,131, 2,191,166, + 85,166, 96,166,107,225,242,237,229,238,233,225,110,128, 5, 89, + 226,229,236,239,247,227,237, 98,128, 3, 28,227,229,238,244,229, + 242,229,100,128, 2,211,242,233,231,232,116,130, 2,190,166,130, + 166,141,226,229,236,239,247,227,237, 98,128, 3, 57,227,229,238, + 244,229,242,229,100,128, 2,210,246,229,242,244,229,228,226,242, + 229,246,101,128, 2, 19,244,244,239,242,245,243,241,245,225,242, + 101,128, 51, 81,108, 2,166,186,166,197,233,238,229,226,229,236, + 239,119,128, 30, 95,239,238,231,236,229,103,129, 2,124,166,208, + 244,245,242,238,229,100,128, 2,122,237,239,238,239,243,240,225, + 227,101,128,255, 82,111, 3,166,237,166,248,167, 17,232,233,242, + 225,231,225,238, 97,128, 48,141,235,225,244,225,235,225,238, 97, + 129, 48,237,167, 5,232,225,236,230,247,233,228,244,104,128,255, + 155,242,245,225,244,232,225,105,128, 14, 35,240,225,242,229,110, + 128, 36,173,114, 3,167, 43,167, 79,167,109, 97, 3,167, 51,167, + 61,167, 68,226,229,238,231,225,236,105,128, 9,220,228,229,246, + 97,128, 9, 49,231,245,242,237,245,235,232,105,128, 10, 92,229, + 104, 2,167, 86,167, 95,225,242,225,226,233, 99,128, 6,145,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,141,246,239,227, + 225,236,233, 99, 4,167,125,167,135,167,142,167,153,226,229,238, + 231,225,236,105,128, 9,224,228,229,246, 97,128, 9, 96,231,245, + 234,225,242,225,244,105,128, 10,224,246,239,247,229,236,243,233, + 231,110, 3,167,169,167,179,167,186,226,229,238,231,225,236,105, + 128, 9,196,228,229,246, 97,128, 9, 68,231,245,234,225,242,225, + 244,105,128, 10,196,243,245,240,229,242,233,239,114,128,246,241, + 116, 2,167,214,167,222,226,236,239,227,107,128, 37,144,245,242, + 238,229,100,129, 2,121,167,232,243,245,240,229,242,233,239,114, + 128, 2,180,117, 4,167,253,168, 8,168, 33,168, 80,232,233,242, + 225,231,225,238, 97,128, 48,139,235,225,244,225,235,225,238, 97, + 129, 48,235,168, 21,232,225,236,230,247,233,228,244,104,128,255, + 153,112, 2,168, 39,168, 74,229,101, 2,168, 46,168, 60,237,225, + 242,235,226,229,238,231,225,236,105,128, 9,242,243,233,231,238, + 226,229,238,231,225,236,105,128, 9,243,233,225,104,128,246,221, + 244,232,225,105,128, 14, 36,246,239,227,225,236,233, 99, 4,168, + 103,168,113,168,120,168,131,226,229,238,231,225,236,105,128, 9, + 139,228,229,246, 97,128, 9, 11,231,245,234,225,242,225,244,105, + 128, 10,139,246,239,247,229,236,243,233,231,110, 3,168,147,168, + 157,168,164,226,229,238,231,225,236,105,128, 9,195,228,229,246, + 97,128, 9, 67,231,245,234,225,242,225,244,105,128, 10,195,115, + 147, 0,115,168,217,170,187,170,198,171, 68,171,107,174, 49,174, + 60,176,203,179, 85,179,131,179,158,180, 93,180,160,181,193,181, + 203,182,133,182,206,183,120,183,130, 97, 9,168,237,168,247,169, + 12,169, 84,169,109,169,120,169,145,169,177,169,217,226,229,238, + 231,225,236,105,128, 9,184,227,245,244,101,129, 1, 91,169, 0, + 228,239,244,225,227,227,229,238,116,128, 30,101,100, 5,169, 24, + 169, 33,169, 39,169, 53,169, 69,225,242,225,226,233, 99,128, 6, + 53,229,246, 97,128, 9, 56,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,186,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,254,187,237,229,228,233,225,236,225,242,225,226,233, + 99,128,254,188,231,117, 2,169, 91,169,100,234,225,242,225,244, + 105,128, 10,184,242,237,245,235,232,105,128, 10, 56,232,233,242, + 225,231,225,238, 97,128, 48, 85,235,225,244,225,235,225,238, 97, + 129, 48,181,169,133,232,225,236,230,247,233,228,244,104,128,255, + 123,236,236,225,236,236,225,232,239,245,225,236,225,249,232,229, + 247,225,243,225,236,236,225,237,225,242,225,226,233, 99,128,253, + 250,237,229,235,104,130, 5,225,169,188,169,208,228,225,231,229, + 243,104,129,251, 65,169,199,232,229,226,242,229,119,128,251, 65, + 232,229,226,242,229,119,128, 5,225,242, 97, 5,169,230,170, 48, + 170, 56,170,106,170,114, 97, 5,169,242,169,250,170, 2,170, 33, + 170, 41,225,244,232,225,105,128, 14, 50,229,244,232,225,105,128, + 14, 65,233,237,225,233,109, 2,170, 12,170, 23,225,236,225,233, + 244,232,225,105,128, 14, 68,245,225,238,244,232,225,105,128, 14, + 67,237,244,232,225,105,128, 14, 51,244,232,225,105,128, 14, 48, + 229,244,232,225,105,128, 14, 64,105, 3,170, 64,170, 88,170, 99, + 105, 2,170, 70,170, 81,236,229,230,244,244,232,225,105,128,248, + 134,244,232,225,105,128, 14, 53,236,229,230,244,244,232,225,105, + 128,248,133,244,232,225,105,128, 14, 52,239,244,232,225,105,128, + 14, 66,117, 3,170,122,170,172,170,179,101, 3,170,130,170,154, + 170,165,101, 2,170,136,170,147,236,229,230,244,244,232,225,105, + 128,248,136,244,232,225,105,128, 14, 55,236,229,230,244,244,232, + 225,105,128,248,135,244,232,225,105,128, 14, 54,244,232,225,105, + 128, 14, 56,245,244,232,225,105,128, 14, 57,226,239,240,239,237, + 239,230,111,128, 49, 25, 99, 5,170,210,170,231,170,240,171, 33, + 171, 55,225,242,239,110,129, 1, 97,170,219,228,239,244,225,227, + 227,229,238,116,128, 30,103,229,228,233,236,236, 97,128, 1, 95, + 232,247, 97,131, 2, 89,170,252,171, 7,171, 26,227,249,242,233, + 236,236,233, 99,128, 4,217,228,233,229,242,229,243,233,243,227, + 249,242,233,236,236,233, 99,128, 4,219,232,239,239,107,128, 2, + 90,233,242, 99, 2,171, 41,171, 46,236,101,128, 36,226,245,237, + 230,236,229,120,128, 1, 93,239,237,237,225,225,227,227,229,238, + 116,128, 2, 25,228,239,116, 2,171, 76,171, 85,225,227,227,229, + 238,116,128, 30, 97,226,229,236,239,119,129, 30, 99,171, 95,228, + 239,244,225,227,227,229,238,116,128, 30,105,101, 9,171,127,171, + 143,171,178,171,243,172, 90,172,117,172,142,172,223,172,250,225, + 231,245,236,236,226,229,236,239,247,227,237, 98,128, 3, 60, 99, + 2,171,149,171,171,239,238,100,129, 32, 51,171,157,244,239,238, + 229,227,232,233,238,229,243,101,128, 2,202,244,233,239,110,128, + 0,167,229,110, 4,171,189,171,198,171,212,171,228,225,242,225, + 226,233, 99,128, 6, 51,230,233,238,225,236,225,242,225,226,233, + 99,128,254,178,233,238,233,244,233,225,236,225,242,225,226,233, + 99,128,254,179,237,229,228,233,225,236,225,242,225,226,233, 99, + 128,254,180,231,239,108,135, 5,182,172, 7,172, 21,172, 26,172, + 35,172, 50,172, 66,172, 77, 49, 2,172, 13,172, 17, 51,128, 5, + 182,102,128, 5,182,178, 99,128, 5,182,232,229,226,242,229,119, + 128, 5,182,238,225,242,242,239,247,232,229,226,242,229,119,128, + 5,182,241,245,225,242,244,229,242,232,229,226,242,229,119,128, + 5,182,244,225,232,229,226,242,229,119,128, 5,146,247,233,228, + 229,232,229,226,242,229,119,128, 5,182,104, 2,172, 96,172,107, + 225,242,237,229,238,233,225,110,128, 5,125,233,242,225,231,225, + 238, 97,128, 48, 91,235,225,244,225,235,225,238, 97,129, 48,187, + 172,130,232,225,236,230,247,233,228,244,104,128,255,126,237,105, + 2,172,149,172,192,227,239,236,239,110,131, 0, 59,172,163,172, + 172,172,184,225,242,225,226,233, 99,128, 6, 27,237,239,238,239, + 243,240,225,227,101,128,255, 27,243,237,225,236,108,128,254, 84, + 246,239,233,227,229,228,237,225,242,235,235,225,238, 97,129, 48, + 156,172,211,232,225,236,230,247,233,228,244,104,128,255,159,238, + 116, 2,172,230,172,240,233,243,241,245,225,242,101,128, 51, 34, + 239,243,241,245,225,242,101,128, 51, 35,246,229,110,142, 0, 55, + 173, 28,173, 37,173, 47,173, 77,173, 84,173, 94,173,119,173,146, + 173,180,173,192,173,203,173,236,173,244,173,255,225,242,225,226, + 233, 99,128, 6,103,226,229,238,231,225,236,105,128, 9,237,227, + 233,242,227,236,101,129, 36,102,173, 58,233,238,246,229,242,243, + 229,243,225,238,243,243,229,242,233,102,128, 39,144,228,229,246, + 97,128, 9,109,229,233,231,232,244,232,115,128, 33, 94,231,117, + 2,173,101,173,110,234,225,242,225,244,105,128, 10,237,242,237, + 245,235,232,105,128, 10,109,232, 97, 2,173,126,173,137,227,235, + 225,242,225,226,233, 99,128, 6,103,238,231,250,232,239,117,128, + 48, 39,105, 2,173,152,173,170,228,229,239,231,242,225,240,232, + 233,227,240,225,242,229,110,128, 50, 38,238,230,229,242,233,239, + 114,128, 32,135,237,239,238,239,243,240,225,227,101,128,255, 23, + 239,236,228,243,244,249,236,101,128,247, 55,112, 2,173,209,173, + 216,225,242,229,110,128, 36,122,229,114, 2,173,223,173,229,233, + 239,100,128, 36,142,243,233,225,110,128, 6,247,242,239,237,225, + 110,128, 33,118,243,245,240,229,242,233,239,114,128, 32,119,116, + 2,174, 5,174, 43,229,229,110, 2,174, 13,174, 22,227,233,242, + 227,236,101,128, 36,112,112, 2,174, 28,174, 35,225,242,229,110, + 128, 36,132,229,242,233,239,100,128, 36,152,232,225,105,128, 14, + 87,230,244,232,249,240,232,229,110,128, 0,173,104, 7,174, 76, + 175, 50,175, 61,175, 75,176, 20,176, 33,176,197, 97, 6,174, 90, + 174,101,174,111,174,122,175, 9,175, 34,225,242,237,229,238,233, + 225,110,128, 5,119,226,229,238,231,225,236,105,128, 9,182,227, + 249,242,233,236,236,233, 99,128, 4, 72,100, 2,174,128,174,224, + 228, 97, 4,174,139,174,148,174,179,174,193,225,242,225,226,233, + 99,128, 6, 81,228,225,237,237, 97, 2,174,158,174,167,225,242, + 225,226,233, 99,128,252, 97,244,225,238,225,242,225,226,233, 99, + 128,252, 94,230,225,244,232,225,225,242,225,226,233, 99,128,252, + 96,235,225,243,242, 97, 2,174,203,174,212,225,242,225,226,233, + 99,128,252, 98,244,225,238,225,242,225,226,233, 99,128,252, 95, + 101,132, 37,146,174,236,174,243,174,251,175, 4,228,225,242,107, + 128, 37,147,236,233,231,232,116,128, 37,145,237,229,228,233,245, + 109,128, 37,146,246, 97,128, 9, 54,231,117, 2,175, 16,175, 25, + 234,225,242,225,244,105,128, 10,182,242,237,245,235,232,105,128, + 10, 54,236,243,232,229,236,229,244,232,229,226,242,229,119,128, + 5,147,226,239,240,239,237,239,230,111,128, 49, 21,227,232,225, + 227,249,242,233,236,236,233, 99,128, 4, 73,101, 4,175, 85,175, + 150,175,160,175,177,229,110, 4,175, 96,175,105,175,119,175,135, + 225,242,225,226,233, 99,128, 6, 52,230,233,238,225,236,225,242, + 225,226,233, 99,128,254,182,233,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,254,183,237,229,228,233,225,236,225,242,225, + 226,233, 99,128,254,184,233,227,239,240,244,233, 99,128, 3,227, + 241,229,108,129, 32,170,175,168,232,229,226,242,229,119,128, 32, + 170,246, 97,134, 5,176,175,194,175,209,175,223,175,232,175,247, + 176, 7, 49, 2,175,200,175,205,177, 53,128, 5,176, 53,128, 5, + 176, 50, 2,175,215,175,219, 50,128, 5,176,101,128, 5,176,232, + 229,226,242,229,119,128, 5,176,238,225,242,242,239,247,232,229, + 226,242,229,119,128, 5,176,241,245,225,242,244,229,242,232,229, + 226,242,229,119,128, 5,176,247,233,228,229,232,229,226,242,229, + 119,128, 5,176,232,225,227,249,242,233,236,236,233, 99,128, 4, + 187,105, 2,176, 39,176, 50,237,225,227,239,240,244,233, 99,128, + 3,237,110,131, 5,233,176, 60,176,143,176,152,100, 2,176, 66, + 176,132,225,231,229,243,104,130,251, 73,176, 78,176, 87,232,229, + 226,242,229,119,128,251, 73,115, 2,176, 93,176,113,232,233,238, + 228,239,116,129,251, 44,176,104,232,229,226,242,229,119,128,251, + 44,233,238,228,239,116,129,251, 45,176,123,232,229,226,242,229, + 119,128,251, 45,239,244,232,229,226,242,229,119,128, 5,193,232, + 229,226,242,229,119,128, 5,233,115, 2,176,158,176,178,232,233, + 238,228,239,116,129,251, 42,176,169,232,229,226,242,229,119,128, + 251, 42,233,238,228,239,116,129,251, 43,176,188,232,229,226,242, + 229,119,128,251, 43,239,239,107,128, 2,130,105, 8,176,221,177, + 9,177, 20,177, 45,177, 75,177, 83,177, 96,178, 11,231,237, 97, + 131, 3,195,176,233,176,237,176,245, 49,128, 3,194,230,233,238, + 225,108,128, 3,194,236,245,238,225,244,229,243,249,237,226,239, + 236,231,242,229,229,107,128, 3,242,232,233,242,225,231,225,238, + 97,128, 48, 87,235,225,244,225,235,225,238, 97,129, 48,183,177, + 33,232,225,236,230,247,233,228,244,104,128,255,124,236,245,113, + 2,177, 53,177, 62,232,229,226,242,229,119,128, 5,189,236,229, + 230,244,232,229,226,242,229,119,128, 5,189,237,233,236,225,114, + 128, 34, 60,238,228,239,244,232,229,226,242,229,119,128, 5,194, + 239,115, 6,177,111,177,146,177,178,177,206,177,220,177,252, 97, + 2,177,117,177,132,227,233,242,227,236,229,235,239,242,229,225, + 110,128, 50,116,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 20,227,105, 2,177,153,177,165,229,245,227,235,239,242,229, + 225,110,128, 49,126,242,227,236,229,235,239,242,229,225,110,128, + 50,102,107, 2,177,184,177,198,233,249,229,239,235,235,239,242, + 229,225,110,128, 49,122,239,242,229,225,110,128, 49, 69,238,233, + 229,245,238,235,239,242,229,225,110,128, 49,123,112, 2,177,226, + 177,239,225,242,229,238,235,239,242,229,225,110,128, 50, 6,233, + 229,245,240,235,239,242,229,225,110,128, 49,125,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49,124,120,141, 0, 54,178, + 41,178, 50,178, 60,178, 90,178, 97,178,122,178,149,178,183,178, + 195,178,206,178,239,178,247,179, 2,225,242,225,226,233, 99,128, + 6,102,226,229,238,231,225,236,105,128, 9,236,227,233,242,227, + 236,101,129, 36,101,178, 71,233,238,246,229,242,243,229,243,225, + 238,243,243,229,242,233,102,128, 39,143,228,229,246, 97,128, 9, + 108,231,117, 2,178,104,178,113,234,225,242,225,244,105,128, 10, + 236,242,237,245,235,232,105,128, 10,108,232, 97, 2,178,129,178, + 140,227,235,225,242,225,226,233, 99,128, 6,102,238,231,250,232, + 239,117,128, 48, 38,105, 2,178,155,178,173,228,229,239,231,242, + 225,240,232,233,227,240,225,242,229,110,128, 50, 37,238,230,229, + 242,233,239,114,128, 32,134,237,239,238,239,243,240,225,227,101, + 128,255, 22,239,236,228,243,244,249,236,101,128,247, 54,112, 2, + 178,212,178,219,225,242,229,110,128, 36,121,229,114, 2,178,226, + 178,232,233,239,100,128, 36,141,243,233,225,110,128, 6,246,242, + 239,237,225,110,128, 33,117,243,245,240,229,242,233,239,114,128, + 32,118,116, 2,179, 8,179, 79,229,229,110, 2,179, 16,179, 58, + 99, 2,179, 22,179, 30,233,242,227,236,101,128, 36,111,245,242, + 242,229,238,227,249,228,229,238,239,237,233,238,225,244,239,242, + 226,229,238,231,225,236,105,128, 9,249,112, 2,179, 64,179, 71, + 225,242,229,110,128, 36,131,229,242,233,239,100,128, 36,151,232, + 225,105,128, 14, 86,108, 2,179, 91,179,111,225,243,104,129, 0, + 47,179, 99,237,239,238,239,243,240,225,227,101,128,255, 15,239, + 238,103,129, 1,127,179,119,228,239,244,225,227,227,229,238,116, + 128, 30,155,109, 2,179,137,179,147,233,236,229,230,225,227,101, + 128, 38, 58,239,238,239,243,240,225,227,101,128,255, 83,111, 6, + 179,172,179,222,179,233,180, 2,180, 47,180, 58,102, 2,179,178, + 179,192,240,225,243,245,241,232,229,226,242,229,119,128, 5,195, + 116, 2,179,198,179,207,232,249,240,232,229,110,128, 0,173,243, + 233,231,238,227,249,242,233,236,236,233, 99,128, 4, 76,232,233, + 242,225,231,225,238, 97,128, 48, 93,235,225,244,225,235,225,238, + 97,129, 48,189,179,246,232,225,236,230,247,233,228,244,104,128, + 255,127,236,233,228,245,115, 2,180, 12,180, 29,236,239,238,231, + 239,246,229,242,236,225,249,227,237, 98,128, 3, 56,243,232,239, + 242,244,239,246,229,242,236,225,249,227,237, 98,128, 3, 55,242, + 245,243,233,244,232,225,105,128, 14, 41,115, 3,180, 66,180, 76, + 180, 84,225,236,225,244,232,225,105,128, 14, 40,239,244,232,225, + 105,128, 14, 11,245,225,244,232,225,105,128, 14, 42,240, 97, 3, + 180,102,180,122,180,154,227,101,129, 0, 32,180,109,232,225,227, + 235,225,242,225,226,233, 99,128, 0, 32,228,101,129, 38, 96,180, + 129,243,245,233,116, 2,180,138,180,146,226,236,225,227,107,128, + 38, 96,247,232,233,244,101,128, 38,100,242,229,110,128, 36,174, + 241,245,225,242,101, 11,180,188,180,199,180,213,180,238,180,255, + 181, 25,181, 40,181, 73,181,100,181,156,181,171,226,229,236,239, + 247,227,237, 98,128, 3, 59, 99, 2,180,205,180,209, 99,128, 51, + 196,109,128, 51,157,228,233,225,231,239,238,225,236,227,242,239, + 243,243,232,225,244,227,232,230,233,236,108,128, 37,169,232,239, + 242,233,250,239,238,244,225,236,230,233,236,108,128, 37,164,107, + 2,181, 5,181, 9,103,128, 51,143,109,129, 51,158,181, 15,227, + 225,240,233,244,225,108,128, 51,206,108, 2,181, 31,181, 35,110, + 128, 51,209,239,103,128, 51,210,109, 4,181, 50,181, 54,181, 59, + 181, 63,103,128, 51,142,233,108,128, 51,213,109,128, 51,156,243, + 241,245,225,242,229,100,128, 51,161,239,242,244,232,239,231,239, + 238,225,236,227,242,239,243,243,232,225,244,227,232,230,233,236, + 108,128, 37,166,245,240,240,229,114, 2,181,110,181,133,236,229, + 230,244,244,239,236,239,247,229,242,242,233,231,232,244,230,233, + 236,108,128, 37,167,242,233,231,232,244,244,239,236,239,247,229, + 242,236,229,230,244,230,233,236,108,128, 37,168,246,229,242,244, + 233,227,225,236,230,233,236,108,128, 37,165,247,232,233,244,229, + 247,233,244,232,243,237,225,236,236,226,236,225,227,107,128, 37, + 163,242,243,241,245,225,242,101,128, 51,219,115, 2,181,209,182, + 123, 97, 4,181,219,181,229,181,236,181,247,226,229,238,231,225, + 236,105,128, 9,183,228,229,246, 97,128, 9, 55,231,245,234,225, + 242,225,244,105,128, 10,183,238,103, 8,182, 10,182, 24,182, 38, + 182, 52,182, 67,182, 81,182, 95,182,108,227,233,229,245,227,235, + 239,242,229,225,110,128, 49, 73,232,233,229,245,232,235,239,242, + 229,225,110,128, 49,133,233,229,245,238,231,235,239,242,229,225, + 110,128, 49,128,235,233,249,229,239,235,235,239,242,229,225,110, + 128, 49, 50,238,233,229,245,238,235,239,242,229,225,110,128, 49, + 101,240,233,229,245,240,235,239,242,229,225,110,128, 49, 67,243, + 233,239,243,235,239,242,229,225,110,128, 49, 70,244,233,235,229, + 245,244,235,239,242,229,225,110,128, 49, 56,245,240,229,242,233, + 239,114,128,246,242,116, 2,182,139,182,162,229,242,236,233,238, + 103,129, 0,163,182,150,237,239,238,239,243,240,225,227,101,128, + 255,225,242,239,235,101, 2,182,171,182,188,236,239,238,231,239, + 246,229,242,236,225,249,227,237, 98,128, 3, 54,243,232,239,242, + 244,239,246,229,242,236,225,249,227,237, 98,128, 3, 53,117, 7, + 182,222,182,254,183, 20,183, 31,183, 72,183, 82,183, 86,226,243, + 229,116,130, 34,130,182,233,182,244,238,239,244,229,241,245,225, + 108,128, 34,138,239,242,229,241,245,225,108,128, 34,134, 99, 2, + 183, 4,183, 12,227,229,229,228,115,128, 34,123,232,244,232,225, + 116,128, 34, 11,232,233,242,225,231,225,238, 97,128, 48, 89,107, + 2,183, 37,183, 61,225,244,225,235,225,238, 97,129, 48,185,183, + 49,232,225,236,230,247,233,228,244,104,128,255,125,245,238,225, + 242,225,226,233, 99,128, 6, 82,237,237,225,244,233,239,110,128, + 34, 17,110,128, 38, 60,240,229,242,243,229,116,130, 34,131,183, + 99,183,110,238,239,244,229,241,245,225,108,128, 34,139,239,242, + 229,241,245,225,108,128, 34,135,246,243,241,245,225,242,101,128, + 51,220,249,239,245,247,225,229,242,225,243,241,245,225,242,101, + 128, 51,124,116,144, 0,116,183,183,184,192,184,213,185,100,185, + 140,187,188,191, 70,192,145,192,157,192,169,193,202,193,227,194, + 57,194,237,195,165,195,255, 97, 10,183,205,183,215,183,236,183, + 243,184, 12,184, 90,184,107,184,132,184,146,184,150,226,229,238, + 231,225,236,105,128, 9,164,227,107, 2,183,222,183,229,228,239, + 247,110,128, 34,164,236,229,230,116,128, 34,163,228,229,246, 97, + 128, 9, 36,231,117, 2,183,250,184, 3,234,225,242,225,244,105, + 128, 10,164,242,237,245,235,232,105,128, 10, 36,104, 4,184, 22, + 184, 31,184, 45,184, 75,225,242,225,226,233, 99,128, 6, 55,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,194,105, 2,184, + 51,184, 66,238,233,244,233,225,236,225,242,225,226,233, 99,128, + 254,195,242,225,231,225,238, 97,128, 48, 95,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,254,196,233,243,249,239,245,229, + 242,225,243,241,245,225,242,101,128, 51,125,235,225,244,225,235, + 225,238, 97,129, 48,191,184,120,232,225,236,230,247,233,228,244, + 104,128,255,128,244,247,229,229,236,225,242,225,226,233, 99,128, + 6, 64,117,128, 3,196,118,130, 5,234,184,158,184,183,228,225, + 231,229,115,129,251, 74,184,168,104,129,251, 74,184,174,232,229, + 226,242,229,119,128,251, 74,232,229,226,242,229,119,128, 5,234, + 98, 2,184,198,184,203,225,114,128, 1,103,239,240,239,237,239, + 230,111,128, 49, 10, 99, 6,184,227,184,234,184,241,184,250,185, + 60,185, 87,225,242,239,110,128, 1,101,227,245,242,108,128, 2, + 168,229,228,233,236,236, 97,128, 1, 99,232,229,104, 4,185, 6, + 185, 15,185, 29,185, 45,225,242,225,226,233, 99,128, 6,134,230, + 233,238,225,236,225,242,225,226,233, 99,128,251,123,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,251,124,237,229,228, + 233,225,236,225,242,225,226,233, 99,128,251,125,233,242, 99, 2, + 185, 68,185, 73,236,101,128, 36,227,245,237,230,236,229,248,226, + 229,236,239,119,128, 30,113,239,237,237,225,225,227,227,229,238, + 116,128, 1, 99,100, 2,185,106,185,116,233,229,242,229,243,233, + 115,128, 30,151,239,116, 2,185,123,185,132,225,227,227,229,238, + 116,128, 30,107,226,229,236,239,119,128, 30,109,101, 9,185,160, + 185,171,185,191,186,201,186,226,187, 34,187,101,187,106,187,158, + 227,249,242,233,236,236,233, 99,128, 4, 66,228,229,243,227,229, + 238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,173,104, + 7,185,207,185,216,185,230,186, 14,186, 44,186, 85,186,183,225, + 242,225,226,233, 99,128, 6, 42,230,233,238,225,236,225,242,225, + 226,233, 99,128,254,150,232,225,232,105, 2,185,239,185,254,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,252,162,243,239, + 236,225,244,229,228,225,242,225,226,233, 99,128,252, 12,105, 2, + 186, 20,186, 35,238,233,244,233,225,236,225,242,225,226,233, 99, + 128,254,151,242,225,231,225,238, 97,128, 48,102,234,229,229,237, + 105, 2,186, 54,186, 69,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,252,161,243,239,236,225,244,229,228,225,242,225,226, + 233, 99,128,252, 11,109, 2,186, 91,186,125,225,242,226,245,244, + 97, 2,186,102,186,111,225,242,225,226,233, 99,128, 6, 41,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,148,101, 2,186, + 131,186,144,228,233,225,236,225,242,225,226,233, 99,128,254,152, + 229,237,105, 2,186,152,186,167,238,233,244,233,225,236,225,242, + 225,226,233, 99,128,252,164,243,239,236,225,244,229,228,225,242, + 225,226,233, 99,128,252, 14,238,239,239,238,230,233,238,225,236, + 225,242,225,226,233, 99,128,252,115,235,225,244,225,235,225,238, + 97,129, 48,198,186,214,232,225,236,230,247,233,228,244,104,128, + 255,131,108, 2,186,232,186,251,229,240,232,239,238,101,129, 33, + 33,186,243,226,236,225,227,107,128, 38, 14,233,243,232, 97, 2, + 187, 4,187, 19,231,229,228,239,236,225,232,229,226,242,229,119, + 128, 5,160,241,229,244,225,238,225,232,229,226,242,229,119,128, + 5,169,110, 4,187, 44,187, 53,187, 72,187, 93,227,233,242,227, + 236,101,128, 36,105,233,228,229,239,231,242,225,240,232,233,227, + 240,225,242,229,110,128, 50, 41,112, 2,187, 78,187, 85,225,242, + 229,110,128, 36,125,229,242,233,239,100,128, 36,145,242,239,237, + 225,110,128, 33,121,243,104,128, 2,167,116,131, 5,216,187,116, + 187,136,187,145,228,225,231,229,243,104,129,251, 56,187,127,232, + 229,226,242,229,119,128,251, 56,232,229,226,242,229,119,128, 5, + 216,243,229,227,249,242,233,236,236,233, 99,128, 4,181,246,233, + 114, 2,187,166,187,175,232,229,226,242,229,119,128, 5,155,236, + 229,230,244,232,229,226,242,229,119,128, 5,155,104, 6,187,202, + 188, 98,188,220,189, 96,190, 3,191, 60, 97, 5,187,214,187,224, + 187,231,188, 0,188, 29,226,229,238,231,225,236,105,128, 9,165, + 228,229,246, 97,128, 9, 37,231,117, 2,187,238,187,247,234,225, + 242,225,244,105,128, 10,165,242,237,245,235,232,105,128, 10, 37, + 108, 2,188, 6,188, 15,225,242,225,226,233, 99,128, 6, 48,230, + 233,238,225,236,225,242,225,226,233, 99,128,254,172,238,244,232, + 225,235,232,225,116, 3,188, 44,188, 75,188, 82,236,239,119, 2, + 188, 52,188, 63,236,229,230,244,244,232,225,105,128,248,152,242, + 233,231,232,244,244,232,225,105,128,248,151,244,232,225,105,128, + 14, 76,245,240,240,229,242,236,229,230,244,244,232,225,105,128, + 248,150,101, 3,188,106,188,170,188,193,104, 4,188,116,188,125, + 188,139,188,155,225,242,225,226,233, 99,128, 6, 43,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,154,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,254,155,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,254,156,242,101, 2,188,177,188, + 186,229,248,233,243,244,115,128, 34, 3,230,239,242,101,128, 34, + 52,244, 97,130, 3,184,188,202,188,206, 49,128, 3,209,243,249, + 237,226,239,236,231,242,229,229,107,128, 3,209,105, 2,188,226, + 189, 56,229,245,244,104, 4,188,239,189, 18,189, 33,189, 42, 97, + 2,188,245,189, 4,227,233,242,227,236,229,235,239,242,229,225, + 110,128, 50,121,240,225,242,229,238,235,239,242,229,225,110,128, + 50, 25,227,233,242,227,236,229,235,239,242,229,225,110,128, 50, + 107,235,239,242,229,225,110,128, 49, 76,240,225,242,229,238,235, + 239,242,229,225,110,128, 50, 11,242,244,229,229,110, 2,189, 66, + 189, 75,227,233,242,227,236,101,128, 36,108,112, 2,189, 81,189, + 88,225,242,229,110,128, 36,128,229,242,233,239,100,128, 36,148, + 111, 6,189,110,189,127,189,132,189,146,189,151,189,204,238,225, + 238,231,237,239,238,244,232,239,244,232,225,105,128, 14, 17,239, + 107,128, 1,173,240,232,245,244,232,225,239,244,232,225,105,128, + 14, 18,242,110,128, 0,254,244,104, 3,189,160,189,184,189,194, + 97, 2,189,166,189,176,232,225,238,244,232,225,105,128, 14, 23, + 238,244,232,225,105,128, 14, 16,239,238,231,244,232,225,105,128, + 14, 24,245,238,231,244,232,225,105,128, 14, 22,245,243,225,238, + 100, 2,189,214,189,225,227,249,242,233,236,236,233, 99,128, 4, + 130,243,243,229,240,225,242,225,244,239,114, 2,189,240,189,249, + 225,242,225,226,233, 99,128, 6,108,240,229,242,243,233,225,110, + 128, 6,108,242,229,101,144, 0, 51,190, 41,190, 50,190, 60,190, + 90,190, 97,190,107,190,132,190,159,190,193,190,205,190,224,190, + 235,191, 12,191, 34,191, 42,191, 53,225,242,225,226,233, 99,128, + 6, 99,226,229,238,231,225,236,105,128, 9,233,227,233,242,227, + 236,101,129, 36, 98,190, 71,233,238,246,229,242,243,229,243,225, + 238,243,243,229,242,233,102,128, 39,140,228,229,246, 97,128, 9, + 105,229,233,231,232,244,232,115,128, 33, 92,231,117, 2,190,114, + 190,123,234,225,242,225,244,105,128, 10,233,242,237,245,235,232, + 105,128, 10,105,232, 97, 2,190,139,190,150,227,235,225,242,225, + 226,233, 99,128, 6, 99,238,231,250,232,239,117,128, 48, 35,105, + 2,190,165,190,183,228,229,239,231,242,225,240,232,233,227,240, + 225,242,229,110,128, 50, 34,238,230,229,242,233,239,114,128, 32, + 131,237,239,238,239,243,240,225,227,101,128,255, 19,238,245,237, + 229,242,225,244,239,242,226,229,238,231,225,236,105,128, 9,246, + 239,236,228,243,244,249,236,101,128,247, 51,112, 2,190,241,190, + 248,225,242,229,110,128, 36,118,229,114, 2,190,255,191, 5,233, + 239,100,128, 36,138,243,233,225,110,128, 6,243,241,245,225,242, + 244,229,242,115,129, 0,190,191, 25,229,237,228,225,243,104,128, + 246,222,242,239,237,225,110,128, 33,114,243,245,240,229,242,233, + 239,114,128, 0,179,244,232,225,105,128, 14, 83,250,243,241,245, + 225,242,101,128, 51,148,105, 7,191, 86,191, 97,191,212,192, 54, + 192, 66,192,115,192,132,232,233,242,225,231,225,238, 97,128, 48, + 97,107, 2,191,103,191,127,225,244,225,235,225,238, 97,129, 48, + 193,191,115,232,225,236,230,247,233,228,244,104,128,255,129,229, + 245,116, 4,191,139,191,174,191,189,191,198, 97, 2,191,145,191, + 160,227,233,242,227,236,229,235,239,242,229,225,110,128, 50,112, + 240,225,242,229,238,235,239,242,229,225,110,128, 50, 16,227,233, + 242,227,236,229,235,239,242,229,225,110,128, 50, 98,235,239,242, + 229,225,110,128, 49, 55,240,225,242,229,238,235,239,242,229,225, + 110,128, 50, 2,236,228,101,133, 2,220,191,228,191,239,192, 0, + 192, 12,192, 40,226,229,236,239,247,227,237, 98,128, 3, 48, 99, + 2,191,245,191,250,237, 98,128, 3, 3,239,237, 98,128, 3, 3, + 228,239,245,226,236,229,227,237, 98,128, 3, 96,111, 2,192, 18, + 192, 28,240,229,242,225,244,239,114,128, 34, 60,246,229,242,236, + 225,249,227,237, 98,128, 3, 52,246,229,242,244,233,227,225,236, + 227,237, 98,128, 3, 62,237,229,243,227,233,242,227,236,101,128, + 34,151,112, 2,192, 72,192,102,229,232, 97, 2,192, 80,192, 89, + 232,229,226,242,229,119,128, 5,150,236,229,230,244,232,229,226, + 242,229,119,128, 5,150,240,233,231,245,242,237,245,235,232,105, + 128, 10,112,244,236,239,227,249,242,233,236,236,233,227,227,237, + 98,128, 4,131,247,238,225,242,237,229,238,233,225,110,128, 5, + 127,236,233,238,229,226,229,236,239,119,128, 30,111,237,239,238, + 239,243,240,225,227,101,128,255, 84,111, 7,192,185,192,196,192, + 207,192,232,193, 96,193,108,193,192,225,242,237,229,238,233,225, + 110,128, 5,105,232,233,242,225,231,225,238, 97,128, 48,104,235, + 225,244,225,235,225,238, 97,129, 48,200,192,220,232,225,236,230, + 247,233,228,244,104,128,255,132,110, 3,192,240,193, 82,193, 87, + 101, 4,192,250,193, 63,193, 70,193, 76,226,225,114, 4,193, 6, + 193, 35,193, 45,193, 54,229,248,244,242, 97, 2,193, 16,193, 26, + 232,233,231,232,237,239,100,128, 2,229,236,239,247,237,239,100, + 128, 2,233,232,233,231,232,237,239,100,128, 2,230,236,239,247, + 237,239,100,128, 2,232,237,233,228,237,239,100,128, 2,231,230, + 233,246,101,128, 1,189,243,233,120,128, 1,133,244,247,111,128, + 1,168,239,115,128, 3,132,243,241,245,225,242,101,128, 51, 39, + 240,225,244,225,235,244,232,225,105,128, 14, 15,242,244,239,233, + 243,229,243,232,229,236,236,226,242,225,227,235,229,116, 2,193, + 131,193,161,236,229,230,116,130, 48, 20,193,142,193,150,243,237, + 225,236,108,128,254, 93,246,229,242,244,233,227,225,108,128,254, + 57,242,233,231,232,116,130, 48, 21,193,173,193,181,243,237,225, + 236,108,128,254, 94,246,229,242,244,233,227,225,108,128,254, 58, + 244,225,239,244,232,225,105,128, 14, 21,240, 97, 2,193,209,193, + 221,236,225,244,225,236,232,239,239,107,128, 1,171,242,229,110, + 128, 36,175,114, 3,193,235,194, 10,194, 25,225,228,229,237,225, + 242,107,129, 33, 34,193,247,115, 2,193,253,194, 3,225,238,115, + 128,248,234,229,242,233,102,128,246,219,229,244,242,239,230,236, + 229,248,232,239,239,107,128, 2,136,233,225,103, 4,194, 37,194, + 42,194, 47,194, 52,228,110,128, 37,188,236,102,128, 37,196,242, + 116,128, 37,186,245,112,128, 37,178,115,132, 2,166,194, 69,194, + 108,194,214,194,227,225,228,105,130, 5,230,194, 79,194, 99,228, + 225,231,229,243,104,129,251, 70,194, 90,232,229,226,242,229,119, + 128,251, 70,232,229,226,242,229,119,128, 5,230,101, 2,194,114, + 194,125,227,249,242,233,236,236,233, 99,128, 4, 70,242,101,134, + 5,181,194,142,194,156,194,161,194,170,194,185,194,201, 49, 2, + 194,148,194,152, 50,128, 5,181,101,128, 5,181,178, 98,128, 5, + 181,232,229,226,242,229,119,128, 5,181,238,225,242,242,239,247, + 232,229,226,242,229,119,128, 5,181,241,245,225,242,244,229,242, + 232,229,226,242,229,119,128, 5,181,247,233,228,229,232,229,226, + 242,229,119,128, 5,181,232,229,227,249,242,233,236,236,233, 99, + 128, 4, 91,245,240,229,242,233,239,114,128,246,243,116, 4,194, + 247,195, 41,195,106,195,157, 97, 3,194,255,195, 9,195, 16,226, + 229,238,231,225,236,105,128, 9,159,228,229,246, 97,128, 9, 31, + 231,117, 2,195, 23,195, 32,234,225,242,225,244,105,128, 10,159, + 242,237,245,235,232,105,128, 10, 31,229,104, 4,195, 52,195, 61, + 195, 75,195, 91,225,242,225,226,233, 99,128, 6,121,230,233,238, + 225,236,225,242,225,226,233, 99,128,251,103,233,238,233,244,233, + 225,236,225,242,225,226,233, 99,128,251,104,237,229,228,233,225, + 236,225,242,225,226,233, 99,128,251,105,232, 97, 3,195,115,195, + 125,195,132,226,229,238,231,225,236,105,128, 9,160,228,229,246, + 97,128, 9, 32,231,117, 2,195,139,195,148,234,225,242,225,244, + 105,128, 10,160,242,237,245,235,232,105,128, 10, 32,245,242,238, + 229,100,128, 2,135,117, 3,195,173,195,184,195,209,232,233,242, + 225,231,225,238, 97,128, 48,100,235,225,244,225,235,225,238, 97, + 129, 48,196,195,197,232,225,236,230,247,233,228,244,104,128,255, + 130,243,237,225,236,108, 2,195,219,195,230,232,233,242,225,231, + 225,238, 97,128, 48, 99,235,225,244,225,235,225,238, 97,129, 48, + 195,195,243,232,225,236,230,247,233,228,244,104,128,255,111,119, + 2,196, 5,196,110,101, 2,196, 11,196, 59,236,246,101, 3,196, + 21,196, 30,196, 51,227,233,242,227,236,101,128, 36,107,112, 2, + 196, 36,196, 43,225,242,229,110,128, 36,127,229,242,233,239,100, + 128, 36,147,242,239,237,225,110,128, 33,123,238,244,121, 3,196, + 69,196, 78,196, 89,227,233,242,227,236,101,128, 36,115,232,225, + 238,231,250,232,239,117,128, 83, 68,112, 2,196, 95,196,102,225, + 242,229,110,128, 36,135,229,242,233,239,100,128, 36,155,111,142, + 0, 50,196,142,196,151,196,161,196,191,196,243,197, 12,197, 39, + 197, 73,197, 85,197,104,197,115,197,148,197,156,197,180,225,242, + 225,226,233, 99,128, 6, 98,226,229,238,231,225,236,105,128, 9, + 232,227,233,242,227,236,101,129, 36, 97,196,172,233,238,246,229, + 242,243,229,243,225,238,243,243,229,242,233,102,128, 39,139,100, + 2,196,197,196,203,229,246, 97,128, 9,104,239,116, 2,196,210, + 196,221,229,238,236,229,225,228,229,114,128, 32, 37,236,229,225, + 228,229,114,129, 32, 37,196,232,246,229,242,244,233,227,225,108, + 128,254, 48,231,117, 2,196,250,197, 3,234,225,242,225,244,105, + 128, 10,232,242,237,245,235,232,105,128, 10,104,232, 97, 2,197, + 19,197, 30,227,235,225,242,225,226,233, 99,128, 6, 98,238,231, + 250,232,239,117,128, 48, 34,105, 2,197, 45,197, 63,228,229,239, + 231,242,225,240,232,233,227,240,225,242,229,110,128, 50, 33,238, + 230,229,242,233,239,114,128, 32,130,237,239,238,239,243,240,225, + 227,101,128,255, 18,238,245,237,229,242,225,244,239,242,226,229, + 238,231,225,236,105,128, 9,245,239,236,228,243,244,249,236,101, + 128,247, 50,112, 2,197,121,197,128,225,242,229,110,128, 36,117, + 229,114, 2,197,135,197,141,233,239,100,128, 36,137,243,233,225, + 110,128, 6,242,242,239,237,225,110,128, 33,113,115, 2,197,162, + 197,170,244,242,239,235,101,128, 1,187,245,240,229,242,233,239, + 114,128, 0,178,244,104, 2,197,187,197,192,225,105,128, 14, 82, + 233,242,228,115,128, 33, 84,117,145, 0,117,197,237,197,245,198, + 30,198, 87,198,225,199, 6,199,129,199,145,199,196,200, 10,200, + 91,200,100,200,219,200,243,201, 95,201,123,201,237,225,227,245, + 244,101,128, 0,250, 98, 4,197,255,198, 4,198, 13,198, 23,225, + 114,128, 2,137,229,238,231,225,236,105,128, 9,137,239,240,239, + 237,239,230,111,128, 49, 40,242,229,246,101,128, 1,109, 99, 3, + 198, 38,198, 45,198, 77,225,242,239,110,128, 1,212,233,242, 99, + 2,198, 53,198, 58,236,101,128, 36,228,245,237,230,236,229,120, + 129, 0,251,198, 69,226,229,236,239,119,128, 30,119,249,242,233, + 236,236,233, 99,128, 4, 67,100, 5,198, 99,198,110,198,133,198, + 139,198,215,225,244,244,225,228,229,246, 97,128, 9, 81,226,108, + 2,198,117,198,125,225,227,245,244,101,128, 1,113,231,242,225, + 246,101,128, 2, 21,229,246, 97,128, 9, 9,233,229,242,229,243, + 233,115,133, 0,252,198,159,198,167,198,175,198,198,198,206,225, + 227,245,244,101,128, 1,216,226,229,236,239,119,128, 30,115, 99, + 2,198,181,198,188,225,242,239,110,128, 1,218,249,242,233,236, + 236,233, 99,128, 4,241,231,242,225,246,101,128, 1,220,237,225, + 227,242,239,110,128, 1,214,239,244,226,229,236,239,119,128, 30, + 229,103, 2,198,231,198,238,242,225,246,101,128, 0,249,117, 2, + 198,244,198,253,234,225,242,225,244,105,128, 10,137,242,237,245, + 235,232,105,128, 10, 9,104, 3,199, 14,199, 24,199,102,233,242, + 225,231,225,238, 97,128, 48, 70,111, 2,199, 30,199, 40,239,235, + 225,226,239,246,101,128, 30,231,242,110,133, 1,176,199, 55,199, + 63,199, 74,199, 82,199, 94,225,227,245,244,101,128, 30,233,228, + 239,244,226,229,236,239,119,128, 30,241,231,242,225,246,101,128, + 30,235,232,239,239,235,225,226,239,246,101,128, 30,237,244,233, + 236,228,101,128, 30,239,245,238,231,225,242,245,237,236,225,245, + 116,129, 1,113,199,118,227,249,242,233,236,236,233, 99,128, 4, + 243,233,238,246,229,242,244,229,228,226,242,229,246,101,128, 2, + 23,107, 3,199,153,199,177,199,188,225,244,225,235,225,238, 97, + 129, 48,166,199,165,232,225,236,230,247,233,228,244,104,128,255, + 115,227,249,242,233,236,236,233, 99,128, 4,121,239,242,229,225, + 110,128, 49, 92,109, 2,199,202,199,255, 97, 2,199,208,199,241, + 227,242,239,110,130, 1,107,199,219,199,230,227,249,242,233,236, + 236,233, 99,128, 4,239,228,233,229,242,229,243,233,115,128, 30, + 123,244,242,225,231,245,242,237,245,235,232,105,128, 10, 65,239, + 238,239,243,240,225,227,101,128,255, 85,110, 2,200, 16,200, 71, + 228,229,242,243,227,239,242,101,132, 0, 95,200, 35,200, 41,200, + 53,200, 64,228,226,108,128, 32, 23,237,239,238,239,243,240,225, + 227,101,128,255, 63,246,229,242,244,233,227,225,108,128,254, 51, + 247,225,246,121,128,254, 79,105, 2,200, 77,200, 82,239,110,128, + 34, 42,246,229,242,243,225,108,128, 34, 0,239,231,239,238,229, + 107,128, 1,115,112, 5,200,112,200,119,200,127,200,142,200,193, + 225,242,229,110,128, 36,176,226,236,239,227,107,128, 37,128,240, + 229,242,228,239,244,232,229,226,242,229,119,128, 5,196,243,233, + 236,239,110,131, 3,197,200,156,200,177,200,185,228,233,229,242, + 229,243,233,115,129, 3,203,200,169,244,239,238,239,115,128, 3, + 176,236,225,244,233,110,128, 2,138,244,239,238,239,115,128, 3, + 205,244,225,227,107, 2,200,202,200,213,226,229,236,239,247,227, + 237, 98,128, 3, 29,237,239,100,128, 2,212,114, 2,200,225,200, + 237,225,231,245,242,237,245,235,232,105,128, 10,115,233,238,103, + 128, 1,111,115, 3,200,251,201, 10,201, 55,232,239,242,244,227, + 249,242,233,236,236,233, 99,128, 4, 94,237,225,236,108, 2,201, + 19,201, 30,232,233,242,225,231,225,238, 97,128, 48, 69,235,225, + 244,225,235,225,238, 97,129, 48,165,201, 43,232,225,236,230,247, + 233,228,244,104,128,255,105,244,242,225,233,231,232,116, 2,201, + 67,201, 78,227,249,242,233,236,236,233, 99,128, 4,175,243,244, + 242,239,235,229,227,249,242,233,236,236,233, 99,128, 4,177,244, + 233,236,228,101,130, 1,105,201,107,201,115,225,227,245,244,101, + 128, 30,121,226,229,236,239,119,128, 30,117,117, 5,201,135,201, + 145,201,152,201,177,201,193,226,229,238,231,225,236,105,128, 9, + 138,228,229,246, 97,128, 9, 10,231,117, 2,201,159,201,168,234, + 225,242,225,244,105,128, 10,138,242,237,245,235,232,105,128, 10, + 10,237,225,244,242,225,231,245,242,237,245,235,232,105,128, 10, + 66,246,239,247,229,236,243,233,231,110, 3,201,209,201,219,201, + 226,226,229,238,231,225,236,105,128, 9,194,228,229,246, 97,128, + 9, 66,231,245,234,225,242,225,244,105,128, 10,194,246,239,247, + 229,236,243,233,231,110, 3,201,253,202, 7,202, 14,226,229,238, + 231,225,236,105,128, 9,193,228,229,246, 97,128, 9, 65,231,245, + 234,225,242,225,244,105,128, 10,193,118,139, 0,118,202, 51,202, + 199,202,208,202,219,203,148,203,155,203,253,204, 9,204,109,204, + 117,204,138, 97, 4,202, 61,202, 68,202, 93,202,104,228,229,246, + 97,128, 9, 53,231,117, 2,202, 75,202, 84,234,225,242,225,244, + 105,128, 10,181,242,237,245,235,232,105,128, 10, 53,235,225,244, + 225,235,225,238, 97,128, 48,247,118,132, 5,213,202,116,202,143, + 202,175,202,187,228,225,231,229,243,104,130,251, 53,202,129,202, + 134,182, 53,128,251, 53,232,229,226,242,229,119,128,251, 53,104, + 2,202,149,202,157,229,226,242,229,119,128, 5,213,239,236,225, + 109,129,251, 75,202,166,232,229,226,242,229,119,128,251, 75,246, + 225,246,232,229,226,242,229,119,128, 5,240,249,239,228,232,229, + 226,242,229,119,128, 5,241,227,233,242,227,236,101,128, 36,229, + 228,239,244,226,229,236,239,119,128, 30,127,101, 6,202,233,202, + 244,203, 52,203, 63,203, 69,203,136,227,249,242,233,236,236,233, + 99,128, 4, 50,104, 4,202,254,203, 7,203, 21,203, 37,225,242, + 225,226,233, 99,128, 6,164,230,233,238,225,236,225,242,225,226, + 233, 99,128,251,107,233,238,233,244,233,225,236,225,242,225,226, + 233, 99,128,251,108,237,229,228,233,225,236,225,242,225,226,233, + 99,128,251,109,235,225,244,225,235,225,238, 97,128, 48,249,238, + 245,115,128, 38, 64,242,244,233,227,225,108, 2,203, 80,203, 86, + 226,225,114,128, 0,124,236,233,238,101, 4,203, 99,203,110,203, + 121,203,130,225,226,239,246,229,227,237, 98,128, 3, 13,226,229, + 236,239,247,227,237, 98,128, 3, 41,236,239,247,237,239,100,128, + 2,204,237,239,100,128, 2,200,247,225,242,237,229,238,233,225, + 110,128, 5,126,232,239,239,107,128, 2,139,105, 3,203,163,203, + 174,203,213,235,225,244,225,235,225,238, 97,128, 48,248,242,225, + 237, 97, 3,203,185,203,195,203,202,226,229,238,231,225,236,105, + 128, 9,205,228,229,246, 97,128, 9, 77,231,245,234,225,242,225, + 244,105,128, 10,205,243,225,242,231, 97, 3,203,225,203,235,203, + 242,226,229,238,231,225,236,105,128, 9,131,228,229,246, 97,128, + 9, 3,231,245,234,225,242,225,244,105,128, 10,131,237,239,238, + 239,243,240,225,227,101,128,255, 86,111, 3,204, 17,204, 28,204, + 98,225,242,237,229,238,233,225,110,128, 5,120,233,227,229,100, + 2,204, 37,204, 73,233,244,229,242,225,244,233,239,110, 2,204, + 51,204, 62,232,233,242,225,231,225,238, 97,128, 48,158,235,225, + 244,225,235,225,238, 97,128, 48,254,237,225,242,235,235,225,238, + 97,129, 48,155,204, 86,232,225,236,230,247,233,228,244,104,128, + 255,158,235,225,244,225,235,225,238, 97,128, 48,250,240,225,242, + 229,110,128, 36,177,116, 2,204,123,204,130,233,236,228,101,128, + 30,125,245,242,238,229,100,128, 2,140,117, 2,204,144,204,155, + 232,233,242,225,231,225,238, 97,128, 48,148,235,225,244,225,235, + 225,238, 97,128, 48,244,119,143, 0,119,204,200,205,177,205,187, + 205,210,205,250,206, 61,206, 69,208, 40,208, 81,208, 93,208,168, + 208,176,208,183,208,194,208,203, 97, 8,204,218,204,225,204,235, + 204,246,205, 28,205, 60,205, 72,205,108,227,245,244,101,128, 30, + 131,229,235,239,242,229,225,110,128, 49, 89,232,233,242,225,231, + 225,238, 97,128, 48,143,107, 2,204,252,205, 20,225,244,225,235, + 225,238, 97,129, 48,239,205, 8,232,225,236,230,247,233,228,244, + 104,128,255,156,239,242,229,225,110,128, 49, 88,243,237,225,236, + 108, 2,205, 38,205, 49,232,233,242,225,231,225,238, 97,128, 48, + 142,235,225,244,225,235,225,238, 97,128, 48,238,244,244,239,243, + 241,245,225,242,101,128, 51, 87,118, 2,205, 78,205, 86,229,228, + 225,243,104,128, 48, 28,249,245,238,228,229,242,243,227,239,242, + 229,246,229,242,244,233,227,225,108,128,254, 52,119, 3,205,116, + 205,125,205,139,225,242,225,226,233, 99,128, 6, 72,230,233,238, + 225,236,225,242,225,226,233, 99,128,254,238,232,225,237,250,225, + 225,226,239,246,101, 2,205,154,205,163,225,242,225,226,233, 99, + 128, 6, 36,230,233,238,225,236,225,242,225,226,233, 99,128,254, + 134,226,243,241,245,225,242,101,128, 51,221,227,233,242, 99, 2, + 205,196,205,201,236,101,128, 36,230,245,237,230,236,229,120,128, + 1,117,100, 2,205,216,205,226,233,229,242,229,243,233,115,128, + 30,133,239,116, 2,205,233,205,242,225,227,227,229,238,116,128, + 30,135,226,229,236,239,119,128, 30,137,101, 4,206, 4,206, 15, + 206, 27,206, 51,232,233,242,225,231,225,238, 97,128, 48,145,233, + 229,242,243,244,242,225,243,115,128, 33, 24,107, 2,206, 33,206, + 43,225,244,225,235,225,238, 97,128, 48,241,239,242,229,225,110, + 128, 49, 94,239,235,239,242,229,225,110,128, 49, 93,231,242,225, + 246,101,128, 30,129,232,233,244,101, 8,206, 90,206, 99,206,183, + 207, 17,207,101,207,146,207,198,207,254,226,245,236,236,229,116, + 128, 37,230, 99, 2,206,105,206,125,233,242,227,236,101,129, 37, + 203,206,115,233,238,246,229,242,243,101,128, 37,217,239,242,238, + 229,242,226,242,225,227,235,229,116, 2,206,142,206,162,236,229, + 230,116,129, 48, 14,206,151,246,229,242,244,233,227,225,108,128, + 254, 67,242,233,231,232,116,129, 48, 15,206,172,246,229,242,244, + 233,227,225,108,128,254, 68,100, 2,206,189,206,230,233,225,237, + 239,238,100,129, 37,199,206,200,227,239,238,244,225,233,238,233, + 238,231,226,236,225,227,235,243,237,225,236,236,228,233,225,237, + 239,238,100,128, 37,200,239,247,238,240,239,233,238,244,233,238, + 103, 2,206,246,207, 6,243,237,225,236,236,244,242,233,225,238, + 231,236,101,128, 37,191,244,242,233,225,238,231,236,101,128, 37, + 189,236,101, 2,207, 24,207, 66,230,244,240,239,233,238,244,233, + 238,103, 2,207, 39,207, 55,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,195,244,242,233,225,238,231,236,101,128, + 37,193,238,244,233,227,245,236,225,242,226,242,225,227,235,229, + 116, 2,207, 86,207, 93,236,229,230,116,128, 48, 22,242,233,231, + 232,116,128, 48, 23,242,233,231,232,244,240,239,233,238,244,233, + 238,103, 2,207,119,207,135,243,237,225,236,236,244,242,233,225, + 238,231,236,101,128, 37,185,244,242,233,225,238,231,236,101,128, + 37,183,115, 3,207,154,207,184,207,192,109, 2,207,160,207,172, + 225,236,236,243,241,245,225,242,101,128, 37,171,233,236,233,238, + 231,230,225,227,101,128, 38, 58,241,245,225,242,101,128, 37,161, + 244,225,114,128, 38, 6,116, 2,207,204,207,215,229,236,229,240, + 232,239,238,101,128, 38, 15,239,242,244,239,233,243,229,243,232, + 229,236,236,226,242,225,227,235,229,116, 2,207,239,207,246,236, + 229,230,116,128, 48, 24,242,233,231,232,116,128, 48, 25,245,240, + 240,239,233,238,244,233,238,103, 2,208, 13,208, 29,243,237,225, + 236,236,244,242,233,225,238,231,236,101,128, 37,181,244,242,233, + 225,238,231,236,101,128, 37,179,105, 2,208, 46,208, 57,232,233, + 242,225,231,225,238, 97,128, 48,144,107, 2,208, 63,208, 73,225, + 244,225,235,225,238, 97,128, 48,240,239,242,229,225,110,128, 49, + 95,237,239,238,239,243,240,225,227,101,128,255, 87,111, 4,208, + 103,208,114,208,139,208,157,232,233,242,225,231,225,238, 97,128, + 48,146,235,225,244,225,235,225,238, 97,129, 48,242,208,127,232, + 225,236,230,247,233,228,244,104,128,255,102,110,129, 32,169,208, + 145,237,239,238,239,243,240,225,227,101,128,255,230,247,225,229, + 238,244,232,225,105,128, 14, 39,240,225,242,229,110,128, 36,178, + 242,233,238,103,128, 30,152,243,245,240,229,242,233,239,114,128, + 2,183,244,245,242,238,229,100,128, 2,141,249,238,110,128, 1, + 191,120,137, 0,120,208,231,208,242,208,253,209, 6,209, 33,209, + 46,209, 50,209, 62,209, 70,225,226,239,246,229,227,237, 98,128, + 3, 61,226,239,240,239,237,239,230,111,128, 49, 18,227,233,242, + 227,236,101,128, 36,231,100, 2,209, 12,209, 22,233,229,242,229, + 243,233,115,128, 30,141,239,244,225,227,227,229,238,116,128, 30, + 139,229,232,225,242,237,229,238,233,225,110,128, 5,109,105,128, + 3,190,237,239,238,239,243,240,225,227,101,128,255, 88,240,225, + 242,229,110,128, 36,179,243,245,240,229,242,233,239,114,128, 2, + 227,121,143, 0,121,209,115,210, 74,210, 97,210,137,212,103,212, + 111,212,128,212,192,212,204,213,201,213,241,213,253,214, 8,214, + 29,215, 2, 97, 11,209,139,209,151,209,161,209,168,209,175,209, + 185,209,210,209,221,210, 3,210, 16,210, 62,225,228,239,243,241, + 245,225,242,101,128, 51, 78,226,229,238,231,225,236,105,128, 9, + 175,227,245,244,101,128, 0,253,228,229,246, 97,128, 9, 47,229, + 235,239,242,229,225,110,128, 49, 82,231,117, 2,209,192,209,201, + 234,225,242,225,244,105,128, 10,175,242,237,245,235,232,105,128, + 10, 47,232,233,242,225,231,225,238, 97,128, 48,132,107, 2,209, + 227,209,251,225,244,225,235,225,238, 97,129, 48,228,209,239,232, + 225,236,230,247,233,228,244,104,128,255,148,239,242,229,225,110, + 128, 49, 81,237,225,235,235,225,238,244,232,225,105,128, 14, 78, + 243,237,225,236,108, 2,210, 26,210, 37,232,233,242,225,231,225, + 238, 97,128, 48,131,235,225,244,225,235,225,238, 97,129, 48,227, + 210, 50,232,225,236,230,247,233,228,244,104,128,255,108,244,227, + 249,242,233,236,236,233, 99,128, 4, 99,227,233,242, 99, 2,210, + 83,210, 88,236,101,128, 36,232,245,237,230,236,229,120,128, 1, + 119,100, 2,210,103,210,113,233,229,242,229,243,233,115,128, 0, + 255,239,116, 2,210,120,210,129,225,227,227,229,238,116,128, 30, + 143,226,229,236,239,119,128, 30,245,101, 7,210,153,211,161,211, + 170,211,188,211,220,212, 40,212, 91,104, 8,210,171,210,180,210, + 214,210,228,211, 45,211, 61,211,120,211,138,225,242,225,226,233, + 99,128, 6, 74,226,225,242,242,229,101, 2,210,191,210,200,225, + 242,225,226,233, 99,128, 6,210,230,233,238,225,236,225,242,225, + 226,233, 99,128,251,175,230,233,238,225,236,225,242,225,226,233, + 99,128,254,242,232,225,237,250,225,225,226,239,246,101, 4,210, + 247,211, 0,211, 14,211, 30,225,242,225,226,233, 99,128, 6, 38, + 230,233,238,225,236,225,242,225,226,233, 99,128,254,138,233,238, + 233,244,233,225,236,225,242,225,226,233, 99,128,254,139,237,229, + 228,233,225,236,225,242,225,226,233, 99,128,254,140,233,238,233, + 244,233,225,236,225,242,225,226,233, 99,128,254,243,237,101, 2, + 211, 68,211, 81,228,233,225,236,225,242,225,226,233, 99,128,254, + 244,229,237,105, 2,211, 89,211,104,238,233,244,233,225,236,225, + 242,225,226,233, 99,128,252,221,243,239,236,225,244,229,228,225, + 242,225,226,233, 99,128,252, 88,238,239,239,238,230,233,238,225, + 236,225,242,225,226,233, 99,128,252,148,244,232,242,229,229,228, + 239,244,243,226,229,236,239,247,225,242,225,226,233, 99,128, 6, + 209,235,239,242,229,225,110,128, 49, 86,110,129, 0,165,211,176, + 237,239,238,239,243,240,225,227,101,128,255,229,111, 2,211,194, + 211,203,235,239,242,229,225,110,128, 49, 85,242,233,238,232,233, + 229,245,232,235,239,242,229,225,110,128, 49,134,114, 3,211,228, + 212, 8,212, 20,225,232,226,229,238,249,239,237,111, 2,211,242, + 211,251,232,229,226,242,229,119,128, 5,170,236,229,230,244,232, + 229,226,242,229,119,128, 5,170,233,227,249,242,233,236,236,233, + 99,128, 4, 75,245,228,233,229,242,229,243,233,243,227,249,242, + 233,236,236,233, 99,128, 4,249,243,233,229,245,238,103, 3,212, + 53,212, 62,212, 78,235,239,242,229,225,110,128, 49,129,240,225, + 238,243,233,239,243,235,239,242,229,225,110,128, 49,131,243,233, + 239,243,235,239,242,229,225,110,128, 49,130,244,233,246,232,229, + 226,242,229,119,128, 5,154,231,242,225,246,101,128, 30,243,232, + 239,239,107,129, 1,180,212,120,225,226,239,246,101,128, 30,247, + 105, 5,212,140,212,151,212,162,212,171,212,179,225,242,237,229, + 238,233,225,110,128, 5,117,227,249,242,233,236,236,233, 99,128, + 4, 87,235,239,242,229,225,110,128, 49, 98,238,249,225,238,103, + 128, 38, 47,247,238,225,242,237,229,238,233,225,110,128, 5,130, + 237,239,238,239,243,240,225,227,101,128,255, 89,111, 7,212,220, + 213, 34,213, 45,213, 55,213, 93,213,139,213,148,100,131, 5,217, + 212,230,212,250,213, 3,228,225,231,229,243,104,129,251, 57,212, + 241,232,229,226,242,229,119,128,251, 57,232,229,226,242,229,119, + 128, 5,217,249,239,100, 2,213, 11,213, 20,232,229,226,242,229, + 119,128, 5,242,240,225,244,225,232,232,229,226,242,229,119,128, + 251, 31,232,233,242,225,231,225,238, 97,128, 48,136,233,235,239, + 242,229,225,110,128, 49,137,107, 2,213, 61,213, 85,225,244,225, + 235,225,238, 97,129, 48,232,213, 73,232,225,236,230,247,233,228, + 244,104,128,255,150,239,242,229,225,110,128, 49, 91,243,237,225, + 236,108, 2,213,103,213,114,232,233,242,225,231,225,238, 97,128, + 48,135,235,225,244,225,235,225,238, 97,129, 48,231,213,127,232, + 225,236,230,247,233,228,244,104,128,255,110,244,231,242,229,229, + 107,128, 3,243,121, 2,213,154,213,191, 97, 2,213,160,213,170, + 229,235,239,242,229,225,110,128, 49,136,107, 2,213,176,213,184, + 239,242,229,225,110,128, 49,135,244,232,225,105,128, 14, 34,233, + 238,231,244,232,225,105,128, 14, 13,112, 2,213,207,213,214,225, + 242,229,110,128, 36,180,239,231,229,231,242,225,237,237,229,238, + 105,129, 3,122,213,230,231,242,229,229,235,227,237, 98,128, 3, + 69,114,129, 1,166,213,247,233,238,103,128, 30,153,243,245,240, + 229,242,233,239,114,128, 2,184,116, 2,214, 14,214, 21,233,236, + 228,101,128, 30,249,245,242,238,229,100,128, 2,142,117, 5,214, + 41,214, 52,214, 62,214,100,214,232,232,233,242,225,231,225,238, + 97,128, 48,134,233,235,239,242,229,225,110,128, 49,140,107, 2, + 214, 68,214, 92,225,244,225,235,225,238, 97,129, 48,230,214, 80, + 232,225,236,230,247,233,228,244,104,128,255,149,239,242,229,225, + 110,128, 49, 96,115, 3,214,108,214,146,214,187,226,233,103, 2, + 214,116,214,127,227,249,242,233,236,236,233, 99,128, 4,107,233, + 239,244,233,230,233,229,228,227,249,242,233,236,236,233, 99,128, + 4,109,236,233,244,244,236,101, 2,214,157,214,168,227,249,242, + 233,236,236,233, 99,128, 4,103,233,239,244,233,230,233,229,228, + 227,249,242,233,236,236,233, 99,128, 4,105,237,225,236,108, 2, + 214,196,214,207,232,233,242,225,231,225,238, 97,128, 48,133,235, + 225,244,225,235,225,238, 97,129, 48,229,214,220,232,225,236,230, + 247,233,228,244,104,128,255,109,249,101, 2,214,239,214,248,235, + 239,242,229,225,110,128, 49,139,239,235,239,242,229,225,110,128, + 49,138,249, 97, 2,215, 9,215, 19,226,229,238,231,225,236,105, + 128, 9,223,228,229,246, 97,128, 9, 95,122,142, 0,122,215, 58, + 216, 66,216, 77,216,120,216,147,217,182,218, 34,218, 76,218, 88, + 218,100,218,128,218,136,218,152,218,161, 97, 10,215, 80,215, 91, + 215, 98,215,105,215,116,215,194,215,224,215,235,216, 15,216, 27, + 225,242,237,229,238,233,225,110,128, 5,102,227,245,244,101,128, + 1,122,228,229,246, 97,128, 9, 91,231,245,242,237,245,235,232, + 105,128, 10, 91,104, 4,215,126,215,135,215,149,215,179,225,242, + 225,226,233, 99,128, 6, 56,230,233,238,225,236,225,242,225,226, + 233, 99,128,254,198,105, 2,215,155,215,170,238,233,244,233,225, + 236,225,242,225,226,233, 99,128,254,199,242,225,231,225,238, 97, + 128, 48, 86,237,229,228,233,225,236,225,242,225,226,233, 99,128, + 254,200,233,110, 2,215,201,215,210,225,242,225,226,233, 99,128, + 6, 50,230,233,238,225,236,225,242,225,226,233, 99,128,254,176, + 235,225,244,225,235,225,238, 97,128, 48,182,241,229,102, 2,215, + 243,216, 1,231,225,228,239,236,232,229,226,242,229,119,128, 5, + 149,241,225,244,225,238,232,229,226,242,229,119,128, 5,148,242, + 241,225,232,229,226,242,229,119,128, 5,152,249,233,110,130, 5, + 214,216, 37,216, 57,228,225,231,229,243,104,129,251, 54,216, 48, + 232,229,226,242,229,119,128,251, 54,232,229,226,242,229,119,128, + 5,214,226,239,240,239,237,239,230,111,128, 49, 23, 99, 3,216, + 85,216, 92,216,114,225,242,239,110,128, 1,126,233,242, 99, 2, + 216,100,216,105,236,101,128, 36,233,245,237,230,236,229,120,128, + 30,145,245,242,108,128, 2,145,228,239,116,130, 1,124,216,130, + 216,139,225,227,227,229,238,116,128, 1,124,226,229,236,239,119, + 128, 30,147,101, 6,216,161,216,172,216,215,216,226,216,237,217, + 177,227,249,242,233,236,236,233, 99,128, 4, 55,100, 2,216,178, + 216,197,229,243,227,229,238,228,229,242,227,249,242,233,236,236, + 233, 99,128, 4,153,233,229,242,229,243,233,243,227,249,242,233, + 236,236,233, 99,128, 4,223,232,233,242,225,231,225,238, 97,128, + 48, 92,235,225,244,225,235,225,238, 97,128, 48,188,242,111,140, + 0, 48,217, 10,217, 19,217, 29,217, 36,217, 61,217, 74,217, 85, + 217, 97,217,108,217,118,217,129,217,136,225,242,225,226,233, 99, + 128, 6, 96,226,229,238,231,225,236,105,128, 9,230,228,229,246, + 97,128, 9,102,231,117, 2,217, 43,217, 52,234,225,242,225,244, + 105,128, 10,230,242,237,245,235,232,105,128, 10,102,232,225,227, + 235,225,242,225,226,233, 99,128, 6, 96,233,238,230,229,242,233, + 239,114,128, 32,128,237,239,238,239,243,240,225,227,101,128,255, + 16,239,236,228,243,244,249,236,101,128,247, 48,240,229,242,243, + 233,225,110,128, 6,240,243,245,240,229,242,233,239,114,128, 32, + 112,244,232,225,105,128, 14, 80,247,233,228,244,104, 3,217,148, + 217,157,217,169,234,239,233,238,229,114,128,254,255,238,239,238, + 234,239,233,238,229,114,128, 32, 12,243,240,225,227,101,128, 32, + 11,244, 97,128, 3,182,104, 2,217,188,217,199,226,239,240,239, + 237,239,230,111,128, 49, 19,101, 4,217,209,217,220,217,236,217, + 247,225,242,237,229,238,233,225,110,128, 5,106,226,242,229,246, + 229,227,249,242,233,236,236,233, 99,128, 4,194,227,249,242,233, + 236,236,233, 99,128, 4, 54,100, 2,217,253,218, 16,229,243,227, + 229,238,228,229,242,227,249,242,233,236,236,233, 99,128, 4,151, + 233,229,242,229,243,233,243,227,249,242,233,236,236,233, 99,128, + 4,221,105, 3,218, 42,218, 53,218, 64,232,233,242,225,231,225, + 238, 97,128, 48, 88,235,225,244,225,235,225,238, 97,128, 48,184, + 238,239,242,232,229,226,242,229,119,128, 5,174,236,233,238,229, + 226,229,236,239,119,128, 30,149,237,239,238,239,243,240,225,227, + 101,128,255, 90,111, 2,218,106,218,117,232,233,242,225,231,225, + 238, 97,128, 48, 94,235,225,244,225,235,225,238, 97,128, 48,190, + 240,225,242,229,110,128, 36,181,242,229,244,242,239,230,236,229, + 248,232,239,239,107,128, 2,144,243,244,242,239,235,101,128, 1, + 182,117, 2,218,167,218,178,232,233,242,225,231,225,238, 97,128, + 48, 90,235,225,244,225,235,225,238, 97,128, 48,186 + }; +/* + * This function searches the compressed table efficiently. + */ + static unsigned long + ft_get_adobe_glyph_index( const char* name, + const char* limit ) + { + int c = 0; + int count, min, max; + const unsigned char* p = ft_adobe_glyph_list; + if ( name == 0 || name >= limit ) + goto NotFound; + c = *name++; + count = p[1]; + p += 2; + min = 0; + max = count; + while ( min < max ) + { + int mid = ( min + max ) >> 1; + const unsigned char* q = p + mid * 2; + int c2; + q = ft_adobe_glyph_list + ( ( (int)q[0] << 8 ) | q[1] ); + c2 = q[0] & 127; + if ( c2 == c ) + { + p = q; + goto Found; + } + if ( c2 < c ) + min = mid + 1; + else + max = mid; + } + goto NotFound; + Found: + for (;;) + { +/* assert (*p & 127) == c */ + if ( name >= limit ) + { + if ( (p[0] & 128) == 0 && + (p[1] & 128) != 0 ) + return (unsigned long)( ( (int)p[2] << 8 ) | p[3] ); + goto NotFound; + } + c = *name++; + if ( p[0] & 128 ) + { + p++; + if ( c != (p[0] & 127) ) + goto NotFound; + continue; + } + p++; + count = p[0] & 127; + if ( p[0] & 128 ) + p += 2; + p++; + for ( ; count > 0; count--, p += 2 ) + { + int offset = ( (int)p[0] << 8 ) | p[1]; + const unsigned char* q = ft_adobe_glyph_list + offset; + if ( c == ( q[0] & 127 ) ) + { + p = q; + goto NextIter; + } + } + goto NotFound; + NextIter: + ; + } + NotFound: + return 0; + } +/* END */ +#define VARIANT_BIT 0x80000000UL +#define BASE_GLYPH( code ) ( (FT_UInt32)( (code) & ~VARIANT_BIT ) ) +/* Return the Unicode value corresponding to a given glyph. Note that */ +/* we do deal with glyph variants by detecting a non-initial dot in */ +/* the name, as in `A.swash' or `e.final'; in this case, the */ +/* VARIANT_BIT is set in the return value. */ +/* */ + static FT_UInt32 + ps_unicode_value( const char* glyph_name ) + { +/* If the name begins with `uni', then the glyph name may be a */ +/* hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' && + glyph_name[1] == 'n' && + glyph_name[2] == 'i' ) + { +/* determine whether the next four characters following are */ +/* hexadecimal. */ +/* XXX: Add code to deal with ligatures, i.e. glyph names like */ +/* `uniXXXXYYYYZZZZ'... */ + FT_Int count; + FT_UInt32 value = 0; + const char* p = glyph_name + 3; + for ( count = 4; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } +/* Exit if a non-uppercase hexadecimal character was found */ +/* -- this also catches character codes below `0' since such */ +/* negative numbers cast to `unsigned int' are far too big. */ + if ( d >= 16 ) + break; + value = ( value << 4 ) + d; + } +/* there must be exactly four hex digits */ + if ( count == 0 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return (FT_UInt32)( value | VARIANT_BIT ); + } + } +/* If the name begins with `u', followed by four to six uppercase */ +/* hexadecimal digits, it is a hard-coded unicode character code. */ + if ( glyph_name[0] == 'u' ) + { + FT_Int count; + FT_UInt32 value = 0; + const char* p = glyph_name + 1; + for ( count = 6; count > 0; count--, p++ ) + { + char c = *p; + unsigned int d; + d = (unsigned char)c - '0'; + if ( d >= 10 ) + { + d = (unsigned char)c - 'A'; + if ( d >= 6 ) + d = 16; + else + d += 10; + } + if ( d >= 16 ) + break; + value = ( value << 4 ) + d; + } + if ( count <= 2 ) + { + if ( *p == '\0' ) + return value; + if ( *p == '.' ) + return (FT_UInt32)( value | VARIANT_BIT ); + } + } +/* Look for a non-initial dot in the glyph name in order to */ +/* find variants like `A.swash', `e.final', etc. */ + { + const char* p = glyph_name; + const char* dot = NULL; + for ( ; *p; p++ ) + { + if ( *p == '.' && p > glyph_name ) + { + dot = p; + break; + } + } +/* now look up the glyph in the Adobe Glyph List */ + if ( !dot ) + return (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); + else + return (FT_UInt32)( ft_get_adobe_glyph_index( glyph_name, dot ) | + VARIANT_BIT ); + } + } +/* ft_qsort callback to sort the unicode map */ + FT_CALLBACK_DEF( int ) + compare_uni_maps( const void* a, + const void* b ) + { + PS_UniMap* map1 = (PS_UniMap*)a; + PS_UniMap* map2 = (PS_UniMap*)b; + FT_UInt32 unicode1 = BASE_GLYPH( map1->unicode ); + FT_UInt32 unicode2 = BASE_GLYPH( map2->unicode ); +/* sort base glyphs before glyph variants */ + if ( unicode1 == unicode2 ) + { + if ( map1->unicode > map2->unicode ) + return 1; + else if ( map1->unicode < map2->unicode ) + return -1; + else + return 0; + } + else + { + if ( unicode1 > unicode2 ) + return 1; + else if ( unicode1 < unicode2 ) + return -1; + else + return 0; + } + } +/* support for extra glyphs not handled (well) in AGL; */ +/* we add extra mappings for them if necessary */ +#define EXTRA_GLYPH_LIST_SIZE 10 + static const FT_UInt32 ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] = + { +/* WGL 4 */ + 0x0394, + 0x03A9, + 0x2215, + 0x00AD, + 0x02C9, + 0x03BC, + 0x2219, + 0x00A0, +/* Romanian */ + 0x021A, + 0x021B + }; + static const char ft_extra_glyph_names[] = + { + 'D','e','l','t','a',0, + 'O','m','e','g','a',0, + 'f','r','a','c','t','i','o','n',0, + 'h','y','p','h','e','n',0, + 'm','a','c','r','o','n',0, + 'm','u',0, + 'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0, + 's','p','a','c','e',0, + 'T','c','o','m','m','a','a','c','c','e','n','t',0, + 't','c','o','m','m','a','a','c','c','e','n','t',0 + }; + static const FT_Int + ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] = + { + 0, + 6, + 12, + 21, + 28, + 35, + 38, + 53, + 59, + 72 + }; + static void + ps_check_extra_glyph_name( const char* gname, + FT_UInt glyph, + FT_UInt* extra_glyphs, + FT_UInt *states ) + { + FT_UInt n; + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( ft_strcmp( ft_extra_glyph_names + + ft_extra_glyph_name_offsets[n], gname ) == 0 ) + { + if ( states[n] == 0 ) + { +/* mark this extra glyph as a candidate for the cmap */ + states[n] = 1; + extra_glyphs[n] = glyph; + } + return; + } + } + } + static void + ps_check_extra_glyph_unicode( FT_UInt32 uni_char, + FT_UInt *states ) + { + FT_UInt n; + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( uni_char == ft_extra_glyph_unicodes[n] ) + { +/* disable this extra glyph from being added to the cmap */ + states[n] = 2; + return; + } + } + } +/* Build a table that maps Unicode values to glyph indices. */ + static FT_Error + ps_unicodes_init( FT_Memory memory, + PS_Unicodes table, + FT_UInt num_glyphs, + PS_GetGlyphNameFunc get_glyph_name, + PS_FreeGlyphNameFunc free_glyph_name, + FT_Pointer glyph_data ) + { + FT_Error error; + FT_UInt extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + FT_UInt extra_glyphs[EXTRA_GLYPH_LIST_SIZE]; +/* we first allocate the table */ + table->num_maps = 0; + table->maps = 0; + if ( !FT_NEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) + { + FT_UInt n; + FT_UInt count; + PS_UniMap* map; + FT_UInt32 uni_char; + map = table->maps; + for ( n = 0; n < num_glyphs; n++ ) + { + const char* gname = get_glyph_name( glyph_data, n ); + if ( gname ) + { + ps_check_extra_glyph_name( gname, n, + extra_glyphs, extra_glyph_list_states ); + uni_char = ps_unicode_value( gname ); + if ( BASE_GLYPH( uni_char ) != 0 ) + { + ps_check_extra_glyph_unicode( uni_char, + extra_glyph_list_states ); + map->unicode = uni_char; + map->glyph_index = n; + map++; + } + if ( free_glyph_name ) + free_glyph_name( glyph_data, gname ); + } + } + for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ ) + { + if ( extra_glyph_list_states[n] == 1 ) + { +/* This glyph name has an additional representation. */ +/* Add it to the cmap. */ + map->unicode = ft_extra_glyph_unicodes[n]; + map->glyph_index = extra_glyphs[n]; + map++; + } + } +/* now compress the table a bit */ + count = (FT_UInt)( map - table->maps ); + if ( count == 0 ) + { +/* No unicode chars here! */ + FT_FREE( table->maps ); + if ( !error ) + error = PSnames_Err_No_Unicode_Glyph_Name; + } + else + { +/* Reallocate if the number of used entries is much smaller. */ + if ( count < num_glyphs / 2 ) + { + (void)FT_RENEW_ARRAY( table->maps, num_glyphs, count ); + error = PSnames_Err_Ok; + } +/* Sort the table in increasing order of unicode values, */ +/* taking care of glyph variants. */ + ft_qsort( table->maps, count, sizeof ( PS_UniMap ), + compare_uni_maps ); + } + table->num_maps = count; + } + return error; + } + static FT_UInt + ps_unicodes_char_index( PS_Unicodes table, + FT_UInt32 unicode ) + { + PS_UniMap *min, *max, *mid, *result = NULL; +/* Perform a binary search on the table. */ + min = table->maps; + max = min + table->num_maps - 1; + while ( min <= max ) + { + FT_UInt32 base_glyph; + mid = min + ( ( max - min ) >> 1 ); + if ( mid->unicode == unicode ) + { + result = mid; + break; + } + base_glyph = BASE_GLYPH( mid->unicode ); + if ( base_glyph == unicode ) +/* remember match but continue search for base glyph */ + result = mid; + if ( min == max ) + break; + if ( base_glyph < unicode ) + min = mid + 1; + else + max = mid - 1; + } + if ( result ) + return result->glyph_index; + else + return 0; + } + static FT_UInt32 + ps_unicodes_char_next( PS_Unicodes table, + FT_UInt32 *unicode ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *unicode + 1; + { + FT_UInt min = 0; + FT_UInt max = table->num_maps; + FT_UInt mid; + PS_UniMap* map; + FT_UInt32 base_glyph; + while ( min < max ) + { + mid = min + ( ( max - min ) >> 1 ); + map = table->maps + mid; + if ( map->unicode == char_code ) + { + result = map->glyph_index; + goto Exit; + } + base_glyph = BASE_GLYPH( map->unicode ); + if ( base_glyph == char_code ) + result = map->glyph_index; + if ( base_glyph < char_code ) + min = mid + 1; + else + max = mid; + } + if ( result ) +/* we have a variant glyph */ + goto Exit; +/* we didn't find it; check whether we have a map just above it */ + char_code = 0; + if ( min < table->num_maps ) + { + map = table->maps + min; + result = map->glyph_index; + char_code = BASE_GLYPH( map->unicode ); + } + } + Exit: + *unicode = char_code; + return result; + } + static const char* + ps_get_macintosh_name( FT_UInt name_index ) + { + if ( name_index >= FT_NUM_MAC_NAMES ) + name_index = 0; + return ft_standard_glyph_names + ft_mac_names[name_index]; + } + static const char* + ps_get_standard_strings( FT_UInt sid ) + { + if ( sid >= FT_NUM_SID_NAMES ) + return 0; + return ft_standard_glyph_names + ft_sid_names[sid]; + } + FT_DEFINE_SERVICE_PSCMAPSREC( + pscmaps_interface, + (PS_Unicode_ValueFunc) ps_unicode_value, + (PS_Unicodes_InitFunc) ps_unicodes_init, + (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index, + (PS_Unicodes_CharNextFunc) ps_unicodes_char_next, + (PS_Macintosh_NameFunc) ps_get_macintosh_name, + (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, + t1_standard_encoding, + t1_expert_encoding ) + FT_DEFINE_SERVICEDESCREC1( + pscmaps_services, + FT_SERVICE_ID_POSTSCRIPT_CMAPS, &PSCMAPS_INTERFACE_GET ) + static FT_Pointer + psnames_get_service( FT_Module module, + const char* service_id ) + { +/* PSCMAPS_SERVICES_GET derefers `library' in PIC mode */ + FT_UNUSED( module ); + return ft_service_list_lookup( PSCMAPS_SERVICES_GET, service_id ); + } +#define PUT_PS_NAMES_SERVICE( a ) a + FT_DEFINE_MODULE( + psnames_module_class, +/* this is not a font driver, nor a renderer */ + 0, + sizeof ( FT_ModuleRec ), +/* driver name */ + "psnames", +/* driver version */ + 0x10000L, +/* driver requires FreeType 2 or above */ + 0x20000L, + PUT_PS_NAMES_SERVICE( +/* module specific interface */ + (void*)&PSCMAPS_INTERFACE_GET ), + (FT_Module_Constructor)NULL, + (FT_Module_Destructor) NULL, + (FT_Module_Requester) PUT_PS_NAMES_SERVICE( psnames_get_service ) ) +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* type1cid.c */ +/* */ +/* FreeType OpenType driver component (body only). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* cidparse.c */ +/* */ +/* CID-keyed Type1 parser (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* cidparse.h */ +/* */ +/* CID-keyed Type1 parser (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004 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. */ +/* */ +/***************************************************************************/ +#define __CIDPARSE_H__ +/***************************************************************************/ +/* */ +/* psaux.h */ +/* */ +/* Auxiliary functions and data structures related to PostScript fonts */ +/* (specification). */ +/* */ +/* Copyright 1996-2004, 2006, 2008, 2009, 2012 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. */ +/* */ +/***************************************************************************/ +#define __PSAUX_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1_TABLE *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct PS_TableRec_* PS_Table; + typedef const struct PS_Table_FuncsRec_* PS_Table_Funcs; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_Table_FuncsRec */ +/* */ +/* <Description> */ +/* A set of function pointers to manage PS_Table objects. */ +/* */ +/* <Fields> */ +/* table_init :: Used to initialize a table. */ +/* */ +/* table_done :: Finalizes resp. destroy a given table. */ +/* */ +/* table_add :: Adds a new object to a table. */ +/* */ +/* table_release :: Releases table data, then finalizes it. */ +/* */ + typedef struct PS_Table_FuncsRec_ + { + FT_Error + (*init)( PS_Table table, + FT_Int count, + FT_Memory memory ); + void + (*done)( PS_Table table ); + FT_Error + (*add)( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ); + void + (*release)( PS_Table table ); + } PS_Table_FuncsRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_TableRec */ +/* */ +/* <Description> */ +/* A PS_Table is a simple object used to store an array of objects in */ +/* a single memory block. */ +/* */ +/* <Fields> */ +/* block :: The address in memory of the growheap's block. This */ +/* can change between two object adds, due to */ +/* reallocation. */ +/* */ +/* cursor :: The current top of the grow heap within its block. */ +/* */ +/* capacity :: The current size of the heap block. Increments by */ +/* 1kByte chunks. */ +/* */ +/* max_elems :: The maximum number of elements in table. */ +/* */ +/* num_elems :: The current number of elements in table. */ +/* */ +/* elements :: A table of element addresses within the block. */ +/* */ +/* lengths :: A table of element sizes within the block. */ +/* */ +/* memory :: The object used for memory operations */ +/* (alloc/realloc). */ +/* */ +/* funcs :: A table of method pointers for this object. */ +/* */ + typedef struct PS_TableRec_ + { +/* current memory block */ + FT_Byte* block; +/* current cursor in memory block */ + FT_Offset cursor; +/* current size of memory block */ + FT_Offset capacity; + FT_Long init; + FT_Int max_elems; + FT_Int num_elems; +/* addresses of table elements */ + FT_Byte** elements; +/* lengths of table elements */ + FT_PtrDist* lengths; + FT_Memory memory; + PS_Table_FuncsRec funcs; + } PS_TableRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 FIELDS & TOKENS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct PS_ParserRec_* PS_Parser; + typedef struct T1_TokenRec_* T1_Token; + typedef struct T1_FieldRec_* T1_Field; +/* simple enumeration type used to identify token types */ + typedef enum T1_TokenType_ + { + T1_TOKEN_TYPE_NONE = 0, + T1_TOKEN_TYPE_ANY, + T1_TOKEN_TYPE_STRING, + T1_TOKEN_TYPE_ARRAY, +/* aka `name' */ + T1_TOKEN_TYPE_KEY, +/* do not remove */ + T1_TOKEN_TYPE_MAX + } T1_TokenType; +/* a simple structure used to identify tokens */ + typedef struct T1_TokenRec_ + { +/* first character of token in input stream */ + FT_Byte* start; +/* first character after the token */ + FT_Byte* limit; +/* type of token */ + T1_TokenType type; + } T1_TokenRec; +/* enumeration type used to identify object fields */ + typedef enum T1_FieldType_ + { + T1_FIELD_TYPE_NONE = 0, + T1_FIELD_TYPE_BOOL, + T1_FIELD_TYPE_INTEGER, + T1_FIELD_TYPE_FIXED, + T1_FIELD_TYPE_FIXED_1000, + T1_FIELD_TYPE_STRING, + T1_FIELD_TYPE_KEY, + T1_FIELD_TYPE_BBOX, + T1_FIELD_TYPE_INTEGER_ARRAY, + T1_FIELD_TYPE_FIXED_ARRAY, + T1_FIELD_TYPE_CALLBACK, +/* do not remove */ + T1_FIELD_TYPE_MAX + } T1_FieldType; + typedef enum T1_FieldLocation_ + { + T1_FIELD_LOCATION_CID_INFO, + T1_FIELD_LOCATION_FONT_DICT, + T1_FIELD_LOCATION_FONT_EXTRA, + T1_FIELD_LOCATION_FONT_INFO, + T1_FIELD_LOCATION_PRIVATE, + T1_FIELD_LOCATION_BBOX, + T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, + T1_FIELD_LOCATION_BLEND, +/* do not remove */ + T1_FIELD_LOCATION_MAX + } T1_FieldLocation; + typedef void + (*T1_Field_ParseFunc)( FT_Face face, + FT_Pointer parser ); +/* structure type used to model object fields */ + typedef struct T1_FieldRec_ + { +/* field identifier */ + const char* ident; + T1_FieldLocation location; +/* type of field */ + T1_FieldType type; + T1_Field_ParseFunc reader; +/* offset of field in object */ + FT_UInt offset; +/* size of field in bytes */ + FT_Byte size; +/* maximum number of elements for */ + FT_UInt array_max; +/* array */ +/* offset of element count for */ + FT_UInt count_offset; +/* arrays; must not be zero if in */ +/* use -- in other words, a */ +/* `num_FOO' element must not */ +/* start the used structure if we */ +/* parse a `FOO' array */ +/* where we expect it */ + FT_UInt dict; + } T1_FieldRec; +/* also FontInfo and FDArray */ +#define T1_FIELD_DICT_FONTDICT ( 1 << 0 ) +#define T1_FIELD_DICT_PRIVATE ( 1 << 1 ) +#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE( _fname ), \ + 0, 0, \ + _dict \ + }, +#define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ + { \ + _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ + (T1_Field_ParseFunc)_reader, \ + 0, 0, \ + 0, 0, \ + _dict \ + }, +#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, \ + FT_FIELD_OFFSET( num_ ## _fname ), \ + _dict \ + }, +#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ + { \ + _ident, T1CODE, _type, \ + 0, \ + FT_FIELD_OFFSET( _fname ), \ + FT_FIELD_SIZE_DELTA( _fname ), \ + _max, 0, \ + _dict \ + }, +#define T1_FIELD_BOOL( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BOOL, _fname, _dict ) +#define T1_FIELD_NUM( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER, _fname, _dict ) +#define T1_FIELD_FIXED( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED, _fname, _dict ) +#define T1_FIELD_FIXED_1000( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_1000, _fname, \ + _dict ) +#define T1_FIELD_STRING( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_STRING, _fname, _dict ) +#define T1_FIELD_KEY( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_KEY, _fname, _dict ) +#define T1_FIELD_BBOX( _ident, _fname, _dict ) \ + T1_NEW_SIMPLE_FIELD( _ident, T1_FIELD_TYPE_BBOX, _fname, _dict ) +#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) +#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) +#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_INTEGER_ARRAY, \ + _fname, _fmax, _dict ) +#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax, _dict ) \ + T1_NEW_TABLE_FIELD2( _ident, T1_FIELD_TYPE_FIXED_ARRAY, \ + _fname, _fmax, _dict ) +#define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ + T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 PARSER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef const struct PS_Parser_FuncsRec_* PS_Parser_Funcs; + typedef struct PS_Parser_FuncsRec_ + { + void + (*init)( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + void + (*done)( PS_Parser parser ); + void + (*skip_spaces)( PS_Parser parser ); + void + (*skip_PS_token)( PS_Parser parser ); + FT_Long + (*to_int)( PS_Parser parser ); + FT_Fixed + (*to_fixed)( PS_Parser parser, + FT_Int power_ten ); + FT_Error + (*to_bytes)( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); + FT_Int + (*to_coord_array)( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + FT_Int + (*to_fixed_array)( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + void + (*to_token)( PS_Parser parser, + T1_Token token ); + void + (*to_token_array)( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + FT_Error + (*load_field)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + FT_Error + (*load_field_table)( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + } PS_Parser_FuncsRec; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* PS_ParserRec */ +/* */ +/* <Description> */ +/* A PS_Parser is an object used to parse a Type 1 font very quickly. */ +/* */ +/* <Fields> */ +/* cursor :: The current position in the text. */ +/* */ +/* base :: Start of the processed text. */ +/* */ +/* limit :: End of the processed text. */ +/* */ +/* error :: The last error returned. */ +/* */ +/* memory :: The object used for memory operations (alloc/realloc). */ +/* */ +/* funcs :: A table of functions for the parser. */ +/* */ + typedef struct PS_ParserRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + FT_Error error; + FT_Memory memory; + PS_Parser_FuncsRec funcs; + } PS_ParserRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 BUILDER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct T1_BuilderRec_* T1_Builder; + typedef FT_Error + (*T1_Builder_Check_Points_Func)( T1_Builder builder, + FT_Int count ); + typedef void + (*T1_Builder_Add_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + typedef FT_Error + (*T1_Builder_Add_Point1_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + typedef FT_Error + (*T1_Builder_Add_Contour_Func)( T1_Builder builder ); + typedef FT_Error + (*T1_Builder_Start_Point_Func)( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + typedef void + (*T1_Builder_Close_Contour_Func)( T1_Builder builder ); + typedef const struct T1_Builder_FuncsRec_* T1_Builder_Funcs; + typedef struct T1_Builder_FuncsRec_ + { + void + (*init)( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Bool hinting ); + void + (*done)( T1_Builder builder ); + T1_Builder_Check_Points_Func check_points; + T1_Builder_Add_Point_Func add_point; + T1_Builder_Add_Point1_Func add_point1; + T1_Builder_Add_Contour_Func add_contour; + T1_Builder_Start_Point_Func start_point; + T1_Builder_Close_Contour_Func close_contour; + } T1_Builder_FuncsRec; +/* an enumeration type to handle charstring parsing states */ + typedef enum T1_ParseState_ + { + T1_Parse_Start, + T1_Parse_Have_Width, + T1_Parse_Have_Moveto, + T1_Parse_Have_Path + } T1_ParseState; +/*************************************************************************/ +/* */ +/* <Structure> */ +/* T1_BuilderRec */ +/* */ +/* <Description> */ +/* A structure used during glyph loading to store its outline. */ +/* */ +/* <Fields> */ +/* memory :: The current memory object. */ +/* */ +/* face :: The current face object. */ +/* */ +/* glyph :: The current glyph slot. */ +/* */ +/* loader :: XXX */ +/* */ +/* base :: The base glyph outline. */ +/* */ +/* current :: The current glyph outline. */ +/* */ +/* max_points :: maximum points in builder outline */ +/* */ +/* max_contours :: Maximum number of contours in builder outline. */ +/* */ +/* pos_x :: The horizontal translation (if composite glyph). */ +/* */ +/* pos_y :: The vertical translation (if composite glyph). */ +/* */ +/* left_bearing :: The left side bearing point. */ +/* */ +/* advance :: The horizontal advance vector. */ +/* */ +/* bbox :: Unused. */ +/* */ +/* parse_state :: An enumeration which controls the charstring */ +/* parsing state. */ +/* */ +/* load_points :: If this flag is not set, no points are loaded. */ +/* */ +/* no_recurse :: Set but not used. */ +/* */ +/* metrics_only :: A boolean indicating that we only want to compute */ +/* the metrics of a given glyph, not load all of its */ +/* points. */ +/* */ +/* funcs :: An array of function pointers for the builder. */ +/* */ + typedef struct T1_BuilderRec_ + { + FT_Memory memory; + FT_Face face; + FT_GlyphSlot glyph; + FT_GlyphLoader loader; + FT_Outline* base; + FT_Outline* current; + FT_Pos pos_x; + FT_Pos pos_y; + FT_Vector left_bearing; + FT_Vector advance; +/* bounding box */ + FT_BBox bbox; + T1_ParseState parse_state; + FT_Bool load_points; + FT_Bool no_recurse; + FT_Bool metrics_only; +/* hinter-specific */ + void* hints_funcs; +/* hinter-specific */ + void* hints_globals; + T1_Builder_FuncsRec funcs; + } T1_BuilderRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 DECODER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#if 0 +/*************************************************************************/ +/* */ +/* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ +/* calls during glyph loading. */ +/* */ +#define T1_MAX_SUBRS_CALLS 8 +/*************************************************************************/ +/* */ +/* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */ +/* minimum of 16 is required. */ +/* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 +/* 0 */ +#endif + typedef struct T1_Decoder_ZoneRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + } T1_Decoder_ZoneRec, *T1_Decoder_Zone; + typedef struct T1_DecoderRec_* T1_Decoder; + typedef const struct T1_Decoder_FuncsRec_* T1_Decoder_Funcs; + typedef FT_Error + (*T1_Decoder_Callback)( T1_Decoder decoder, + FT_UInt glyph_index ); + typedef struct T1_Decoder_FuncsRec_ + { + FT_Error + (*init)( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback callback ); + void + (*done)( T1_Decoder decoder ); + FT_Error + (*parse_charstrings)( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); + } T1_Decoder_FuncsRec; + typedef struct T1_DecoderRec_ + { + T1_BuilderRec builder; + FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Long* top; + T1_Decoder_ZoneRec zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone zone; +/* for seac */ + FT_Service_PsCMaps psnames; + FT_UInt num_glyphs; + FT_Byte** glyph_names; +/* internal for sub routine calls */ + FT_Int lenIV; + FT_UInt num_subrs; + FT_Byte** subrs; +/* array of subrs length (optional) */ + FT_PtrDist* subrs_len; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; +/* for multiple master support */ + PS_Blend blend; + FT_Render_Mode hint_mode; + T1_Decoder_Callback parse_callback; + T1_Decoder_FuncsRec funcs; + FT_Long* buildchar; + FT_UInt len_buildchar; + FT_Bool seac; + } T1_DecoderRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** AFM PARSER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct AFM_ParserRec_* AFM_Parser; + typedef struct AFM_Parser_FuncsRec_ + { + FT_Error + (*init)( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ); + void + (*done)( AFM_Parser parser ); + FT_Error + (*parse)( AFM_Parser parser ); + } AFM_Parser_FuncsRec; + typedef struct AFM_StreamRec_* AFM_Stream; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* AFM_ParserRec */ +/* */ +/* <Description> */ +/* An AFM_Parser is a parser for the AFM files. */ +/* */ +/* <Fields> */ +/* memory :: The object used for memory operations (alloc and */ +/* realloc). */ +/* */ +/* stream :: This is an opaque object. */ +/* */ +/* FontInfo :: The result will be stored here. */ +/* */ +/* get_index :: A user provided function to get a glyph index by its */ +/* name. */ +/* */ + typedef struct AFM_ParserRec_ + { + FT_Memory memory; + AFM_Stream stream; + AFM_FontInfo FontInfo; + FT_Int + (*get_index)( const char* name, + FT_Offset len, + void* user_data ); + void* user_data; + } AFM_ParserRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 CHARMAPS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef const struct T1_CMap_ClassesRec_* T1_CMap_Classes; + typedef struct T1_CMap_ClassesRec_ + { + FT_CMap_Class standard; + FT_CMap_Class expert; + FT_CMap_Class custom; + FT_CMap_Class unicode; + } T1_CMap_ClassesRec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PSAux Module Interface *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct PSAux_ServiceRec_ + { +/* don't use `PS_Table_Funcs' and friends to avoid compiler warnings */ + const PS_Table_FuncsRec* ps_table_funcs; + const PS_Parser_FuncsRec* ps_parser_funcs; + const T1_Builder_FuncsRec* t1_builder_funcs; + const T1_Decoder_FuncsRec* t1_decoder_funcs; + void + (*t1_decrypt)( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); + T1_CMap_Classes t1_cmap_classes; +/* fields after this comment line were added after version 2.1.10 */ + const AFM_Parser_FuncsRec* afm_parser_funcs; + } PSAux_ServiceRec, *PSAux_Service; +/* backwards-compatible type definition */ + typedef PSAux_ServiceRec PSAux_Interface; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** Some convenience functions *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#define IS_PS_NEWLINE( ch ) \ + ( (ch) == '\r' || \ + (ch) == '\n' ) +#define IS_PS_SPACE( ch ) \ + ( (ch) == ' ' || \ + IS_PS_NEWLINE( ch ) || \ + (ch) == '\t' || \ + (ch) == '\f' || \ + (ch) == '\0' ) +#define IS_PS_SPECIAL( ch ) \ + ( (ch) == '/' || \ + (ch) == '(' || (ch) == ')' || \ + (ch) == '<' || (ch) == '>' || \ + (ch) == '[' || (ch) == ']' || \ + (ch) == '{' || (ch) == '}' || \ + (ch) == '%' ) +#define IS_PS_DELIM( ch ) \ + ( IS_PS_SPACE( ch ) || \ + IS_PS_SPECIAL( ch ) ) +#define IS_PS_DIGIT( ch ) \ + ( (ch) >= '0' && (ch) <= '9' ) +#define IS_PS_XDIGIT( ch ) \ + ( IS_PS_DIGIT( ch ) || \ + ( (ch) >= 'A' && (ch) <= 'F' ) || \ + ( (ch) >= 'a' && (ch) <= 'f' ) ) +#define IS_PS_BASE85( ch ) \ + ( (ch) >= '!' && (ch) <= 'u' ) +#define IS_PS_TOKEN( cur, limit, token ) \ + ( (char)(cur)[0] == (token)[0] && \ + ( (cur) + sizeof ( (token) ) == (limit) || \ + ( (cur) + sizeof( (token) ) < (limit) && \ + IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) ) && \ + ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 ) +FT_END_HEADER +/* END */ +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_Long postscript_len; + FT_ULong data_offset; + FT_Long binary_length; + CID_FaceInfo cid; + FT_Int 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 +/* END */ +/***************************************************************************/ +/* */ +/* ciderrs.h */ +/* */ +/* CID error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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. */ +/* */ +/*************************************************************************/ +#define __CIDERRS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX CID_Err_ +#define FT_ERR_BASE FT_Mod_Err_CID +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_cidparse +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** INPUT STREAM PARSER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + 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_MEM_ZERO( parser, sizeof ( *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 ) ) + goto Exit; + if ( ft_strncmp( (char *)stream->cursor, + "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = CID_Err_Unknown_File_Format; + } + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + Again: +/* now, read the rest of the file until we find */ +/* `StartData' or `/sfnts' */ + { + FT_Byte buffer[256 + 10]; +/* same as signed FT_Stream->size */ + FT_Long read_len = 256 + 10; + FT_Byte* p = buffer; + for ( offset = FT_STREAM_POS(); ; offset += 256 ) + { +/* same as signed FT_Stream->size */ + FT_Long stream_len; + stream_len = stream->size - FT_STREAM_POS(); + if ( stream_len == 0 ) + { + FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); + error = CID_Err_Invalid_File_Format; + goto Exit; + } + read_len = FT_MIN( read_len, stream_len ); + if ( FT_STREAM_READ( p, read_len ) ) + goto Exit; + if ( read_len < 256 ) + p[read_len] = '\0'; + limit = p + read_len - 10; + for ( p = buffer; p < limit; p++ ) + { + if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 ) + { +/* save offset of binary data after `StartData' */ + offset += p - buffer + 10; + goto Found; + } + else if ( p[1] == 's' && ft_strncmp( (char*)p, "/sfnts", 6 ) == 0 ) + { + offset += p - buffer + 7; + goto Found; + } + } + FT_MEM_MOVE( buffer, p, 10 ); + read_len = 256; + p = buffer + 10; + } + } + 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 = -1; +/* 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 ) + { + if ( parser->root.error ) + { + error = parser->root.error; + goto Exit; + } + if ( cur[0] == 'S' && ft_strncmp( (char*)cur, "StartData", 9 ) == 0 ) + { + if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 ) + parser->binary_length = ft_atol( (const char *)arg2 ); + limit = parser->root.limit; + cur = parser->root.cursor; + goto Exit; + } + else if ( cur[1] == 's' && ft_strncmp( (char*)cur, "/sfnts", 6 ) == 0 ) + { + FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); + error = CID_Err_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; + } + 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 */ +/***************************************************************************/ +/* */ +/* cidload.c */ +/* */ +/* CID-keyed Type1 font loader (body). */ +/* */ +/* Copyright 1996-2006, 2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* cidload.h */ +/* */ +/* CID-keyed Type1 font loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004 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. */ +/* */ +/***************************************************************************/ +#define __CIDLOAD_H__ +FT_BEGIN_HEADER + typedef struct CID_Loader_ + { +/* parser used to read the stream */ + CID_Parser parser; +/* number of characters in encoding */ + FT_Int num_chars; + } CID_Loader; + FT_LOCAL( FT_Long ) + cid_get_offset( FT_Byte** start, + FT_Byte offsize ); + FT_LOCAL( FT_Error ) + cid_face_open( CID_Face face, + FT_Int face_index ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_cidload +/* read a single offset */ + FT_LOCAL_DEF( FT_Long ) + cid_get_offset( FT_Byte* *start, + FT_Byte offsize ) + { + FT_Long 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 ) + { + 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 < 0 || parser->num_dict >= cid->num_dicts ) + { + FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", + keyword->ident )); + error = CID_Err_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; + } + } + } + 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 ); + Exit: + return error; + } + FT_CALLBACK_DEF( FT_Error ) + cid_parse_font_matrix( CID_Face face, + CID_Parser* parser ) + { + FT_Matrix* matrix; + FT_Vector* offset; + CID_FaceDict dict; + FT_Face root = (FT_Face)&face->root; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + { + dict = face->cid.font_dicts + parser->num_dict; + matrix = &dict->font_matrix; + offset = &dict->font_offset; + (void)cid_parser_to_fixed_array( parser, 6, temp, 3 ); + temp_scale = FT_ABS( temp[3] ); +/* Set Units per EM based on FontMatrix values. We set the value to */ +/* 1000 / temp_scale, because temp_scale was already multiplied by */ +/* 1000 (in t1_tofixed, from psobjs.c). */ + root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); +/* we need to scale the values by 1.0/temp[3] */ + if ( temp_scale != 0x10000L ) + { + 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] = 0x10000L; + } + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; +/* note that the font offsets are expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } +/* this is a callback function; */ + return CID_Err_Ok; +/* we must return an error code */ + } + FT_CALLBACK_DEF( FT_Error ) + parse_fd_array( CID_Face face, + CID_Parser* parser ) + { + CID_FaceInfo cid = &face->cid; + FT_Memory memory = face->root.memory; + FT_Error error = CID_Err_Ok; + FT_Long num_dicts; + num_dicts = cid_parser_to_int( parser ); + if ( !cid->font_dicts ) + { + FT_Int n; + if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) + goto Exit; + cid->num_dicts = (FT_UInt)num_dicts; +/* don't forget to set a few defaults */ + for ( n = 0; n < cid->num_dicts; n++ ) + { + CID_FaceDict dict = cid->font_dicts + n; +/* default value for lenIV */ + dict->private_dict.lenIV = 4; + } + } + Exit: + return error; + } +/* by mistake, `expansion_factor' appears both in PS_PrivateRec */ +/* and CID_FaceDictRec (both are public header files and can't */ +/* changed); we simply copy the value */ + FT_CALLBACK_DEF( FT_Error ) + parse_expansion_factor( CID_Face face, + CID_Parser* parser ) + { + CID_FaceDict dict; + if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + { + dict = face->cid.font_dicts + parser->num_dict; + dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); + dict->private_dict.expansion_factor = dict->expansion_factor; + } + return CID_Err_Ok; + } + static + const T1_FieldRec cid_field_records[] = + { +/***************************************************************************/ +/* */ +/* cidtoken.h */ +/* */ +/* CID token definitions (specification only). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2006, 2008, 2009 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 ( "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 */ + 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 ) + { 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_Long size ) + { + CID_Parser* parser = &loader->parser; + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = CID_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++; + } + } + 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_PtrDist len; + cur++; + len = 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_PtrDist)ft_strlen( (const char*)name ) ) + { + FT_PtrDist 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; + } + } + 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_Int n; + CID_Subrs subr; + FT_UInt max_offsets = 0; + FT_ULong* offsets = 0; + 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; +/* Check for possible overflow. */ + if ( num_subrs == FT_UINT_MAX ) + { + error = CID_Err_Syntax_Error; + goto Fail; + } +/* 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 = CID_Err_Syntax_Error; + goto Fail; + } + if ( FT_RENEW_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, (FT_Byte)dict->sd_bytes ); + FT_FRAME_EXIT(); +/* offsets must be ordered */ + for ( count = 1; count <= num_subrs; count++ ) + if ( offsets[count - 1] > offsets[count] ) + goto Fail; +/* now, compute the size of subrs charstrings, */ +/* allocate, and read them */ + data_len = offsets[num_subrs] - offsets[0]; + if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) || + FT_ALLOC( 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 = 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_MEM_ZERO( loader, sizeof ( *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_Long data_len, + FT_ULong offset, + CID_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Error error; + FT_Byte buffer[256]; + FT_Byte *p, *plimit; + FT_Byte *d, *dlimit; + FT_Byte val; + FT_Bool upper_nibble, done; + if ( FT_STREAM_SEEK( offset ) ) + goto Exit; + d = data; + 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 = CID_Err_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' ); + 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 = CID_Err_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 = CID_Err_Ok; + Exit: + 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; + 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 ) + { +/* we must convert the data section from hexadecimal to binary */ + if ( FT_ALLOC( face->binary_data, parser->binary_length ) || + cid_hex_to_binary( face->binary_data, parser->binary_length, + parser->data_offset, face ) ) + goto Exit; + FT_Stream_OpenMemory( face->cid_stream, + face->binary_data, parser->binary_length ); + face->cid.data_offset = 0; + } + else + { + *face->cid_stream = *face->root.stream; + face->cid.data_offset = loader.parser.data_offset; + } + error = cid_read_subrs( face ); + Exit: + cid_done_loader( &loader ); + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* cidobjs.c */ +/* */ +/* CID objects manager (body). */ +/* */ +/* Copyright 1996-2006, 2008, 2010-2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* cidgload.h */ +/* */ +/* OpenType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004 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. */ +/* */ +/***************************************************************************/ +#define __CIDGLOAD_H__ +/***************************************************************************/ +/* */ +/* cidobjs.h */ +/* */ +/* CID objects manager (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006 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. */ +/* */ +/***************************************************************************/ +#define __CIDOBJS_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 */ + cid_size_done( FT_Size size ); + FT_LOCAL( FT_Error ) +/* CID_Size */ + cid_size_init( FT_Size size ); + FT_LOCAL( FT_Error ) +/* CID_Size */ + cid_size_request( FT_Size size, + FT_Size_Request req ); + FT_LOCAL( FT_Error ) + cid_face_init( FT_Stream stream, +/* CID_Face */ + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) +/* CID_Face */ + cid_face_done( FT_Face face ); + FT_LOCAL( FT_Error ) + cid_driver_init( FT_Module driver ); + FT_LOCAL( void ) + cid_driver_done( FT_Module driver ); +FT_END_HEADER +/* END */ +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 ); +/* 0 */ +#endif + FT_LOCAL( FT_Error ) +/* CID_Glyph_Slot */ + cid_slot_load_glyph( FT_GlyphSlot glyph, +/* CID_Size */ + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_cidobjs +/*************************************************************************/ +/* */ +/* SLOT FUNCTIONS */ +/* */ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + cid_slot_done( FT_GlyphSlot slot ) + { + slot->internal->glyph_hints = 0; + } + 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->face->driver->root.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 */ + cid_size_done( FT_Size cidsize ) + { + CID_Size size = (CID_Size)cidsize; + if ( cidsize->internal ) + { + PSH_Globals_Funcs funcs; + funcs = cid_size_get_globals_funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)cidsize->internal ); + cidsize->internal = 0; + } + } + FT_LOCAL_DEF( FT_Error ) +/* CID_Size */ + cid_size_init( FT_Size cidsize ) + { + CID_Size size = (CID_Size)cidsize; + FT_Error error = CID_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 = (FT_Size_Internal)(void*)globals; + } + return error; + } + FT_LOCAL( FT_Error ) + cid_size_request( FT_Size size, + FT_Size_Request req ) + { + PSH_Globals_Funcs funcs; + FT_Request_Metrics( size->face, req ); + funcs = cid_size_get_globals_funcs( (CID_Size)size ); + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->internal, + size->metrics.x_scale, + size->metrics.y_scale, + 0, 0 ); + return CID_Err_Ok; + } +/*************************************************************************/ +/* */ +/* 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 */ + cid_face_done( FT_Face cidface ) + { + 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_Int 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 = 0; + cidface->style_name = 0; + FT_FREE( face->binary_data ); + FT_FREE( face->cid_stream ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* cid_face_init */ +/* */ +/* <Description> */ +/* Initializes a given CID face object. */ +/* */ +/* <Input> */ +/* stream :: The source font 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, +/* CID_Face */ + FT_Face cidface, + 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 = CID_Err_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 != 0 ) + { + FT_ERROR(( "cid_face_init: invalid face index\n" )); + error = CID_Err_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 = cid->cid_count; + cidface->num_charmaps = 0; + cidface->face_index = face_index; +/* scalable outlines */ + cidface->face_flags = FT_FACE_FLAG_SCALABLE | +/* horizontal data */ + FT_FACE_FLAG_HORIZONTAL | +/* has native hinter */ + FT_FACE_FLAG_HINTER; + if ( info->is_fixed_pitch ) + cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; +/* 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 = 0; + 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 driver ) + { + FT_UNUSED( driver ); + return CID_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 */ +/***************************************************************************/ +/* */ +/* cidriver.c */ +/* */ +/* CID driver interface (body). */ +/* */ +/* Copyright 1996-2004, 2006, 2008, 2009, 2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* cidriver.h */ +/* */ +/* High-level CID driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ +#define __CIDRIVER_H__ +FT_BEGIN_HEADER + FT_CALLBACK_TABLE + const FT_Driver_ClassRec t1cid_driver_class; +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ciddriver +/* + * POSTSCRIPT NAME SERVICE + * + */ + static const char* + cid_get_postscript_name( CID_Face face ) + { + const char* result = face->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 + }; +/* + * POSTSCRIPT INFO SERVICE + * + */ + static FT_Error + cid_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((CID_Face)face)->cid.font_info; + return CID_Err_Ok; + } + static FT_Error + cid_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((CID_Face)face)->font_extra; + return CID_Err_Ok; + } + static const FT_Service_PsInfoRec cid_service_ps_info = + { + (PS_GetFontInfoFunc) cid_ps_get_font_info, + (PS_GetFontExtraFunc) cid_ps_get_font_extra, +/* unsupported with CID fonts */ + (PS_HasGlyphNamesFunc) NULL, +/* unsupported */ + (PS_GetFontPrivateFunc)NULL, +/* not implemented */ + (PS_GetFontValueFunc) NULL + }; +/* + * CID INFO SERVICE + * + */ + static FT_Error + cid_get_ros( CID_Face face, + const char* *registry, + const char* *ordering, + FT_Int *supplement ) + { + CID_FaceInfo cid = &face->cid; + if ( registry ) + *registry = cid->registry; + if ( ordering ) + *ordering = cid->ordering; + if ( supplement ) + *supplement = cid->supplement; + return CID_Err_Ok; + } + static FT_Error + cid_get_is_cid( CID_Face face, + FT_Bool *is_cid ) + { + FT_Error error = CID_Err_Ok; + FT_UNUSED( face ); + if ( is_cid ) +/* cid driver is only used for CID keyed fonts */ + *is_cid = 1; + return error; + } + static FT_Error + cid_get_cid_from_glyph_index( CID_Face face, + FT_UInt glyph_index, + FT_UInt *cid ) + { + FT_Error error = CID_Err_Ok; + FT_UNUSED( face ); + if ( cid ) +/* identity mapping */ + *cid = glyph_index; + return error; + } + static const FT_Service_CIDRec cid_service_cid_info = + { + (FT_CID_GetRegistryOrderingSupplementFunc)cid_get_ros, + (FT_CID_GetIsInternallyCIDKeyedFunc) cid_get_is_cid, + (FT_CID_GetCIDFromGlyphIndexFunc) cid_get_cid_from_glyph_index + }; +/* + * SERVICE LIST + * + */ + static const FT_ServiceDescRec cid_services[] = + { + { FT_SERVICE_ID_XF86_NAME, FT_XF86_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 }, + { 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 = + { +/* first of all, the FT_Module_Class fields */ + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + sizeof ( FT_DriverRec ), +/* module name */ + "t1cid", +/* version 1.0 of driver */ + 0x10000L, +/* requires FreeType 2.0 */ + 0x20000L, + 0, + cid_driver_init, + cid_driver_done, + cid_get_interface + }, +/* then the other font drivers fields */ + sizeof ( CID_FaceRec ), + sizeof ( CID_SizeRec ), + sizeof ( CID_GlyphSlotRec ), + cid_face_init, + cid_face_done, + cid_size_init, + cid_size_done, + cid_slot_init, + cid_slot_done, + cid_slot_load_glyph, +/* FT_Face_GetKerningFunc */ + 0, +/* FT_Face_AttachFunc */ + 0, +/* FT_Face_GetAdvancesFunc */ + 0, + cid_size_request, +/* FT_Size_SelectFunc */ + 0 + }; +/* END */ +/***************************************************************************/ +/* */ +/* cidgload.c */ +/* */ +/* CID-keyed Type1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 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 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 trace_cidgload + 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_UInt fd_select; + FT_Stream stream = face->cid_stream; + FT_Error error = CID_Err_Ok; + FT_Byte* charstring = 0; + FT_Memory memory = face->root.memory; + FT_ULong glyph_length = 0; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; + FT_TRACE4(( "cid_load_glyph: glyph index %d\n", glyph_index )); +/* 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 ) + goto Exit; + p = (FT_Byte*)glyph_data.pointer; + fd_select = (FT_UInt)cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + if ( glyph_data.length != 0 ) + { + glyph_length = glyph_data.length - cid->fd_bytes; + (void)FT_ALLOC( charstring, glyph_length ); + if ( !error ) + ft_memcpy( charstring, glyph_data.pointer + cid->fd_bytes, + glyph_length ); + } + inc->funcs->free_glyph_data( inc->object, &glyph_data ); + if ( error ) + goto Exit; + } + else +/* For ordinary fonts read the CID font dictionary index */ +/* and charstring offset from the CIDMap. */ + { + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + FT_ULong off1; + if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len ) || + FT_FRAME_ENTER( 2 * entry_len ) ) + goto Exit; + p = (FT_Byte*)stream->cursor; + fd_select = (FT_UInt) cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + off1 = (FT_ULong)cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); + p += cid->fd_bytes; + glyph_length = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ) - off1; + FT_FRAME_EXIT(); + if ( fd_select >= (FT_UInt)cid->num_dicts ) + { + error = CID_Err_Invalid_Offset; + goto Exit; + } + if ( glyph_length == 0 ) + goto Exit; + if ( FT_ALLOC( charstring, glyph_length ) ) + goto Exit; + if ( 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_Int cs_offset; +/* Set up subrs */ + decoder->num_subrs = cid_subrs->num_subrs; + decoder->subrs = cid_subrs->code; + decoder->subrs_len = 0; +/* 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 ? decoder->lenIV : 0 ); +/* Decrypt only if lenIV >= 0. */ + if ( decoder->lenIV >= 0 ) + psaux->t1_decrypt( charstring, glyph_length, 4330 ); + error = decoder->funcs.parse_charstrings( + decoder, charstring + cs_offset, + (FT_Int)glyph_length - cs_offset ); + } + FT_FREE( charstring ); +/* 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 ); + } + Exit: + 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, +/* size */ + 0, +/* glyph slot */ + 0, +/* glyph names! XXX */ + 0, +/* blend == 0 */ + 0, +/* hinting == 0 */ + 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 CID_Err_Ok; + } +/* 0 */ +#endif + FT_LOCAL_DEF( FT_Error ) +/* CID_GlyphSlot */ + cid_slot_load_glyph( FT_GlyphSlot cidglyph, +/* CID_Size */ + FT_Size cidsize, + 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; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Matrix font_matrix; + FT_Vector font_offset; + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = CID_Err_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 ); + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + error = psaux->t1_decoder_funcs->init( &decoder, + cidglyph->face, + cidsize, + cidglyph, +/* glyph names -- XXX */ + 0, +/* blend == 0 */ + 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 */ +/* set up the decoder */ + decoder.builder.no_recurse = FT_BOOL( + ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) ); + error = cid_load_glyph( &decoder, glyph_index ); + if ( error ) + goto Exit; + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; +/* save new glyph tables */ + psaux->t1_decoder_funcs->done( &decoder ); +/* 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; + FT_Vector advance; +/* 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 */ + FT_Outline_Transform( &cidglyph->outline, &font_matrix ); + FT_Outline_Translate( &cidglyph->outline, + font_offset.x, + font_offset.y ); + advance.x = metrics->horiAdvance; + advance.y = 0; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->horiAdvance = advance.x + font_offset.x; + advance.x = 0; + advance.y = metrics->vertAdvance; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->vertAdvance = advance.y + font_offset.y; + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { +/* 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: + return error; + } +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* psaux.c */ +/* */ +/* FreeType auxiliary PostScript driver component (body only). */ +/* */ +/* Copyright 1996-2001, 2002, 2006 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* psobjs.c */ +/* */ +/* Auxiliary functions for PostScript fonts (body). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* psobjs.h */ +/* */ +/* Auxiliary functions for PostScript fonts (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003 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. */ +/* */ +/***************************************************************************/ +#define __PSOBJS_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1_TABLE *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_TABLE + const PS_Table_FuncsRec ps_table_funcs; + FT_CALLBACK_TABLE + const PS_Parser_FuncsRec ps_parser_funcs; + FT_CALLBACK_TABLE + const T1_Builder_FuncsRec t1_builder_funcs; + FT_LOCAL( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ); + FT_LOCAL( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ); + FT_LOCAL( void ) + ps_table_done( PS_Table table ); + FT_LOCAL( void ) + ps_table_release( PS_Table table ); +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 PARSER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL( void ) + ps_parser_skip_spaces( PS_Parser parser ); + FT_LOCAL( void ) + ps_parser_skip_PS_token( PS_Parser parser ); + FT_LOCAL( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ); + FT_LOCAL( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ); + FT_LOCAL( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + FT_LOCAL( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ); + FT_LOCAL( FT_Long ) + ps_parser_to_int( PS_Parser parser ); + FT_LOCAL( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ); + FT_LOCAL( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ); + FT_LOCAL( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ); + FT_LOCAL( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ); + FT_LOCAL( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ); + FT_LOCAL( void ) + ps_parser_done( PS_Parser parser ); +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 BUILDER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ); + FT_LOCAL( void ) + t1_builder_done( T1_Builder builder ); + FT_LOCAL( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ); + FT_LOCAL( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ); + FT_LOCAL( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + FT_LOCAL( FT_Error ) + t1_builder_add_contour( T1_Builder builder ); + FT_LOCAL( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ); + FT_LOCAL( void ) + t1_builder_close_contour( T1_Builder builder ); +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** OTHER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* psconv.h */ +/* */ +/* Some convenience conversions (specification). */ +/* */ +/* Copyright 2006, 2012 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. */ +/* */ +/***************************************************************************/ +#define __PSCONV_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Long ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Long base ); + FT_LOCAL( FT_Long ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ); + FT_LOCAL( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ); +#if 0 + FT_LOCAL( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ); +#endif + FT_LOCAL( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ); + FT_LOCAL( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n, + FT_UShort* seed ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* psauxerr.h */ +/* */ +/* PS auxiliary module error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 PS auxiliary module error enumeration */ +/* constants. */ +/* */ +/*************************************************************************/ +#define __PSAUXERR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PSaux_Err_ +#define FT_ERR_BASE FT_Mod_Err_PSaux +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_psobjs +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PS_TABLE *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* ps_table_new */ +/* */ +/* <Description> */ +/* Initializes a PS_Table. */ +/* */ +/* <InOut> */ +/* table :: The address of the target table. */ +/* */ +/* <Input> */ +/* count :: The table size = the maximum number of elements. */ +/* */ +/* memory :: The memory object to use for all subsequent */ +/* reallocations. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + ps_table_new( PS_Table table, + FT_Int count, + FT_Memory memory ) + { + FT_Error error; + table->memory = memory; + if ( FT_NEW_ARRAY( table->elements, count ) || + FT_NEW_ARRAY( table->lengths, count ) ) + goto Exit; + table->max_elems = count; + table->init = 0xDEADBEEFUL; + table->num_elems = 0; + table->block = 0; + table->capacity = 0; + table->cursor = 0; + *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; + Exit: + if ( error ) + FT_FREE( table->elements ); + return error; + } + static void + shift_elements( PS_Table table, + FT_Byte* old_base ) + { + FT_PtrDist delta = table->block - old_base; + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + for ( ; offset < limit; offset++ ) + { + if ( offset[0] ) + offset[0] += delta; + } + } + static FT_Error + reallocate_t1_table( PS_Table table, + FT_Long new_size ) + { + FT_Memory memory = table->memory; + FT_Byte* old_base = table->block; + FT_Error error; +/* allocate new base block */ + if ( FT_ALLOC( table->block, new_size ) ) + { + table->block = old_base; + return error; + } +/* copy elements and shift offsets */ + if ( old_base ) + { + FT_MEM_COPY( table->block, old_base, table->capacity ); + shift_elements( table, old_base ); + FT_FREE( old_base ); + } + table->capacity = new_size; + return PSaux_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ps_table_add */ +/* */ +/* <Description> */ +/* Adds an object to a PS_Table, possibly growing its memory block. */ +/* */ +/* <InOut> */ +/* table :: The target table. */ +/* */ +/* <Input> */ +/* idx :: The index of the object in the table. */ +/* */ +/* object :: The address of the object to copy in memory. */ +/* */ +/* length :: The length in bytes of the source object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. An error is returned if a */ +/* reallocation fails. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + ps_table_add( PS_Table table, + FT_Int idx, + void* object, + FT_PtrDist length ) + { + if ( idx < 0 || idx >= table->max_elems ) + { + FT_ERROR(( "ps_table_add: invalid index\n" )); + return PSaux_Err_Invalid_Argument; + } + if ( length < 0 ) + { + FT_ERROR(( "ps_table_add: invalid length\n" )); + return PSaux_Err_Invalid_Argument; + } +/* grow the base block if needed */ + if ( table->cursor + length > table->capacity ) + { + FT_Error error; + FT_Offset new_size = table->capacity; + FT_PtrDist in_offset; + in_offset = (FT_Byte*)object - table->block; + if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity ) + in_offset = -1; + while ( new_size < table->cursor + length ) + { +/* increase size by 25% and round up to the nearest multiple + of 1024 */ + new_size += ( new_size >> 2 ) + 1; + new_size = FT_PAD_CEIL( new_size, 1024 ); + } + error = reallocate_t1_table( table, new_size ); + if ( error ) + return error; + if ( in_offset >= 0 ) + object = table->block + in_offset; + } +/* add the object to the base block and adjust offset */ + table->elements[idx] = table->block + table->cursor; + table->lengths [idx] = length; + FT_MEM_COPY( table->block + table->cursor, object, length ); + table->cursor += length; + return PSaux_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ps_table_done */ +/* */ +/* <Description> */ +/* Finalizes a PS_TableRec (i.e., reallocate it to its current */ +/* cursor). */ +/* */ +/* <InOut> */ +/* table :: The target table. */ +/* */ +/* <Note> */ +/* This function does NOT release the heap's memory block. It is up */ +/* to the caller to clean it, or reference it in its own structures. */ +/* */ + FT_LOCAL_DEF( void ) + ps_table_done( PS_Table table ) + { + FT_Memory memory = table->memory; + FT_Error error; + FT_Byte* old_base = table->block; +/* should never fail, because rec.cursor <= rec.size */ + if ( !old_base ) + return; + if ( FT_ALLOC( table->block, table->cursor ) ) + return; + FT_MEM_COPY( table->block, old_base, table->cursor ); + shift_elements( table, old_base ); + table->capacity = table->cursor; + FT_FREE( old_base ); + FT_UNUSED( error ); + } + FT_LOCAL_DEF( void ) + ps_table_release( PS_Table table ) + { + FT_Memory memory = table->memory; + if ( (FT_ULong)table->init == 0xDEADBEEFUL ) + { + FT_FREE( table->block ); + FT_FREE( table->elements ); + FT_FREE( table->lengths ); + table->init = 0; + } + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 PARSER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* first character must be already part of the comment */ + static void + skip_comment( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + while ( cur < limit ) + { + if ( IS_PS_NEWLINE( *cur ) ) + break; + cur++; + } + *acur = cur; + } + static void + skip_spaces( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + while ( cur < limit ) + { + if ( !IS_PS_SPACE( *cur ) ) + { + if ( *cur == '%' ) +/* According to the PLRM, a comment is equal to a space. */ + skip_comment( &cur, limit ); + else + break; + } + cur++; + } + *acur = cur; + } +#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) +/* first character must be `('; */ +/* *acur is positioned at the character after the closing `)' */ + static FT_Error + skip_literal_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Int embed = 0; + FT_Error error = PSaux_Err_Invalid_File_Format; + unsigned int i; + while ( cur < limit ) + { + FT_Byte c = *cur; + ++cur; + if ( c == '\\' ) + { +/* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ +/* A backslash can introduce three different types */ +/* of escape sequences: */ +/* - a special escaped char like \r, \n, etc. */ +/* - a one-, two-, or three-digit octal number */ +/* - none of the above in which case the backslash is ignored */ + if ( cur == limit ) +/* error (or to be ignored?) */ + break; + switch ( *cur ) + { +/* skip `special' escape */ + case 'n': + case 'r': + case 't': + case 'b': + case 'f': + case '\\': + case '(': + case ')': + ++cur; + break; + default: +/* skip octal escape or ignore backslash */ + for ( i = 0; i < 3 && cur < limit; ++i ) + { + if ( !IS_OCTAL_DIGIT( *cur ) ) + break; + ++cur; + } + } + } + else if ( c == '(' ) + embed++; + else if ( c == ')' ) + { + embed--; + if ( embed == 0 ) + { + error = PSaux_Err_Ok; + break; + } + } + } + *acur = cur; + return error; + } +/* first character must be `<' */ + static FT_Error + skip_string( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Error err = PSaux_Err_Ok; + while ( ++cur < limit ) + { +/* All whitespace characters are ignored. */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + break; + if ( !IS_PS_XDIGIT( *cur ) ) + break; + } + if ( cur < limit && *cur != '>' ) + { + FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); + err = PSaux_Err_Invalid_File_Format; + } + else + cur++; + *acur = cur; + return err; + } +/* first character must be the opening brace that */ +/* starts the procedure */ +/* NB: [ and ] need not match: */ +/* `/foo {[} def' is a valid PostScript fragment, */ +/* even within a Type1 font */ + static FT_Error + skip_procedure( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur; + FT_Int embed = 0; + FT_Error error = PSaux_Err_Ok; + FT_ASSERT( **acur == '{' ); + for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur ) + { + switch ( *cur ) + { + case '{': + ++embed; + break; + case '}': + --embed; + if ( embed == 0 ) + { + ++cur; + goto end; + } + break; + case '(': + error = skip_literal_string( &cur, limit ); + break; + case '<': + error = skip_string( &cur, limit ); + break; + case '%': + skip_comment( &cur, limit ); + break; + } + } + end: + if ( embed != 0 ) + error = PSaux_Err_Invalid_File_Format; + *acur = cur; + return error; + } +/***********************************************************************/ +/* */ +/* All exported parsing routines handle leading whitespace and stop at */ +/* the first character which isn't part of the just handled token. */ +/* */ +/***********************************************************************/ + FT_LOCAL_DEF( void ) + ps_parser_skip_PS_token( PS_Parser parser ) + { +/* Note: PostScript allows any non-delimiting, non-whitespace */ +/* character in a name (PS Ref Manual, 3rd ed, p31). */ +/* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ + FT_Byte* cur = parser->cursor; + FT_Byte* limit = parser->limit; + FT_Error error = PSaux_Err_Ok; +/* this also skips comments */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; +/* self-delimiting, single-character tokens */ + if ( *cur == '[' || *cur == ']' ) + { + cur++; + goto Exit; + } +/* skip balanced expressions (procedures and strings) */ +/* {...} */ + if ( *cur == '{' ) + { + error = skip_procedure( &cur, limit ); + goto Exit; + } +/* (...) */ + if ( *cur == '(' ) + { + error = skip_literal_string( &cur, limit ); + goto Exit; + } +/* <...> */ + if ( *cur == '<' ) + { +/* << */ + if ( cur + 1 < limit && *(cur + 1) == '<' ) + { + cur++; + cur++; + } + else + error = skip_string( &cur, limit ); + goto Exit; + } + if ( *cur == '>' ) + { + cur++; +/* >> */ + if ( cur >= limit || *cur != '>' ) + { + FT_ERROR(( "ps_parser_skip_PS_token:" + " unexpected closing delimiter `>'\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + cur++; + goto Exit; + } + if ( *cur == '/' ) + cur++; +/* anything else */ + while ( cur < limit ) + { +/* *cur might be invalid (e.g., ')' or '}'), but this */ +/* is handled by the test `cur == parser->cursor' below */ + if ( IS_PS_DELIM( *cur ) ) + break; + cur++; + } + Exit: + if ( cur < limit && cur == parser->cursor ) + { + FT_ERROR(( "ps_parser_skip_PS_token:" + " current token is `%c' which is self-delimiting\n" + " " + " but invalid at this point\n", + *cur )); + error = PSaux_Err_Invalid_File_Format; + } + parser->error = error; + parser->cursor = cur; + } + FT_LOCAL_DEF( void ) + ps_parser_skip_spaces( PS_Parser parser ) + { + skip_spaces( &parser->cursor, parser->limit ); + } +/* `token' here means either something between balanced delimiters */ +/* or the next token; the delimiters are not removed. */ + FT_LOCAL_DEF( void ) + ps_parser_to_token( PS_Parser parser, + T1_Token token ) + { + FT_Byte* cur; + FT_Byte* limit; + FT_Int embed; + token->type = T1_TOKEN_TYPE_NONE; + token->start = 0; + token->limit = 0; +/* first of all, skip leading whitespace */ + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + limit = parser->limit; + if ( cur >= limit ) + return; + switch ( *cur ) + { +/************* check for literal string *****************/ + case '(': + token->type = T1_TOKEN_TYPE_STRING; + token->start = cur; + if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok ) + token->limit = cur; + break; +/************* check for programs/array *****************/ + case '{': + token->type = T1_TOKEN_TYPE_ARRAY; + token->start = cur; + if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok ) + token->limit = cur; + break; +/************* check for table/array ********************/ +/* XXX: in theory we should also look for "<<" */ +/* since this is semantically equivalent to "["; */ +/* in practice it doesn't matter (?) */ + case '[': + token->type = T1_TOKEN_TYPE_ARRAY; + embed = 1; + token->start = cur++; +/* we need this to catch `[ ]' */ + parser->cursor = cur; + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + while ( cur < limit && !parser->error ) + { +/* XXX: this is wrong because it does not */ +/* skip comments, procedures, and strings */ + if ( *cur == '[' ) + embed++; + else if ( *cur == ']' ) + { + embed--; + if ( embed <= 0 ) + { + token->limit = ++cur; + break; + } + } + parser->cursor = cur; + ps_parser_skip_PS_token( parser ); +/* we need this to catch `[XXX ]' */ + ps_parser_skip_spaces ( parser ); + cur = parser->cursor; + } + break; +/* ************ otherwise, it is any token **************/ + default: + token->start = cur; + token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); + ps_parser_skip_PS_token( parser ); + cur = parser->cursor; + if ( !parser->error ) + token->limit = cur; + } + if ( !token->limit ) + { + token->start = 0; + token->type = T1_TOKEN_TYPE_NONE; + } + parser->cursor = cur; + } +/* NB: `tokens' can be NULL if we only want to count */ +/* the number of array elements */ + FT_LOCAL_DEF( void ) + ps_parser_to_token_array( PS_Parser parser, + T1_Token tokens, + FT_UInt max_tokens, + FT_Int* pnum_tokens ) + { + T1_TokenRec master; + *pnum_tokens = -1; +/* this also handles leading whitespace */ + ps_parser_to_token( parser, &master ); + if ( master.type == T1_TOKEN_TYPE_ARRAY ) + { + FT_Byte* old_cursor = parser->cursor; + FT_Byte* old_limit = parser->limit; + T1_Token cur = tokens; + T1_Token limit = cur + max_tokens; +/* don't include outermost delimiters */ + parser->cursor = master.start + 1; + parser->limit = master.limit - 1; + while ( parser->cursor < parser->limit ) + { + T1_TokenRec token; + ps_parser_to_token( parser, &token ); + if ( !token.type ) + break; + if ( tokens != NULL && cur < limit ) + *cur = token; + cur++; + } + *pnum_tokens = (FT_Int)( cur - tokens ); + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } +/* first character must be a delimiter or a part of a number */ +/* NB: `coords' can be NULL if we just want to skip the */ +/* array; in this case we ignore `max_coords' */ + static FT_Int + ps_tocoordarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_coords, + FT_Short* coords ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + if ( cur >= limit ) + goto Exit; +/* check for the beginning of an array; otherwise, only one number */ +/* will be read */ + c = *cur; + ender = 0; + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + if ( ender ) + cur++; +/* now, read the coordinates */ + while ( cur < limit ) + { + FT_Short dummy; + FT_Byte* old_cur; +/* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + if ( *cur == ender ) + { + cur++; + break; + } + old_cur = cur; + if ( coords != NULL && count >= max_coords ) + break; +/* call PS_Conv_ToFixed() even if coords == NULL */ +/* to properly parse number at `cur' */ + *( coords != NULL ? &coords[count] : &dummy ) = + (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + if ( !ender ) + break; + } + Exit: + *acur = cur; + return count; + } +/* first character must be a delimiter or a part of a number */ +/* NB: `values' can be NULL if we just want to skip the */ +/* array; in this case we ignore `max_values' */ + static FT_Int + ps_tofixedarray( FT_Byte* *acur, + FT_Byte* limit, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + FT_Byte* cur = *acur; + FT_Int count = 0; + FT_Byte c, ender; + if ( cur >= limit ) + goto Exit; +/* Check for the beginning of an array. Otherwise, only one number */ +/* will be read. */ + c = *cur; + ender = 0; + if ( c == '[' ) + ender = ']'; + else if ( c == '{' ) + ender = '}'; + if ( ender ) + cur++; +/* now, read the values */ + while ( cur < limit ) + { + FT_Fixed dummy; + FT_Byte* old_cur; +/* skip whitespace in front of data */ + skip_spaces( &cur, limit ); + if ( cur >= limit ) + goto Exit; + if ( *cur == ender ) + { + cur++; + break; + } + old_cur = cur; + if ( values != NULL && count >= max_values ) + break; +/* call PS_Conv_ToFixed() even if coords == NULL */ +/* to properly parse number at `cur' */ + *( values != NULL ? &values[count] : &dummy ) = + PS_Conv_ToFixed( &cur, limit, power_ten ); + if ( old_cur == cur ) + { + count = -1; + goto Exit; + } + else + count++; + if ( !ender ) + break; + } + Exit: + *acur = cur; + return count; + } +#if 0 + static FT_String* + ps_tostring( FT_Byte** cursor, + FT_Byte* limit, + FT_Memory memory ) + { + FT_Byte* cur = *cursor; + FT_PtrDist len = 0; + FT_Int count; + FT_String* result; + FT_Error error; +/* XXX: some stupid fonts have a `Notice' or `Copyright' string */ +/* that simply doesn't begin with an opening parenthesis, even */ +/* though they have a closing one! E.g. "amuncial.pfb" */ +/* */ +/* We must deal with these ill-fated cases there. Note that */ +/* these fonts didn't work with the old Type 1 driver as the */ +/* notice/copyright was not recognized as a valid string token */ +/* and made the old token parser commit errors. */ + while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) + cur++; + if ( cur + 1 >= limit ) + return 0; + if ( *cur == '(' ) +/* skip the opening parenthesis, if there is one */ + cur++; + *cursor = cur; + count = 0; +/* then, count its length */ + for ( ; cur < limit; cur++ ) + { + if ( *cur == '(' ) + count++; + else if ( *cur == ')' ) + { + count--; + if ( count < 0 ) + break; + } + } + len = cur - *cursor; + if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) + return 0; +/* now copy the string */ + FT_MEM_COPY( result, *cursor, len ); + result[len] = '\0'; + *cursor = cur; + return result; + } +/* 0 */ +#endif + static int + ps_tobool( FT_Byte* *acur, + FT_Byte* limit ) + { + FT_Byte* cur = *acur; + FT_Bool result = 0; +/* return 1 if we find `true', 0 otherwise */ + if ( cur + 3 < limit && + cur[0] == 't' && + cur[1] == 'r' && + cur[2] == 'u' && + cur[3] == 'e' ) + { + result = 1; + cur += 5; + } + else if ( cur + 4 < limit && + cur[0] == 'f' && + cur[1] == 'a' && + cur[2] == 'l' && + cur[3] == 's' && + cur[4] == 'e' ) + { + result = 0; + cur += 6; + } + *acur = cur; + return result; + } +/* load a simple field (i.e. non-table) into the current list of objects */ + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec token; + FT_Byte* cur; + FT_Byte* limit; + FT_UInt count; + FT_UInt idx; + FT_Error error; +/* this also skips leading whitespace */ + ps_parser_to_token( parser, &token ); + if ( !token.type ) + goto Fail; + count = 1; + idx = 0; + cur = token.start; + limit = token.limit; +/* we must detect arrays in /FontBBox */ + if ( field->type == T1_FIELD_TYPE_BBOX ) + { + T1_TokenRec token2; + FT_Byte* old_cur = parser->cursor; + FT_Byte* old_limit = parser->limit; +/* don't include delimiters */ + parser->cursor = token.start + 1; + parser->limit = token.limit - 1; + ps_parser_to_token( parser, &token2 ); + parser->cursor = old_cur; + parser->limit = old_limit; + if ( token2.type == T1_TOKEN_TYPE_ARRAY ) + goto FieldArray; + } + else if ( token.type == T1_TOKEN_TYPE_ARRAY ) + { + FieldArray: +/* if this is an array and we have no blend, an error occurs */ + if ( max_objects == 0 ) + goto Fail; + count = max_objects; + idx = 1; +/* don't include delimiters */ + cur++; + limit--; + } + for ( ; count > 0; count--, idx++ ) + { + FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; + FT_Long val; + FT_String* string; + skip_spaces( &cur, limit ); + switch ( field->type ) + { + case T1_FIELD_TYPE_BOOL: + val = ps_tobool( &cur, limit ); + goto Store_Integer; + case T1_FIELD_TYPE_FIXED: + val = PS_Conv_ToFixed( &cur, limit, 0 ); + goto Store_Integer; + case T1_FIELD_TYPE_FIXED_1000: + val = PS_Conv_ToFixed( &cur, limit, 3 ); + goto Store_Integer; + case T1_FIELD_TYPE_INTEGER: + val = PS_Conv_ToInt( &cur, limit ); +/* fall through */ + Store_Integer: + switch ( field->size ) + { + case (8 / FT_CHAR_BIT): + *(FT_Byte*)q = (FT_Byte)val; + break; + case (16 / FT_CHAR_BIT): + *(FT_UShort*)q = (FT_UShort)val; + break; + case (32 / FT_CHAR_BIT): + *(FT_UInt32*)q = (FT_UInt32)val; + break; +/* for 64-bit systems */ + default: + *(FT_Long*)q = val; + } + break; + case T1_FIELD_TYPE_STRING: + case T1_FIELD_TYPE_KEY: + { + FT_Memory memory = parser->memory; + FT_UInt len = (FT_UInt)( limit - cur ); + if ( cur >= limit ) + break; +/* we allow both a string or a name */ +/* for cases like /FontName (foo) def */ + if ( token.type == T1_TOKEN_TYPE_KEY ) + { +/* don't include leading `/' */ + len--; + cur++; + } + else if ( token.type == T1_TOKEN_TYPE_STRING ) + { +/* don't include delimiting parentheses */ +/* XXX we don't handle <<...>> here */ +/* XXX should we convert octal escapes? */ +/* if so, what encoding should we use? */ + cur++; + len -= 2; + } + else + { + FT_ERROR(( "ps_parser_load_field:" + " expected a name or string\n" + " " + " but found token of type %d instead\n", + token.type )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } +/* for this to work (FT_String**)q must have been */ +/* initialized to NULL */ + if ( *(FT_String**)q != NULL ) + { + FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", + field->ident )); + FT_FREE( *(FT_String**)q ); + *(FT_String**)q = NULL; + } + if ( FT_ALLOC( string, len + 1 ) ) + goto Exit; + FT_MEM_COPY( string, cur, len ); + string[len] = 0; + *(FT_String**)q = string; + } + break; + case T1_FIELD_TYPE_BBOX: + { + FT_Fixed temp[4]; + FT_BBox* bbox = (FT_BBox*)q; + FT_Int result; + result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); + if ( result < 0 ) + { + FT_ERROR(( "ps_parser_load_field:" + " expected four integers in bounding box\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + bbox->xMin = FT_RoundFix( temp[0] ); + bbox->yMin = FT_RoundFix( temp[1] ); + bbox->xMax = FT_RoundFix( temp[2] ); + bbox->yMax = FT_RoundFix( temp[3] ); + } + break; + default: +/* an error occurred */ + goto Fail; + } + } +/* obsolete -- keep for reference */ +#if 0 + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + error = PSaux_Err_Ok; + Exit: + return error; + Fail: + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } +#define T1_MAX_TABLE_ELEMENTS 32 + FT_LOCAL_DEF( FT_Error ) + ps_parser_load_field_table( PS_Parser parser, + const T1_Field field, + void** objects, + FT_UInt max_objects, + FT_ULong* pflags ) + { + T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; + T1_Token token; + FT_Int num_elements; + FT_Error error = PSaux_Err_Ok; + FT_Byte* old_cursor; + FT_Byte* old_limit; + T1_FieldRec fieldrec = *(T1_Field)field; + fieldrec.type = T1_FIELD_TYPE_INTEGER; + if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || + field->type == T1_FIELD_TYPE_BBOX ) + fieldrec.type = T1_FIELD_TYPE_FIXED; + ps_parser_to_token_array( parser, elements, + T1_MAX_TABLE_ELEMENTS, &num_elements ); + if ( num_elements < 0 ) + { + error = PSaux_Err_Ignore; + goto Exit; + } + if ( (FT_UInt)num_elements > field->array_max ) + num_elements = field->array_max; + old_cursor = parser->cursor; + old_limit = parser->limit; +/* we store the elements count if necessary; */ +/* we further assume that `count_offset' can't be zero */ + if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) + *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = + (FT_Byte)num_elements; +/* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 ); + fieldrec.offset += fieldrec.size; + } +/* obsolete -- keep for reference */ +#if 0 + if ( pflags ) + *pflags |= 1L << field->flag_bit; +#else + FT_UNUSED( pflags ); +#endif + parser->cursor = old_cursor; + parser->limit = old_limit; + Exit: + return error; + } + FT_LOCAL_DEF( FT_Long ) + ps_parser_to_int( PS_Parser parser ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToInt( &parser->cursor, parser->limit ); + } +/* first character must be `<' if `delimiters' is non-zero */ + FT_LOCAL_DEF( FT_Error ) + ps_parser_to_bytes( PS_Parser parser, + FT_Byte* bytes, + FT_Offset max_bytes, + FT_Long* pnum_bytes, + FT_Bool delimiters ) + { + FT_Error error = PSaux_Err_Ok; + FT_Byte* cur; + ps_parser_skip_spaces( parser ); + cur = parser->cursor; + if ( cur >= parser->limit ) + goto Exit; + if ( delimiters ) + { + if ( *cur != '<' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + cur++; + } + *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, + parser->limit, + bytes, + max_bytes ); + if ( delimiters ) + { + if ( cur < parser->limit && *cur != '>' ) + { + FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); + error = PSaux_Err_Invalid_File_Format; + goto Exit; + } + cur++; + } + parser->cursor = cur; + Exit: + return error; + } + FT_LOCAL_DEF( FT_Fixed ) + ps_parser_to_fixed( PS_Parser parser, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); + } + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_coord_array( PS_Parser parser, + FT_Int max_coords, + FT_Short* coords ) + { + ps_parser_skip_spaces( parser ); + return ps_tocoordarray( &parser->cursor, parser->limit, + max_coords, coords ); + } + FT_LOCAL_DEF( FT_Int ) + ps_parser_to_fixed_array( PS_Parser parser, + FT_Int max_values, + FT_Fixed* values, + FT_Int power_ten ) + { + ps_parser_skip_spaces( parser ); + return ps_tofixedarray( &parser->cursor, parser->limit, + max_values, values, power_ten ); + } +#if 0 + FT_LOCAL_DEF( FT_String* ) + T1_ToString( PS_Parser parser ) + { + return ps_tostring( &parser->cursor, parser->limit, parser->memory ); + } + FT_LOCAL_DEF( FT_Bool ) + T1_ToBool( PS_Parser parser ) + { + return ps_tobool( &parser->cursor, parser->limit ); + } +/* 0 */ +#endif + FT_LOCAL_DEF( void ) + ps_parser_init( PS_Parser parser, + FT_Byte* base, + FT_Byte* limit, + FT_Memory memory ) + { + parser->error = PSaux_Err_Ok; + parser->base = base; + parser->limit = limit; + parser->cursor = base; + parser->memory = memory; + parser->funcs = ps_parser_funcs; + } + FT_LOCAL_DEF( void ) + ps_parser_done( PS_Parser parser ) + { + FT_UNUSED( parser ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** T1 BUILDER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* t1_builder_init */ +/* */ +/* <Description> */ +/* Initializes a given glyph builder. */ +/* */ +/* <InOut> */ +/* builder :: A pointer to the glyph builder to initialize. */ +/* */ +/* <Input> */ +/* face :: The current face object. */ +/* */ +/* size :: The current size object. */ +/* */ +/* glyph :: The current glyph object. */ +/* */ +/* hinting :: Whether hinting should be applied. */ +/* */ + FT_LOCAL_DEF( void ) + t1_builder_init( T1_Builder builder, + FT_Face face, + FT_Size size, + FT_GlyphSlot glyph, + FT_Bool hinting ) + { + builder->parse_state = T1_Parse_Start; + builder->load_points = 1; + builder->face = face; + builder->glyph = glyph; + builder->memory = face->memory; + if ( glyph ) + { + FT_GlyphLoader loader = glyph->internal->loader; + builder->loader = loader; + builder->base = &loader->base.outline; + builder->current = &loader->current.outline; + FT_GlyphLoader_Rewind( loader ); + builder->hints_globals = size->internal; + builder->hints_funcs = 0; + if ( hinting ) + builder->hints_funcs = glyph->internal->glyph_hints; + } + builder->pos_x = 0; + builder->pos_y = 0; + builder->left_bearing.x = 0; + builder->left_bearing.y = 0; + builder->advance.x = 0; + builder->advance.y = 0; + builder->funcs = t1_builder_funcs; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* t1_builder_done */ +/* */ +/* <Description> */ +/* Finalizes a given glyph builder. Its contents can still be used */ +/* after the call, but the function saves important information */ +/* within the corresponding glyph slot. */ +/* */ +/* <Input> */ +/* builder :: A pointer to the glyph builder to finalize. */ +/* */ + FT_LOCAL_DEF( void ) + t1_builder_done( T1_Builder builder ) + { + FT_GlyphSlot glyph = builder->glyph; + if ( glyph ) + glyph->outline = *builder->base; + } +/* check that there is enough space for `count' more points */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_check_points( T1_Builder builder, + FT_Int count ) + { + return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); + } +/* add a new point, do not check space */ + FT_LOCAL_DEF( void ) + t1_builder_add_point( T1_Builder builder, + FT_Pos x, + FT_Pos y, + FT_Byte flag ) + { + FT_Outline* outline = builder->current; + if ( builder->load_points ) + { + FT_Vector* point = outline->points + outline->n_points; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + point->x = FIXED_TO_INT( x ); + point->y = FIXED_TO_INT( y ); + *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); + } + outline->n_points++; + } +/* check space for a new on-curve point, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_point1( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error; + error = t1_builder_check_points( builder, 1 ); + if ( !error ) + t1_builder_add_point( builder, x, y, 1 ); + return error; + } +/* check space for a new contour, then add it */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_add_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Error error; +/* this might happen in invalid fonts */ + if ( !outline ) + { + FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); + return PSaux_Err_Invalid_File_Format; + } + if ( !builder->load_points ) + { + outline->n_contours++; + return PSaux_Err_Ok; + } + error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); + if ( !error ) + { + if ( outline->n_contours > 0 ) + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + outline->n_contours++; + } + return error; + } +/* if a path was begun, add its first on-curve point */ + FT_LOCAL_DEF( FT_Error ) + t1_builder_start_point( T1_Builder builder, + FT_Pos x, + FT_Pos y ) + { + FT_Error error = PSaux_Err_Invalid_File_Format; +/* test whether we are building a new contour */ + if ( builder->parse_state == T1_Parse_Have_Path ) + error = PSaux_Err_Ok; + else + { + builder->parse_state = T1_Parse_Have_Path; + error = t1_builder_add_contour( builder ); + if ( !error ) + error = t1_builder_add_point1( builder, x, y ); + } + return error; + } +/* close the current contour */ + FT_LOCAL_DEF( void ) + t1_builder_close_contour( T1_Builder builder ) + { + FT_Outline* outline = builder->current; + FT_Int first; + if ( !outline ) + return; + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; +/* We must not include the last point in the path if it */ +/* is located on the first point. */ + if ( outline->n_points > 1 ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + outline->n_points - 1; + FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; +/* `delete' last point only if it coincides with the first */ +/* point and it is not a control point (which can happen). */ + if ( p1->x == p2->x && p1->y == p2->y ) + if ( *control == FT_CURVE_TAG_ON ) + outline->n_points--; + } + if ( outline->n_contours > 0 ) + { +/* Don't add contours only consisting of one point, i.e., */ +/* check whether the first and the last point is the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** OTHER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + t1_decrypt( FT_Byte* buffer, + FT_Offset length, + FT_UShort seed ) + { + PS_Conv_EexecDecode( &buffer, + buffer + length, + buffer, + length, + &seed ); + } +/* END */ +/***************************************************************************/ +/* */ +/* psauxmod.c */ +/* */ +/* FreeType auxiliary PostScript module implementation (body). */ +/* */ +/* Copyright 2000-2001, 2002, 2003, 2006 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* psauxmod.h */ +/* */ +/* FreeType auxiliary PostScript module implementation (specification). */ +/* */ +/* Copyright 2000-2001 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. */ +/* */ +/***************************************************************************/ +#define __PSAUXMOD_H__ +FT_BEGIN_HEADER + FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* t1decode.h */ +/* */ +/* PostScript Type 1 decoding routines (specification). */ +/* */ +/* Copyright 2000-2001, 2002, 2003 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. */ +/* */ +/***************************************************************************/ +#define __T1DECODE_H__ +FT_BEGIN_HEADER + FT_CALLBACK_TABLE + const T1_Decoder_FuncsRec t1_decoder_funcs; + FT_LOCAL( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph_index ); + FT_LOCAL( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* base, + FT_UInt len ); + FT_LOCAL( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_glyph ); + FT_LOCAL( void ) + t1_decoder_done( T1_Decoder decoder ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* t1cmap.h */ +/* */ +/* Type 1 character map support (specification). */ +/* */ +/* Copyright 2002, 2003, 2006 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. */ +/* */ +/***************************************************************************/ +#define __T1CMAP_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* standard (and expert) encoding cmaps */ + typedef struct T1_CMapStdRec_* T1_CMapStd; + typedef struct T1_CMapStdRec_ + { + FT_CMapRec cmap; + const FT_UShort* code_to_sid; + PS_Adobe_Std_StringsFunc sid_to_string; + FT_UInt num_glyphs; + const char* const* glyph_names; + } T1_CMapStdRec; + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_standard_class_rec; + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_expert_class_rec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 CUSTOM ENCODING CMAP *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct T1_CMapCustomRec_* T1_CMapCustom; + typedef struct T1_CMapCustomRec_ + { + FT_CMapRec cmap; + FT_UInt first; + FT_UInt count; + FT_UShort* indices; + } T1_CMapCustomRec; + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_custom_class_rec; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* unicode (synthetic) cmaps */ + FT_CALLBACK_TABLE const FT_CMap_ClassRec + t1_cmap_unicode_class_rec; +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* afmparse.h */ +/* */ +/* AFM parser (specification). */ +/* */ +/* Copyright 2006 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. */ +/* */ +/***************************************************************************/ +#define __AFMPARSE_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, +/* real number */ + AFM_VALUE_TYPE_FIXED, + AFM_VALUE_TYPE_INTEGER, + AFM_VALUE_TYPE_BOOL, +/* glyph index */ + AFM_VALUE_TYPE_INDEX + }; + typedef struct AFM_ValueRec_ + { + enum AFM_ValueType_ type; + union + { + char* s; + FT_Fixed f; + FT_Int i; + 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_UInt 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 +/* END */ + FT_CALLBACK_TABLE_DEF + const PS_Table_FuncsRec ps_table_funcs = + { + ps_table_new, + ps_table_done, + ps_table_add, + ps_table_release + }; + FT_CALLBACK_TABLE_DEF + const PS_Parser_FuncsRec ps_parser_funcs = + { + ps_parser_init, + ps_parser_done, + ps_parser_skip_spaces, + ps_parser_skip_PS_token, + ps_parser_to_int, + ps_parser_to_fixed, + ps_parser_to_bytes, + ps_parser_to_coord_array, + ps_parser_to_fixed_array, + ps_parser_to_token, + ps_parser_to_token_array, + ps_parser_load_field, + ps_parser_load_field_table + }; + FT_CALLBACK_TABLE_DEF + const T1_Builder_FuncsRec t1_builder_funcs = + { + t1_builder_init, + t1_builder_done, + t1_builder_check_points, + t1_builder_add_point, + t1_builder_add_point1, + t1_builder_add_contour, + t1_builder_start_point, + t1_builder_close_contour + }; + FT_CALLBACK_TABLE_DEF + const T1_Decoder_FuncsRec t1_decoder_funcs = + { + t1_decoder_init, + t1_decoder_done, + t1_decoder_parse_charstrings + }; + FT_CALLBACK_TABLE_DEF + const AFM_Parser_FuncsRec afm_parser_funcs = + { + afm_parser_init, + afm_parser_done, + afm_parser_parse + }; + FT_CALLBACK_TABLE_DEF + const T1_CMap_ClassesRec t1_cmap_classes = + { + &t1_cmap_standard_class_rec, + &t1_cmap_expert_class_rec, + &t1_cmap_custom_class_rec, + &t1_cmap_unicode_class_rec + }; + static + const PSAux_Interface psaux_interface = + { + &ps_table_funcs, + &ps_parser_funcs, + &t1_builder_funcs, + &t1_decoder_funcs, + t1_decrypt, + (const T1_CMap_ClassesRec*) &t1_cmap_classes, + &afm_parser_funcs, + }; + FT_CALLBACK_TABLE_DEF + const FT_Module_Class psaux_module_class = + { + 0, + sizeof ( FT_ModuleRec ), + "psaux", + 0x20000L, + 0x20000L, +/* module-specific interface */ + &psaux_interface, + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }; +/* END */ +/***************************************************************************/ +/* */ +/* t1decode.c */ +/* */ +/* PostScript Type 1 decoding routines (body). */ +/* */ +/* Copyright 2000-2012 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. */ +/* */ +/***************************************************************************/ +/* ensure proper sign extension */ +#define Fix2Int( f ) ( (FT_Int)(FT_Short)( (f) >> 16 ) ) +/*************************************************************************/ +/* */ +/* 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 trace_t1decode + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + op_unknown15, +/* never remove this one */ + op_max + } T1_Operator; + static + const FT_Int t1_args_count[op_max] = + { +/* none */ + 0, +/* endchar */ + 0, +/* hsbw */ + 2, +/* seac */ + 5, +/* sbw */ + 4, +/* closepath */ + 0, +/* hlineto */ + 1, +/* hmoveto */ + 1, +/* hvcurveto */ + 4, +/* rlineto */ + 2, +/* rmoveto */ + 2, +/* rrcurveto */ + 6, +/* vhcurveto */ + 4, +/* vlineto */ + 1, +/* vmoveto */ + 1, +/* dotsection */ + 0, +/* hstem */ + 2, +/* hstem3 */ + 6, +/* vstem */ + 2, +/* vstem3 */ + 6, +/* div */ + 2, +/* callothersubr */ + -1, +/* callsubr */ + 1, +/* pop */ + 0, +/* return */ + 0, +/* setcurrentpoint */ + 2, +/* opcode 15 (undocumented and obsolete) */ + 2 + }; +/*************************************************************************/ +/* */ +/* <Function> */ +/* t1_lookup_glyph_by_stdcharcode */ +/* */ +/* <Description> */ +/* Looks up a given glyph by its StandardEncoding charcode. Used to */ +/* implement the SEAC Type 1 operator. */ +/* */ +/* <Input> */ +/* face :: The current face object. */ +/* */ +/* charcode :: The character code to look for. */ +/* */ +/* <Return> */ +/* A glyph index in the font face. Returns -1 if the corresponding */ +/* glyph wasn't found. */ +/* */ + static FT_Int + t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + FT_Service_PsCMaps psnames = decoder->psnames; +/* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + if ( name && + name[0] == glyph_name[0] && + ft_strcmp( name, glyph_name ) == 0 ) + return n; + } + return -1; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* t1operator_seac */ +/* */ +/* <Description> */ +/* Implements the `seac' Type 1 operator for a Type 1 decoder. */ +/* */ +/* <Input> */ +/* decoder :: The current CID decoder. */ +/* */ +/* asb :: The accent's side bearing. */ +/* */ +/* adx :: The horizontal offset of the accent. */ +/* */ +/* ady :: The vertical offset of the accent. */ +/* */ +/* bchar :: The base character's StandardEncoding charcode. */ +/* */ +/* achar :: The accent character's StandardEncoding charcode. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + static FT_Error + t1operator_seac( T1_Decoder decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index; +#if 0 + FT_Int n_base_points; + FT_Outline* base = decoder->builder.base; +#endif + FT_Vector left_bearing, advance; + T1_Face face = (T1_Face)decoder->builder.face; + if ( decoder->seac ) + { + FT_ERROR(( "t1operator_seac: invalid nested seac\n" )); + return PSaux_Err_Syntax_Error; + } + if ( decoder->builder.metrics_only ) + { + FT_ERROR(( "t1operator_seac: unexpected seac\n" )); + return PSaux_Err_Syntax_Error; + } +/* seac weirdness */ + adx += decoder->builder.left_bearing.x; +/* `glyph_names' is set to 0 for CID fonts which do not */ +/* include an encoding. How can we deal with these? */ + if ( decoder->glyph_names == 0 && + !face->root.internal->incremental_interface ) + { + FT_ERROR(( "t1operator_seac:" + " glyph names table not available in this font\n" )); + return PSaux_Err_Syntax_Error; + } + if ( face->root.internal->incremental_interface ) + { +/* the caller must handle the font encoding also */ + bchar_index = bchar; + achar_index = achar; + } + else + { + bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); + } + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" + " invalid seac character code arguments\n" )); + return PSaux_Err_Syntax_Error; + } +/* if we are trying to load a composite glyph, do not load the */ +/* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader loader = glyph->internal->loader; + FT_SubGlyph subg; +/* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 ); + if ( error ) + goto Exit; + subg = loader->current.subglyphs; +/* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; +/* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = (FT_Int)FIXED_TO_INT( adx - asb ); + subg->arg2 = (FT_Int)FIXED_TO_INT( ady ); +/* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + loader->current.num_subglyphs = 2; + goto Exit; + } +/* First load `bchar' in builder */ +/* now load the unscaled outline */ +/* prepare loader */ + FT_GlyphLoader_Prepare( decoder->builder.loader ); +/* the seac operator must not be nested */ + decoder->seac = TRUE; + error = t1_decoder_parse_glyph( decoder, bchar_index ); + decoder->seac = FALSE; + if ( error ) + goto Exit; +/* save the left bearing and width of the base character */ +/* as they will be erased by the next load. */ + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + decoder->builder.pos_x = adx - asb; + decoder->builder.pos_y = ady; +/* Now load `achar' on top of */ +/* the base outline */ +/* the seac operator must not be nested */ + decoder->seac = TRUE; + error = t1_decoder_parse_glyph( decoder, achar_index ); + decoder->seac = FALSE; + if ( error ) + goto Exit; +/* restore the left side bearing and */ +/* advance width of the base character */ + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + decoder->builder.pos_x = 0; + decoder->builder.pos_y = 0; + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* t1_decoder_parse_charstrings */ +/* */ +/* <Description> */ +/* Parses a given Type 1 charstrings program. */ +/* */ +/* <Input> */ +/* decoder :: The current Type 1 decoder. */ +/* */ +/* charstring_base :: The base address of the charstring stream. */ +/* */ +/* charstring_len :: The length in bytes of the charstring stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_charstrings( T1_Decoder decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + FT_Error error; + T1_Decoder_Zone zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder builder = &decoder->builder; + FT_Pos x, y, orig_x, orig_y; + FT_Int known_othersubr_result_cnt = 0; + FT_Int unknown_othersubr_result_cnt = 0; + FT_Bool large_int; + FT_Fixed seed; + T1_Hints_Funcs hinter; +/* compute random seed from stack address of parameter */ + seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed ^ + (FT_PtrDist)(char*)&decoder ^ + (FT_PtrDist)(char*)&charstring_base ) & + FT_ULONG_MAX ) ; + seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; + if ( seed == 0 ) + seed = 0x7384; +/* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + builder->parse_state = T1_Parse_Start; + hinter = (T1_Hints_Funcs)builder->hints_funcs; +/* a font that reads BuildCharArray without setting */ +/* its values first is buggy, but ... */ + FT_ASSERT( ( decoder->len_buildchar == 0 ) == + ( decoder->buildchar == NULL ) ); + if ( decoder->buildchar && decoder->len_buildchar > 0 ) + ft_memset( &decoder->buildchar[0], + 0, + sizeof ( decoder->buildchar[0] ) * decoder->len_buildchar ); + FT_TRACE4(( "\n" + "Start charstring\n" )); + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + error = PSaux_Err_Ok; + x = orig_x = builder->pos_x; + y = orig_y = builder->pos_y; +/* begin hints recording session, if any */ + if ( hinter ) + hinter->open( hinter->hints ); + large_int = FALSE; +/* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Int32 value = 0; + FT_ASSERT( known_othersubr_result_cnt == 0 || + unknown_othersubr_result_cnt == 0 ); +/*********************************************************************/ +/* */ +/* Decode operator or operand */ +/* */ +/* */ +/* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; +/* undocumented, obsolete operator */ + case 15: + op = op_unknown15; + break; + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + case 12: + if ( ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + default: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; +/* four bytes integer */ + case 255: + if ( ip + 4 > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + value = (FT_Int32)( ( (FT_Long)ip[0] << 24 ) | + ( (FT_Long)ip[1] << 16 ) | + ( (FT_Long)ip[2] << 8 ) | + ip[3] ); + ip += 4; +/* According to the specification, values > 32000 or < -32000 must */ +/* be followed by a `div' operator to make the result be in the */ +/* range [-32000;32000]. We expect that the second argument of */ +/* `div' is not a large number. Additionally, we don't handle */ +/* stuff like `<large1> <large2> <num> div <num> div' or */ +/* <large1> <large2> <num> div div'. This is probably not allowed */ +/* anyway. */ + if ( value > 32000 || value < -32000 ) + { + if ( large_int ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no `div' after large integer\n" )); + } + else + large_int = TRUE; + } + else + { + if ( !large_int ) + value <<= 16; + } + break; + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Int32)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + if ( ip[-2] < 251 ) + value = ( ( (FT_Int32)ip[-2] - 247 ) << 8 ) + ip[-1] + 108; + else + value = -( ( ( (FT_Int32)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); + } + if ( !large_int ) + value <<= 16; + } + else + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid byte (%d)\n", ip[-1] )); + goto Syntax_Error; + } + } + if ( unknown_othersubr_result_cnt > 0 ) + { + switch ( op ) + { + case op_callsubr: + case op_return: + case op_none: + case op_pop: + break; + default: +/* all operands have been transferred by previous pops */ + unknown_othersubr_result_cnt = 0; + break; + } + } + if ( large_int && !( op == op_none || op == op_div ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no `div' after large integer\n" )); + large_int = FALSE; + } +/*********************************************************************/ +/* */ +/* Push value on stack, or process operator */ +/* */ +/* */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow\n" )); + goto Syntax_Error; + } + *top++ = value; + decoder->top = top; + } +/* callothersubr */ + else if ( op == op_callothersubr ) + { + FT_Int subr_no; + FT_Int arg_cnt; + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + top -= 2; + subr_no = Fix2Int( top[1] ); + arg_cnt = Fix2Int( top[0] ); +/***********************************************************/ +/* */ +/* remove all operands to callothersubr from the stack */ +/* */ +/* for handled othersubrs, where we know the number of */ +/* arguments, we increase the stack by the value of */ +/* known_othersubr_result_cnt */ +/* */ +/* for unhandled othersubrs the following pops adjust the */ +/* stack pointer as necessary */ + if ( arg_cnt > top - decoder->stack ) + goto Stack_Underflow; + top -= arg_cnt; + known_othersubr_result_cnt = 0; + unknown_othersubr_result_cnt = 0; +/* XXX TODO: The checks to `arg_count == <whatever>' */ +/* might not be correct; an othersubr expects a certain */ +/* number of operands on the PostScript stack (as opposed */ +/* to the T1 stack) but it doesn't have to put them there */ +/* by itself; previous othersubrs might have left the */ +/* operands there if they were not followed by an */ +/* appropriate number of pops */ +/* */ +/* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */ +/* accept a font that contains charstrings like */ +/* */ +/* 100 200 2 20 callothersubr */ +/* 300 1 20 callothersubr pop */ +/* */ +/* Perhaps this is the reason why BuildCharArray exists. */ + switch ( subr_no ) + { +/* end flex feature */ + case 0: + if ( arg_cnt != 3 ) + goto Unexpected_OtherSubr; + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected flex end\n" )); + goto Syntax_Error; + } +/* the two `results' are popped by the following setcurrentpoint */ + top[0] = x; + top[1] = y; + known_othersubr_result_cnt = 2; + break; +/* start flex feature */ + case 1: + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok || + ( error = t1_builder_check_points( builder, 6 ) ) + != PSaux_Err_Ok ) + goto Fail; + break; +/* add flex vectors */ + case 2: + { + FT_Int idx; + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + if ( decoder->flex_state == 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " missing flex start\n" )); + goto Syntax_Error; + } +/* note that we should not add a point for index 0; */ +/* this will move our current position to the flex */ +/* point without adding any point to the outline */ + idx = decoder->num_flex_vectors++; + if ( idx > 0 && idx < 7 ) + t1_builder_add_point( builder, + x, + y, + (FT_Byte)( idx == 3 || idx == 6 ) ); + } + break; +/* change hints */ + case 3: + if ( arg_cnt != 1 ) + goto Unexpected_OtherSubr; + known_othersubr_result_cnt = 1; + if ( hinter ) + hinter->reset( hinter->hints, builder->current->n_points ); + break; + case 12: + case 13: +/* counter control hints, clear stack */ + top = decoder->stack; + break; + case 14: + case 15: + case 16: + case 17: +/* multiple masters */ + case 18: + { + PS_Blend blend = decoder->blend; + FT_UInt num_points, nn, mm; + FT_Long* delta; + FT_Long* values; + if ( !blend ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected multiple masters operator\n" )); + goto Syntax_Error; + } + num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 ); + if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " incorrect number of multiple masters arguments\n" )); + goto Syntax_Error; + } +/* We want to compute */ +/* */ +/* a0*w0 + a1*w1 + ... + ak*wk */ +/* */ +/* but we only have a0, a1-a0, a2-a0, ..., ak-a0. */ +/* */ +/* However, given that w0 + w1 + ... + wk == 1, we can */ +/* rewrite it easily as */ +/* */ +/* a0 + (a1-a0)*w1 + (a2-a0)*w2 + ... + (ak-a0)*wk */ +/* */ +/* where k == num_designs-1. */ +/* */ +/* I guess that's why it's written in this `compact' */ +/* form. */ +/* */ + delta = top + num_points; + values = top; + for ( nn = 0; nn < num_points; nn++ ) + { + FT_Long tmp = values[0]; + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp += FT_MulFix( *delta++, blend->weight_vector[mm] ); + *values++ = tmp; + } + known_othersubr_result_cnt = num_points; + break; + } + case 19: +/* <idx> 1 19 callothersubr */ +/* => replace elements starting from index cvi( <idx> ) */ +/* of BuildCharArray with WeightVector */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + if ( arg_cnt != 1 || blend == NULL ) + goto Unexpected_OtherSubr; + idx = Fix2Int( top[0] ); + if ( idx < 0 || + idx + blend->num_designs > decoder->len_buildchar ) + goto Unexpected_OtherSubr; + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); + } + break; + case 20: +/* <arg1> <arg2> 2 20 callothersubr pop */ +/* ==> push <arg1> + <arg2> onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; +/* XXX (over|under)flow */ + top[0] += top[1]; + known_othersubr_result_cnt = 1; + break; + case 21: +/* <arg1> <arg2> 2 21 callothersubr pop */ +/* ==> push <arg1> - <arg2> onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; +/* XXX (over|under)flow */ + top[0] -= top[1]; + known_othersubr_result_cnt = 1; + break; + case 22: +/* <arg1> <arg2> 2 22 callothersubr pop */ +/* ==> push <arg1> * <arg2> onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + top[0] = FT_MulFix( top[0], top[1] ); + known_othersubr_result_cnt = 1; + break; + case 23: +/* <arg1> <arg2> 2 23 callothersubr pop */ +/* ==> push <arg1> / <arg2> onto T1 stack */ + if ( arg_cnt != 2 || top[1] == 0 ) + goto Unexpected_OtherSubr; + top[0] = FT_DivFix( top[0], top[1] ); + known_othersubr_result_cnt = 1; + break; + case 24: +/* <val> <idx> 2 24 callothersubr */ +/* ==> set BuildCharArray[cvi( <idx> )] = <val> */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + if ( arg_cnt != 2 || blend == NULL ) + goto Unexpected_OtherSubr; + idx = Fix2Int( top[1] ); + if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + decoder->buildchar[idx] = top[0]; + } + break; + case 25: +/* <idx> 1 25 callothersubr pop */ +/* ==> push BuildCharArray[cvi( idx )] */ +/* onto T1 stack */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + if ( arg_cnt != 1 || blend == NULL ) + goto Unexpected_OtherSubr; + idx = Fix2Int( top[0] ); + if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + goto Unexpected_OtherSubr; + top[0] = decoder->buildchar[idx]; + } + known_othersubr_result_cnt = 1; + break; +#if 0 + case 26: +/* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */ +/* leave mark on T1 stack */ +/* <val> <idx> ==> set BuildCharArray[cvi( <idx> )] = <val> */ + XXX which routine has left its mark on the (PostScript) stack?; + break; +#endif + case 27: +/* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */ +/* ==> push <res1> onto T1 stack if <val1> <= <val2>, */ +/* otherwise push <res2> */ + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + if ( top[2] > top[3] ) + top[0] = top[1]; + known_othersubr_result_cnt = 1; + break; + case 28: +/* 0 28 callothersubr pop */ +/* => push random value from interval [0, 1) onto stack */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + { + FT_Fixed Rand; + Rand = seed; + if ( Rand >= 0x8000L ) + Rand++; + top[0] = Rand; + seed = FT_MulFix( seed, 0x10000L - seed ); + if ( seed == 0 ) + seed += 0x2873; + } + known_othersubr_result_cnt = 1; + break; + default: + if ( arg_cnt >= 0 && subr_no >= 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unknown othersubr [%d %d], wish me luck\n", + arg_cnt, subr_no )); + unknown_othersubr_result_cnt = arg_cnt; + break; + } +/* fall through */ + Unexpected_OtherSubr: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid othersubr [%d %d]\n", arg_cnt, subr_no )); + goto Syntax_Error; + } + top += known_othersubr_result_cnt; + decoder->top = top; + } +/* general operator */ + else + { + FT_Int num_args = t1_args_count[op]; + FT_ASSERT( num_args >= 0 ); + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; +/* XXX Operators usually take their operands from the */ +/* bottom of the stack, i.e., the operands are */ +/* decoder->stack[0], ..., decoder->stack[num_args - 1]; */ +/* only div, callsubr, and callothersubr are different. */ +/* In practice it doesn't matter (?). */ + top -= num_args; + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar\n" )); + t1_builder_close_contour( builder ); +/* close hints recording session */ + if ( hinter ) + { + if ( hinter->close( hinter->hints, builder->current->n_points ) ) + goto Syntax_Error; +/* apply hints to the loaded glyph outline now */ + hinter->apply( hinter->hints, + builder->current, + (PSH_Globals)builder->hints_globals, + decoder->hint_mode ); + } +/* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); +/* the compiler should optimize away this empty loop but ... */ + FT_TRACE4(( "\n" )); +/* return now! */ + return PSaux_Err_Ok; + case op_hsbw: + FT_TRACE4(( " hsbw" )); + builder->parse_state = T1_Parse_Have_Width; + builder->left_bearing.x += top[0]; + builder->advance.x = top[1]; + builder->advance.y = 0; + orig_x = x = builder->pos_x + top[0]; + orig_y = y = builder->pos_y; + FT_UNUSED( orig_y ); +/* the `metrics_only' indicates that we only want to compute */ +/* the glyph's metrics (lsb + advance width), not load the */ +/* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return PSaux_Err_Ok; + break; + case op_seac: + return t1operator_seac( decoder, + top[0], + top[1], + top[2], + Fix2Int( top[3] ), + Fix2Int( top[4] ) ); + case op_sbw: + FT_TRACE4(( " sbw" )); + builder->parse_state = T1_Parse_Have_Width; + builder->left_bearing.x += top[0]; + builder->left_bearing.y += top[1]; + builder->advance.x = top[2]; + builder->advance.y = top[3]; + x = builder->pos_x + top[0]; + y = builder->pos_y + top[1]; +/* the `metrics_only' indicates that we only want to compute */ +/* the glyph's metrics (lsb + advance width), not load the */ +/* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return PSaux_Err_Ok; + break; + case op_closepath: + FT_TRACE4(( " closepath" )); +/* if there is no path, `closepath' is a no-op */ + if ( builder->parse_state == T1_Parse_Have_Path || + builder->parse_state == T1_Parse_Have_Moveto ) + t1_builder_close_contour( builder ); + builder->parse_state = T1_Parse_Have_Width; + break; + case op_hlineto: + FT_TRACE4(( " hlineto" )); + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok ) + goto Fail; + x += top[0]; + goto Add_Line; + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + x += top[0]; + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok || + ( error = t1_builder_check_points( builder, 3 ) ) + != PSaux_Err_Ok ) + goto Fail; + x += top[0]; + t1_builder_add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + t1_builder_add_point( builder, x, y, 0 ); + y += top[3]; + t1_builder_add_point( builder, x, y, 1 ); + break; + case op_rlineto: + FT_TRACE4(( " rlineto" )); + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok ) + goto Fail; + x += top[0]; + y += top[1]; + Add_Line: + if ( ( error = t1_builder_add_point1( builder, x, y ) ) + != PSaux_Err_Ok ) + goto Fail; + break; + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + x += top[0]; + y += top[1]; + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + case op_rrcurveto: + FT_TRACE4(( " rrcurveto" )); + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok || + ( error = t1_builder_check_points( builder, 3 ) ) + != PSaux_Err_Ok ) + goto Fail; + x += top[0]; + y += top[1]; + t1_builder_add_point( builder, x, y, 0 ); + x += top[2]; + y += top[3]; + t1_builder_add_point( builder, x, y, 0 ); + x += top[4]; + y += top[5]; + t1_builder_add_point( builder, x, y, 1 ); + break; + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok || + ( error = t1_builder_check_points( builder, 3 ) ) + != PSaux_Err_Ok ) + goto Fail; + y += top[0]; + t1_builder_add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + t1_builder_add_point( builder, x, y, 0 ); + x += top[3]; + t1_builder_add_point( builder, x, y, 1 ); + break; + case op_vlineto: + FT_TRACE4(( " vlineto" )); + if ( ( error = t1_builder_start_point( builder, x, y ) ) + != PSaux_Err_Ok ) + goto Fail; + y += top[0]; + goto Add_Line; + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + y += top[0]; + if ( !decoder->flex_state ) + { + if ( builder->parse_state == T1_Parse_Start ) + goto Syntax_Error; + builder->parse_state = T1_Parse_Have_Moveto; + } + break; + case op_div: + FT_TRACE4(( " div" )); +/* if `large_int' is set, we divide unscaled numbers; */ +/* otherwise, we divide numbers in 16.16 format -- */ +/* in both cases, it is the same operation */ + *top = FT_DivFix( top[0], top[1] ); + ++top; + large_int = FALSE; + break; + case op_callsubr: + { + FT_Int idx; + FT_TRACE4(( " callsubr" )); + idx = Fix2Int( top[0] ); + if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invalid subrs index\n" )); + goto Syntax_Error; + } + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " too many nested subrs\n" )); + goto Syntax_Error; + } +/* save current instruction pointer */ + zone->cursor = ip; + zone++; +/* The Type 1 driver stores subroutines without the seed bytes. */ +/* The CID driver stores subroutines with seed bytes. This */ +/* case is taken care of when decoder->subrs_len == 0. */ + zone->base = decoder->subrs[idx]; + if ( decoder->subrs_len ) + zone->limit = zone->base + decoder->subrs_len[idx]; + else + { +/* We are using subroutines from a CID font. We must adjust */ +/* for the seed bytes. */ + zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 ); + zone->limit = decoder->subrs[idx + 1]; + } + zone->cursor = zone->base; + if ( !zone->base ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + case op_pop: + FT_TRACE4(( " pop" )); + if ( known_othersubr_result_cnt > 0 ) + { + known_othersubr_result_cnt--; +/* ignore, we pushed the operands ourselves */ + break; + } + if ( unknown_othersubr_result_cnt == 0 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " no more operands for othersubr\n" )); + goto Syntax_Error; + } + unknown_othersubr_result_cnt--; +/* `push' the operand to callothersubr onto the stack */ + top++; + break; + case op_return: + FT_TRACE4(( " return" )); + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected return\n" )); + goto Syntax_Error; + } + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + case op_dotsection: + FT_TRACE4(( " dotsection" )); + break; + case op_hstem: + FT_TRACE4(( " hstem" )); +/* record horizontal hint */ + if ( hinter ) + { +/* top[0] += builder->left_bearing.y; */ + hinter->stem( hinter->hints, 1, top ); + } + break; + case op_hstem3: + FT_TRACE4(( " hstem3" )); +/* record horizontal counter-controlled hints */ + if ( hinter ) + hinter->stem3( hinter->hints, 1, top ); + break; + case op_vstem: + FT_TRACE4(( " vstem" )); +/* record vertical hint */ + if ( hinter ) + { + top[0] += orig_x; + hinter->stem( hinter->hints, 0, top ); + } + break; + case op_vstem3: + FT_TRACE4(( " vstem3" )); +/* record vertical counter-controlled hints */ + if ( hinter ) + { + FT_Pos dx = orig_x; + top[0] += dx; + top[2] += dx; + top[4] += dx; + hinter->stem3( hinter->hints, 0, top ); + } + break; + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); +/* From the T1 specification, section 6.4: */ +/* */ +/* The setcurrentpoint command is used only in */ +/* conjunction with results from OtherSubrs procedures. */ +/* known_othersubr_result_cnt != 0 is already handled */ +/* above. */ +/* Note, however, that both Ghostscript and Adobe */ +/* Distiller handle this situation by silently ignoring */ +/* the inappropriate `setcurrentpoint' instruction. So */ +/* we do the same. */ +#if 0 + if ( decoder->flex_state != 1 ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + } + else + ... +#endif + x = top[0]; + y = top[1]; + decoder->flex_state = 0; + break; + case op_unknown15: + FT_TRACE4(( " opcode_15" )); +/* nothing to do except to pop the two arguments */ + break; + default: + FT_ERROR(( "t1_decoder_parse_charstrings:" + " unhandled opcode %d\n", op )); + goto Syntax_Error; + } +/* XXX Operators usually clear the operand stack; */ +/* only div, callsubr, callothersubr, pop, and */ +/* return are different. */ +/* In practice it doesn't matter (?). */ + decoder->top = top; +/* general operator processing */ + } +/* while ip < limit */ + } + FT_TRACE4(( "..end..\n\n" )); + Fail: + return error; + Syntax_Error: + return PSaux_Err_Syntax_Error; + Stack_Underflow: + return PSaux_Err_Stack_Underflow; + } +/* parse a single Type 1 glyph */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_parse_glyph( T1_Decoder decoder, + FT_UInt glyph ) + { + return decoder->parse_callback( decoder, glyph ); + } +/* initialize T1 decoder */ + FT_LOCAL_DEF( FT_Error ) + t1_decoder_init( T1_Decoder decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + PS_Blend blend, + FT_Bool hinting, + FT_Render_Mode hint_mode, + T1_Decoder_Callback parse_callback ) + { + FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); +/* retrieve PSNames interface from list of current modules */ + { + FT_Service_PsCMaps psnames = 0; + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + if ( !psnames ) + { + FT_ERROR(( "t1_decoder_init:" + " the `psnames' module is not available\n" )); + return PSaux_Err_Unimplemented_Feature; + } + decoder->psnames = psnames; + } + t1_builder_init( &decoder->builder, face, size, slot, hinting ); +/* decoder->buildchar and decoder->len_buildchar have to be */ +/* initialized by the caller since we cannot know the length */ +/* of the BuildCharArray */ + decoder->num_glyphs = (FT_UInt)face->num_glyphs; + decoder->glyph_names = glyph_names; + decoder->hint_mode = hint_mode; + decoder->blend = blend; + decoder->parse_callback = parse_callback; + decoder->funcs = t1_decoder_funcs; + return PSaux_Err_Ok; + } +/* finalize T1 decoder */ + FT_LOCAL_DEF( void ) + t1_decoder_done( T1_Decoder decoder ) + { + t1_builder_done( &decoder->builder ); + } +/* END */ +/***************************************************************************/ +/* */ +/* t1cmap.c */ +/* */ +/* Type 1 character map support (body). */ +/* */ +/* Copyright 2002, 2003, 2006, 2007, 2012 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static void + t1_cmap_std_init( T1_CMapStd cmap, + FT_Int is_expert ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + cmap->num_glyphs = face->type1.num_glyphs; + cmap->glyph_names = (const char* const*)face->type1.glyph_names; + cmap->sid_to_string = psnames->adobe_std_strings; + cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding + : psnames->adobe_std_encoding; + FT_ASSERT( cmap->code_to_sid != NULL ); + } + FT_CALLBACK_DEF( void ) + t1_cmap_std_done( T1_CMapStd cmap ) + { + cmap->num_glyphs = 0; + cmap->glyph_names = NULL; + cmap->sid_to_string = NULL; + cmap->code_to_sid = NULL; + } + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_index( T1_CMapStd cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + if ( char_code < 256 ) + { + FT_UInt code, n; + const char* glyph_name; +/* convert character code to Adobe SID string */ + code = cmap->code_to_sid[char_code]; + glyph_name = cmap->sid_to_string( code ); +/* look for the corresponding glyph name */ + for ( n = 0; n < cmap->num_glyphs; n++ ) + { + const char* gname = cmap->glyph_names[n]; + if ( gname && gname[0] == glyph_name[0] && + ft_strcmp( gname, glyph_name ) == 0 ) + { + result = n; + break; + } + } + } + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + t1_cmap_std_char_next( T1_CMapStd cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + while ( char_code < 256 ) + { + result = t1_cmap_std_char_index( cmap, char_code ); + if ( result != 0 ) + goto Exit; + char_code++; + } + char_code = 0; + Exit: + *pchar_code = char_code; + return result; + } + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_standard_init( T1_CMapStd cmap ) + { + t1_cmap_std_init( cmap, 0 ); + return 0; + } + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_standard_class_rec = + { + sizeof ( T1_CMapStdRec ), + (FT_CMap_InitFunc) t1_cmap_standard_init, + (FT_CMap_DoneFunc) t1_cmap_std_done, + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, + NULL, NULL, NULL, NULL, NULL + }; + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_expert_init( T1_CMapStd cmap ) + { + t1_cmap_std_init( cmap, 1 ); + return 0; + } + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_expert_class_rec = + { + sizeof ( T1_CMapStdRec ), + (FT_CMap_InitFunc) t1_cmap_expert_init, + (FT_CMap_DoneFunc) t1_cmap_std_done, + (FT_CMap_CharIndexFunc)t1_cmap_std_char_index, + (FT_CMap_CharNextFunc) t1_cmap_std_char_next, + NULL, NULL, NULL, NULL, NULL + }; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 CUSTOM ENCODING CMAP *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_custom_init( T1_CMapCustom cmap ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + T1_Encoding encoding = &face->type1.encoding; + cmap->first = encoding->code_first; + cmap->count = (FT_UInt)( encoding->code_last - cmap->first ); + cmap->indices = encoding->char_index; + FT_ASSERT( cmap->indices != NULL ); + FT_ASSERT( encoding->code_first <= encoding->code_last ); + return 0; + } + FT_CALLBACK_DEF( void ) + t1_cmap_custom_done( T1_CMapCustom cmap ) + { + cmap->indices = NULL; + cmap->first = 0; + cmap->count = 0; + } + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_index( T1_CMapCustom cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + if ( ( char_code >= cmap->first ) && + ( char_code < ( cmap->first + cmap->count ) ) ) + result = cmap->indices[char_code]; + return result; + } + FT_CALLBACK_DEF( FT_UInt32 ) + t1_cmap_custom_char_next( T1_CMapCustom cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; + ++char_code; + if ( char_code < cmap->first ) + char_code = cmap->first; + for ( ; char_code < ( cmap->first + cmap->count ); char_code++ ) + { + result = cmap->indices[char_code]; + if ( result != 0 ) + goto Exit; + } + char_code = 0; + Exit: + *pchar_code = char_code; + return result; + } + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_custom_class_rec = + { + sizeof ( T1_CMapCustomRec ), + (FT_CMap_InitFunc) t1_cmap_custom_init, + (FT_CMap_DoneFunc) t1_cmap_custom_done, + (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index, + (FT_CMap_CharNextFunc) t1_cmap_custom_char_next, + NULL, NULL, NULL, NULL, NULL + }; +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_CALLBACK_DEF( const char * ) + psaux_get_glyph_name( T1_Face face, + FT_UInt idx ) + { + return face->type1.glyph_names[idx]; + } + FT_CALLBACK_DEF( FT_Error ) + t1_cmap_unicode_init( PS_Unicodes unicodes ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + return psnames->unicodes_init( memory, + unicodes, + face->type1.num_glyphs, + (PS_GetGlyphNameFunc)&psaux_get_glyph_name, + (PS_FreeGlyphNameFunc)NULL, + (FT_Pointer)face ); + } + FT_CALLBACK_DEF( void ) + t1_cmap_unicode_done( PS_Unicodes unicodes ) + { + FT_Face face = FT_CMAP_FACE( unicodes ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_FREE( unicodes->maps ); + unicodes->num_maps = 0; + } + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_index( PS_Unicodes unicodes, + FT_UInt32 char_code ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + return psnames->unicodes_char_index( unicodes, char_code ); + } + FT_CALLBACK_DEF( FT_UInt32 ) + t1_cmap_unicode_char_next( PS_Unicodes unicodes, + FT_UInt32 *pchar_code ) + { + T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + return psnames->unicodes_char_next( unicodes, pchar_code ); + } + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + t1_cmap_unicode_class_rec = + { + sizeof ( PS_UnicodesRec ), + (FT_CMap_InitFunc) t1_cmap_unicode_init, + (FT_CMap_DoneFunc) t1_cmap_unicode_done, + (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index, + (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next, + NULL, NULL, NULL, NULL, NULL + }; +/* END */ +/***************************************************************************/ +/* */ +/* afmparse.c */ +/* */ +/* AFM parser (body). */ +/* */ +/* Copyright 2006-2010, 2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* AFM_Stream */ +/* */ +/* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. */ +/* */ +/* */ + enum + { + AFM_STREAM_STATUS_NORMAL, + AFM_STREAM_STATUS_EOC, + AFM_STREAM_STATUS_EOL, + AFM_STREAM_STATUS_EOF + }; + typedef struct AFM_StreamRec_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + FT_Int status; + } AFM_StreamRec; +#ifndef EOF +#define EOF -1 +#endif +/* this works because empty lines are ignored */ +#define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' ) +#define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' ) +#define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' ) +/* column separator; there is no `column' in the spec actually */ +#define AFM_IS_SEP( ch ) ( (ch) == ';' ) +#define AFM_GETC() \ + ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \ + : EOF ) +#define AFM_STREAM_KEY_BEGIN( stream ) \ + (char*)( (stream)->cursor - 1 ) +#define AFM_STREAM_KEY_LEN( stream, key ) \ + ( (char*)(stream)->cursor - key - 1 ) +#define AFM_STATUS_EOC( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOC ) +#define AFM_STATUS_EOL( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOL ) +#define AFM_STATUS_EOF( stream ) \ + ( (stream)->status >= AFM_STREAM_STATUS_EOF ) + static int + afm_stream_skip_spaces( AFM_Stream stream ) + { +/* make stupid compiler happy */ + int ch = 0; + if ( AFM_STATUS_EOC( stream ) ) + return ';'; + while ( 1 ) + { + ch = AFM_GETC(); + if ( !AFM_IS_SPACE( ch ) ) + break; + } + if ( AFM_IS_NEWLINE( ch ) ) + stream->status = AFM_STREAM_STATUS_EOL; + else if ( AFM_IS_SEP( ch ) ) + stream->status = AFM_STREAM_STATUS_EOC; + else if ( AFM_IS_EOF( ch ) ) + stream->status = AFM_STREAM_STATUS_EOF; + return ch; + } +/* read a key or value in current column */ + static char* + afm_stream_read_one( AFM_Stream stream ) + { + char* str; + int ch; + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOC( stream ) ) + return NULL; + str = AFM_STREAM_KEY_BEGIN( stream ); + while ( 1 ) + { + ch = AFM_GETC(); + if ( AFM_IS_SPACE( ch ) ) + break; + else if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_SEP( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOC; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + return str; + } +/* read a string (i.e., read to EOL) */ + static char* + afm_stream_read_string( AFM_Stream stream ) + { + char* str; + int ch; + afm_stream_skip_spaces( stream ); + if ( AFM_STATUS_EOL( stream ) ) + return NULL; + str = AFM_STREAM_KEY_BEGIN( stream ); +/* scan to eol */ + while ( 1 ) + { + ch = AFM_GETC(); + if ( AFM_IS_NEWLINE( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOL; + break; + } + else if ( AFM_IS_EOF( ch ) ) + { + stream->status = AFM_STREAM_STATUS_EOF; + break; + } + } + return str; + } +/*************************************************************************/ +/* */ +/* AFM_Parser */ +/* */ +/* */ +/* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */ + typedef enum AFM_Token_ + { + AFM_TOKEN_ASCENDER, + AFM_TOKEN_AXISLABEL, + AFM_TOKEN_AXISTYPE, + AFM_TOKEN_B, + AFM_TOKEN_BLENDAXISTYPES, + AFM_TOKEN_BLENDDESIGNMAP, + AFM_TOKEN_BLENDDESIGNPOSITIONS, + AFM_TOKEN_C, + AFM_TOKEN_CC, + AFM_TOKEN_CH, + AFM_TOKEN_CAPHEIGHT, + AFM_TOKEN_CHARWIDTH, + AFM_TOKEN_CHARACTERSET, + AFM_TOKEN_CHARACTERS, + AFM_TOKEN_DESCENDER, + AFM_TOKEN_ENCODINGSCHEME, + AFM_TOKEN_ENDAXIS, + AFM_TOKEN_ENDCHARMETRICS, + AFM_TOKEN_ENDCOMPOSITES, + AFM_TOKEN_ENDDIRECTION, + AFM_TOKEN_ENDFONTMETRICS, + AFM_TOKEN_ENDKERNDATA, + AFM_TOKEN_ENDKERNPAIRS, + AFM_TOKEN_ENDTRACKKERN, + AFM_TOKEN_ESCCHAR, + AFM_TOKEN_FAMILYNAME, + AFM_TOKEN_FONTBBOX, + AFM_TOKEN_FONTNAME, + AFM_TOKEN_FULLNAME, + AFM_TOKEN_ISBASEFONT, + AFM_TOKEN_ISCIDFONT, + AFM_TOKEN_ISFIXEDPITCH, + AFM_TOKEN_ISFIXEDV, + AFM_TOKEN_ITALICANGLE, + AFM_TOKEN_KP, + AFM_TOKEN_KPH, + AFM_TOKEN_KPX, + AFM_TOKEN_KPY, + AFM_TOKEN_L, + AFM_TOKEN_MAPPINGSCHEME, + AFM_TOKEN_METRICSSETS, + AFM_TOKEN_N, + AFM_TOKEN_NOTICE, + AFM_TOKEN_PCC, + AFM_TOKEN_STARTAXIS, + AFM_TOKEN_STARTCHARMETRICS, + AFM_TOKEN_STARTCOMPOSITES, + AFM_TOKEN_STARTDIRECTION, + AFM_TOKEN_STARTFONTMETRICS, + AFM_TOKEN_STARTKERNDATA, + AFM_TOKEN_STARTKERNPAIRS, + AFM_TOKEN_STARTKERNPAIRS0, + AFM_TOKEN_STARTKERNPAIRS1, + AFM_TOKEN_STARTTRACKKERN, + AFM_TOKEN_STDHW, + AFM_TOKEN_STDVW, + AFM_TOKEN_TRACKKERN, + AFM_TOKEN_UNDERLINEPOSITION, + AFM_TOKEN_UNDERLINETHICKNESS, + AFM_TOKEN_VV, + AFM_TOKEN_VVECTOR, + AFM_TOKEN_VERSION, + AFM_TOKEN_W, + AFM_TOKEN_W0, + AFM_TOKEN_W0X, + AFM_TOKEN_W0Y, + AFM_TOKEN_W1, + AFM_TOKEN_W1X, + AFM_TOKEN_W1Y, + AFM_TOKEN_WX, + AFM_TOKEN_WY, + AFM_TOKEN_WEIGHT, + AFM_TOKEN_WEIGHTVECTOR, + AFM_TOKEN_XHEIGHT, + N_AFM_TOKENS, + AFM_TOKEN_UNKNOWN + } AFM_Token; + static const char* const afm_key_table[N_AFM_TOKENS] = + { + "Ascender", + "AxisLabel", + "AxisType", + "B", + "BlendAxisTypes", + "BlendDesignMap", + "BlendDesignPositions", + "C", + "CC", + "CH", + "CapHeight", + "CharWidth", + "CharacterSet", + "Characters", + "Descender", + "EncodingScheme", + "EndAxis", + "EndCharMetrics", + "EndComposites", + "EndDirection", + "EndFontMetrics", + "EndKernData", + "EndKernPairs", + "EndTrackKern", + "EscChar", + "FamilyName", + "FontBBox", + "FontName", + "FullName", + "IsBaseFont", + "IsCIDFont", + "IsFixedPitch", + "IsFixedV", + "ItalicAngle", + "KP", + "KPH", + "KPX", + "KPY", + "L", + "MappingScheme", + "MetricsSets", + "N", + "Notice", + "PCC", + "StartAxis", + "StartCharMetrics", + "StartComposites", + "StartDirection", + "StartFontMetrics", + "StartKernData", + "StartKernPairs", + "StartKernPairs0", + "StartKernPairs1", + "StartTrackKern", + "StdHW", + "StdVW", + "TrackKern", + "UnderlinePosition", + "UnderlineThickness", + "VV", + "VVector", + "Version", + "W", + "W0", + "W0X", + "W0Y", + "W1", + "W1X", + "W1Y", + "WX", + "WY", + "Weight", + "WeightVector", + "XHeight" + }; +/* + * `afm_parser_read_vals' and `afm_parser_next_key' provide + * high-level operations to an AFM_Stream. The rest of the + * parser functions should use them without accessing the + * AFM_Stream directly. + */ + FT_LOCAL_DEF( FT_Int ) + afm_parser_read_vals( AFM_Parser parser, + AFM_Value vals, + FT_UInt n ) + { + AFM_Stream stream = parser->stream; + char* str; + FT_UInt i; + if ( n > AFM_MAX_ARGUMENTS ) + return 0; + for ( i = 0; i < n; i++ ) + { + FT_Offset len; + AFM_Value val = vals + i; + if ( val->type == AFM_VALUE_TYPE_STRING ) + str = afm_stream_read_string( stream ); + else + str = afm_stream_read_one( stream ); + if ( !str ) + break; + len = AFM_STREAM_KEY_LEN( stream, str ); + switch ( val->type ) + { + case AFM_VALUE_TYPE_STRING: + case AFM_VALUE_TYPE_NAME: + { + FT_Memory memory = parser->memory; + FT_Error error; + if ( !FT_QALLOC( val->u.s, len + 1 ) ) + { + ft_memcpy( val->u.s, str, len ); + val->u.s[len] = '\0'; + } + } + break; + case AFM_VALUE_TYPE_FIXED: + val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len, 0 ); + break; + case AFM_VALUE_TYPE_INTEGER: + val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str, + (FT_Byte*)str + len ); + break; + case AFM_VALUE_TYPE_BOOL: + val->u.b = FT_BOOL( len == 4 && + !ft_strncmp( str, "true", 4 ) ); + break; + case AFM_VALUE_TYPE_INDEX: + if ( parser->get_index ) + val->u.i = parser->get_index( str, len, parser->user_data ); + else + val->u.i = 0; + break; + } + } + return i; + } + FT_LOCAL_DEF( char* ) + afm_parser_next_key( AFM_Parser parser, + FT_Bool line, + FT_Offset* len ) + { + AFM_Stream stream = parser->stream; +/* make stupid compiler happy */ + char* key = 0; + if ( line ) + { + while ( 1 ) + { +/* skip current line */ + if ( !AFM_STATUS_EOL( stream ) ) + afm_stream_read_string( stream ); + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); +/* skip empty line */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOL( stream ) ) + continue; + break; + } + } + else + { + while ( 1 ) + { +/* skip current column */ + while ( !AFM_STATUS_EOC( stream ) ) + afm_stream_read_one( stream ); + stream->status = AFM_STREAM_STATUS_NORMAL; + key = afm_stream_read_one( stream ); +/* skip empty column */ + if ( !key && + !AFM_STATUS_EOF( stream ) && + AFM_STATUS_EOC( stream ) ) + continue; + break; + } + } + if ( len ) + *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key ) + : 0; + return key; + } + static AFM_Token + afm_tokenize( const char* key, + FT_Offset len ) + { + int n; + for ( n = 0; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) == *key ) + { + for ( ; n < N_AFM_TOKENS; n++ ) + { + if ( *( afm_key_table[n] ) != *key ) + return AFM_TOKEN_UNKNOWN; + if ( ft_strncmp( afm_key_table[n], key, len ) == 0 ) + return (AFM_Token) n; + } + } + } + return AFM_TOKEN_UNKNOWN; + } + FT_LOCAL_DEF( FT_Error ) + afm_parser_init( AFM_Parser parser, + FT_Memory memory, + FT_Byte* base, + FT_Byte* limit ) + { + AFM_Stream stream = NULL; + FT_Error error; + if ( FT_NEW( stream ) ) + return error; + stream->cursor = stream->base = base; + stream->limit = limit; +/* don't skip the first line during the first call */ + stream->status = AFM_STREAM_STATUS_EOL; + parser->memory = memory; + parser->stream = stream; + parser->FontInfo = NULL; + parser->get_index = NULL; + return PSaux_Err_Ok; + } + FT_LOCAL( void ) + afm_parser_done( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + FT_FREE( parser->stream ); + } + FT_LOCAL_DEF( FT_Error ) + afm_parser_read_int( AFM_Parser parser, + FT_Int* aint ) + { + AFM_ValueRec val; + val.type = AFM_VALUE_TYPE_INTEGER; + if ( afm_parser_read_vals( parser, &val, 1 ) == 1 ) + { + *aint = val.u.i; + return PSaux_Err_Ok; + } + else + return PSaux_Err_Syntax_Error; + } + static FT_Error + afm_parse_track_kern( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_TrackKern tk; + char* key; + FT_Offset len; + int n = -1; + if ( afm_parser_read_int( parser, &fi->NumTrackKern ) ) + goto Fail; + if ( fi->NumTrackKern ) + { + FT_Memory memory = parser->memory; + FT_Error error; + if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) ) + return error; + } + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[5]; + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_TRACKKERN: + n++; + if ( n >= fi->NumTrackKern ) + goto Fail; + tk = fi->TrackKerns + n; + shared_vals[0].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + shared_vals[4].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 ) + goto Fail; + tk->degree = shared_vals[0].u.i; + tk->min_ptsize = shared_vals[1].u.f; + tk->min_kern = shared_vals[2].u.f; + tk->max_ptsize = shared_vals[3].u.f; + tk->max_kern = shared_vals[4].u.f; + break; + case AFM_TOKEN_ENDTRACKKERN: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + fi->NumTrackKern = n + 1; + return PSaux_Err_Ok; + case AFM_TOKEN_UNKNOWN: + break; + default: + goto Fail; + } + } + Fail: + return PSaux_Err_Syntax_Error; + } +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) +/* compare two kerning pairs */ + FT_CALLBACK_DEF( int ) + afm_compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair kp1 = (AFM_KernPair)a; + AFM_KernPair kp2 = (AFM_KernPair)b; + FT_ULong index1 = KERN_INDEX( kp1->index1, kp1->index2 ); + FT_ULong index2 = KERN_INDEX( kp2->index1, kp2->index2 ); + if ( index1 > index2 ) + return 1; + else if ( index1 < index2 ) + return -1; + else + return 0; + } + static FT_Error + afm_parse_kern_pairs( AFM_Parser parser ) + { + AFM_FontInfo fi = parser->FontInfo; + AFM_KernPair kp; + char* key; + FT_Offset len; + int n = -1; + if ( afm_parser_read_int( parser, &fi->NumKernPair ) ) + goto Fail; + if ( fi->NumKernPair ) + { + FT_Memory memory = parser->memory; + FT_Error error; + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + return error; + } + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + switch ( token ) + { + case AFM_TOKEN_KP: + case AFM_TOKEN_KPX: + case AFM_TOKEN_KPY: + { + FT_Int r; + AFM_ValueRec shared_vals[4]; + n++; + if ( n >= fi->NumKernPair ) + goto Fail; + kp = fi->KernPairs + n; + shared_vals[0].type = AFM_VALUE_TYPE_INDEX; + shared_vals[1].type = AFM_VALUE_TYPE_INDEX; + shared_vals[2].type = AFM_VALUE_TYPE_INTEGER; + shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; + r = afm_parser_read_vals( parser, shared_vals, 4 ); + if ( r < 3 ) + goto Fail; + kp->index1 = shared_vals[0].u.i; + kp->index2 = shared_vals[1].u.i; + if ( token == AFM_TOKEN_KPY ) + { + kp->x = 0; + kp->y = shared_vals[2].u.i; + } + else + { + kp->x = shared_vals[2].u.i; + kp->y = ( token == AFM_TOKEN_KP && r == 4 ) + ? shared_vals[3].u.i : 0; + } + } + break; + case AFM_TOKEN_ENDKERNPAIRS: + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + fi->NumKernPair = n + 1; + ft_qsort( fi->KernPairs, fi->NumKernPair, + sizeof ( AFM_KernPairRec ), + afm_compare_kern_pairs ); + return PSaux_Err_Ok; + case AFM_TOKEN_UNKNOWN: + break; + default: + goto Fail; + } + } + Fail: + return PSaux_Err_Syntax_Error; + } + static FT_Error + afm_parse_kern_data( AFM_Parser parser ) + { + FT_Error error; + char* key; + FT_Offset len; + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_STARTTRACKKERN: + error = afm_parse_track_kern( parser ); + if ( error ) + return error; + break; + case AFM_TOKEN_STARTKERNPAIRS: + case AFM_TOKEN_STARTKERNPAIRS0: + error = afm_parse_kern_pairs( parser ); + if ( error ) + return error; + break; + case AFM_TOKEN_ENDKERNDATA: + case AFM_TOKEN_ENDFONTMETRICS: + return PSaux_Err_Ok; + case AFM_TOKEN_UNKNOWN: + break; + default: + goto Fail; + } + } + Fail: + return PSaux_Err_Syntax_Error; + } + static FT_Error + afm_parser_skip_section( AFM_Parser parser, + FT_UInt n, + AFM_Token end_section ) + { + char* key; + FT_Offset len; + while ( n-- > 0 ) + { + key = afm_parser_next_key( parser, 1, NULL ); + if ( !key ) + goto Fail; + } + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_Token token = afm_tokenize( key, len ); + if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS ) + return PSaux_Err_Ok; + } + Fail: + return PSaux_Err_Syntax_Error; + } + FT_LOCAL_DEF( FT_Error ) + afm_parser_parse( AFM_Parser parser ) + { + FT_Memory memory = parser->memory; + AFM_FontInfo fi = parser->FontInfo; + FT_Error error = PSaux_Err_Syntax_Error; + char* key; + FT_Offset len; + FT_Int metrics_sets = 0; + if ( !fi ) + return PSaux_Err_Invalid_Argument; + key = afm_parser_next_key( parser, 1, &len ); + if ( !key || len != 16 || + ft_strncmp( key, "StartFontMetrics", 16 ) != 0 ) + return PSaux_Err_Unknown_File_Format; + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) + { + AFM_ValueRec shared_vals[4]; + switch ( afm_tokenize( key, len ) ) + { + case AFM_TOKEN_METRICSSETS: + if ( afm_parser_read_int( parser, &metrics_sets ) ) + goto Fail; + if ( metrics_sets != 0 && metrics_sets != 2 ) + { + error = PSaux_Err_Unimplemented_Feature; + goto Fail; + } + break; + case AFM_TOKEN_ISCIDFONT: + shared_vals[0].type = AFM_VALUE_TYPE_BOOL; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + fi->IsCIDFont = shared_vals[0].u.b; + break; + case AFM_TOKEN_FONTBBOX: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + shared_vals[1].type = AFM_VALUE_TYPE_FIXED; + shared_vals[2].type = AFM_VALUE_TYPE_FIXED; + shared_vals[3].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 ) + goto Fail; + fi->FontBBox.xMin = shared_vals[0].u.f; + fi->FontBBox.yMin = shared_vals[1].u.f; + fi->FontBBox.xMax = shared_vals[2].u.f; + fi->FontBBox.yMax = shared_vals[3].u.f; + break; + case AFM_TOKEN_ASCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + fi->Ascender = shared_vals[0].u.f; + break; + case AFM_TOKEN_DESCENDER: + shared_vals[0].type = AFM_VALUE_TYPE_FIXED; + if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 ) + goto Fail; + fi->Descender = shared_vals[0].u.f; + break; + case AFM_TOKEN_STARTCHARMETRICS: + { + FT_Int n = 0; + if ( afm_parser_read_int( parser, &n ) ) + goto Fail; + error = afm_parser_skip_section( parser, n, + AFM_TOKEN_ENDCHARMETRICS ); + if ( error ) + return error; + } + break; + case AFM_TOKEN_STARTKERNDATA: + error = afm_parse_kern_data( parser ); + if ( error ) + goto Fail; +/* fall through since we only support kern data */ + case AFM_TOKEN_ENDFONTMETRICS: + return PSaux_Err_Ok; + default: + break; + } + } + Fail: + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + fi->IsCIDFont = 0; + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* psconv.c */ +/* */ +/* Some convenience conversions (body). */ +/* */ +/* Copyright 2006, 2008, 2009, 2012 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 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 trace_psconv +/* The following array is used by various functions to quickly convert */ +/* digits (both decimal and non-decimal) into numbers. */ +#if 'A' == 65 +/* ASCII */ + static const FT_Char ft_char_table[128] = + { +/* 0x00 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + }; +/* no character >= 0x80 can represent a valid number */ +#define OP >= +/* 'A' == 65 */ +#endif +#if 'A' == 193 +/* EBCDIC */ + static const FT_Char ft_char_table[128] = + { +/* 0x80 */ + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1, + -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + }; +/* no character < 0x80 can represent a valid number */ +#define OP < +/* 'A' == 193 */ +#endif + FT_LOCAL_DEF( FT_Long ) + PS_Conv_Strtol( FT_Byte** cursor, + FT_Byte* limit, + FT_Long base ) + { + FT_Byte* p = *cursor; + FT_Long num = 0; + FT_Bool sign = 0; + FT_Bool have_overflow = 0; + FT_Long num_limit; + FT_Char c_limit; + if ( p >= limit ) + goto Bad; + if ( base < 2 || base > 36 ) + { + FT_TRACE4(( "!!!INVALID BASE:!!!" )); + return 0; + } + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + p++; + if ( p == limit ) + goto Bad; + } + num_limit = 0x7FFFFFFFL / base; + c_limit = (FT_Char)( 0x7FFFFFFFL % base ); + for ( ; p < limit; p++ ) + { + FT_Char c; + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + c = ft_char_table[*p & 0x7f]; + if ( c < 0 || c >= base ) + break; + if ( num > num_limit || ( num == num_limit && c > c_limit ) ) + have_overflow = 1; + else + num = num * base + c; + } + *cursor = p; + if ( have_overflow ) + { + num = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + } + if ( sign ) + num = -num; + return num; + Bad: + FT_TRACE4(( "!!!END OF DATA:!!!" )); + return 0; + } + FT_LOCAL_DEF( FT_Long ) + PS_Conv_ToInt( FT_Byte** cursor, + FT_Byte* limit ) + { + FT_Byte* p = *cursor; + FT_Byte* curp; + FT_Long num; + curp = p; + num = PS_Conv_Strtol( &p, limit, 10 ); + if ( p == curp ) + return 0; + if ( p < limit && *p == '#' ) + { + p++; + curp = p; + num = PS_Conv_Strtol( &p, limit, num ); + if ( p == curp ) + return 0; + } + *cursor = p; + return num; + } + FT_LOCAL_DEF( FT_Fixed ) + PS_Conv_ToFixed( FT_Byte** cursor, + FT_Byte* limit, + FT_Long power_ten ) + { + FT_Byte* p = *cursor; + FT_Byte* curp; + FT_Fixed integral = 0; + FT_Long decimal = 0; + FT_Long divider = 1; + FT_Bool sign = 0; + FT_Bool have_overflow = 0; + FT_Bool have_underflow = 0; + if ( p >= limit ) + goto Bad; + if ( *p == '-' || *p == '+' ) + { + sign = FT_BOOL( *p == '-' ); + p++; + if ( p == limit ) + goto Bad; + } +/* read the integer part */ + if ( *p != '.' ) + { + curp = p; + integral = PS_Conv_ToInt( &p, limit ); + if ( p == curp ) + return 0; + if ( integral > 0x7FFF ) + have_overflow = 1; + else + integral <<= 16; + } +/* read the decimal part */ + if ( p < limit && *p == '.' ) + { + p++; + for ( ; p < limit; p++ ) + { + FT_Char c; + if ( IS_PS_SPACE( *p ) || *p OP 0x80 ) + break; + c = ft_char_table[*p & 0x7f]; + if ( c < 0 || c >= 10 ) + break; + if ( decimal < 0xCCCCCCCL ) + { + decimal = decimal * 10 + c; + if ( !integral && power_ten > 0 ) + power_ten--; + else + divider *= 10; + } + } + } +/* read exponent, if any */ + if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) ) + { + FT_Long exponent; + p++; + curp = p; + exponent = PS_Conv_ToInt( &p, limit ); + if ( curp == p ) + return 0; +/* arbitrarily limit exponent */ + if ( exponent > 1000 ) + have_overflow = 1; + else if ( exponent < -1000 ) + have_underflow = 1; + else + power_ten += exponent; + } + *cursor = p; + if ( !integral && !decimal ) + return 0; + if ( have_overflow ) + goto Overflow; + if ( have_underflow ) + goto Underflow; + while ( power_ten > 0 ) + { + if ( integral >= 0xCCCCCCCL ) + goto Overflow; + integral *= 10; + if ( decimal >= 0xCCCCCCCL ) + { + if ( divider == 1 ) + goto Overflow; + divider /= 10; + } + else + decimal *= 10; + power_ten--; + } + while ( power_ten < 0 ) + { + integral /= 10; + if ( divider < 0xCCCCCCCL ) + divider *= 10; + else + decimal /= 10; + if ( !integral && !decimal ) + goto Underflow; + power_ten++; + } + if ( decimal ) + { + decimal = FT_DivFix( decimal, divider ); +/* it's not necessary to check this addition for overflow */ +/* due to the structure of the real number representation */ + integral += decimal; + } + Exit: + if ( sign ) + integral = -integral; + return integral; + Bad: + FT_TRACE4(( "!!!END OF DATA:!!!" )); + return 0; + Overflow: + integral = 0x7FFFFFFFL; + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + goto Exit; + Underflow: + FT_TRACE4(( "!!!UNDERFLOW:!!!" )); + return 0; + } +#if 0 + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_StringDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ) + { + FT_Byte* p; + FT_UInt r = 0; + for ( p = *cursor; r < n && p < limit; p++ ) + { + FT_Byte b; + if ( *p != '\\' ) + { + buffer[r++] = *p; + continue; + } + p++; + switch ( *p ) + { + case 'n': + b = '\n'; + break; + case 'r': + b = '\r'; + break; + case 't': + b = '\t'; + break; + case 'b': + b = '\b'; + break; + case 'f': + b = '\f'; + break; + case '\r': + p++; + if ( *p != '\n' ) + { + b = *p; + break; + } +/* no break */ + case '\n': + continue; + break; + default: + if ( IS_PS_DIGIT( *p ) ) + { + b = *p - '0'; + p++; + if ( IS_PS_DIGIT( *p ) ) + { + b = b * 8 + *p - '0'; + p++; + if ( IS_PS_DIGIT( *p ) ) + b = b * 8 + *p - '0'; + else + { + buffer[r++] = b; + b = *p; + } + } + else + { + buffer[r++] = b; + b = *p; + } + } + else + b = *p; + break; + } + buffer[r++] = b; + } + *cursor = p; + return r; + } +/* 0 */ +#endif + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_ASCIIHexDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n ) + { + FT_Byte* p; + FT_UInt r = 0; + FT_UInt w = 0; + FT_UInt pad = 0x01; + n *= 2; +#if 1 + p = *cursor; + if ( p >= limit ) + return 0; + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); +/* we try to process two nibbles at a time to be as fast as possible */ + for ( ; r < n; r++ ) + { + FT_UInt c = p[r]; + if ( IS_PS_SPACE( c ) ) + continue; + if ( c OP 0x80 ) + break; + c = ft_char_table[c & 0x7F]; + if ( (unsigned)c >= 16 ) + break; + pad = ( pad << 4 ) | c; + if ( pad & 0x100 ) + { + buffer[w++] = (FT_Byte)pad; + pad = 0x01; + } + } + if ( pad != 0x01 ) + buffer[w++] = (FT_Byte)( pad << 4 ); + *cursor = p + r; + return w; +/* 0 */ +#else + for ( r = 0; r < n; r++ ) + { + FT_Char c; + if ( IS_PS_SPACE( *p ) ) + continue; + if ( *p OP 0x80 ) + break; + c = ft_char_table[*p & 0x7f]; + if ( (unsigned)c >= 16 ) + break; + if ( r & 1 ) + { + *buffer = (FT_Byte)(*buffer + c); + buffer++; + } + else + *buffer = (FT_Byte)(c << 4); + r++; + } + *cursor = p; + return ( r + 1 ) / 2; +/* 0 */ +#endif + } + FT_LOCAL_DEF( FT_UInt ) + PS_Conv_EexecDecode( FT_Byte** cursor, + FT_Byte* limit, + FT_Byte* buffer, + FT_Offset n, + FT_UShort* seed ) + { + FT_Byte* p; + FT_UInt r; + FT_UInt s = *seed; +#if 1 + p = *cursor; + if ( p >= limit ) + return 0; + if ( n > (FT_UInt)(limit - p) ) + n = (FT_UInt)(limit - p); + for ( r = 0; r < n; r++ ) + { + FT_UInt val = p[r]; + FT_UInt b = ( val ^ ( s >> 8 ) ); + s = ( (val + s)*52845U + 22719 ) & 0xFFFFU; + buffer[r] = (FT_Byte) b; + } + *cursor = p + n; + *seed = (FT_UShort)s; +/* 0 */ +#else + for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ ) + { + FT_Byte b = (FT_Byte)( *p ^ ( s >> 8 ) ); + s = (FT_UShort)( ( *p + s ) * 52845U + 22719 ); + *buffer++ = b; + } + *cursor = p; + *seed = s; +/* 0 */ +#endif + return r; + } +/* END */ +/* END */ +/* pcf.c + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2003 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. +*/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/* + +Copyright 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */ +/* + * Author: Keith Packard, MIT X Consortium + */ +/* Modified for use with FreeType */ +/* pcfutil.h + + FreeType font driver for pcf fonts + + Copyright 2000, 2001, 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. +*/ +#define __PCFUTIL_H__ +FT_BEGIN_HEADER + FT_LOCAL( void ) + BitOrderInvert( unsigned char* buf, + size_t nbytes ); + FT_LOCAL( void ) + TwoByteSwap( unsigned char* buf, + size_t nbytes ); + FT_LOCAL( void ) + FourByteSwap( unsigned char* buf, + size_t nbytes ); +FT_END_HEADER +/* END */ +/* + * Invert bit order within each BYTE of an array. + */ + FT_LOCAL_DEF( void ) + BitOrderInvert( unsigned char* buf, + size_t nbytes ) + { + for ( ; nbytes > 0; nbytes--, buf++ ) + { + unsigned int val = *buf; + val = ( ( val >> 1 ) & 0x55 ) | ( ( val << 1 ) & 0xAA ); + val = ( ( val >> 2 ) & 0x33 ) | ( ( val << 2 ) & 0xCC ); + val = ( ( val >> 4 ) & 0x0F ) | ( ( val << 4 ) & 0xF0 ); + *buf = (unsigned char)val; + } + } +/* + * Invert byte order within each 16-bits of an array. + */ + FT_LOCAL_DEF( void ) + TwoByteSwap( unsigned char* buf, + size_t nbytes ) + { + unsigned char c; + for ( ; nbytes >= 2; nbytes -= 2, buf += 2 ) + { + c = buf[0]; + buf[0] = buf[1]; + buf[1] = c; + } + } +/* + * Invert byte order within each 32-bits of an array. + */ + FT_LOCAL_DEF( void ) + FourByteSwap( unsigned char* buf, + size_t nbytes ) + { + unsigned char c; + for ( ; nbytes >= 4; nbytes -= 4, buf += 4 ) + { + c = buf[0]; + buf[0] = buf[3]; + buf[3] = c; + c = buf[1]; + buf[1] = buf[2]; + buf[2] = c; + } + } +/* END */ +/* pcfread.c + + FreeType font driver for pcf fonts + + Copyright 2000-2010, 2012 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. +*/ +/* pcf.h + + FreeType font driver for pcf fonts + + Copyright (C) 2000, 2001, 2002, 2003, 2006, 2010 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. +*/ +#define __PCF_H__ +FT_BEGIN_HEADER + typedef struct PCF_TableRec_ + { + FT_ULong type; + FT_ULong format; + FT_ULong size; + FT_ULong offset; + } PCF_TableRec, *PCF_Table; + typedef struct PCF_TocRec_ + { + FT_ULong version; + FT_ULong count; + PCF_Table tables; + } PCF_TocRec, *PCF_Toc; + typedef struct PCF_ParsePropertyRec_ + { + FT_Long name; + FT_Byte isString; + FT_Long value; + } PCF_ParsePropertyRec, *PCF_ParseProperty; + typedef struct PCF_PropertyRec_ + { + FT_String* name; + FT_Byte isString; + union + { + FT_String* atom; + FT_Long l; + FT_ULong ul; + } value; + } PCF_PropertyRec, *PCF_Property; + typedef struct PCF_Compressed_MetricRec_ + { + FT_Byte leftSideBearing; + FT_Byte rightSideBearing; + FT_Byte characterWidth; + FT_Byte ascent; + FT_Byte descent; + } PCF_Compressed_MetricRec, *PCF_Compressed_Metric; + typedef struct PCF_MetricRec_ + { + FT_Short leftSideBearing; + FT_Short rightSideBearing; + FT_Short characterWidth; + FT_Short ascent; + FT_Short descent; + FT_Short attributes; + FT_ULong bits; + } PCF_MetricRec, *PCF_Metric; + typedef struct PCF_AccelRec_ + { + FT_Byte noOverlap; + FT_Byte constantMetrics; + FT_Byte terminalFont; + FT_Byte constantWidth; + FT_Byte inkInside; + FT_Byte inkMetrics; + FT_Byte drawDirection; + FT_Long fontAscent; + FT_Long fontDescent; + FT_Long maxOverlap; + PCF_MetricRec minbounds; + PCF_MetricRec maxbounds; + PCF_MetricRec ink_minbounds; + PCF_MetricRec ink_maxbounds; + } PCF_AccelRec, *PCF_Accel; + typedef struct PCF_EncodingRec_ + { + FT_Long enc; + FT_UShort glyph; + } PCF_EncodingRec, *PCF_Encoding; + typedef struct PCF_FaceRec_ + { + FT_FaceRec root; + FT_StreamRec comp_stream; + FT_Stream comp_source; + char* charset_encoding; + char* charset_registry; + PCF_TocRec toc; + PCF_AccelRec accel; + int nprops; + PCF_Property properties; + FT_Long nmetrics; + PCF_Metric metrics; + FT_Long nencodings; + PCF_Encoding encodings; + FT_Short defaultChar; + FT_ULong bitmapsFormat; + FT_CharMap charmap_handle; +/* a single charmap per face */ + FT_CharMapRec charmap; + } PCF_FaceRec, *PCF_Face; +/* macros for pcf font format */ +#define LSBFirst 0 +#define MSBFirst 1 +#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \ + ( 'c' << 16 ) | \ + ( 'f' << 8 ) | 1 ) +#define PCF_FORMAT_MASK 0xFFFFFF00UL +#define PCF_DEFAULT_FORMAT 0x00000000UL +#define PCF_INKBOUNDS 0x00000200UL +#define PCF_ACCEL_W_INKBOUNDS 0x00000100UL +#define PCF_COMPRESSED_METRICS 0x00000100UL +#define PCF_FORMAT_MATCH( a, b ) \ + ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) ) +#define PCF_GLYPH_PAD_MASK ( 3 << 0 ) +#define PCF_BYTE_MASK ( 1 << 2 ) +#define PCF_BIT_MASK ( 1 << 3 ) +#define PCF_SCAN_UNIT_MASK ( 3 << 4 ) +#define PCF_BYTE_ORDER( f ) \ + ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_BIT_ORDER( f ) \ + ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst ) +#define PCF_GLYPH_PAD_INDEX( f ) \ + ( (f) & PCF_GLYPH_PAD_MASK ) +#define PCF_GLYPH_PAD( f ) \ + ( 1 << PCF_GLYPH_PAD_INDEX( f ) ) +#define PCF_SCAN_UNIT_INDEX( f ) \ + ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 ) +#define PCF_SCAN_UNIT( f ) \ + ( 1 << PCF_SCAN_UNIT_INDEX( f ) ) +#define PCF_FORMAT_BITS( f ) \ + ( (f) & ( PCF_GLYPH_PAD_MASK | \ + PCF_BYTE_MASK | \ + PCF_BIT_MASK | \ + PCF_SCAN_UNIT_MASK ) ) +#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 ) +#define PCF_INDEX_TO_SIZE( b ) ( 1 << b ) +#define PCF_FORMAT( bit, byte, glyph, scan ) \ + ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \ + ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \ + ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \ + ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) ) +#define PCF_PROPERTIES ( 1 << 0 ) +#define PCF_ACCELERATORS ( 1 << 1 ) +#define PCF_METRICS ( 1 << 2 ) +#define PCF_BITMAPS ( 1 << 3 ) +#define PCF_INK_METRICS ( 1 << 4 ) +#define PCF_BDF_ENCODINGS ( 1 << 5 ) +#define PCF_SWIDTHS ( 1 << 6 ) +#define PCF_GLYPH_NAMES ( 1 << 7 ) +#define PCF_BDF_ACCELERATORS ( 1 << 8 ) +/* I'm not sure about this */ +#define GLYPHPADOPTIONS 4 + FT_LOCAL( FT_Error ) + pcf_load_font( FT_Stream, + PCF_Face ); +FT_END_HEADER +/* END */ +/* pcfread.h + + FreeType font driver for pcf fonts + + Copyright 2003 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. +*/ +#define __PCFREAD_H__ +FT_BEGIN_HEADER + FT_LOCAL( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* pcferror.h */ +/* */ +/* PCF error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 PCF error enumeration constants. */ +/* */ +/*************************************************************************/ +#define __PCFERROR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PCF_Err_ +#define FT_ERR_BASE FT_Mod_Err_PCF +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_pcfread + static + const FT_Frame_Field pcf_toc_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TocRec + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( version ), + FT_FRAME_ULONG_LE( count ), + FT_FRAME_END + }; + static + const FT_Frame_Field pcf_table_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_TableRec + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( type ), + FT_FRAME_ULONG_LE( format ), + FT_FRAME_ULONG_LE( size ), + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + static FT_Error + pcf_read_TOC( FT_Stream stream, + PCF_Face face ) + { + FT_Error error; + PCF_Toc toc = &face->toc; + PCF_Table tables; + FT_Memory memory = FT_FACE(face)->memory; + FT_UInt n; + if ( FT_STREAM_SEEK ( 0 ) || + FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) + return PCF_Err_Cannot_Open_Resource; + if ( toc->version != PCF_FILE_VERSION || + toc->count > FT_ARRAY_MAX( face->toc.tables ) || + toc->count == 0 ) + return PCF_Err_Invalid_File_Format; + if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) + return PCF_Err_Out_Of_Memory; + tables = face->toc.tables; + for ( n = 0; n < toc->count; n++ ) + { + if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) + goto Exit; + tables++; + } +/* Sort tables and check for overlaps. Because they are almost */ +/* always ordered already, an in-place bubble sort with simultaneous */ +/* boundary checking seems appropriate. */ + tables = face->toc.tables; + for ( n = 0; n < toc->count - 1; n++ ) + { + FT_UInt i, have_change; + have_change = 0; + for ( i = 0; i < toc->count - 1 - n; i++ ) + { + PCF_TableRec tmp; + if ( tables[i].offset > tables[i + 1].offset ) + { + tmp = tables[i]; + tables[i] = tables[i + 1]; + tables[i + 1] = tmp; + have_change = 1; + } + if ( ( tables[i].size > tables[i + 1].offset ) || + ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) + return PCF_Err_Invalid_Offset; + } + if ( !have_change ) + break; + } + return PCF_Err_Ok; + Exit: + FT_FREE( face->toc.tables ); + return error; + } +#define PCF_METRIC_SIZE 12 + static + const FT_Frame_Field pcf_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT_LE( leftSideBearing ), + FT_FRAME_SHORT_LE( rightSideBearing ), + FT_FRAME_SHORT_LE( characterWidth ), + FT_FRAME_SHORT_LE( ascent ), + FT_FRAME_SHORT_LE( descent ), + FT_FRAME_SHORT_LE( attributes ), + FT_FRAME_END + }; + static + const FT_Frame_Field pcf_metric_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_MetricRec + FT_FRAME_START( PCF_METRIC_SIZE ), + FT_FRAME_SHORT( leftSideBearing ), + FT_FRAME_SHORT( rightSideBearing ), + FT_FRAME_SHORT( characterWidth ), + FT_FRAME_SHORT( ascent ), + FT_FRAME_SHORT( descent ), + FT_FRAME_SHORT( attributes ), + FT_FRAME_END + }; +#define PCF_COMPRESSED_METRIC_SIZE 5 + static + const FT_Frame_Field pcf_compressed_metric_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_Compressed_MetricRec + FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), + FT_FRAME_BYTE( leftSideBearing ), + FT_FRAME_BYTE( rightSideBearing ), + FT_FRAME_BYTE( characterWidth ), + FT_FRAME_BYTE( ascent ), + FT_FRAME_BYTE( descent ), + FT_FRAME_END + }; + static FT_Error + pcf_get_metric( FT_Stream stream, + FT_ULong format, + PCF_Metric metric ) + { + FT_Error error = PCF_Err_Ok; + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + const FT_Frame_Field* fields; +/* parsing normal metrics */ + fields = PCF_BYTE_ORDER( format ) == MSBFirst + ? pcf_metric_msb_header + : pcf_metric_header; +/* the following sets `error' but doesn't return in case of failure */ + (void)FT_STREAM_READ_FIELDS( fields, metric ); + } + else + { + PCF_Compressed_MetricRec compr; +/* parsing compressed metrics */ + if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) + goto Exit; + metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); + metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); + metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); + metric->ascent = (FT_Short)( compr.ascent - 0x80 ); + metric->descent = (FT_Short)( compr.descent - 0x80 ); + metric->attributes = 0; + } + Exit: + return error; + } + static FT_Error + pcf_seek_to_table_type( FT_Stream stream, + PCF_Table tables, +/* same as PCF_Toc->count */ + FT_ULong ntables, + FT_ULong type, + FT_ULong *aformat, + FT_ULong *asize ) + { + FT_Error error = PCF_Err_Invalid_File_Format; + FT_ULong i; + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + { + if ( stream->pos > tables[i].offset ) + { + error = PCF_Err_Invalid_Stream_Skip; + goto Fail; + } + if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) + { + error = PCF_Err_Invalid_Stream_Skip; + goto Fail; + } + *asize = tables[i].size; + *aformat = tables[i].format; + return PCF_Err_Ok; + } + Fail: + *asize = 0; + return error; + } + static FT_Bool + pcf_has_table_type( PCF_Table tables, +/* same as PCF_Toc->count */ + FT_ULong ntables, + FT_ULong type ) + { + FT_ULong i; + for ( i = 0; i < ntables; i++ ) + if ( tables[i].type == type ) + return TRUE; + return FALSE; + } +#define PCF_PROPERTY_SIZE 9 + static + const FT_Frame_Field pcf_property_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG_LE( name ), + FT_FRAME_BYTE ( isString ), + FT_FRAME_LONG_LE( value ), + FT_FRAME_END + }; + static + const FT_Frame_Field pcf_property_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_ParsePropertyRec + FT_FRAME_START( PCF_PROPERTY_SIZE ), + FT_FRAME_LONG( name ), + FT_FRAME_BYTE( isString ), + FT_FRAME_LONG( value ), + FT_FRAME_END + }; + FT_LOCAL_DEF( PCF_Property ) + pcf_find_property( PCF_Face face, + const FT_String* prop ) + { + PCF_Property properties = face->properties; + FT_Bool found = 0; + int i; + for ( i = 0 ; i < face->nprops && !found; i++ ) + { + if ( !ft_strcmp( properties[i].name, prop ) ) + found = 1; + } + if ( found ) + return properties + i - 1; + else + return NULL; + } + static FT_Error + pcf_get_properties( FT_Stream stream, + PCF_Face face ) + { + PCF_ParseProperty props = 0; + PCF_Property properties = NULL; + FT_ULong nprops, i; + FT_ULong format, size; + FT_Error error; + FT_Memory memory = FT_FACE(face)->memory; + FT_ULong string_size; + FT_String* strings = 0; + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_PROPERTIES, + &format, + &size ); + if ( error ) + goto Bail; + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + FT_TRACE4(( "pcf_get_properties:\n" )); + FT_TRACE4(( " format = %ld\n", format )); + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + goto Bail; + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( nprops ); + else + (void)FT_READ_ULONG_LE( nprops ); + if ( error ) + goto Bail; + FT_TRACE4(( " nprop = %d (truncate %d props)\n", + (int)nprops, nprops - (int)nprops )); + nprops = (int)nprops; +/* rough estimate */ + if ( nprops > size / PCF_PROPERTY_SIZE ) + { + error = PCF_Err_Invalid_Table; + goto Bail; + } + face->nprops = (int)nprops; + if ( FT_NEW_ARRAY( props, nprops ) ) + goto Bail; + for ( i = 0; i < nprops; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) + goto Bail; + } + } +/* pad the property array */ +/* */ +/* clever here - nprops is the same as the number of odd-units read, */ +/* as only isStringProp are odd length (Keith Packard) */ +/* */ + if ( nprops & 3 ) + { + i = 4 - ( nprops & 3 ); + if ( FT_STREAM_SKIP( i ) ) + { + error = PCF_Err_Invalid_Stream_Skip; + goto Bail; + } + } + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( string_size ); + else + (void)FT_READ_ULONG_LE( string_size ); + if ( error ) + goto Bail; + FT_TRACE4(( " string_size = %ld\n", string_size )); +/* rough estimate */ + if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) + { + error = PCF_Err_Invalid_Table; + goto Bail; + } +/* allocate one more byte so that we have a final null byte */ + if ( FT_NEW_ARRAY( strings, string_size + 1 ) ) + goto Bail; + error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); + if ( error ) + goto Bail; + if ( FT_NEW_ARRAY( properties, nprops ) ) + goto Bail; + face->properties = properties; + for ( i = 0; i < nprops; i++ ) + { + FT_Long name_offset = props[i].name; + if ( ( name_offset < 0 ) || + ( (FT_ULong)name_offset > string_size ) ) + { + error = PCF_Err_Invalid_Offset; + goto Bail; + } + if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) + goto Bail; + FT_TRACE4(( " %s:", properties[i].name )); + properties[i].isString = props[i].isString; + if ( props[i].isString ) + { + FT_Long value_offset = props[i].value; + if ( ( value_offset < 0 ) || + ( (FT_ULong)value_offset > string_size ) ) + { + error = PCF_Err_Invalid_Offset; + goto Bail; + } + if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) + goto Bail; + FT_TRACE4(( " `%s'\n", properties[i].value.atom )); + } + else + { + properties[i].value.l = props[i].value; + FT_TRACE4(( " %d\n", properties[i].value.l )); + } + } + error = PCF_Err_Ok; + Bail: + FT_FREE( props ); + FT_FREE( strings ); + return error; + } + static FT_Error + pcf_get_metrics( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_ULong format, size; + PCF_Metric metrics = 0; + FT_ULong nmetrics, i; + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_METRICS, + &format, + &size ); + if ( error ) + return error; + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) + return PCF_Err_Invalid_File_Format; + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_ULONG( nmetrics ); + else + (void)FT_READ_ULONG_LE( nmetrics ); + } + else + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_USHORT( nmetrics ); + else + (void)FT_READ_USHORT_LE( nmetrics ); + } + if ( error ) + return PCF_Err_Invalid_File_Format; + face->nmetrics = nmetrics; + if ( !nmetrics ) + return PCF_Err_Invalid_Table; + FT_TRACE4(( "pcf_get_metrics:\n" )); + FT_TRACE4(( " number of metrics: %d\n", nmetrics )); +/* rough estimate */ + if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + { + if ( nmetrics > size / PCF_METRIC_SIZE ) + return PCF_Err_Invalid_Table; + } + else + { + if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) + return PCF_Err_Invalid_Table; + } + if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) + return PCF_Err_Out_Of_Memory; + metrics = face->metrics; + for ( i = 0; i < nmetrics; i++ ) + { + error = pcf_get_metric( stream, format, metrics + i ); + metrics[i].bits = 0; + FT_TRACE5(( " idx %d: width=%d, " + "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", + i, + ( metrics + i )->characterWidth, + ( metrics + i )->leftSideBearing, + ( metrics + i )->rightSideBearing, + ( metrics + i )->ascent, + ( metrics + i )->descent, + ( metrics + i )->attributes )); + if ( error ) + break; + } + if ( error ) + FT_FREE( face->metrics ); + Bail: + return error; + } + static FT_Error + pcf_get_bitmaps( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_Long* offsets = NULL; + FT_Long bitmapSizes[GLYPHPADOPTIONS]; + FT_ULong format, size; + FT_ULong nbitmaps, i, sizebitmaps = 0; + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BITMAPS, + &format, + &size ); + if ( error ) + return error; + error = FT_Stream_EnterFrame( stream, 8 ); + if ( error ) + return error; + format = FT_GET_ULONG_LE(); + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + nbitmaps = FT_GET_ULONG(); + else + nbitmaps = FT_GET_ULONG_LE(); + FT_Stream_ExitFrame( stream ); + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + return PCF_Err_Invalid_File_Format; + FT_TRACE4(( "pcf_get_bitmaps:\n" )); + FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); +/* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */ + if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics ) + return PCF_Err_Invalid_File_Format; + if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) + return error; + for ( i = 0; i < nbitmaps; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_LONG( offsets[i] ); + else + (void)FT_READ_LONG_LE( offsets[i] ); + FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", + i, offsets[i], offsets[i] )); + } + if ( error ) + goto Bail; + for ( i = 0; i < GLYPHPADOPTIONS; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + (void)FT_READ_LONG( bitmapSizes[i] ); + else + (void)FT_READ_LONG_LE( bitmapSizes[i] ); + if ( error ) + goto Bail; + sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; + FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); + } + FT_TRACE4(( " %d bitmaps, padding index %ld\n", + nbitmaps, + PCF_GLYPH_PAD_INDEX( format ) )); + FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); +/* only used for debugging */ + FT_UNUSED( sizebitmaps ); + for ( i = 0; i < nbitmaps; i++ ) + { +/* rough estimate */ + if ( ( offsets[i] < 0 ) || + ( (FT_ULong)offsets[i] > size ) ) + { + FT_TRACE0(( "pcf_get_bitmaps:" + " invalid offset to bitmap data of glyph %d\n", i )); + } + else + face->metrics[i].bits = stream->pos + offsets[i]; + } + face->bitmapsFormat = format; + Bail: + FT_FREE( offsets ); + return error; + } + static FT_Error + pcf_get_encodings( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_ULong format, size; + int firstCol, lastCol; + int firstRow, lastRow; + int nencoding, encodingOffset; + int i, j; + PCF_Encoding tmpEncoding = NULL, encoding = 0; + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + PCF_BDF_ENCODINGS, + &format, + &size ); + if ( error ) + return error; + error = FT_Stream_EnterFrame( stream, 14 ); + if ( error ) + return error; + format = FT_GET_ULONG_LE(); + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + firstCol = FT_GET_SHORT(); + lastCol = FT_GET_SHORT(); + firstRow = FT_GET_SHORT(); + lastRow = FT_GET_SHORT(); + face->defaultChar = FT_GET_SHORT(); + } + else + { + firstCol = FT_GET_SHORT_LE(); + lastCol = FT_GET_SHORT_LE(); + firstRow = FT_GET_SHORT_LE(); + lastRow = FT_GET_SHORT_LE(); + face->defaultChar = FT_GET_SHORT_LE(); + } + FT_Stream_ExitFrame( stream ); + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) + return PCF_Err_Invalid_File_Format; + FT_TRACE4(( "pdf_get_encodings:\n" )); + FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", + firstCol, lastCol, firstRow, lastRow )); + nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); + if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) + return PCF_Err_Out_Of_Memory; + error = FT_Stream_EnterFrame( stream, 2 * nencoding ); + if ( error ) + goto Bail; + for ( i = 0, j = 0 ; i < nencoding; i++ ) + { + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + encodingOffset = FT_GET_SHORT(); + else + encodingOffset = FT_GET_SHORT_LE(); + if ( encodingOffset != -1 ) + { + tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + + firstRow ) * 256 ) + + ( ( i % ( lastCol - firstCol + 1 ) ) + + firstCol ); + tmpEncoding[j].glyph = (FT_Short)encodingOffset; + FT_TRACE5(( " code %d (0x%04X): idx %d\n", + tmpEncoding[j].enc, tmpEncoding[j].enc, + tmpEncoding[j].glyph )); + j++; + } + } + FT_Stream_ExitFrame( stream ); + if ( FT_NEW_ARRAY( encoding, j ) ) + goto Bail; + for ( i = 0; i < j; i++ ) + { + encoding[i].enc = tmpEncoding[i].enc; + encoding[i].glyph = tmpEncoding[i].glyph; + } + face->nencodings = j; + face->encodings = encoding; + FT_FREE( tmpEncoding ); + return error; + Bail: + FT_FREE( encoding ); + FT_FREE( tmpEncoding ); + return error; + } + static + const FT_Frame_Field pcf_accel_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG_LE ( fontAscent ), + FT_FRAME_LONG_LE ( fontDescent ), + FT_FRAME_LONG_LE ( maxOverlap ), + FT_FRAME_END + }; + static + const FT_Frame_Field pcf_accel_msb_header[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PCF_AccelRec + FT_FRAME_START( 20 ), + FT_FRAME_BYTE ( noOverlap ), + FT_FRAME_BYTE ( constantMetrics ), + FT_FRAME_BYTE ( terminalFont ), + FT_FRAME_BYTE ( constantWidth ), + FT_FRAME_BYTE ( inkInside ), + FT_FRAME_BYTE ( inkMetrics ), + FT_FRAME_BYTE ( drawDirection ), + FT_FRAME_SKIP_BYTES( 1 ), + FT_FRAME_LONG ( fontAscent ), + FT_FRAME_LONG ( fontDescent ), + FT_FRAME_LONG ( maxOverlap ), + FT_FRAME_END + }; + static FT_Error + pcf_get_accel( FT_Stream stream, + PCF_Face face, + FT_ULong type ) + { + FT_ULong format, size; + FT_Error error = PCF_Err_Ok; + PCF_Accel accel = &face->accel; + error = pcf_seek_to_table_type( stream, + face->toc.tables, + face->toc.count, + type, + &format, + &size ); + if ( error ) + goto Bail; + if ( FT_READ_ULONG_LE( format ) ) + goto Bail; + if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && + !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + goto Bail; + if ( PCF_BYTE_ORDER( format ) == MSBFirst ) + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) + goto Bail; + } + else + { + if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) + goto Bail; + } + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->minbounds) ); + if ( error ) + goto Bail; + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->maxbounds) ); + if ( error ) + goto Bail; + if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) + { + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_minbounds) ); + if ( error ) + goto Bail; + error = pcf_get_metric( stream, + format & ( ~PCF_FORMAT_MASK ), + &(accel->ink_maxbounds) ); + if ( error ) + goto Bail; + } + else + { +/* I'm not sure about this */ + accel->ink_minbounds = accel->minbounds; + accel->ink_maxbounds = accel->maxbounds; + } + Bail: + return error; + } + static FT_Error + pcf_interpret_style( PCF_Face pcf ) + { + FT_Error error = PCF_Err_Ok; + FT_Face face = FT_FACE( pcf ); + FT_Memory memory = face->memory; + PCF_Property prop; + size_t nn, len; + char* strings[4] = { NULL, NULL, NULL, NULL }; + size_t lengths[4]; + face->style_flags = 0; + prop = pcf_find_property( pcf, "SLANT" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || + *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) + { + face->style_flags |= FT_STYLE_FLAG_ITALIC; + strings[2] = ( *(prop->value.atom) == 'O' || + *(prop->value.atom) == 'o' ) ? (char *)"Oblique" + : (char *)"Italic"; + } + prop = pcf_find_property( pcf, "WEIGHT_NAME" ); + if ( prop && prop->isString && + ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) + { + face->style_flags |= FT_STYLE_FLAG_BOLD; + strings[1] = (char *)"Bold"; + } + prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[3] = (char *)(prop->value.atom); + prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); + if ( prop && prop->isString && + *(prop->value.atom) && + !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) + strings[0] = (char *)(prop->value.atom); + for ( len = 0, nn = 0; nn < 4; nn++ ) + { + lengths[nn] = 0; + if ( strings[nn] ) + { + lengths[nn] = ft_strlen( strings[nn] ); + len += lengths[nn] + 1; + } + } + if ( len == 0 ) + { + strings[0] = (char *)"Regular"; + lengths[0] = ft_strlen( strings[0] ); + len = lengths[0] + 1; + } + { + char* s; + if ( FT_ALLOC( face->style_name, len ) ) + return error; + s = face->style_name; + for ( nn = 0; nn < 4; nn++ ) + { + char* src = strings[nn]; + len = lengths[nn]; + if ( src == NULL ) + continue; +/* separate elements with a space */ + if ( s != face->style_name ) + *s++ = ' '; + ft_memcpy( s, src, len ); +/* need to convert spaces to dashes for */ +/* add_style_name and setwidth_name */ + if ( nn == 0 || nn == 3 ) + { + size_t mm; + for ( mm = 0; mm < len; mm++ ) + if (s[mm] == ' ') + s[mm] = '-'; + } + s += len; + } + *s = 0; + } + return error; + } + FT_LOCAL_DEF( FT_Error ) + pcf_load_font( FT_Stream stream, + PCF_Face face ) + { + FT_Error error = PCF_Err_Ok; + FT_Memory memory = FT_FACE(face)->memory; + FT_Bool hasBDFAccelerators; + error = pcf_read_TOC( stream, face ); + if ( error ) + goto Exit; + error = pcf_get_properties( stream, face ); + if ( error ) + goto Exit; +/* Use the old accelerators if no BDF accelerators are in the file. */ + hasBDFAccelerators = pcf_has_table_type( face->toc.tables, + face->toc.count, + PCF_BDF_ACCELERATORS ); + if ( !hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); + if ( error ) + goto Exit; + } +/* metrics */ + error = pcf_get_metrics( stream, face ); + if ( error ) + goto Exit; +/* bitmaps */ + error = pcf_get_bitmaps( stream, face ); + if ( error ) + goto Exit; +/* encodings */ + error = pcf_get_encodings( stream, face ); + if ( error ) + goto Exit; +/* BDF style accelerators (i.e. bounds based on encoded glyphs) */ + if ( hasBDFAccelerators ) + { + error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); + if ( error ) + goto Exit; + } +/* XXX: TO DO: inkmetrics and glyph_names are missing */ +/* now construct the face object */ + { + FT_Face root = FT_FACE( face ); + PCF_Property prop; + root->num_faces = 1; + root->face_index = 0; + root->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_FAST_GLYPHS; + if ( face->accel.constantWidth ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + if ( ( error = pcf_interpret_style( face ) ) != 0 ) + goto Exit; + prop = pcf_find_property( face, "FAMILY_NAME" ); + if ( prop && prop->isString ) + { + if ( FT_STRDUP( root->family_name, prop->value.atom ) ) + goto Exit; + } + else + root->family_name = NULL; +/* + * Note: We shift all glyph indices by +1 since we must + * respect the convention that glyph 0 always corresponds + * to the `missing glyph'. + * + * This implies bumping the number of `available' glyphs by 1. + */ + root->num_glyphs = face->nmetrics + 1; + root->num_fixed_sizes = 1; + if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) + goto Exit; + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_Short resolution_x = 0, resolution_y = 0; + FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); +#if 0 + bsize->height = face->accel.maxbounds.ascent << 6; +#endif + bsize->height = (FT_Short)( face->accel.fontAscent + + face->accel.fontDescent ); + prop = pcf_find_property( face, "AVERAGE_WIDTH" ); + if ( prop ) + bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 ); + else + bsize->width = (FT_Short)( bsize->height * 2/3 ); + prop = pcf_find_property( face, "POINT_SIZE" ); + if ( prop ) +/* convert from 722.7 decipoints to 72 points per inch */ + bsize->size = + (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L ); + prop = pcf_find_property( face, "PIXEL_SIZE" ); + if ( prop ) + bsize->y_ppem = (FT_Short)prop->value.l << 6; + prop = pcf_find_property( face, "RESOLUTION_X" ); + if ( prop ) + resolution_x = (FT_Short)prop->value.l; + prop = pcf_find_property( face, "RESOLUTION_Y" ); + if ( prop ) + resolution_y = (FT_Short)prop->value.l; + if ( bsize->y_ppem == 0 ) + { + bsize->y_ppem = bsize->size; + if ( resolution_y ) + bsize->y_ppem = bsize->y_ppem * resolution_y / 72; + } + if ( resolution_x && resolution_y ) + bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; + else + bsize->x_ppem = bsize->y_ppem; + } +/* set up charset */ + { + PCF_Property charset_registry = 0, charset_encoding = 0; + charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); + charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); + if ( charset_registry && charset_registry->isString && + charset_encoding && charset_encoding->isString ) + { + if ( FT_STRDUP( face->charset_encoding, + charset_encoding->value.atom ) || + FT_STRDUP( face->charset_registry, + charset_registry->value.atom ) ) + goto Exit; + } + } + } + Exit: + if ( error ) + { +/* This is done to respect the behaviour of the original */ +/* PCF font driver. */ + error = PCF_Err_Invalid_File_Format; + } + return error; + } +/* END */ +/* pcfdrivr.c + + FreeType font driver for pcf files + + Copyright (C) 2000-2004, 2006-2011 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. +*/ +/***************************************************************************/ +/* */ +/* ftgzip.h */ +/* */ +/* Gzip-compressed stream support. */ +/* */ +/* Copyright 2002, 2003, 2004, 2006 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. */ +/* */ +/***************************************************************************/ +#define __FTGZIP_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* gzip */ +/* */ +/* <Title> */ +/* GZIP Streams */ +/* */ +/* <Abstract> */ +/* Using gzip-compressed font files. */ +/* */ +/* <Description> */ +/* This section contains the declaration of Gzip-specific functions. */ +/* */ +/*************************************************************************/ +/************************************************************************ + * + * @function: + * FT_Stream_OpenGzip + * + * @description: + * Open a new stream to parse gzip-compressed font files. This is + * mainly used to support the compressed `*.pcf.gz' fonts that come + * with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream. + * + * In certain builds of the library, gzip compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a gzipped stream from + * it and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with zlib support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenGzip( FT_Stream stream, + FT_Stream source ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftlzw.h */ +/* */ +/* LZW-compressed stream support. */ +/* */ +/* Copyright 2004, 2006 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. */ +/* */ +/***************************************************************************/ +#define __FTLZW_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* lzw */ +/* */ +/* <Title> */ +/* LZW Streams */ +/* */ +/* <Abstract> */ +/* Using LZW-compressed font files. */ +/* */ +/* <Description> */ +/* This section contains the declaration of LZW-specific functions. */ +/* */ +/*************************************************************************/ +/************************************************************************ + * + * @function: + * FT_Stream_OpenLZW + * + * @description: + * Open a new stream to parse LZW-compressed font files. This is + * mainly used to support the compressed `*.pcf.Z' fonts that come + * with XFree86. + * + * @input: + * stream :: The target embedding stream. + * + * source :: The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream + * + * In certain builds of the library, LZW compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a LZW stream from it + * and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with LZW support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenLZW( FT_Stream stream, + FT_Stream source ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftbzip2.h */ +/* */ +/* Bzip2-compressed stream support. */ +/* */ +/* Copyright 2010 by */ +/* Joel Klinghed. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __FTBZIP2_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 +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Section> */ +/* bzip2 */ +/* */ +/* <Title> */ +/* BZIP2 Streams */ +/* */ +/* <Abstract> */ +/* Using bzip2-compressed font files. */ +/* */ +/* <Description> */ +/* This section contains the declaration of Bzip2-specific functions. */ +/* */ +/*************************************************************************/ +/************************************************************************ + * + * @function: + * FT_Stream_OpenBzip2 + * + * @description: + * Open a new stream to parse bzip2-compressed font files. This is + * mainly used to support the compressed `*.pcf.bz2' fonts that come + * with XFree86. + * + * @input: + * stream :: + * The target embedding stream. + * + * source :: + * The source stream. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The source stream must be opened _before_ calling this function. + * + * Calling the internal function `FT_Stream_Close' on the new stream will + * *not* call `FT_Stream_Close' on the source stream. None of the stream + * objects will be released to the heap. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream. + * + * In certain builds of the library, bzip2 compression recognition is + * automatically handled when calling @FT_New_Face or @FT_Open_Face. + * This means that if no font driver is capable of handling the raw + * compressed file, the library will try to open a bzip2 compressed stream + * from it and re-open the face with it. + * + * This function may return `FT_Err_Unimplemented_Feature' if your build + * of FreeType was not compiled with bzip2 support. + */ + FT_EXPORT( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* pcfdrivr.h + + FreeType font driver for pcf fonts + + Copyright 2000-2001, 2002 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. +*/ +#define __PCFDRIVR_H__ +FT_BEGIN_HEADER + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class; +FT_END_HEADER +/* END */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_pcfread +/*************************************************************************/ +/* */ +/* 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 trace_pcfdriver + typedef struct PCF_CMapRec_ + { + FT_CMapRec root; + FT_UInt num_encodings; + PCF_Encoding encodings; + } PCF_CMapRec, *PCF_CMap; + FT_CALLBACK_DEF( FT_Error ) +/* PCF_CMap */ + pcf_cmap_init( FT_CMap pcfcmap, + FT_Pointer init_data ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_Face face = (PCF_Face)FT_CMAP_FACE( pcfcmap ); + FT_UNUSED( init_data ); + cmap->num_encodings = (FT_UInt)face->nencodings; + cmap->encodings = face->encodings; + return PCF_Err_Ok; + } + FT_CALLBACK_DEF( void ) +/* PCF_CMap */ + pcf_cmap_done( FT_CMap pcfcmap ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + cmap->encodings = NULL; + cmap->num_encodings = 0; + } + FT_CALLBACK_DEF( FT_UInt ) +/* PCF_CMap */ + pcf_cmap_char_index( FT_CMap pcfcmap, + FT_UInt32 charcode ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_Encoding encodings = cmap->encodings; + FT_UInt min, max, mid; + FT_UInt result = 0; + min = 0; + max = cmap->num_encodings; + while ( min < max ) + { + FT_ULong code; + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + if ( charcode == code ) + { + result = encodings[mid].glyph + 1; + break; + } + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + return result; + } + FT_CALLBACK_DEF( FT_UInt ) +/* PCF_CMap */ + pcf_cmap_char_next( FT_CMap pcfcmap, + FT_UInt32 *acharcode ) + { + PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_Encoding encodings = cmap->encodings; + FT_UInt min, max, mid; + FT_ULong charcode = *acharcode + 1; + FT_UInt result = 0; + min = 0; + max = cmap->num_encodings; + while ( min < max ) + { + FT_ULong code; + mid = ( min + max ) >> 1; + code = encodings[mid].enc; + if ( charcode == code ) + { + result = encodings[mid].glyph + 1; + goto Exit; + } + if ( charcode < code ) + max = mid; + else + min = mid + 1; + } + charcode = 0; + if ( min < cmap->num_encodings ) + { + charcode = encodings[min].enc; + result = encodings[min].glyph + 1; + } + Exit: + if ( charcode > 0xFFFFFFFFUL ) + { + FT_TRACE1(( "pcf_cmap_char_next: charcode 0x%x > 32bit API" )); + *acharcode = 0; +/* XXX: result should be changed to indicate an overflow error */ + } + else + *acharcode = (FT_UInt32)charcode; + return result; + } + FT_CALLBACK_TABLE_DEF + const FT_CMap_ClassRec pcf_cmap_class = + { + sizeof ( PCF_CMapRec ), + pcf_cmap_init, + pcf_cmap_done, + pcf_cmap_char_index, + pcf_cmap_char_next, + NULL, NULL, NULL, NULL, NULL + }; + FT_CALLBACK_DEF( void ) +/* PCF_Face */ + PCF_Face_Done( FT_Face pcfface ) + { + PCF_Face face = (PCF_Face)pcfface; + FT_Memory memory; + if ( !face ) + return; + memory = FT_FACE_MEMORY( face ); + FT_FREE( face->encodings ); + FT_FREE( face->metrics ); +/* free properties */ + { + PCF_Property prop; + FT_Int i; + if ( face->properties ) + { + for ( i = 0; i < face->nprops; i++ ) + { + prop = &face->properties[i]; + if ( prop ) + { + FT_FREE( prop->name ); + if ( prop->isString ) + FT_FREE( prop->value.atom ); + } + } + } + FT_FREE( face->properties ); + } + FT_FREE( face->toc.tables ); + FT_FREE( pcfface->family_name ); + FT_FREE( pcfface->style_name ); + FT_FREE( pcfface->available_sizes ); + FT_FREE( face->charset_encoding ); + FT_FREE( face->charset_registry ); +/* close compressed stream if any */ + if ( pcfface->stream == &face->comp_stream ) + { + FT_Stream_Close( &face->comp_stream ); + pcfface->stream = face->comp_source; + } + } + FT_CALLBACK_DEF( FT_Error ) + PCF_Face_Init( FT_Stream stream, +/* PCF_Face */ + FT_Face pcfface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PCF_Face face = (PCF_Face)pcfface; + FT_Error error = PCF_Err_Ok; + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_TRACE2(( "PCF driver\n" )); + error = pcf_load_font( stream, face ); + if ( error ) + { + PCF_Face_Done( pcfface ); +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_LZW ) || \ + defined( FT_CONFIG_OPTION_USE_BZIP2 ) + if ( error ) + goto Fail; + face->comp_source = stream; + pcfface->stream = &face->comp_stream; + stream = pcfface->stream; + error = pcf_load_font( stream, face ); + if ( error ) + goto Fail; +/* !(FT_CONFIG_OPTION_USE_ZLIB || + FT_CONFIG_OPTION_USE_LZW || + FT_CONFIG_OPTION_USE_BZIP2) */ +#else + goto Fail; +#endif + } +/* set up charmap */ + { + FT_String *charset_registry = face->charset_registry; + FT_String *charset_encoding = face->charset_encoding; + FT_Bool unicode_charmap = 0; + if ( charset_registry && charset_encoding ) + { + char* s = charset_registry; +/* Uh, oh, compare first letters manually to avoid dependency + on locales. */ + if ( ( s[0] == 'i' || s[0] == 'I' ) && + ( s[1] == 's' || s[1] == 'S' ) && + ( s[2] == 'o' || s[2] == 'O' ) ) + { + s += 3; + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( face->charset_encoding, "1" ) ) ) + unicode_charmap = 1; + } + } + { + FT_CharMapRec charmap; + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; +/* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + if ( unicode_charmap ) + { + charmap.encoding = FT_ENCODING_UNICODE; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + } + error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL ); +#if 0 +/* Select default charmap */ + if ( pcfface->num_charmaps ) + pcfface->charmap = pcfface->charmaps[0]; +#endif + } + } + Exit: + return error; + Fail: + FT_TRACE2(( " not a PCF file\n" )); + PCF_Face_Done( pcfface ); +/* error */ + error = PCF_Err_Unknown_File_Format; + goto Exit; + } + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + PCF_Accel accel = &( (PCF_Face)size->face )->accel; + FT_Select_Metrics( size->face, strike_index ); + size->metrics.ascender = accel->fontAscent << 6; + size->metrics.descender = -accel->fontDescent << 6; + size->metrics.max_advance = accel->maxbounds.characterWidth << 6; + return PCF_Err_Ok; + } + FT_CALLBACK_DEF( FT_Error ) + PCF_Size_Request( FT_Size size, + FT_Size_Request req ) + { + PCF_Face face = (PCF_Face)size->face; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = PCF_Err_Invalid_Pixel_Size; + FT_Long height; + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = PCF_Err_Ok; + break; + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == ( face->accel.fontAscent + + face->accel.fontDescent ) ) + error = PCF_Err_Ok; + break; + default: + error = PCF_Err_Unimplemented_Feature; + break; + } + if ( error ) + return error; + else + return PCF_Size_Select( size, 0 ); + } + FT_CALLBACK_DEF( FT_Error ) + PCF_Glyph_Load( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); + FT_Stream stream; + FT_Error error = PCF_Err_Ok; + FT_Bitmap* bitmap = &slot->bitmap; + PCF_Metric metric; + FT_Offset bytes; + FT_UNUSED( load_flags ); + FT_TRACE4(( "load_glyph %d ---", glyph_index )); + if ( !face || glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = PCF_Err_Invalid_Argument; + goto Exit; + } + stream = face->root.stream; + if ( glyph_index > 0 ) + glyph_index--; + metric = face->metrics + glyph_index; + bitmap->rows = metric->ascent + metric->descent; + bitmap->width = metric->rightSideBearing - metric->leftSideBearing; + bitmap->num_grays = 1; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n", + PCF_BIT_ORDER( face->bitmapsFormat ), + PCF_BYTE_ORDER( face->bitmapsFormat ), + PCF_GLYPH_PAD( face->bitmapsFormat ) )); + switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) ) + { + case 1: + bitmap->pitch = ( bitmap->width + 7 ) >> 3; + break; + case 2: + bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1; + break; + case 4: + bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2; + break; + case 8: + bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3; + break; + default: + return PCF_Err_Invalid_File_Format; + } +/* XXX: to do: are there cases that need repadding the bitmap? */ + bytes = bitmap->pitch * bitmap->rows; + error = ft_glyphslot_alloc_bitmap( slot, bytes ); + if ( error ) + goto Exit; + if ( FT_STREAM_SEEK( metric->bits ) || + FT_STREAM_READ( bitmap->buffer, bytes ) ) + goto Exit; + if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst ) + BitOrderInvert( bitmap->buffer, bytes ); + if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) != + PCF_BIT_ORDER( face->bitmapsFormat ) ) ) + { + switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) ) + { + case 1: + break; + case 2: + TwoByteSwap( bitmap->buffer, bytes ); + break; + case 4: + FourByteSwap( bitmap->buffer, bytes ); + break; + } + } + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = metric->leftSideBearing; + slot->bitmap_top = metric->ascent; + slot->metrics.horiAdvance = metric->characterWidth << 6; + slot->metrics.horiBearingX = metric->leftSideBearing << 6; + slot->metrics.horiBearingY = metric->ascent << 6; + slot->metrics.width = ( metric->rightSideBearing - + metric->leftSideBearing ) << 6; + slot->metrics.height = bitmap->rows << 6; + ft_synthesize_vertical_metrics( &slot->metrics, + ( face->accel.fontAscent + + face->accel.fontDescent ) << 6 ); + FT_TRACE4(( " --- ok\n" )); + Exit: + return error; + } +/* + * + * BDF SERVICE + * + */ + static FT_Error + pcf_get_bdf_property( PCF_Face face, + const char* prop_name, + BDF_PropertyRec *aproperty ) + { + PCF_Property prop; + prop = pcf_find_property( face, prop_name ); + if ( prop != NULL ) + { + if ( prop->isString ) + { + aproperty->type = BDF_PROPERTY_TYPE_ATOM; + aproperty->u.atom = prop->value.atom; + } + else + { + if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) + { + FT_TRACE1(( "pcf_get_bdf_property: " )); + FT_TRACE1(( "too large integer 0x%x is truncated\n" )); + } +/* Apparently, the PCF driver loads all properties as signed integers! + * This really doesn't seem to be a problem, because this is + * sufficient for any meaningful values. + */ + aproperty->type = BDF_PROPERTY_TYPE_INTEGER; + aproperty->u.integer = (FT_Int32)prop->value.l; + } + return 0; + } + return PCF_Err_Invalid_Argument; + } + static FT_Error + pcf_get_charset_id( PCF_Face face, + const char* *acharset_encoding, + const char* *acharset_registry ) + { + *acharset_encoding = face->charset_encoding; + *acharset_registry = face->charset_registry; + return 0; + } + static const FT_Service_BDFRec pcf_service_bdf = + { + (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id, + (FT_BDF_GetPropertyFunc) pcf_get_bdf_property + }; +/* + * + * SERVICE LIST + * + */ + static const FT_ServiceDescRec pcf_services[] = + { + { FT_SERVICE_ID_BDF, &pcf_service_bdf }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_PCF }, + { NULL, NULL } + }; + FT_CALLBACK_DEF( FT_Module_Interface ) + pcf_driver_requester( FT_Module module, + const char* name ) + { + FT_UNUSED( module ); + return ft_service_list_lookup( pcf_services, name ); + } + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pcf_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + "pcf", + 0x10000L, + 0x20000L, + 0, +/* FT_Module_Constructor */ + 0, +/* FT_Module_Destructor */ + 0, + pcf_driver_requester + }, + sizeof ( PCF_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + PCF_Face_Init, + PCF_Face_Done, +/* FT_Size_InitFunc */ + 0, +/* FT_Size_DoneFunc */ + 0, +/* FT_Slot_InitFunc */ + 0, +/* FT_Slot_DoneFunc */ + 0, + PCF_Glyph_Load, +/* FT_Face_GetKerningFunc */ + 0, +/* FT_Face_AttachFunc */ + 0, +/* FT_Face_GetAdvancesFunc */ + 0, + PCF_Size_Request, + PCF_Size_Select + }; +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* pfr.c */ +/* */ +/* FreeType PFR driver component. */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* pfrload.c */ +/* */ +/* FreeType PFR loader (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005, 2007, 2009, 2010 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pfrload.h */ +/* */ +/* FreeType PFR loader (specification). */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define __PFRLOAD_H__ +/***************************************************************************/ +/* */ +/* pfrobjs.h */ +/* */ +/* FreeType PFR object methods (specification). */ +/* */ +/* Copyright 2002, 2003, 2004 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. */ +/* */ +/***************************************************************************/ +#define __PFROBJS_H__ +/***************************************************************************/ +/* */ +/* pfrtypes.h */ +/* */ +/* FreeType PFR data structures (specification only). */ +/* */ +/* Copyright 2002, 2003, 2005, 2007 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. */ +/* */ +/***************************************************************************/ +#define __PFRTYPES_H__ +FT_BEGIN_HEADER +/************************************************************************/ +/* the PFR Header structure */ + typedef struct PFR_HeaderRec_ + { + FT_UInt32 signature; + FT_UInt version; + FT_UInt signature2; + FT_UInt header_size; + FT_UInt log_dir_size; + FT_UInt log_dir_offset; + FT_UInt log_font_max_size; + FT_UInt32 log_font_section_size; + FT_UInt32 log_font_section_offset; + FT_UInt32 phy_font_max_size; + FT_UInt32 phy_font_section_size; + FT_UInt32 phy_font_section_offset; + FT_UInt gps_max_size; + FT_UInt32 gps_section_size; + FT_UInt32 gps_section_offset; + FT_UInt max_blue_values; + FT_UInt max_x_orus; + FT_UInt max_y_orus; + FT_UInt phy_font_max_size_high; + FT_UInt color_flags; + FT_UInt32 bct_max_size; + FT_UInt32 bct_set_max_size; + FT_UInt32 phy_bct_set_max_size; + FT_UInt num_phy_fonts; + FT_UInt max_vert_stem_snap; + FT_UInt max_horz_stem_snap; + FT_UInt max_chars; + } PFR_HeaderRec, *PFR_Header; +/* used in `color_flags' field of the PFR_Header */ + typedef enum PFR_HeaderFlags_ + { + PFR_FLAG_BLACK_PIXEL = 1, + PFR_FLAG_INVERT_BITMAP = 2 + } PFR_HeaderFlags; +/************************************************************************/ + typedef struct PFR_LogFontRec_ + { + FT_UInt32 size; + FT_UInt32 offset; + FT_Int32 matrix[4]; + FT_UInt stroke_flags; + FT_Int stroke_thickness; + FT_Int bold_thickness; + FT_Int32 miter_limit; + FT_UInt32 phys_size; + FT_UInt32 phys_offset; + } PFR_LogFontRec, *PFR_LogFont; + typedef enum PFR_LogFlags_ + { + PFR_LOG_EXTRA_ITEMS = 0x40, + PFR_LOG_2BYTE_BOLD = 0x20, + PFR_LOG_BOLD = 0x10, + PFR_LOG_2BYTE_STROKE = 8, + PFR_LOG_STROKE = 4, + PFR_LINE_JOIN_MASK = 3 + } PFR_LogFlags; + typedef enum PFR_LineJoinFlags_ + { + PFR_LINE_JOIN_MITER = 0, + PFR_LINE_JOIN_ROUND = 1, + PFR_LINE_JOIN_BEVEL = 2 + } PFR_LineJoinFlags; +/************************************************************************/ + typedef enum PFR_BitmapFlags_ + { + PFR_BITMAP_3BYTE_OFFSET = 4, + PFR_BITMAP_2BYTE_SIZE = 2, + PFR_BITMAP_2BYTE_CHARCODE = 1 + } PFR_BitmapFlags; + typedef struct PFR_BitmapCharRec_ + { + FT_UInt char_code; + FT_UInt gps_size; + FT_UInt32 gps_offset; + } PFR_BitmapCharRec, *PFR_BitmapChar; + typedef enum PFR_StrikeFlags_ + { + PFR_STRIKE_2BYTE_COUNT = 0x10, + PFR_STRIKE_3BYTE_OFFSET = 0x08, + PFR_STRIKE_3BYTE_SIZE = 0x04, + PFR_STRIKE_2BYTE_YPPM = 0x02, + PFR_STRIKE_2BYTE_XPPM = 0x01 + } PFR_StrikeFlags; + typedef struct PFR_StrikeRec_ + { + FT_UInt x_ppm; + FT_UInt y_ppm; + FT_UInt flags; + FT_UInt32 gps_size; + FT_UInt32 gps_offset; + FT_UInt32 bct_size; + FT_UInt32 bct_offset; +/* optional */ + FT_UInt num_bitmaps; + PFR_BitmapChar bitmaps; + } PFR_StrikeRec, *PFR_Strike; +/************************************************************************/ + typedef struct PFR_CharRec_ + { + FT_UInt char_code; + FT_Int advance; + FT_UInt gps_size; + FT_UInt32 gps_offset; + } PFR_CharRec, *PFR_Char; +/************************************************************************/ + typedef struct PFR_DimensionRec_ + { + FT_UInt standard; + FT_UInt num_stem_snaps; + FT_Int* stem_snaps; + } PFR_DimensionRec, *PFR_Dimension; +/************************************************************************/ + typedef struct PFR_KernItemRec_* PFR_KernItem; + typedef struct PFR_KernItemRec_ + { + PFR_KernItem next; + FT_Byte pair_count; + FT_Byte flags; + FT_Short base_adj; + FT_UInt pair_size; + FT_Offset offset; + FT_UInt32 pair1; + FT_UInt32 pair2; + } PFR_KernItemRec; +#define PFR_KERN_INDEX( g1, g2 ) \ + ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) ) +#define PFR_KERN_PAIR_INDEX( pair ) \ + PFR_KERN_INDEX( (pair)->glyph1, (pair)->glyph2 ) +#define PFR_NEXT_KPAIR( p ) ( p += 2, \ + ( (FT_UInt32)p[-2] << 16 ) | p[-1] ) +/************************************************************************/ + typedef struct PFR_PhyFontRec_ + { + FT_Memory memory; + FT_UInt32 offset; + FT_UInt font_ref_number; + FT_UInt outline_resolution; + FT_UInt metrics_resolution; + FT_BBox bbox; + FT_UInt flags; + FT_UInt standard_advance; +/* optional, bbox.yMax if not present */ + FT_Int ascent; +/* optional, bbox.yMin if not present */ + FT_Int descent; +/* optional, 0 if not present */ + FT_Int leading; + PFR_DimensionRec horizontal; + PFR_DimensionRec vertical; + FT_String* font_id; + FT_String* family_name; + FT_String* style_name; + FT_UInt num_strikes; + FT_UInt max_strikes; + PFR_StrikeRec* strikes; + FT_UInt num_blue_values; + FT_Int *blue_values; + FT_UInt blue_fuzz; + FT_UInt blue_scale; + FT_UInt num_chars; + FT_Offset chars_offset; + PFR_Char chars; + FT_UInt num_kern_pairs; + PFR_KernItem kern_items; + PFR_KernItem* kern_items_tail; +/* not part of the spec, but used during load */ + FT_Long bct_offset; + FT_Byte* cursor; + } PFR_PhyFontRec, *PFR_PhyFont; + typedef enum PFR_PhyFlags_ + { + PFR_PHY_EXTRA_ITEMS = 0x80, + PFR_PHY_3BYTE_GPS_OFFSET = 0x20, + PFR_PHY_2BYTE_GPS_SIZE = 0x10, + PFR_PHY_ASCII_CODE = 0x08, + PFR_PHY_PROPORTIONAL = 0x04, + PFR_PHY_2BYTE_CHARCODE = 0x02, + PFR_PHY_VERTICAL = 0x01 + } PFR_PhyFlags; + typedef enum PFR_KernFlags_ + { + PFR_KERN_2BYTE_CHAR = 0x01, + PFR_KERN_2BYTE_ADJ = 0x02 + } PFR_KernFlags; +/************************************************************************/ + typedef enum PFR_GlyphFlags_ + { + PFR_GLYPH_IS_COMPOUND = 0x80, + PFR_GLYPH_EXTRA_ITEMS = 0x08, + PFR_GLYPH_1BYTE_XYCOUNT = 0x04, + PFR_GLYPH_XCOUNT = 0x02, + PFR_GLYPH_YCOUNT = 0x01 + } PFR_GlyphFlags; +/* controlled coordinate */ + typedef struct PFR_CoordRec_ + { + FT_UInt org; + FT_UInt cur; + } PFR_CoordRec, *PFR_Coord; + typedef struct PFR_SubGlyphRec_ + { + FT_Fixed x_scale; + FT_Fixed y_scale; + FT_Int x_delta; + FT_Int y_delta; + FT_UInt32 gps_offset; + FT_UInt gps_size; + } PFR_SubGlyphRec, *PFR_SubGlyph; + typedef enum PFR_SubgGlyphFlags_ + { + PFR_SUBGLYPH_3BYTE_OFFSET = 0x80, + PFR_SUBGLYPH_2BYTE_SIZE = 0x40, + PFR_SUBGLYPH_YSCALE = 0x20, + PFR_SUBGLYPH_XSCALE = 0x10 + } PFR_SubGlyphFlags; + typedef struct PFR_GlyphRec_ + { + FT_Byte format; +#if 0 + FT_UInt num_x_control; + FT_UInt num_y_control; +#endif + FT_UInt max_xy_control; + FT_Pos* x_control; + FT_Pos* y_control; + FT_UInt num_subs; + FT_UInt max_subs; + PFR_SubGlyphRec* subs; + FT_GlyphLoader loader; + FT_Bool path_begun; + } PFR_GlyphRec, *PFR_Glyph; +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER + typedef struct PFR_FaceRec_* PFR_Face; + typedef struct PFR_SizeRec_* PFR_Size; + typedef struct PFR_SlotRec_* PFR_Slot; + typedef struct PFR_FaceRec_ + { + FT_FaceRec root; + PFR_HeaderRec header; + PFR_LogFontRec log_font; + PFR_PhyFontRec phy_font; + } PFR_FaceRec; + typedef struct PFR_SizeRec_ + { + FT_SizeRec root; + } PFR_SizeRec; + typedef struct PFR_SlotRec_ + { + FT_GlyphSlotRec root; + PFR_GlyphRec glyph; + } PFR_SlotRec; + FT_LOCAL( FT_Error ) + pfr_face_init( FT_Stream stream, +/* PFR_Face */ + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) +/* PFR_Face */ + pfr_face_done( FT_Face face ); + FT_LOCAL( FT_Error ) +/* PFR_Face */ + pfr_face_get_kerning( FT_Face face, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + FT_LOCAL( FT_Error ) +/* PFR_Slot */ + pfr_slot_init( FT_GlyphSlot slot ); + FT_LOCAL( void ) +/* PFR_Slot */ + pfr_slot_done( FT_GlyphSlot slot ); + FT_LOCAL( FT_Error ) +/* PFR_Slot */ + pfr_slot_load( FT_GlyphSlot slot, +/* PFR_Size */ + FT_Size size, + FT_UInt gindex, + FT_Int32 load_flags ); +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +#ifdef PFR_CONFIG_NO_CHECKS +#define PFR_CHECK( x ) do { } while ( 0 ) +#else +#define PFR_CHECK( x ) do \ + { \ + if ( p + (x) > limit ) \ + goto Too_Short; \ + } while ( 0 ) +#endif +#define PFR_NEXT_BYTE( p ) FT_NEXT_BYTE( p ) +#define PFR_NEXT_INT8( p ) FT_NEXT_CHAR( p ) +#define PFR_NEXT_SHORT( p ) FT_NEXT_SHORT( p ) +#define PFR_NEXT_USHORT( p ) FT_NEXT_USHORT( p ) +#define PFR_NEXT_LONG( p ) FT_NEXT_OFF3( p ) +#define PFR_NEXT_ULONG( p ) FT_NEXT_UOFF3( p ) +/* handling extra items */ + typedef FT_Error + (*PFR_ExtraItem_ParseFunc)( FT_Byte* p, + FT_Byte* limit, + FT_Pointer data ); + typedef struct PFR_ExtraItemRec_ + { + FT_UInt type; + PFR_ExtraItem_ParseFunc parser; + } PFR_ExtraItemRec; + typedef const struct PFR_ExtraItemRec_* PFR_ExtraItem; + FT_LOCAL( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ); + FT_LOCAL( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ); +/* load a PFR header */ + FT_LOCAL( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ); +/* check a PFR header */ + FT_LOCAL( FT_Bool ) + pfr_header_check( PFR_Header header ); +/* return number of logical fonts in this file */ + FT_LOCAL( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 log_section_offset, + FT_UInt *acount ); +/* load a pfr logical font entry */ + FT_LOCAL( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt face_index, + FT_UInt32 section_offset, + FT_Bool size_increment ); +/* load a physical font entry */ + FT_LOCAL( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ); +/* finalize a physical font */ + FT_LOCAL( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* pfrerror.h */ +/* */ +/* PFR error codes (specification only). */ +/* */ +/* Copyright 2002, 2012 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 PFR error enumeration constants. */ +/* */ +/*************************************************************************/ +#define __PFRERROR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX PFR_Err_ +#define FT_ERR_BASE FT_Mod_Err_PFR +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_pfr +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** EXTRA ITEMS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_skip( FT_Byte* *pp, + FT_Byte* limit ) + { + return pfr_extra_items_parse( pp, limit, NULL, NULL ); + } + FT_LOCAL_DEF( FT_Error ) + pfr_extra_items_parse( FT_Byte* *pp, + FT_Byte* limit, + PFR_ExtraItem item_list, + FT_Pointer item_data ) + { + FT_Error error = PFR_Err_Ok; + FT_Byte* p = *pp; + FT_UInt num_items, item_type, item_size; + PFR_CHECK( 1 ); + num_items = PFR_NEXT_BYTE( p ); + for ( ; num_items > 0; num_items-- ) + { + PFR_CHECK( 2 ); + item_size = PFR_NEXT_BYTE( p ); + item_type = PFR_NEXT_BYTE( p ); + PFR_CHECK( item_size ); + if ( item_list ) + { + PFR_ExtraItem extra = item_list; + for ( extra = item_list; extra->parser != NULL; extra++ ) + { + if ( extra->type == item_type ) + { + error = extra->parser( p, p + item_size, item_data ); + if ( error ) goto Exit; + break; + } + } + } + p += item_size; + } + Exit: + *pp = p; + return error; + Too_Short: + FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" )); + error = PFR_Err_Invalid_Table; + goto Exit; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PFR HEADER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static const FT_Frame_Field pfr_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE PFR_HeaderRec + FT_FRAME_START( 58 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_USHORT( version ), + FT_FRAME_USHORT( signature2 ), + FT_FRAME_USHORT( header_size ), + FT_FRAME_USHORT( log_dir_size ), + FT_FRAME_USHORT( log_dir_offset ), + FT_FRAME_USHORT( log_font_max_size ), + FT_FRAME_UOFF3 ( log_font_section_size ), + FT_FRAME_UOFF3 ( log_font_section_offset ), + FT_FRAME_USHORT( phy_font_max_size ), + FT_FRAME_UOFF3 ( phy_font_section_size ), + FT_FRAME_UOFF3 ( phy_font_section_offset ), + FT_FRAME_USHORT( gps_max_size ), + FT_FRAME_UOFF3 ( gps_section_size ), + FT_FRAME_UOFF3 ( gps_section_offset ), + FT_FRAME_BYTE ( max_blue_values ), + FT_FRAME_BYTE ( max_x_orus ), + FT_FRAME_BYTE ( max_y_orus ), + FT_FRAME_BYTE ( phy_font_max_size_high ), + FT_FRAME_BYTE ( color_flags ), + FT_FRAME_UOFF3 ( bct_max_size ), + FT_FRAME_UOFF3 ( bct_set_max_size ), + FT_FRAME_UOFF3 ( phy_bct_set_max_size ), + FT_FRAME_USHORT( num_phy_fonts ), + FT_FRAME_BYTE ( max_vert_stem_snap ), + FT_FRAME_BYTE ( max_horz_stem_snap ), + FT_FRAME_USHORT( max_chars ), + FT_FRAME_END + }; + FT_LOCAL_DEF( FT_Error ) + pfr_header_load( PFR_Header header, + FT_Stream stream ) + { + FT_Error error; +/* read header directly */ + if ( !FT_STREAM_SEEK( 0 ) && + !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) ) + { +/* make a few adjustments to the header */ + header->phy_font_max_size += + (FT_UInt32)header->phy_font_max_size_high << 16; + } + return error; + } + FT_LOCAL_DEF( FT_Bool ) + pfr_header_check( PFR_Header header ) + { + FT_Bool result = 1; +/* check signature and header size */ +/* "PFR0" */ + if ( header->signature != 0x50465230L || + header->version > 4 || + header->header_size < 58 || +/* CR/LF */ + header->signature2 != 0x0d0a ) + { + result = 0; + } + return result; + } +/***********************************************************************/ +/***********************************************************************/ +/***** *****/ +/***** PFR LOGICAL FONTS *****/ +/***** *****/ +/***********************************************************************/ +/***********************************************************************/ + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_count( FT_Stream stream, + FT_UInt32 section_offset, + FT_UInt *acount ) + { + FT_Error error; + FT_UInt count; + FT_UInt result = 0; + if ( FT_STREAM_SEEK( section_offset ) || FT_READ_USHORT( count ) ) + goto Exit; + result = count; + Exit: + *acount = result; + return error; + } + FT_LOCAL_DEF( FT_Error ) + pfr_log_font_load( PFR_LogFont log_font, + FT_Stream stream, + FT_UInt idx, + FT_UInt32 section_offset, + FT_Bool size_increment ) + { + FT_UInt num_log_fonts; + FT_UInt flags; + FT_UInt32 offset; + FT_UInt32 size; + FT_Error error; + if ( FT_STREAM_SEEK( section_offset ) || + FT_READ_USHORT( num_log_fonts ) ) + goto Exit; + if ( idx >= num_log_fonts ) + return PFR_Err_Invalid_Argument; + if ( FT_STREAM_SKIP( idx * 5 ) || + FT_READ_USHORT( size ) || + FT_READ_UOFF3 ( offset ) ) + goto Exit; +/* save logical font size and offset */ + log_font->size = size; + log_font->offset = offset; +/* now, check the rest of the table before loading it */ + { + FT_Byte* p; + FT_Byte* limit; + FT_UInt local; + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) ) + goto Exit; + p = stream->cursor; + limit = p + size; + PFR_CHECK(13); + log_font->matrix[0] = PFR_NEXT_LONG( p ); + log_font->matrix[1] = PFR_NEXT_LONG( p ); + log_font->matrix[2] = PFR_NEXT_LONG( p ); + log_font->matrix[3] = PFR_NEXT_LONG( p ); + flags = PFR_NEXT_BYTE( p ); + local = 0; + if ( flags & PFR_LOG_STROKE ) + { + local++; + if ( flags & PFR_LOG_2BYTE_STROKE ) + local++; + if ( (flags & PFR_LINE_JOIN_MASK) == PFR_LINE_JOIN_MITER ) + local += 3; + } + if ( flags & PFR_LOG_BOLD ) + { + local++; + if ( flags & PFR_LOG_2BYTE_BOLD ) + local++; + } + PFR_CHECK( local ); + if ( flags & PFR_LOG_STROKE ) + { + log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER ) + log_font->miter_limit = PFR_NEXT_LONG( p ); + } + if ( flags & PFR_LOG_BOLD ) + { + log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD ) + ? PFR_NEXT_SHORT( p ) + : PFR_NEXT_BYTE( p ); + } + if ( flags & PFR_LOG_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if (error) goto Fail; + } + PFR_CHECK(5); + log_font->phys_size = PFR_NEXT_USHORT( p ); + log_font->phys_offset = PFR_NEXT_ULONG( p ); + if ( size_increment ) + { + PFR_CHECK( 1 ); + log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16; + } + } + Fail: + FT_FRAME_EXIT(); + Exit: + return error; + Too_Short: + FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" )); + error = PFR_Err_Invalid_Table; + goto Fail; + } +/***********************************************************************/ +/***********************************************************************/ +/***** *****/ +/***** PFR PHYSICAL FONTS *****/ +/***** *****/ +/***********************************************************************/ +/***********************************************************************/ +/* load bitmap strikes lists */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_bitmap_info( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + FT_Memory memory = phy_font->memory; + PFR_Strike strike; + FT_UInt flags0; + FT_UInt n, count, size1; + FT_Error error = PFR_Err_Ok; + PFR_CHECK( 5 ); +/* skip bctSize */ + p += 3; + flags0 = PFR_NEXT_BYTE( p ); + count = PFR_NEXT_BYTE( p ); +/* re-allocate when needed */ + if ( phy_font->num_strikes + count > phy_font->max_strikes ) + { + FT_UInt new_max = FT_PAD_CEIL( phy_font->num_strikes + count, 4 ); + if ( FT_RENEW_ARRAY( phy_font->strikes, + phy_font->num_strikes, + new_max ) ) + goto Exit; + phy_font->max_strikes = new_max; + } + size1 = 1 + 1 + 1 + 2 + 2 + 1; + if ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + size1++; + if ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + size1++; + if ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + size1++; + if ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + size1++; + if ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + size1++; + strike = phy_font->strikes + phy_font->num_strikes; + PFR_CHECK( count * size1 ); + for ( n = 0; n < count; n++, strike++ ) + { + strike->x_ppm = ( flags0 & PFR_STRIKE_2BYTE_XPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + strike->y_ppm = ( flags0 & PFR_STRIKE_2BYTE_YPPM ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + strike->flags = PFR_NEXT_BYTE( p ); + strike->bct_size = ( flags0 & PFR_STRIKE_3BYTE_SIZE ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + strike->bct_offset = ( flags0 & PFR_STRIKE_3BYTE_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + } + phy_font->num_strikes += count; + Exit: + return error; + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_extra_item_load_bitmap_info:" + " invalid bitmap info table\n" )); + goto Exit; + } +/* Load font ID. This is a so-called "unique" name that is rather + * long and descriptive (like "Tiresias ScreenFont v7.51"). + * + * Note that a PFR font's family name is contained in an *undocumented* + * string of the "auxiliary data" portion of a physical font record. This + * may also contain the "real" style name! + * + * If no family name is present, the font ID is used instead for the + * family. + */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_font_id( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + FT_Error error = PFR_Err_Ok; + FT_Memory memory = phy_font->memory; + FT_PtrDist len = limit - p; + if ( phy_font->font_id != NULL ) + goto Exit; + if ( FT_ALLOC( phy_font->font_id, len + 1 ) ) + goto Exit; +/* copy font ID name, and terminate it for safety */ + FT_MEM_COPY( phy_font->font_id, p, len ); + phy_font->font_id[len] = 0; + Exit: + return error; + } +/* load stem snap tables */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_stem_snaps( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + FT_UInt count, num_vert, num_horz; + FT_Int* snaps = NULL; + FT_Error error = PFR_Err_Ok; + FT_Memory memory = phy_font->memory; + if ( phy_font->vertical.stem_snaps != NULL ) + goto Exit; + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + num_vert = count & 15; + num_horz = count >> 4; + count = num_vert + num_horz; + PFR_CHECK( count * 2 ); + if ( FT_NEW_ARRAY( snaps, count ) ) + goto Exit; + phy_font->vertical.stem_snaps = snaps; + phy_font->horizontal.stem_snaps = snaps + num_vert; + for ( ; count > 0; count--, snaps++ ) + *snaps = FT_NEXT_SHORT( p ); + Exit: + return error; + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_exta_item_load_stem_snaps:" + " invalid stem snaps table\n" )); + goto Exit; + } +/* load kerning pair data */ + FT_CALLBACK_DEF( FT_Error ) + pfr_extra_item_load_kerning_pairs( FT_Byte* p, + FT_Byte* limit, + PFR_PhyFont phy_font ) + { + PFR_KernItem item = NULL; + FT_Error error = PFR_Err_Ok; + FT_Memory memory = phy_font->memory; + FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" )); + if ( FT_NEW( item ) ) + goto Exit; + PFR_CHECK( 4 ); + item->pair_count = PFR_NEXT_BYTE( p ); + item->base_adj = PFR_NEXT_SHORT( p ); + item->flags = PFR_NEXT_BYTE( p ); + item->offset = phy_font->offset + ( p - phy_font->cursor ); +#ifndef PFR_CONFIG_NO_CHECKS + item->pair_size = 3; + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + item->pair_size += 2; + if ( item->flags & PFR_KERN_2BYTE_ADJ ) + item->pair_size += 1; + PFR_CHECK( item->pair_count * item->pair_size ); +#endif +/* load first and last pairs into the item to speed up */ +/* lookup later... */ + if ( item->pair_count > 0 ) + { + FT_UInt char1, char2; + FT_Byte* q; + if ( item->flags & PFR_KERN_2BYTE_CHAR ) + { + q = p; + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_USHORT( q ); + char2 = PFR_NEXT_USHORT( q ); + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } + else + { + q = p; + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + item->pair1 = PFR_KERN_INDEX( char1, char2 ); + q = p + item->pair_size * ( item->pair_count - 1 ); + char1 = PFR_NEXT_BYTE( q ); + char2 = PFR_NEXT_BYTE( q ); + item->pair2 = PFR_KERN_INDEX( char1, char2 ); + } +/* add new item to the current list */ + item->next = NULL; + *phy_font->kern_items_tail = item; + phy_font->kern_items_tail = &item->next; + phy_font->num_kern_pairs += item->pair_count; + } + else + { +/* empty item! */ + FT_FREE( item ); + } + Exit: + return error; + Too_Short: + FT_FREE( item ); + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_extra_item_load_kerning_pairs:" + " invalid kerning pairs table\n" )); + goto Exit; + } + static const PFR_ExtraItemRec pfr_phy_font_extra_items[] = + { + { 1, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_bitmap_info }, + { 2, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_font_id }, + { 3, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_stem_snaps }, + { 4, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_kerning_pairs }, + { 0, NULL } + }; +/* Loads a name from the auxiliary data. Since this extracts undocumented + * strings from the font file, we need to be careful here. + */ + static FT_Error + pfr_aux_name_load( FT_Byte* p, + FT_UInt len, + FT_Memory memory, + FT_String* *astring ) + { + FT_Error error = PFR_Err_Ok; + FT_String* result = NULL; + FT_UInt n, ok; + if ( len > 0 && p[len - 1] == 0 ) + len--; +/* check that each character is ASCII for making sure not to + load garbage + */ + ok = ( len > 0 ); + for ( n = 0; n < len; n++ ) + if ( p[n] < 32 || p[n] > 127 ) + { + ok = 0; + break; + } + if ( ok ) + { + if ( FT_ALLOC( result, len + 1 ) ) + goto Exit; + FT_MEM_COPY( result, p, len ); + result[len] = 0; + } + Exit: + *astring = result; + return error; + } + FT_LOCAL_DEF( void ) + pfr_phy_font_done( PFR_PhyFont phy_font, + FT_Memory memory ) + { + FT_FREE( phy_font->font_id ); + FT_FREE( phy_font->family_name ); + FT_FREE( phy_font->style_name ); + FT_FREE( phy_font->vertical.stem_snaps ); + phy_font->vertical.num_stem_snaps = 0; + phy_font->horizontal.stem_snaps = NULL; + phy_font->horizontal.num_stem_snaps = 0; + FT_FREE( phy_font->strikes ); + phy_font->num_strikes = 0; + phy_font->max_strikes = 0; + FT_FREE( phy_font->chars ); + phy_font->num_chars = 0; + phy_font->chars_offset = 0; + FT_FREE( phy_font->blue_values ); + phy_font->num_blue_values = 0; + { + PFR_KernItem item, next; + item = phy_font->kern_items; + while ( item ) + { + next = item->next; + FT_FREE( item ); + item = next; + } + phy_font->kern_items = NULL; + phy_font->kern_items_tail = NULL; + } + phy_font->num_kern_pairs = 0; + } + FT_LOCAL_DEF( FT_Error ) + pfr_phy_font_load( PFR_PhyFont phy_font, + FT_Stream stream, + FT_UInt32 offset, + FT_UInt32 size ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt flags; + FT_ULong num_aux; + FT_Byte* p; + FT_Byte* limit; + phy_font->memory = memory; + phy_font->offset = offset; + phy_font->kern_items = NULL; + phy_font->kern_items_tail = &phy_font->kern_items; + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) ) + goto Exit; + phy_font->cursor = stream->cursor; + p = stream->cursor; + limit = p + size; + PFR_CHECK( 15 ); + phy_font->font_ref_number = PFR_NEXT_USHORT( p ); + phy_font->outline_resolution = PFR_NEXT_USHORT( p ); + phy_font->metrics_resolution = PFR_NEXT_USHORT( p ); + phy_font->bbox.xMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMin = PFR_NEXT_SHORT( p ); + phy_font->bbox.xMax = PFR_NEXT_SHORT( p ); + phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); + phy_font->flags = flags = PFR_NEXT_BYTE( p ); +/* get the standard advance for non-proportional fonts */ + if ( !(flags & PFR_PHY_PROPORTIONAL) ) + { + PFR_CHECK( 2 ); + phy_font->standard_advance = PFR_NEXT_SHORT( p ); + } +/* load the extra items when present */ + if ( flags & PFR_PHY_EXTRA_ITEMS ) + { + error = pfr_extra_items_parse( &p, limit, + pfr_phy_font_extra_items, phy_font ); + if ( error ) + goto Fail; + } +/* In certain fonts, the auxiliary bytes contain interesting */ +/* information. These are not in the specification but can be */ +/* guessed by looking at the content of a few PFR0 fonts. */ + PFR_CHECK( 3 ); + num_aux = PFR_NEXT_ULONG( p ); + if ( num_aux > 0 ) + { + FT_Byte* q = p; + FT_Byte* q2; + PFR_CHECK( num_aux ); + p += num_aux; + while ( num_aux > 0 ) + { + FT_UInt length, type; + if ( q + 4 > p ) + break; + length = PFR_NEXT_USHORT( q ); + if ( length < 4 || length > num_aux ) + break; + q2 = q + length - 2; + type = PFR_NEXT_USHORT( q ); + switch ( type ) + { + case 1: +/* this seems to correspond to the font's family name, + * padded to 16-bits with one zero when necessary + */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->family_name ); + if ( error ) + goto Exit; + break; + case 2: + if ( q + 32 > q2 ) + break; + q += 10; + phy_font->ascent = PFR_NEXT_SHORT( q ); + phy_font->descent = PFR_NEXT_SHORT( q ); + phy_font->leading = PFR_NEXT_SHORT( q ); + q += 16; + break; + case 3: +/* this seems to correspond to the font's style name, + * padded to 16-bits with one zero when necessary + */ + error = pfr_aux_name_load( q, length - 4U, memory, + &phy_font->style_name ); + if ( error ) + goto Exit; + break; + default: + ; + } + q = q2; + num_aux -= length; + } + } +/* read the blue values */ + { + FT_UInt n, count; + PFR_CHECK( 1 ); + phy_font->num_blue_values = count = PFR_NEXT_BYTE( p ); + PFR_CHECK( count * 2 ); + if ( FT_NEW_ARRAY( phy_font->blue_values, count ) ) + goto Fail; + for ( n = 0; n < count; n++ ) + phy_font->blue_values[n] = PFR_NEXT_SHORT( p ); + } + PFR_CHECK( 8 ); + phy_font->blue_fuzz = PFR_NEXT_BYTE( p ); + phy_font->blue_scale = PFR_NEXT_BYTE( p ); + phy_font->vertical.standard = PFR_NEXT_USHORT( p ); + phy_font->horizontal.standard = PFR_NEXT_USHORT( p ); +/* read the character descriptors */ + { + FT_UInt n, count, Size; + phy_font->num_chars = count = PFR_NEXT_USHORT( p ); + phy_font->chars_offset = offset + ( p - stream->cursor ); + if ( FT_NEW_ARRAY( phy_font->chars, count ) ) + goto Fail; + Size = 1 + 1 + 2; + if ( flags & PFR_PHY_2BYTE_CHARCODE ) + Size += 1; + if ( flags & PFR_PHY_PROPORTIONAL ) + Size += 2; + if ( flags & PFR_PHY_ASCII_CODE ) + Size += 1; + if ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + Size += 1; + if ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + Size += 1; + PFR_CHECK( count * Size ); + for ( n = 0; n < count; n++ ) + { + PFR_Char cur = &phy_font->chars[n]; + cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + cur->advance = ( flags & PFR_PHY_PROPORTIONAL ) + ? PFR_NEXT_SHORT( p ) + : (FT_Int) phy_font->standard_advance; +#if 0 + cur->ascii = ( flags & PFR_PHY_ASCII_CODE ) + ? PFR_NEXT_BYTE( p ) + : 0; +#else + if ( flags & PFR_PHY_ASCII_CODE ) + p += 1; +#endif + cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE ) + ? PFR_NEXT_USHORT( p ) + : PFR_NEXT_BYTE( p ); + cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET ) + ? PFR_NEXT_ULONG( p ) + : PFR_NEXT_USHORT( p ); + } + } +/* that's it! */ + Fail: + FT_FRAME_EXIT(); +/* save position of bitmap info */ + phy_font->bct_offset = FT_STREAM_POS(); + phy_font->cursor = NULL; + Exit: + return error; + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" )); + goto Fail; + } +/* END */ +/***************************************************************************/ +/* */ +/* pfrgload.c */ +/* */ +/* FreeType PFR glyph loader (body). */ +/* */ +/* Copyright 2002, 2003, 2005, 2007, 2010 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pfrgload.h */ +/* */ +/* FreeType PFR glyph loader (specification). */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define __PFRGLOAD_H__ +FT_BEGIN_HEADER + FT_LOCAL( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ); + FT_LOCAL( void ) + pfr_glyph_done( PFR_Glyph glyph ); + FT_LOCAL( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* pfrsbit.h */ +/* */ +/* FreeType PFR bitmap loader (specification). */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define __PFRSBIT_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index ); +FT_END_HEADER +/* END */ +/* for macro definitions */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_pfr +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PFR GLYPH BUILDER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + pfr_glyph_init( PFR_Glyph glyph, + FT_GlyphLoader loader ) + { + FT_ZERO( glyph ); + glyph->loader = loader; + glyph->path_begun = 0; + FT_GlyphLoader_Rewind( loader ); + } + FT_LOCAL_DEF( void ) + pfr_glyph_done( PFR_Glyph glyph ) + { + FT_Memory memory = glyph->loader->memory; + FT_FREE( glyph->x_control ); + glyph->y_control = NULL; + glyph->max_xy_control = 0; +#if 0 + glyph->num_x_control = 0; + glyph->num_y_control = 0; +#endif + FT_FREE( glyph->subs ); + glyph->max_subs = 0; + glyph->num_subs = 0; + glyph->loader = NULL; + glyph->path_begun = 0; + } +/* close current contour, if any */ + static void + pfr_glyph_close_contour( PFR_Glyph glyph ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Int last, first; + if ( !glyph->path_begun ) + return; +/* compute first and last point indices in current glyph outline */ + last = outline->n_points - 1; + first = 0; + if ( outline->n_contours > 0 ) + first = outline->contours[outline->n_contours - 1]; +/* if the last point falls on the same location than the first one */ +/* we need to delete it */ + if ( last > first ) + { + FT_Vector* p1 = outline->points + first; + FT_Vector* p2 = outline->points + last; + if ( p1->x == p2->x && p1->y == p2->y ) + { + outline->n_points--; + last--; + } + } +/* don't add empty contours */ + if ( last >= first ) + outline->contours[outline->n_contours++] = (short)last; + glyph->path_begun = 0; + } +/* reset glyph to start the loading of a new glyph */ + static void + pfr_glyph_start( PFR_Glyph glyph ) + { + glyph->path_begun = 0; + } + static FT_Error + pfr_glyph_line_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; +/* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 ); + if ( !error ) + { + FT_UInt n = outline->n_points; + outline->points[n] = *to; + outline->tags [n] = FT_CURVE_TAG_ON; + outline->n_points++; + } + Exit: + return error; + } + static FT_Error + pfr_glyph_curve_to( PFR_Glyph glyph, + FT_Vector* control1, + FT_Vector* control2, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Outline* outline = &loader->current.outline; + FT_Error error; +/* check that we have begun a new path */ + if ( !glyph->path_begun ) + { + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" )); + goto Exit; + } + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 ); + if ( !error ) + { + FT_Vector* vec = outline->points + outline->n_points; + FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points; + vec[0] = *control1; + vec[1] = *control2; + vec[2] = *to; + tag[0] = FT_CURVE_TAG_CUBIC; + tag[1] = FT_CURVE_TAG_CUBIC; + tag[2] = FT_CURVE_TAG_ON; + outline->n_points = (FT_Short)( outline->n_points + 3 ); + } + Exit: + return error; + } + static FT_Error + pfr_glyph_move_to( PFR_Glyph glyph, + FT_Vector* to ) + { + FT_GlyphLoader loader = glyph->loader; + FT_Error error; +/* close current contour if any */ + pfr_glyph_close_contour( glyph ); +/* indicate that a new contour has started */ + glyph->path_begun = 1; +/* check that there is space for a new contour and a new point */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 ); + if ( !error ) +/* add new start point */ + error = pfr_glyph_line_to( glyph, to ); + return error; + } + static void + pfr_glyph_end( PFR_Glyph glyph ) + { +/* close current contour if any */ + pfr_glyph_close_contour( glyph ); +/* merge the current glyph into the stack */ + FT_GlyphLoader_Add( glyph->loader ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PFR GLYPH LOADER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* load a simple glyph */ + static FT_Error + pfr_glyph_load_simple( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = PFR_Err_Ok; + FT_Memory memory = glyph->loader->memory; + FT_UInt flags, x_count, y_count, i, count, mask; + FT_Int x; + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); +/* test for composite glyphs */ + if ( flags & PFR_GLYPH_IS_COMPOUND ) + goto Failure; + x_count = 0; + y_count = 0; + if ( flags & PFR_GLYPH_1BYTE_XYCOUNT ) + { + PFR_CHECK( 1 ); + count = PFR_NEXT_BYTE( p ); + x_count = count & 15; + y_count = count >> 4; + } + else + { + if ( flags & PFR_GLYPH_XCOUNT ) + { + PFR_CHECK( 1 ); + x_count = PFR_NEXT_BYTE( p ); + } + if ( flags & PFR_GLYPH_YCOUNT ) + { + PFR_CHECK( 1 ); + y_count = PFR_NEXT_BYTE( p ); + } + } + count = x_count + y_count; +/* re-allocate array when necessary */ + if ( count > glyph->max_xy_control ) + { + FT_UInt new_max = FT_PAD_CEIL( count, 8 ); + if ( FT_RENEW_ARRAY( glyph->x_control, + glyph->max_xy_control, + new_max ) ) + goto Exit; + glyph->max_xy_control = new_max; + } + glyph->y_control = glyph->x_control + x_count; + mask = 0; + x = 0; + for ( i = 0; i < count; i++ ) + { + if ( ( i & 7 ) == 0 ) + { + PFR_CHECK( 1 ); + mask = PFR_NEXT_BYTE( p ); + } + if ( mask & 1 ) + { + PFR_CHECK( 2 ); + x = PFR_NEXT_SHORT( p ); + } + else + { + PFR_CHECK( 1 ); + x += PFR_NEXT_BYTE( p ); + } + glyph->x_control[i] = x; + mask >>= 1; + } +/* XXX: for now we ignore the secondary stroke and edge definitions */ +/* since we don't want to support native PFR hinting */ +/* */ + if ( flags & PFR_GLYPH_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if ( error ) + goto Exit; + } + pfr_glyph_start( glyph ); +/* now load a simple glyph */ + { + FT_Vector pos[4]; + FT_Vector* cur; + pos[0].x = pos[0].y = 0; + pos[3] = pos[0]; + for (;;) + { + FT_UInt format, format_low, args_format = 0, args_count, n; +/***************************************************************/ +/* read instruction */ +/* */ + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); + format_low = format & 15; + switch ( format >> 4 ) + { +/* end glyph */ + case 0: + FT_TRACE6(( "- end glyph" )); + args_count = 0; + break; +/* general line operation */ + case 1: + FT_TRACE6(( "- general line" )); + goto Line1; +/* move to inside contour */ + case 4: + FT_TRACE6(( "- move to inside" )); + goto Line1; +/* move to outside contour */ + case 5: + FT_TRACE6(( "- move to outside" )); + Line1: + args_format = format_low; + args_count = 1; + break; +/* horizontal line to */ + case 2: + FT_TRACE6(( "- horizontal line to cx.%d", format_low )); + if ( format_low >= x_count ) + goto Failure; + pos[0].x = glyph->x_control[format_low]; + pos[0].y = pos[3].y; + pos[3] = pos[0]; + args_count = 0; + break; +/* vertical line to */ + case 3: + FT_TRACE6(( "- vertical line to cy.%d", format_low )); + if ( format_low >= y_count ) + goto Failure; + pos[0].x = pos[3].x; + pos[0].y = glyph->y_control[format_low]; + pos[3] = pos[0]; + args_count = 0; + break; +/* horizontal to vertical curve */ + case 6: + FT_TRACE6(( "- hv curve " )); + args_format = 0xB8E; + args_count = 3; + break; +/* vertical to horizontal curve */ + case 7: + FT_TRACE6(( "- vh curve" )); + args_format = 0xE2B; + args_count = 3; + break; +/* general curve to */ + default: + FT_TRACE6(( "- general curve" )); + args_count = 4; + args_format = format_low; + } +/***********************************************************/ +/* now read arguments */ +/* */ + cur = pos; + for ( n = 0; n < args_count; n++ ) + { + FT_UInt idx; + FT_Int delta; +/* read the X argument */ + switch ( args_format & 3 ) + { +/* 8-bit index */ + case 0: + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= x_count ) + goto Failure; + cur->x = glyph->x_control[idx]; + FT_TRACE7(( " cx#%d", idx )); + break; +/* 16-bit value */ + case 1: + PFR_CHECK( 2 ); + cur->x = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " x.%d", cur->x )); + break; +/* 8-bit delta */ + case 2: + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->x = pos[3].x + delta; + FT_TRACE7(( " dx.%d", delta )); + break; + default: + FT_TRACE7(( " |" )); + cur->x = pos[3].x; + } +/* read the Y argument */ + switch ( ( args_format >> 2 ) & 3 ) + { +/* 8-bit index */ + case 0: + PFR_CHECK( 1 ); + idx = PFR_NEXT_BYTE( p ); + if ( idx >= y_count ) + goto Failure; + cur->y = glyph->y_control[idx]; + FT_TRACE7(( " cy#%d", idx )); + break; +/* 16-bit absolute value */ + case 1: + PFR_CHECK( 2 ); + cur->y = PFR_NEXT_SHORT( p ); + FT_TRACE7(( " y.%d", cur->y )); + break; +/* 8-bit delta */ + case 2: + PFR_CHECK( 1 ); + delta = PFR_NEXT_INT8( p ); + cur->y = pos[3].y + delta; + FT_TRACE7(( " dy.%d", delta )); + break; + default: + FT_TRACE7(( " -" )); + cur->y = pos[3].y; + } +/* read the additional format flag for the general curve */ + if ( n == 0 && args_count == 4 ) + { + PFR_CHECK( 1 ); + args_format = PFR_NEXT_BYTE( p ); + args_count--; + } + else + args_format >>= 4; +/* save the previous point */ + pos[3] = cur[0]; + cur++; + } + FT_TRACE7(( "\n" )); +/***********************************************************/ +/* finally, execute instruction */ +/* */ + switch ( format >> 4 ) + { +/* end glyph => EXIT */ + case 0: + pfr_glyph_end( glyph ); + goto Exit; +/* line operations */ + case 1: + case 2: + case 3: + error = pfr_glyph_line_to( glyph, pos ); + goto Test_Error; +/* move to inside contour */ + case 4: +/* move to outside contour */ + case 5: + error = pfr_glyph_move_to( glyph, pos ); + goto Test_Error; +/* curve operations */ + default: + error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 ); +/* test error condition */ + Test_Error: + if ( error ) + goto Exit; + } +/* for (;;) */ + } + } + Exit: + return error; + Failure: + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" )); + goto Exit; + } +/* load a composite/compound glyph */ + static FT_Error + pfr_glyph_load_compound( PFR_Glyph glyph, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Error error = PFR_Err_Ok; + FT_GlyphLoader loader = glyph->loader; + FT_Memory memory = loader->memory; + PFR_SubGlyph subglyph; + FT_UInt flags, i, count, org_count; + FT_Int x_pos, y_pos; + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); +/* test for composite glyphs */ + if ( !( flags & PFR_GLYPH_IS_COMPOUND ) ) + goto Failure; + count = flags & 0x3F; +/* ignore extra items when present */ +/* */ + if ( flags & PFR_GLYPH_EXTRA_ITEMS ) + { + error = pfr_extra_items_skip( &p, limit ); + if (error) goto Exit; + } +/* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */ +/* the PFR format is dumb, using direct file offsets to point to the */ +/* sub-glyphs (instead of glyph indices). Sigh. */ +/* */ +/* For now, we load the list of sub-glyphs into a different array */ +/* but this will prevent us from using the auto-hinter at its best */ +/* quality. */ +/* */ + org_count = glyph->num_subs; + if ( org_count + count > glyph->max_subs ) + { + FT_UInt new_max = ( org_count + count + 3 ) & (FT_UInt)-4; +/* we arbitrarily limit the number of subglyphs */ +/* to avoid endless recursion */ + if ( new_max > 64 ) + { + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_load_compound:" + " too many compound glyphs components\n" )); + goto Exit; + } + if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) ) + goto Exit; + glyph->max_subs = new_max; + } + subglyph = glyph->subs + org_count; + for ( i = 0; i < count; i++, subglyph++ ) + { + FT_UInt format; + x_pos = 0; + y_pos = 0; + PFR_CHECK( 1 ); + format = PFR_NEXT_BYTE( p ); +/* read scale when available */ + subglyph->x_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_XSCALE ) + { + PFR_CHECK( 2 ); + subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4; + } + subglyph->y_scale = 0x10000L; + if ( format & PFR_SUBGLYPH_YSCALE ) + { + PFR_CHECK( 2 ); + subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4; + } +/* read offset */ + switch ( format & 3 ) + { + case 1: + PFR_CHECK( 2 ); + x_pos = PFR_NEXT_SHORT( p ); + break; + case 2: + PFR_CHECK( 1 ); + x_pos += PFR_NEXT_INT8( p ); + break; + default: + ; + } + switch ( ( format >> 2 ) & 3 ) + { + case 1: + PFR_CHECK( 2 ); + y_pos = PFR_NEXT_SHORT( p ); + break; + case 2: + PFR_CHECK( 1 ); + y_pos += PFR_NEXT_INT8( p ); + break; + default: + ; + } + subglyph->x_delta = x_pos; + subglyph->y_delta = y_pos; +/* read glyph position and size now */ + if ( format & PFR_SUBGLYPH_2BYTE_SIZE ) + { + PFR_CHECK( 2 ); + subglyph->gps_size = PFR_NEXT_USHORT( p ); + } + else + { + PFR_CHECK( 1 ); + subglyph->gps_size = PFR_NEXT_BYTE( p ); + } + if ( format & PFR_SUBGLYPH_3BYTE_OFFSET ) + { + PFR_CHECK( 3 ); + subglyph->gps_offset = PFR_NEXT_LONG( p ); + } + else + { + PFR_CHECK( 2 ); + subglyph->gps_offset = PFR_NEXT_USHORT( p ); + } + glyph->num_subs++; + } + Exit: + return error; + Failure: + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" )); + goto Exit; + } + static FT_Error + pfr_glyph_load_rec( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { + FT_Error error; + FT_Byte* p; + FT_Byte* limit; + if ( FT_STREAM_SEEK( gps_offset + offset ) || + FT_FRAME_ENTER( size ) ) + goto Exit; + p = (FT_Byte*)stream->cursor; + limit = p + size; + if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND ) + { + FT_Int n, old_count, count; + FT_GlyphLoader loader = glyph->loader; + FT_Outline* base = &loader->base.outline; + old_count = glyph->num_subs; +/* this is a compound glyph - load it */ + error = pfr_glyph_load_compound( glyph, p, limit ); + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + count = glyph->num_subs - old_count; + FT_TRACE4(( "compound glyph with %d elements (offset %lu):\n", + count, offset )); +/* now, load each individual glyph */ + for ( n = 0; n < count; n++ ) + { + FT_Int i, old_points, num_points; + PFR_SubGlyph subglyph; + FT_TRACE4(( "subglyph %d:\n", n )); + subglyph = glyph->subs + old_count + n; + old_points = base->n_points; + error = pfr_glyph_load_rec( glyph, stream, gps_offset, + subglyph->gps_offset, + subglyph->gps_size ); + if ( error ) + break; +/* note that `glyph->subs' might have been re-allocated */ + subglyph = glyph->subs + old_count + n; + num_points = base->n_points - old_points; +/* translate and eventually scale the new glyph points */ + if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L ) + { + FT_Vector* vec = base->points + old_points; + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x = FT_MulFix( vec->x, subglyph->x_scale ) + + subglyph->x_delta; + vec->y = FT_MulFix( vec->y, subglyph->y_scale ) + + subglyph->y_delta; + } + } + else + { + FT_Vector* vec = loader->base.outline.points + old_points; + for ( i = 0; i < num_points; i++, vec++ ) + { + vec->x += subglyph->x_delta; + vec->y += subglyph->y_delta; + } + } +/* proceed to next sub-glyph */ + } + FT_TRACE4(( "end compound glyph with %d elements\n", count )); + } + else + { + FT_TRACE4(( "simple glyph (offset %lu)\n", offset )); +/* load a simple glyph */ + error = pfr_glyph_load_simple( glyph, p, limit ); + FT_FRAME_EXIT(); + } + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + pfr_glyph_load( PFR_Glyph glyph, + FT_Stream stream, + FT_ULong gps_offset, + FT_ULong offset, + FT_ULong size ) + { +/* initialize glyph loader */ + FT_GlyphLoader_Rewind( glyph->loader ); + glyph->num_subs = 0; +/* load the glyph, recursively when needed */ + return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size ); + } +/* END */ +/***************************************************************************/ +/* */ +/* pfrcmap.c */ +/* */ +/* FreeType PFR cmap handling (body). */ +/* */ +/* Copyright 2002, 2007, 2009 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pfrcmap.h */ +/* */ +/* FreeType PFR cmap handling (specification). */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define __PFRCMAP_H__ +FT_BEGIN_HEADER + typedef struct PFR_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt num_chars; + PFR_Char chars; + } PFR_CMapRec, *PFR_CMap; + FT_CALLBACK_TABLE const FT_CMap_ClassRec pfr_cmap_class_rec; +FT_END_HEADER +/* END */ + FT_CALLBACK_DEF( FT_Error ) + pfr_cmap_init( PFR_CMap cmap ) + { + FT_Error error = PFR_Err_Ok; + PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); + cmap->num_chars = face->phy_font.num_chars; + cmap->chars = face->phy_font.chars; +/* just for safety, check that the character entries are correctly */ +/* sorted in increasing character code order */ + { + FT_UInt n; + for ( n = 1; n < cmap->num_chars; n++ ) + { + if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code ) + { + error = PFR_Err_Invalid_Table; + goto Exit; + } + } + } + Exit: + return error; + } + FT_CALLBACK_DEF( void ) + pfr_cmap_done( PFR_CMap cmap ) + { + cmap->chars = NULL; + cmap->num_chars = 0; + } + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_index( PFR_CMap cmap, + FT_UInt32 char_code ) + { + FT_UInt min = 0; + FT_UInt max = cmap->num_chars; + FT_UInt mid; + PFR_Char gchar; + while ( min < max ) + { + mid = min + ( max - min ) / 2; + gchar = cmap->chars + mid; + if ( gchar->char_code == char_code ) + return mid + 1; + if ( gchar->char_code < char_code ) + min = mid + 1; + else + max = mid; + } + return 0; + } + FT_CALLBACK_DEF( FT_UInt32 ) + pfr_cmap_char_next( PFR_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code + 1; + Restart: + { + FT_UInt min = 0; + FT_UInt max = cmap->num_chars; + FT_UInt mid; + PFR_Char gchar; + while ( min < max ) + { + mid = min + ( ( max - min ) >> 1 ); + gchar = cmap->chars + mid; + if ( gchar->char_code == char_code ) + { + result = mid; + if ( result != 0 ) + { + result++; + goto Exit; + } + char_code++; + goto Restart; + } + if ( gchar->char_code < char_code ) + min = mid+1; + else + max = mid; + } +/* we didn't find it, but we have a pair just above it */ + char_code = 0; + if ( min < cmap->num_chars ) + { + gchar = cmap->chars + min; + result = min; + if ( result != 0 ) + { + result++; + char_code = gchar->char_code; + } + } + } + Exit: + *pchar_code = char_code; + return result; + } + FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec + pfr_cmap_class_rec = + { + sizeof ( PFR_CMapRec ), + (FT_CMap_InitFunc) pfr_cmap_init, + (FT_CMap_DoneFunc) pfr_cmap_done, + (FT_CMap_CharIndexFunc)pfr_cmap_char_index, + (FT_CMap_CharNextFunc) pfr_cmap_char_next, + NULL, NULL, NULL, NULL, NULL + }; +/* END */ +/***************************************************************************/ +/* */ +/* pfrobjs.c */ +/* */ +/* FreeType PFR object methods (body). */ +/* */ +/* Copyright 2002-2008, 2010-2011 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_COMPONENT +#define FT_COMPONENT trace_pfr +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** FACE OBJECT METHODS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( void ) +/* PFR_Face */ + pfr_face_done( FT_Face pfrface ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Memory memory; + if ( !face ) + return; + memory = pfrface->driver->root.memory; +/* we don't want dangling pointers */ + pfrface->family_name = NULL; + pfrface->style_name = NULL; +/* finalize the physical font record */ + pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) ); +/* no need to finalize the logical font or the header */ + FT_FREE( pfrface->available_sizes ); + } + FT_LOCAL_DEF( FT_Error ) + pfr_face_init( FT_Stream stream, + FT_Face pfrface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error; + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_TRACE2(( "PFR driver\n" )); +/* load the header and check it */ + error = pfr_header_load( &face->header, stream ); + if ( error ) + goto Exit; + if ( !pfr_header_check( &face->header ) ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = PFR_Err_Unknown_File_Format; + goto Exit; + } +/* check face index */ + { + FT_UInt num_faces; + error = pfr_log_font_count( stream, + face->header.log_dir_offset, + &num_faces ); + if ( error ) + goto Exit; + pfrface->num_faces = num_faces; + } + if ( face_index < 0 ) + goto Exit; + if ( face_index >= pfrface->num_faces ) + { + FT_ERROR(( "pfr_face_init: invalid face index\n" )); + error = PFR_Err_Invalid_Argument; + goto Exit; + } +/* load the face */ + error = pfr_log_font_load( + &face->log_font, stream, face_index, + face->header.log_dir_offset, + FT_BOOL( face->header.phy_font_max_size_high != 0 ) ); + if ( error ) + goto Exit; +/* now load the physical font descriptor */ + error = pfr_phy_font_load( &face->phy_font, stream, + face->log_font.phys_offset, + face->log_font.phys_size ); + if ( error ) + goto Exit; +/* now set up all root face fields */ + { + PFR_PhyFont phy_font = &face->phy_font; + pfrface->face_index = face_index; + pfrface->num_glyphs = phy_font->num_chars + 1; + pfrface->face_flags = FT_FACE_FLAG_SCALABLE; +/* if all characters point to the same gps_offset 0, we */ +/* assume that the font only contains bitmaps */ + { + FT_UInt nn; + for ( nn = 0; nn < phy_font->num_chars; nn++ ) + if ( phy_font->chars[nn].gps_offset != 0 ) + break; + if ( nn == phy_font->num_chars ) + { + if ( phy_font->num_strikes > 0 ) +/* not scalable */ + pfrface->face_flags = 0; + else + { + FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); + error = PFR_Err_Invalid_File_Format; + goto Exit; + } + } + } + if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + if ( phy_font->flags & PFR_PHY_VERTICAL ) + pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; + else + pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; + if ( phy_font->num_strikes > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; + if ( phy_font->num_kern_pairs > 0 ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; +/* If no family name was found in the "undocumented" auxiliary + * data, use the font ID instead. This sucks but is better than + * nothing. + */ + pfrface->family_name = phy_font->family_name; + if ( pfrface->family_name == NULL ) + pfrface->family_name = phy_font->font_id; +/* note that the style name can be NULL in certain PFR fonts, + * probably meaning "Regular" + */ + pfrface->style_name = phy_font->style_name; + pfrface->num_fixed_sizes = 0; + pfrface->available_sizes = 0; + pfrface->bbox = phy_font->bbox; + pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; + pfrface->ascender = (FT_Short) phy_font->bbox.yMax; + pfrface->descender = (FT_Short) phy_font->bbox.yMin; + pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); + if ( pfrface->height < pfrface->ascender - pfrface->descender ) + pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender); + if ( phy_font->num_strikes > 0 ) + { + FT_UInt n, count = phy_font->num_strikes; + FT_Bitmap_Size* size; + PFR_Strike strike; + FT_Memory memory = pfrface->stream->memory; + if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) ) + goto Exit; + size = pfrface->available_sizes; + strike = phy_font->strikes; + for ( n = 0; n < count; n++, size++, strike++ ) + { + size->height = (FT_UShort)strike->y_ppm; + size->width = (FT_UShort)strike->x_ppm; + size->size = strike->y_ppm << 6; + size->x_ppem = strike->x_ppm << 6; + size->y_ppem = strike->y_ppm << 6; + } + pfrface->num_fixed_sizes = count; + } +/* now compute maximum advance width */ + if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) + pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; + else + { + FT_Int max = 0; + FT_UInt count = phy_font->num_chars; + PFR_Char gchar = phy_font->chars; + for ( ; count > 0; count--, gchar++ ) + { + if ( max < gchar->advance ) + max = gchar->advance; + } + pfrface->max_advance_width = (FT_Short)max; + } + pfrface->max_advance_height = pfrface->height; + pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); + pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); +/* create charmap */ + { + FT_CharMapRec charmap; + charmap.face = pfrface; + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); +#if 0 +/* Select default charmap */ + if ( pfrface->num_charmaps ) + pfrface->charmap = pfrface->charmaps[0]; +#endif + } +/* check whether we've loaded any kerning pairs */ + if ( phy_font->num_kern_pairs ) + pfrface->face_flags |= FT_FACE_FLAG_KERNING; + } + Exit: + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** SLOT OBJECT METHOD *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( FT_Error ) +/* PFR_Slot */ + pfr_slot_init( FT_GlyphSlot pfrslot ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + FT_GlyphLoader loader = pfrslot->internal->loader; + pfr_glyph_init( &slot->glyph, loader ); + return 0; + } + FT_LOCAL_DEF( void ) +/* PFR_Slot */ + pfr_slot_done( FT_GlyphSlot pfrslot ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + pfr_glyph_done( &slot->glyph ); + } + FT_LOCAL_DEF( FT_Error ) +/* PFR_Slot */ + pfr_slot_load( FT_GlyphSlot pfrslot, +/* PFR_Size */ + FT_Size pfrsize, + FT_UInt gindex, + FT_Int32 load_flags ) + { + PFR_Slot slot = (PFR_Slot)pfrslot; + PFR_Size size = (PFR_Size)pfrsize; + FT_Error error; + PFR_Face face = (PFR_Face)pfrslot->face; + PFR_Char gchar; + FT_Outline* outline = &pfrslot->outline; + FT_ULong gps_offset; + if ( gindex > 0 ) + gindex--; + if ( !face || gindex >= face->phy_font.num_chars ) + { + error = PFR_Err_Invalid_Argument; + goto Exit; + } +/* try to load an embedded bitmap */ + if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) + { + error = pfr_slot_load_bitmap( slot, size, gindex ); + if ( error == 0 ) + goto Exit; + } + if ( load_flags & FT_LOAD_SBITS_ONLY ) + { + error = PFR_Err_Invalid_Argument; + goto Exit; + } + gchar = face->phy_font.chars + gindex; + pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; + outline->n_points = 0; + outline->n_contours = 0; + gps_offset = face->header.gps_section_offset; +/* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ + error = pfr_glyph_load( &slot->glyph, face->root.stream, + gps_offset, gchar->gps_offset, gchar->gps_size ); + if ( !error ) + { + FT_BBox cbox; + FT_Glyph_Metrics* metrics = &pfrslot->metrics; + FT_Pos advance; + FT_Int em_metrics, em_outline; + FT_Bool scaling; + scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); +/* copy outline data */ + *outline = slot->glyph.loader->base.outline; + outline->flags &= ~FT_OUTLINE_OWNER; + outline->flags |= FT_OUTLINE_REVERSE_FILL; + if ( size && pfrsize->metrics.y_ppem < 24 ) + outline->flags |= FT_OUTLINE_HIGH_PRECISION; +/* compute the advance vector */ + metrics->horiAdvance = 0; + metrics->vertAdvance = 0; + advance = gchar->advance; + em_metrics = face->phy_font.metrics_resolution; + em_outline = face->phy_font.outline_resolution; + if ( em_metrics != em_outline ) + advance = FT_MulDiv( advance, em_outline, em_metrics ); + if ( face->phy_font.flags & PFR_PHY_VERTICAL ) + metrics->vertAdvance = advance; + else + metrics->horiAdvance = advance; + pfrslot->linearHoriAdvance = metrics->horiAdvance; + pfrslot->linearVertAdvance = metrics->vertAdvance; +/* make-up vertical metrics(?) */ + metrics->vertBearingX = 0; + metrics->vertBearingY = 0; +/* some fonts seem to be broken here! */ +#if 0 +/* Apply the font matrix, if any. */ +/* TODO: Test existing fonts with unusual matrix */ +/* whether we have to adjust Units per EM. */ + { + FT_Matrix font_matrix; + font_matrix.xx = face->log_font.matrix[0] << 8; + font_matrix.yx = face->log_font.matrix[1] << 8; + font_matrix.xy = face->log_font.matrix[2] << 8; + font_matrix.yy = face->log_font.matrix[3] << 8; + FT_Outline_Transform( outline, &font_matrix ); + } +#endif +/* scale when needed */ + if ( scaling ) + { + FT_Int n; + FT_Fixed x_scale = pfrsize->metrics.x_scale; + FT_Fixed y_scale = pfrsize->metrics.y_scale; + FT_Vector* vec = outline->points; +/* scale outline points */ + for ( n = 0; n < outline->n_points; n++, vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } +/* scale the advance */ + metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); + metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); + } +/* compute the rest of the metrics */ + FT_Outline_Get_CBox( outline, &cbox ); + metrics->width = cbox.xMax - cbox.xMin; + metrics->height = cbox.yMax - cbox.yMin; + metrics->horiBearingX = cbox.xMin; + metrics->horiBearingY = cbox.yMax - metrics->height; + } + Exit: + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** KERNING METHOD *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( FT_Error ) +/* PFR_Face */ + pfr_face_get_kerning( FT_Face pfrface, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = PFR_Err_Ok; + PFR_PhyFont phy_font = &face->phy_font; + FT_UInt32 code1, code2, pair; + kerning->x = 0; + kerning->y = 0; + if ( glyph1 > 0 ) + glyph1--; + if ( glyph2 > 0 ) + glyph2--; +/* convert glyph indices to character codes */ + if ( glyph1 > phy_font->num_chars || + glyph2 > phy_font->num_chars ) + goto Exit; + code1 = phy_font->chars[glyph1].char_code; + code2 = phy_font->chars[glyph2].char_code; + pair = PFR_KERN_INDEX( code1, code2 ); +/* now search the list of kerning items */ + { + PFR_KernItem item = phy_font->kern_items; + FT_Stream stream = pfrface->stream; + for ( ; item; item = item->next ) + { + if ( pair >= item->pair1 && pair <= item->pair2 ) + goto FoundPair; + } + goto Exit; +/* we found an item, now parse it and find the value if any */ + FoundPair: + if ( FT_STREAM_SEEK( item->offset ) || + FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) + goto Exit; + { + FT_UInt count = item->pair_count; + FT_UInt size = item->pair_size; + FT_UInt power = (FT_UInt)ft_highpow2( (FT_UInt32)count ); + FT_UInt probe = power * size; + FT_UInt extra = count - power; + FT_Byte* base = stream->cursor; + FT_Bool twobytes = FT_BOOL( item->flags & 1 ); + FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 ); + FT_Byte* p; + FT_UInt32 cpair; + if ( extra > 0 ) + { + p = base + extra * size; + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + if ( cpair == pair ) + goto Found; + if ( cpair < pair ) + { + if ( twobyte_adj ) + p += 2; + else + p++; + base = p; + } + } + while ( probe > size ) + { + probe >>= 1; + p = base + probe; + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + if ( cpair == pair ) + goto Found; + if ( cpair < pair ) + base += probe; + } + p = base; + if ( twobytes ) + cpair = FT_NEXT_ULONG( p ); + else + cpair = PFR_NEXT_KPAIR( p ); + if ( cpair == pair ) + { + FT_Int value; + Found: + if ( twobyte_adj ) + value = FT_PEEK_SHORT( p ); + else + value = p[0]; + kerning->x = item->base_adj + value; + } + } + FT_FRAME_EXIT(); + } + Exit: + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* pfrdrivr.c */ +/* */ +/* FreeType PFR driver interface (body). */ +/* */ +/* Copyright 2002-2004, 2006, 2008, 2010, 2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* pfrdrivr.h */ +/* */ +/* High-level Type PFR driver interface (specification). */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define __PFRDRIVR_H__ +FT_BEGIN_HEADER + FT_EXPORT_VAR( const FT_Driver_ClassRec ) pfr_driver_class; +FT_END_HEADER +/* END */ + FT_CALLBACK_DEF( FT_Error ) +/* PFR_Face */ + pfr_get_kerning( FT_Face pfrface, + FT_UInt left, + FT_UInt right, + FT_Vector *avector ) + { + PFR_Face face = (PFR_Face)pfrface; + PFR_PhyFont phys = &face->phy_font; + pfr_face_get_kerning( pfrface, left, right, avector ); +/* convert from metrics to outline units when necessary */ + if ( phys->outline_resolution != phys->metrics_resolution ) + { + if ( avector->x != 0 ) + avector->x = FT_MulDiv( avector->x, phys->outline_resolution, + phys->metrics_resolution ); + if ( avector->y != 0 ) + avector->y = FT_MulDiv( avector->x, phys->outline_resolution, + phys->metrics_resolution ); + } + return PFR_Err_Ok; + } +/* + * PFR METRICS SERVICE + * + */ + FT_CALLBACK_DEF( FT_Error ) +/* PFR_Face */ + pfr_get_advance( FT_Face pfrface, + FT_UInt gindex, + FT_Pos *anadvance ) + { + PFR_Face face = (PFR_Face)pfrface; + FT_Error error = PFR_Err_Invalid_Argument; + *anadvance = 0; + if ( !gindex ) + goto Exit; + gindex--; + if ( face ) + { + PFR_PhyFont phys = &face->phy_font; + if ( gindex < phys->num_chars ) + { + *anadvance = phys->chars[gindex].advance; + error = PFR_Err_Ok; + } + } + Exit: + return error; + } + FT_CALLBACK_DEF( FT_Error ) +/* PFR_Face */ + pfr_get_metrics( FT_Face pfrface, + FT_UInt *anoutline_resolution, + FT_UInt *ametrics_resolution, + FT_Fixed *ametrics_x_scale, + FT_Fixed *ametrics_y_scale ) + { + PFR_Face face = (PFR_Face)pfrface; + PFR_PhyFont phys = &face->phy_font; + FT_Fixed x_scale, y_scale; + FT_Size size = face->root.size; + if ( anoutline_resolution ) + *anoutline_resolution = phys->outline_resolution; + if ( ametrics_resolution ) + *ametrics_resolution = phys->metrics_resolution; + x_scale = 0x10000L; + y_scale = 0x10000L; + if ( size ) + { + x_scale = FT_DivFix( size->metrics.x_ppem << 6, + phys->metrics_resolution ); + y_scale = FT_DivFix( size->metrics.y_ppem << 6, + phys->metrics_resolution ); + } + if ( ametrics_x_scale ) + *ametrics_x_scale = x_scale; + if ( ametrics_y_scale ) + *ametrics_y_scale = y_scale; + return PFR_Err_Ok; + } + FT_CALLBACK_TABLE_DEF + const FT_Service_PfrMetricsRec pfr_metrics_service_rec = + { + pfr_get_metrics, + pfr_face_get_kerning, + pfr_get_advance + }; +/* + * SERVICE LIST + * + */ + static const FT_ServiceDescRec pfr_services[] = + { + { FT_SERVICE_ID_PFR_METRICS, &pfr_metrics_service_rec }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_PFR }, + { NULL, NULL } + }; + FT_CALLBACK_DEF( FT_Module_Interface ) + pfr_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + return ft_service_list_lookup( pfr_services, service_id ); + } + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec pfr_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE, + sizeof ( FT_DriverRec ), + "pfr", + 0x10000L, + 0x20000L, + NULL, +/* FT_Module_Constructor */ + 0, +/* FT_Module_Destructor */ + 0, + pfr_get_service + }, + sizeof ( PFR_FaceRec ), + sizeof ( PFR_SizeRec ), + sizeof ( PFR_SlotRec ), + pfr_face_init, + pfr_face_done, +/* FT_Size_InitFunc */ + 0, +/* FT_Size_DoneFunc */ + 0, + pfr_slot_init, + pfr_slot_done, + pfr_slot_load, + pfr_get_kerning, +/* FT_Face_AttachFunc */ + 0, +/* FT_Face_GetAdvancesFunc */ + 0, +/* FT_Size_RequestFunc */ + 0, +/* FT_Size_SelectFunc */ + 0, + }; +/* END */ +/***************************************************************************/ +/* */ +/* pfrsbit.c */ +/* */ +/* FreeType PFR bitmap loader (body). */ +/* */ +/* Copyright 2002, 2003, 2006, 2009, 2010 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_COMPONENT +#define FT_COMPONENT trace_pfr +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** PFR BIT WRITER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct PFR_BitWriter_ + { +/* current line start */ + FT_Byte* line; +/* line size in bytes */ + FT_Int pitch; +/* width in pixels/bits */ + FT_Int width; +/* number of remaining rows to scan */ + FT_Int rows; +/* total number of bits to draw */ + FT_Int total; + } PFR_BitWriterRec, *PFR_BitWriter; + static void + pfr_bitwriter_init( PFR_BitWriter writer, + FT_Bitmap* target, + FT_Bool decreasing ) + { + writer->line = target->buffer; + writer->pitch = target->pitch; + writer->width = target->width; + writer->rows = target->rows; + writer->total = writer->width * writer->rows; + if ( !decreasing ) + { + writer->line += writer->pitch * ( target->rows-1 ); + writer->pitch = -writer->pitch; + } + } + static void + pfr_bitwriter_decode_bytes( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int n, reload; + FT_Int left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt val = 0; + FT_UInt c = 0; + n = (FT_Int)( limit - p ) * 8; + if ( n > writer->total ) + n = writer->total; + reload = n & 7; + for ( ; n > 0; n-- ) + { + if ( ( n & 7 ) == reload ) + val = *p++; + if ( val & 0x80 ) + c |= mask; + val <<= 1; + mask >>= 1; + if ( --left <= 0 ) + { + cur[0] = (FT_Byte)c; + left = writer->width; + mask = 0x80; + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur ++; + } + } + if ( mask != 0x80 ) + cur[0] = (FT_Byte)c; + } + static void + pfr_bitwriter_decode_rle1( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int n, phase, count, counts[2], reload; + FT_Int left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + n = writer->total; + phase = 1; + counts[0] = 0; + counts[1] = 0; + count = 0; + reload = 1; + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( phase ) + { + FT_Int v; + if ( p >= limit ) + break; + v = *p++; + counts[0] = v >> 4; + counts[1] = v & 15; + phase = 0; + count = counts[0]; + } + else + { + phase = 1; + count = counts[1]; + } + } while ( count == 0 ); + } + if ( phase ) + c |= mask; + mask >>= 1; + if ( --left <= 0 ) + { + cur[0] = (FT_Byte) c; + left = writer->width; + mask = 0x80; + writer->line += writer->pitch; + cur = writer->line; + c = 0; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + mask = 0x80; + c = 0; + cur ++; + } + reload = ( --count <= 0 ); + } + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } + static void + pfr_bitwriter_decode_rle2( PFR_BitWriter writer, + FT_Byte* p, + FT_Byte* limit ) + { + FT_Int n, phase, count, reload; + FT_Int left = writer->width; + FT_Byte* cur = writer->line; + FT_UInt mask = 0x80; + FT_UInt c = 0; + n = writer->total; + phase = 1; + count = 0; + reload = 1; + for ( ; n > 0; n-- ) + { + if ( reload ) + { + do + { + if ( p >= limit ) + break; + count = *p++; + phase = phase ^ 1; + } while ( count == 0 ); + } + if ( phase ) + c |= mask; + mask >>= 1; + if ( --left <= 0 ) + { + cur[0] = (FT_Byte) c; + c = 0; + mask = 0x80; + left = writer->width; + writer->line += writer->pitch; + cur = writer->line; + } + else if ( mask == 0 ) + { + cur[0] = (FT_Byte)c; + c = 0; + mask = 0x80; + cur ++; + } + reload = ( --count <= 0 ); + } + if ( mask != 0x80 ) + cur[0] = (FT_Byte) c; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** BITMAP DATA DECODING *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static void + pfr_lookup_bitmap_data( FT_Byte* base, + FT_Byte* limit, + FT_UInt count, + FT_UInt flags, + FT_UInt char_code, + FT_ULong* found_offset, + FT_ULong* found_size ) + { + FT_UInt left, right, char_len; + FT_Bool two = FT_BOOL( flags & 1 ); + FT_Byte* buff; + char_len = 4; + if ( two ) char_len += 1; + if ( flags & 2 ) char_len += 1; + if ( flags & 4 ) char_len += 1; + left = 0; + right = count; + while ( left < right ) + { + FT_UInt middle, code; + middle = ( left + right ) >> 1; + buff = base + middle * char_len; +/* check that we are not outside of the table -- */ +/* this is possible with broken fonts... */ + if ( buff + char_len > limit ) + goto Fail; + if ( two ) + code = PFR_NEXT_USHORT( buff ); + else + code = PFR_NEXT_BYTE( buff ); + if ( code == char_code ) + goto Found_It; + if ( code < char_code ) + left = middle; + else + right = middle; + } + Fail: +/* Not found */ + *found_size = 0; + *found_offset = 0; + return; + Found_It: + if ( flags & 2 ) + *found_size = PFR_NEXT_USHORT( buff ); + else + *found_size = PFR_NEXT_BYTE( buff ); + if ( flags & 4 ) + *found_offset = PFR_NEXT_ULONG( buff ); + else + *found_offset = PFR_NEXT_USHORT( buff ); + } +/* load bitmap metrics. "*padvance" must be set to the default value */ +/* before calling this function... */ +/* */ + static FT_Error + pfr_load_bitmap_metrics( FT_Byte** pdata, + FT_Byte* limit, + FT_Long scaled_advance, + FT_Long *axpos, + FT_Long *aypos, + FT_UInt *axsize, + FT_UInt *aysize, + FT_Long *aadvance, + FT_UInt *aformat ) + { + FT_Error error = PFR_Err_Ok; + FT_Byte flags; + FT_Char b; + FT_Byte* p = *pdata; + FT_Long xpos, ypos, advance; + FT_UInt xsize, ysize; + PFR_CHECK( 1 ); + flags = PFR_NEXT_BYTE( p ); + xpos = 0; + ypos = 0; + xsize = 0; + ysize = 0; + advance = 0; + switch ( flags & 3 ) + { + case 0: + PFR_CHECK( 1 ); + b = PFR_NEXT_INT8( p ); + xpos = b >> 4; + ypos = ( (FT_Char)( b << 4 ) ) >> 4; + break; + case 1: + PFR_CHECK( 2 ); + xpos = PFR_NEXT_INT8( p ); + ypos = PFR_NEXT_INT8( p ); + break; + case 2: + PFR_CHECK( 4 ); + xpos = PFR_NEXT_SHORT( p ); + ypos = PFR_NEXT_SHORT( p ); + break; + case 3: + PFR_CHECK( 6 ); + xpos = PFR_NEXT_LONG( p ); + ypos = PFR_NEXT_LONG( p ); + break; + default: + ; + } + flags >>= 2; + switch ( flags & 3 ) + { + case 0: +/* blank image */ + xsize = 0; + ysize = 0; + break; + case 1: + PFR_CHECK( 1 ); + b = PFR_NEXT_BYTE( p ); + xsize = ( b >> 4 ) & 0xF; + ysize = b & 0xF; + break; + case 2: + PFR_CHECK( 2 ); + xsize = PFR_NEXT_BYTE( p ); + ysize = PFR_NEXT_BYTE( p ); + break; + case 3: + PFR_CHECK( 4 ); + xsize = PFR_NEXT_USHORT( p ); + ysize = PFR_NEXT_USHORT( p ); + break; + default: + ; + } + flags >>= 2; + switch ( flags & 3 ) + { + case 0: + advance = scaled_advance; + break; + case 1: + PFR_CHECK( 1 ); + advance = PFR_NEXT_INT8( p ) << 8; + break; + case 2: + PFR_CHECK( 2 ); + advance = PFR_NEXT_SHORT( p ); + break; + case 3: + PFR_CHECK( 3 ); + advance = PFR_NEXT_LONG( p ); + break; + default: + ; + } + *axpos = xpos; + *aypos = ypos; + *axsize = xsize; + *aysize = ysize; + *aadvance = advance; + *aformat = flags >> 2; + *pdata = p; + Exit: + return error; + Too_Short: + error = PFR_Err_Invalid_Table; + FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" )); + goto Exit; + } + static FT_Error + pfr_load_bitmap_bits( FT_Byte* p, + FT_Byte* limit, + FT_UInt format, + FT_Bool decreasing, + FT_Bitmap* target ) + { + FT_Error error = PFR_Err_Ok; + PFR_BitWriterRec writer; + if ( target->rows > 0 && target->width > 0 ) + { + pfr_bitwriter_init( &writer, target, decreasing ); + switch ( format ) + { +/* packed bits */ + case 0: + pfr_bitwriter_decode_bytes( &writer, p, limit ); + break; +/* RLE1 */ + case 1: + pfr_bitwriter_decode_rle1( &writer, p, limit ); + break; +/* RLE2 */ + case 2: + pfr_bitwriter_decode_rle2( &writer, p, limit ); + break; + default: + FT_ERROR(( "pfr_read_bitmap_data: invalid image type\n" )); + error = PFR_Err_Invalid_File_Format; + } + } + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** BITMAP LOADING *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL( FT_Error ) + pfr_slot_load_bitmap( PFR_Slot glyph, + PFR_Size size, + FT_UInt glyph_index ) + { + FT_Error error; + PFR_Face face = (PFR_Face) glyph->root.face; + FT_Stream stream = face->root.stream; + PFR_PhyFont phys = &face->phy_font; + FT_ULong gps_offset; + FT_ULong gps_size; + PFR_Char character; + PFR_Strike strike; + character = &phys->chars[glyph_index]; +/* Look-up a bitmap strike corresponding to the current */ +/* character dimensions */ + { + FT_UInt n; + strike = phys->strikes; + for ( n = 0; n < phys->num_strikes; n++ ) + { + if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem && + strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem ) + { + goto Found_Strike; + } + strike++; + } +/* couldn't find it */ + return PFR_Err_Invalid_Argument; + } + Found_Strike: +/* Now lookup the glyph's position within the file */ + { + FT_UInt char_len; + char_len = 4; + if ( strike->flags & 1 ) char_len += 1; + if ( strike->flags & 2 ) char_len += 1; + if ( strike->flags & 4 ) char_len += 1; +/* Access data directly in the frame to speed lookups */ + if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || + FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) + goto Exit; + pfr_lookup_bitmap_data( stream->cursor, + stream->limit, + strike->num_bitmaps, + strike->flags, + character->char_code, + &gps_offset, + &gps_size ); + FT_FRAME_EXIT(); + if ( gps_size == 0 ) + { +/* Could not find a bitmap program string for this glyph */ + error = PFR_Err_Invalid_Argument; + goto Exit; + } + } +/* get the bitmap metrics */ + { + FT_Long xpos = 0, ypos = 0, advance = 0; + FT_UInt xsize = 0, ysize = 0, format = 0; + FT_Byte* p; +/* compute linear advance */ + advance = character->advance; + if ( phys->metrics_resolution != phys->outline_resolution ) + advance = FT_MulDiv( advance, + phys->outline_resolution, + phys->metrics_resolution ); + glyph->root.linearHoriAdvance = advance; +/* compute default advance, i.e., scaled advance. This can be */ +/* overridden in the bitmap header of certain glyphs. */ + advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8, + character->advance, + phys->metrics_resolution ); + if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) || + FT_FRAME_ENTER( gps_size ) ) + goto Exit; + p = stream->cursor; + error = pfr_load_bitmap_metrics( &p, stream->limit, + advance, + &xpos, &ypos, + &xsize, &ysize, + &advance, &format ); +/* + * XXX: on 16bit system, we return an error for huge bitmap + * which causes a size truncation, because truncated + * size properties makes bitmap glyph broken. + */ + if ( xpos > FT_INT_MAX || ( ypos + ysize ) > FT_INT_MAX ) + { + FT_TRACE1(( "pfr_slot_load_bitmap:" )); + FT_TRACE1(( "huge bitmap glyph %dx%d over FT_GlyphSlot\n", + xpos, ypos )); + error = PFR_Err_Invalid_Pixel_Size; + } + if ( !error ) + { + glyph->root.format = FT_GLYPH_FORMAT_BITMAP; +/* Set up glyph bitmap and metrics */ +/* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */ + glyph->root.bitmap.width = (FT_Int)xsize; + glyph->root.bitmap.rows = (FT_Int)ysize; + glyph->root.bitmap.pitch = (FT_Int)( xsize + 7 ) >> 3; + glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; +/* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */ + glyph->root.metrics.width = (FT_Pos)xsize << 6; + glyph->root.metrics.height = (FT_Pos)ysize << 6; + glyph->root.metrics.horiBearingX = xpos << 6; + glyph->root.metrics.horiBearingY = ypos << 6; + glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) ); + glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; + glyph->root.metrics.vertBearingY = 0; + glyph->root.metrics.vertAdvance = size->root.metrics.height; +/* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */ + glyph->root.bitmap_left = (FT_Int)xpos; + glyph->root.bitmap_top = (FT_Int)(ypos + ysize); +/* Allocate and read bitmap data */ + { + FT_ULong len = glyph->root.bitmap.pitch * ysize; + error = ft_glyphslot_alloc_bitmap( &glyph->root, len ); + if ( !error ) + { + error = pfr_load_bitmap_bits( + p, + stream->limit, + format, + FT_BOOL(face->header.color_flags & 2), + &glyph->root.bitmap ); + } + } + } + FT_FRAME_EXIT(); + } + Exit: + return error; + } +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* truetype.c */ +/* */ +/* FreeType TrueType driver component (body only). */ +/* */ +/* Copyright 1996-2001, 2004, 2006, 2012 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* ttpic.c */ +/* */ +/* The FreeType position independent code services for truetype module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ttpic.h */ +/* */ +/* The FreeType position independent code services for truetype module. */ +/* */ +/* Copyright 2009, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __TTPIC_H__ +FT_BEGIN_HEADER +#define TT_SERVICES_GET tt_services +#define TT_SERVICE_GX_MULTI_MASTERS_GET tt_service_gx_multi_masters +#define TT_SERVICE_TRUETYPE_GLYF_GET tt_service_truetype_glyf +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* tterrors.h */ +/* */ +/* TrueType error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 TrueType error enumeration */ +/* constants. */ +/* */ +/*************************************************************************/ +#define __TTERRORS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX TT_Err_ +#define FT_ERR_BASE FT_Mod_Err_TrueType +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/* driver interface */ +/***************************************************************************/ +/* */ +/* ttdriver.c */ +/* */ +/* TrueType font driver implementation (body). */ +/* */ +/* Copyright 1996-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ttdriver.h */ +/* */ +/* High-level TrueType driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ +#define __TTDRIVER_H__ +FT_BEGIN_HEADER + FT_DECLARE_DRIVER( tt_driver_class ) +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttgload.h */ +/* */ +/* TrueType Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2006, 2008, 2011 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. */ +/* */ +/***************************************************************************/ +#define __TTGLOAD_H__ +/***************************************************************************/ +/* */ +/* ttobjs.h */ +/* */ +/* Objects manager (specification). */ +/* */ +/* Copyright 1996-2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +#define __TTOBJS_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Type> */ +/* TT_Driver */ +/* */ +/* <Description> */ +/* A handle to a TrueType driver object. */ +/* */ + typedef struct TT_DriverRec_* TT_Driver; +/*************************************************************************/ +/* */ +/* <Type> */ +/* TT_Instance */ +/* */ +/* <Description> */ +/* A handle to a TrueType size object. */ +/* */ + typedef struct TT_SizeRec_* TT_Size; +/*************************************************************************/ +/* */ +/* <Type> */ +/* TT_GlyphSlot */ +/* */ +/* <Description> */ +/* A handle to a TrueType glyph slot object. */ +/* */ +/* <Note> */ +/* This is a direct typedef of FT_GlyphSlot, as there is nothing */ +/* specific about the TrueType glyph slot. */ +/* */ + typedef FT_GlyphSlot TT_GlyphSlot; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* TT_GraphicsState */ +/* */ +/* <Description> */ +/* The TrueType graphics state used during bytecode interpretation. */ +/* */ + typedef struct TT_GraphicsState_ + { + FT_UShort rp0; + FT_UShort rp1; + FT_UShort rp2; + FT_UnitVector dualVector; + FT_UnitVector projVector; + FT_UnitVector freeVector; + FT_Long loop; + FT_F26Dot6 minimum_distance; + FT_Int round_state; + FT_Bool auto_flip; + FT_F26Dot6 control_value_cutin; + FT_F26Dot6 single_width_cutin; + FT_F26Dot6 single_width_value; + FT_Short delta_base; + FT_Short delta_shift; + FT_Byte instruct_control; +/* According to Greg Hitchcock from Microsoft, the `scan_control' */ +/* variable as documented in the TrueType specification is a 32-bit */ +/* integer; the high-word part holds the SCANTYPE value, the low-word */ +/* part the SCANCTRL value. We separate it into two fields. */ + FT_Bool scan_control; + FT_Int scan_type; + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + } TT_GraphicsState; + FT_LOCAL( void ) + tt_glyphzone_done( TT_GlyphZone zone ); + FT_LOCAL( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone zone ); +/*************************************************************************/ +/* */ +/* EXECUTION SUBTABLES */ +/* */ +/* These sub-tables relate to instruction execution. */ +/* */ +/*************************************************************************/ +#define TT_MAX_CODE_RANGES 3 +/*************************************************************************/ +/* */ +/* There can only be 3 active code ranges at once: */ +/* - the Font Program */ +/* - the CVT Program */ +/* - a glyph's instructions set */ +/* */ + typedef enum TT_CodeRange_Tag_ + { + tt_coderange_none = 0, + tt_coderange_font, + tt_coderange_cvt, + tt_coderange_glyph + } TT_CodeRange_Tag; + typedef struct TT_CodeRange_ + { + FT_Byte* base; + FT_ULong size; + } TT_CodeRange; + typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; +/*************************************************************************/ +/* */ +/* Defines a function/instruction definition record. */ +/* */ + typedef struct TT_DefRecord_ + { +/* in which code range is it located? */ + FT_Int range; +/* where does it start? */ + FT_Long start; +/* where does it end? */ + FT_Long end; +/* function #, or instruction code */ + FT_UInt opc; +/* is it active? */ + FT_Bool active; +/* is function that defines inline delta? */ + FT_Bool inline_delta; + } TT_DefRecord, *TT_DefArray; +/*************************************************************************/ +/* */ +/* Subglyph transformation record. */ +/* */ + typedef struct TT_Transform_ + { +/* transformation matrix coefficients */ + FT_Fixed xx, xy; + FT_Fixed yx, yy; +/* offsets */ + FT_F26Dot6 ox, oy; + } TT_Transform; +/*************************************************************************/ +/* */ +/* A note regarding non-squared pixels: */ +/* */ +/* (This text will probably go into some docs at some time; for now, it */ +/* is kept here to explain some definitions in the TT_Size_Metrics */ +/* record). */ +/* */ +/* The CVT is a one-dimensional array containing values that control */ +/* certain important characteristics in a font, like the height of all */ +/* capitals, all lowercase letter, default spacing or stem width/height. */ +/* */ +/* These values are found in FUnits in the font file, and must be scaled */ +/* to pixel coordinates before being used by the CVT and glyph programs. */ +/* Unfortunately, when using distinct x and y resolutions (or distinct x */ +/* and y pointsizes), there are two possible scalings. */ +/* */ +/* A first try was to implement a `lazy' scheme where all values were */ +/* scaled when first used. However, while some values are always used */ +/* in the same direction, some others are used under many different */ +/* circumstances and orientations. */ +/* */ +/* I have found a simpler way to do the same, and it even seems to work */ +/* in most of the cases: */ +/* */ +/* - All CVT values are scaled to the maximum ppem size. */ +/* */ +/* - When performing a read or write in the CVT, a ratio factor is used */ +/* to perform adequate scaling. Example: */ +/* */ +/* x_ppem = 14 */ +/* y_ppem = 10 */ +/* */ +/* We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt */ +/* entries are scaled to it. */ +/* */ +/* x_ratio = 1.0 */ +/* y_ratio = y_ppem/ppem (< 1.0) */ +/* */ +/* We compute the current ratio like: */ +/* */ +/* - If projVector is horizontal, */ +/* ratio = x_ratio = 1.0 */ +/* */ +/* - if projVector is vertical, */ +/* ratio = y_ratio */ +/* */ +/* - else, */ +/* ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) */ +/* */ +/* Reading a cvt value returns */ +/* ratio * cvt[index] */ +/* */ +/* Writing a cvt value in pixels: */ +/* cvt[index] / ratio */ +/* */ +/* The current ppem is simply */ +/* ratio * ppem */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Metrics used by the TrueType size and context objects. */ +/* */ + typedef struct TT_Size_Metrics_ + { +/* for non-square pixels */ + FT_Long x_ratio; + FT_Long y_ratio; +/* maximum ppem size */ + FT_UShort ppem; +/* current ratio */ + FT_Long ratio; + FT_Fixed scale; +/* device-specific compensations */ + FT_F26Dot6 compensations[4]; + FT_Bool valid; +/* `is the glyph rotated?'-flag */ + FT_Bool rotated; +/* `is the glyph stretched?'-flag */ + FT_Bool stretched; + } TT_Size_Metrics; +/*************************************************************************/ +/* */ +/* TrueType size class. */ +/* */ + typedef struct TT_SizeRec_ + { + FT_SizeRec root; +/* we have our own copy of metrics so that we can modify */ +/* it without affecting auto-hinting (when used) */ + FT_Size_Metrics metrics; + TT_Size_Metrics ttmetrics; +/* 0xFFFFFFFF to indicate invalid */ + FT_ULong strike_index; +/* number of function definitions */ + FT_UInt num_function_defs; + FT_UInt max_function_defs; +/* table of function definitions */ + TT_DefArray function_defs; +/* number of ins. definitions */ + FT_UInt num_instruction_defs; + FT_UInt max_instruction_defs; +/* table of ins. definitions */ + TT_DefArray instruction_defs; + FT_UInt max_func; + FT_UInt max_ins; + TT_CodeRangeTable codeRangeTable; + TT_GraphicsState GS; +/* the scaled control value table */ + FT_ULong cvt_size; + FT_Long* cvt; +/* The storage area is now part of */ + FT_UShort storage_size; +/* the instance */ + FT_Long* storage; +/* The instance's twilight zone */ + TT_GlyphZoneRec twilight; +/* debugging variables */ +/* When using the debugger, we must keep the */ +/* execution context tied to the instance */ +/* object rather than asking it on demand. */ + FT_Bool debug; + TT_ExecContext context; + FT_Bool bytecode_ready; + FT_Bool cvt_ready; + FT_Bool ttfautohinted; + } TT_SizeRec; +/*************************************************************************/ +/* */ +/* TrueType driver class. */ +/* */ + typedef struct TT_DriverRec_ + { + FT_DriverRec root; +/* execution context */ + TT_ExecContext context; +/* glyph loader points zone */ + TT_GlyphZoneRec zone; + void* extension_component; + } TT_DriverRec; +/* Note: All of the functions below (except tt_size_reset()) are used */ +/* as function pointers in a FT_Driver_ClassRec. Therefore their */ +/* parameters are of types FT_Face, FT_Size, etc., rather than TT_Face, */ +/* TT_Size, etc., so that the compiler can confirm that the types and */ +/* number of parameters are correct. In all cases the FT_xxx types are */ +/* cast to their TT_xxx counterparts inside the functions since FreeType */ +/* will always use the TT driver to create them. */ +/*************************************************************************/ +/* */ +/* Face functions */ +/* */ + FT_LOCAL( FT_Error ) + tt_face_init( FT_Stream stream, +/* TT_Face */ + FT_Face ttface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) +/* TT_Face */ + tt_face_done( FT_Face ttface ); +/*************************************************************************/ +/* */ +/* Size functions */ +/* */ + FT_LOCAL( FT_Error ) +/* TT_Size */ + tt_size_init( FT_Size ttsize ); + FT_LOCAL( void ) +/* TT_Size */ + tt_size_done( FT_Size ttsize ); + FT_LOCAL( FT_Error ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ); + FT_LOCAL( FT_Error ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ); + FT_LOCAL( FT_Error ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ); + FT_LOCAL( FT_Error ) + tt_size_reset( TT_Size size ); +/*************************************************************************/ +/* */ +/* Driver functions */ +/* */ + FT_LOCAL( FT_Error ) +/* TT_Driver */ + tt_driver_init( FT_Module ttdriver ); + FT_LOCAL( void ) +/* TT_Driver */ + tt_driver_done( FT_Module ttdriver ); +/*************************************************************************/ +/* */ +/* Slot functions */ +/* */ + FT_LOCAL( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ); +/* auxiliary */ +#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttinterp.h */ +/* */ +/* TrueType bytecode interpreter (specification). */ +/* */ +/* Copyright 1996-2007, 2010, 2012 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. */ +/* */ +/***************************************************************************/ +#define __TTINTERP_H__ +FT_BEGIN_HEADER +/* indirect implementation */ +#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER +#define EXEC_OP_ TT_ExecContext exc, +#define EXEC_OP TT_ExecContext exc +#define EXEC_ARG_ exc, +#define EXEC_ARG exc +/* static implementation */ +#else +/* void */ +#define EXEC_OP_ +/* void */ +#define EXEC_OP +/* void */ +#define EXEC_ARG_ +/* void */ +#define EXEC_ARG +/* TT_CONFIG_OPTION_STATIC_INTERPRETER */ +#endif +/*************************************************************************/ +/* */ +/* Rounding mode constants. */ +/* */ +#define TT_Round_Off 5 +#define TT_Round_To_Half_Grid 0 +#define TT_Round_To_Grid 1 +#define TT_Round_To_Double_Grid 2 +#define TT_Round_Up_To_Grid 4 +#define TT_Round_Down_To_Grid 3 +#define TT_Round_Super 6 +#define TT_Round_Super_45 7 +/*************************************************************************/ +/* */ +/* Function types used by the interpreter, depending on various modes */ +/* (e.g. the rounding mode, whether to render a vertical or horizontal */ +/* line etc). */ +/* */ +/*************************************************************************/ +/* Rounding function */ + typedef FT_F26Dot6 + (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ); +/* Point displacement along the freedom vector routine */ + typedef void + (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ); +/* Distance projection along one of the projection vectors */ + typedef FT_F26Dot6 + (*TT_Project_Func)( EXEC_OP_ FT_Pos dx, + FT_Pos dy ); +/* reading a cvt value. Take care of non-square pixels if necessary */ + typedef FT_F26Dot6 + (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong idx ); +/* setting or moving a cvt value. Take care of non-square pixels */ +/* if necessary */ + typedef void + (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ); +/*************************************************************************/ +/* */ +/* This structure defines a call record, used to manage function calls. */ +/* */ + typedef struct TT_CallRec_ + { + FT_Int Caller_Range; + FT_Long Caller_IP; + FT_Long Cur_Count; + FT_Long Cur_Restart; + FT_Long Cur_End; + } TT_CallRec, *TT_CallStack; +/*************************************************************************/ +/* */ +/* The main structure for the interpreter which collects all necessary */ +/* variables and states. */ +/* */ + typedef struct TT_ExecContextRec_ + { + TT_Face face; + TT_Size size; + FT_Memory memory; +/* instructions state */ +/* last execution error */ + FT_Error error; +/* top of exec. stack */ + FT_Long top; +/* size of exec. stack */ + FT_UInt stackSize; +/* current exec. stack */ + FT_Long* stack; + FT_Long args; +/* new top after exec. */ + FT_UInt new_top; +/* zone records */ + TT_GlyphZoneRec zp0, + zp1, + zp2, + pts, + twilight; + FT_Size_Metrics metrics; +/* size metrics */ + TT_Size_Metrics tt_metrics; +/* current graphics state */ + TT_GraphicsState GS; +/* current code range number */ + FT_Int curRange; +/* current code range */ + FT_Byte* code; +/* current instruction pointer */ + FT_Long IP; +/* size of current range */ + FT_Long codeSize; +/* current opcode */ + FT_Byte opcode; +/* length of current opcode */ + FT_Int length; +/* true if the interpreter must */ + FT_Bool step_ins; +/* increment IP after ins. exec */ + FT_ULong cvtSize; + FT_Long* cvt; +/* glyph instructions buffer size */ + FT_UInt glyphSize; +/* glyph instructions buffer */ + FT_Byte* glyphIns; +/* number of function defs */ + FT_UInt numFDefs; +/* maximum number of function defs */ + FT_UInt maxFDefs; +/* table of FDefs entries */ + TT_DefArray FDefs; +/* number of instruction defs */ + FT_UInt numIDefs; +/* maximum number of ins defs */ + FT_UInt maxIDefs; +/* table of IDefs entries */ + TT_DefArray IDefs; +/* maximum function index */ + FT_UInt maxFunc; +/* maximum instruction index */ + FT_UInt maxIns; +/* top of call stack during execution */ + FT_Int callTop, +/* size of call stack */ + callSize; +/* call stack */ + TT_CallStack callStack; +/* capacity of this context's `pts' */ + FT_UShort maxPoints; +/* record, expressed in points and */ + FT_Short maxContours; +/* contours. */ +/* table of valid code ranges */ + TT_CodeRangeTable codeRangeTable; +/* useful for the debugger */ +/* size of current storage */ + FT_UShort storeSize; +/* storage area */ + FT_Long* storage; +/* values used for the */ + FT_F26Dot6 period; +/* `SuperRounding' */ + FT_F26Dot6 phase; + FT_F26Dot6 threshold; +#if 0 +/* this seems to be unused */ +/* ppem along the current proj vector */ + FT_Int cur_ppem; +#endif +/* If `True', the interpreter will */ + FT_Bool instruction_trap; +/* exit after each instruction */ +/* graphics state resulting from */ + TT_GraphicsState default_GS; +/* the prep program */ +/* true if the glyph is composite */ + FT_Bool is_composite; +/* true if pedantic interpretation */ + FT_Bool pedantic_hinting; +/* latest interpreter additions */ +/* dot product of freedom and projection */ + FT_Long F_dot_P; +/* vectors */ +/* current rounding function */ + TT_Round_Func func_round; +/* current projection function */ + TT_Project_Func func_project, +/* current dual proj. function */ + func_dualproj, +/* current freedom proj. func */ + func_freeProj; +/* current point move function */ + TT_Move_Func func_move; +/* move original position function */ + TT_Move_Func func_move_orig; +/* read a cvt entry */ + TT_Get_CVT_Func func_read_cvt; +/* write a cvt entry (in pixels) */ + TT_Set_CVT_Func func_write_cvt; +/* incr a cvt entry (in pixels) */ + TT_Set_CVT_Func func_move_cvt; +/* are we hinting for grayscale? */ + FT_Bool grayscale; + } TT_ExecContextRec; + extern const TT_GraphicsState tt_default_graphics_state; + FT_LOCAL( FT_Error ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ); + FT_LOCAL( FT_Error ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ); + FT_LOCAL( FT_Error ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ); + FT_LOCAL( FT_Error ) + Update_Max( FT_Memory memory, + FT_ULong* size, + FT_Long multiplier, + void* _pbuff, + FT_ULong new_max ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_New_Context */ +/* */ +/* <Description> */ +/* Queries the face context for a given font. Note that there is */ +/* now a _single_ execution context in the TrueType driver which is */ +/* shared among faces. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* <Return> */ +/* A handle to the execution context. Initialized for `face'. */ +/* */ +/* <Note> */ +/* Only the glyph loader and debugger should call this function. */ +/* */ + FT_EXPORT( TT_ExecContext ) + TT_New_Context( TT_Driver driver ); + FT_LOCAL( FT_Error ) + TT_Done_Context( TT_ExecContext exec ); + FT_LOCAL( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ); + FT_LOCAL( FT_Error ) + TT_Save_Context( TT_ExecContext exec, + TT_Size ins ); + FT_LOCAL( FT_Error ) + TT_Run_Context( TT_ExecContext exec, + FT_Bool debug ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_RunIns */ +/* */ +/* <Description> */ +/* Executes one or more instruction in the execution context. This */ +/* is the main function of the TrueType opcode interpreter. */ +/* */ +/* <Input> */ +/* exec :: A handle to the target execution context. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only the object manager and debugger should call this function. */ +/* */ +/* This function is publicly exported because it is directly */ +/* invoked by the TrueType debugger. */ +/* */ + FT_EXPORT( FT_Error ) + TT_RunIns( TT_ExecContext exec ); +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER + FT_LOCAL( void ) + TT_Init_Glyph_Loading( TT_Face face ); + FT_LOCAL( void ) + TT_Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Short* lsb, + FT_UShort* aw ); + FT_LOCAL( void ) + TT_Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Short* tsb, + FT_UShort* ah ); + FT_LOCAL( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttpload.h */ +/* */ +/* TrueType-specific tables loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2005, 2006 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. */ +/* */ +/***************************************************************************/ +#define __TTPLOAD_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_ULong ) + tt_face_get_location( TT_Face face, + FT_UInt gindex, + FT_UInt *asize ); + FT_LOCAL( void ) + tt_face_done_loca( TT_Face face ); + FT_LOCAL( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ); + FT_LOCAL( void ) + tt_face_free_hdmx( TT_Face face ); + FT_LOCAL( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ttgxvar.h */ +/* */ +/* TrueType GX Font Variation loader (specification) */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, Werner Lemberg and George Williams. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __TTGXVAR_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Struct> */ +/* GX_AVarCorrespondenceRec */ +/* */ +/* <Description> */ +/* A data structure representing `shortFracCorrespondence' in `avar' */ +/* table according to the specifications from Apple. */ +/* */ + typedef struct GX_AVarCorrespondenceRec_ + { + FT_Fixed fromCoord; + FT_Fixed toCoord; + } GX_AVarCorrespondenceRec_, *GX_AVarCorrespondence; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* GX_AVarRec */ +/* */ +/* <Description> */ +/* Data from the segment field of `avar' table. */ +/* There is one of these for each axis. */ +/* */ + typedef struct GX_AVarSegmentRec_ + { + FT_UShort pairCount; +/* array with pairCount entries */ + GX_AVarCorrespondence correspondence; + } GX_AVarSegmentRec, *GX_AVarSegment; +/*************************************************************************/ +/* */ +/* <Struct> */ +/* GX_BlendRec */ +/* */ +/* <Description> */ +/* Data for interpolating a font from a distortable font specified */ +/* by the GX *var tables ([fgca]var). */ +/* */ +/* <Fields> */ +/* num_axis :: The number of axes along which interpolation */ +/* may happen */ +/* */ +/* normalizedcoords :: A normalized value (between [-1,1]) indicating */ +/* the contribution along each axis to the final */ +/* interpolated font. */ +/* */ + typedef struct GX_BlendRec_ + { + FT_UInt num_axis; + FT_Fixed* normalizedcoords; + FT_MM_Var* mmvar; + FT_Offset mmvar_len; + FT_Bool avar_checked; + GX_AVarSegment avar_segment; +/* shared tuples in `gvar' */ + FT_UInt tuplecount; +/* tuplecoords[tuplecount][num_axis] */ + FT_Fixed* tuplecoords; + FT_UInt gv_glyphcnt; + FT_ULong* glyphoffsets; + } GX_BlendRec; +/*************************************************************************/ +/* */ +/* <enum> */ +/* GX_TupleCountFlags */ +/* */ +/* <Description> */ +/* Flags used within the `TupleCount' field of the `gvar' table. */ +/* */ + typedef enum GX_TupleCountFlags_ + { + GX_TC_TUPLES_SHARE_POINT_NUMBERS = 0x8000, + GX_TC_RESERVED_TUPLE_FLAGS = 0x7000, + GX_TC_TUPLE_COUNT_MASK = 0x0FFF + } GX_TupleCountFlags; +/*************************************************************************/ +/* */ +/* <enum> */ +/* GX_TupleIndexFlags */ +/* */ +/* <Description> */ +/* Flags used within the `TupleIndex' field of the `gvar' and `cvar' */ +/* tables. */ +/* */ + typedef enum GX_TupleIndexFlags_ + { + GX_TI_EMBEDDED_TUPLE_COORD = 0x8000, + GX_TI_INTERMEDIATE_TUPLE = 0x4000, + GX_TI_PRIVATE_POINT_NUMBERS = 0x2000, + GX_TI_RESERVED_TUPLE_FLAG = 0x1000, + GX_TI_TUPLE_INDEX_MASK = 0x0FFF + } GX_TupleIndexFlags; +#define TTAG_wght FT_MAKE_TAG( 'w', 'g', 'h', 't' ) +#define TTAG_wdth FT_MAKE_TAG( 'w', 'd', 't', 'h' ) +#define TTAG_opsz FT_MAKE_TAG( 'o', 'p', 's', 'z' ) +#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' ) + FT_LOCAL( FT_Error ) + TT_Set_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + FT_LOCAL( FT_Error ) + TT_Set_Var_Design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + FT_LOCAL( FT_Error ) + TT_Get_MM_Var( TT_Face face, + FT_MM_Var* *master ); + FT_LOCAL( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ); + FT_LOCAL( FT_Error ) + TT_Vary_Get_Glyph_Deltas( TT_Face face, + FT_UInt glyph_index, + FT_Vector* *deltas, + FT_UInt n_points ); + FT_LOCAL( void ) + tt_done_blend( FT_Memory memory, + GX_Blend blend ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ttdriver +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** F A C E S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +#undef PAIR_TAG +#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \ + (FT_ULong)right ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_get_kerning */ +/* */ +/* <Description> */ +/* A driver method used to return the kerning vector between two */ +/* glyphs of the same face. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* left_glyph :: The index of the left glyph in the kern pair. */ +/* */ +/* right_glyph :: The index of the right glyph in the kern pair. */ +/* */ +/* <Output> */ +/* kerning :: The kerning vector. This is in font units for */ +/* scalable formats, and in pixels for fixed-sizes */ +/* formats. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only horizontal layouts (left-to-right & right-to-left) are */ +/* supported by this function. Other layouts, or more sophisticated */ +/* kernings, are out of scope of this method (the basic driver */ +/* interface is meant to be simple). */ +/* */ +/* They can be implemented by format-specific interfaces. */ +/* */ + static FT_Error +/* TT_Face */ + tt_get_kerning( FT_Face ttface, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + TT_Face face = (TT_Face)ttface; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + kerning->x = 0; + kerning->y = 0; + if ( sfnt ) + kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); + return 0; + } +#undef PAIR_TAG + static FT_Error + tt_get_advances( FT_Face ttface, + FT_UInt start, + FT_UInt count, + FT_Int32 flags, + FT_Fixed *advances ) + { + FT_UInt nn; + TT_Face face = (TT_Face) ttface; +/* XXX: TODO: check for sbits */ + if ( flags & FT_LOAD_VERTICAL_LAYOUT ) + { + for ( nn = 0; nn < count; nn++ ) + { + FT_Short tsb; + FT_UShort ah; + TT_Get_VMetrics( face, start + nn, &tsb, &ah ); + advances[nn] = ah; + } + } + else + { + for ( nn = 0; nn < count; nn++ ) + { + FT_Short lsb; + FT_UShort aw; + TT_Get_HMetrics( face, start + nn, &lsb, &aw ); + advances[nn] = aw; + } + } + return TT_Err_Ok; + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** S I Z E S ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + tt_size_select( FT_Size size, + FT_ULong strike_index ) + { + TT_Face ttface = (TT_Face)size->face; + TT_Size ttsize = (TT_Size)size; + FT_Error error = TT_Err_Ok; + ttsize->strike_index = strike_index; + if ( FT_IS_SCALABLE( size->face ) ) + { +/* use the scaled metrics, even when tt_size_reset fails */ + FT_Select_Metrics( size->face, strike_index ); + tt_size_reset( ttsize ); + } + else + { + SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; + FT_Size_Metrics* metrics = &size->metrics; + error = sfnt->load_strike_metrics( ttface, strike_index, metrics ); + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + } + return error; + } + static FT_Error + tt_size_request( FT_Size size, + FT_Size_Request req ) + { + TT_Size ttsize = (TT_Size)size; + FT_Error error = TT_Err_Ok; + if ( FT_HAS_FIXED_SIZES( size->face ) ) + { + TT_Face ttface = (TT_Face)size->face; + SFNT_Service sfnt = (SFNT_Service) ttface->sfnt; + FT_ULong strike_index; + error = sfnt->set_sbit_strike( ttface, req, &strike_index ); + if ( error ) + ttsize->strike_index = 0xFFFFFFFFUL; + else + return tt_size_select( size, strike_index ); + } + FT_Request_Metrics( size->face, req ); + if ( FT_IS_SCALABLE( size->face ) ) + { + error = tt_size_reset( ttsize ); + ttsize->root.metrics = ttsize->metrics; + } + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_glyph_load */ +/* */ +/* <Description> */ +/* A driver method used to load a glyph within a given glyph slot. */ +/* */ +/* <Input> */ +/* slot :: A handle to the target slot object where the glyph */ +/* will be loaded. */ +/* */ +/* size :: A handle to the source face size at which the glyph */ +/* must be scaled, loaded, etc. */ +/* */ +/* glyph_index :: The index of the glyph in the font file. */ +/* */ +/* load_flags :: A flag indicating what to load for this glyph. The */ +/* FT_LOAD_XXX constants can be used to control the */ +/* glyph loading process (e.g., whether the outline */ +/* should be scaled, whether to load bitmaps or not, */ +/* whether to hint the outline, etc). */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + static FT_Error +/* TT_GlyphSlot */ + tt_glyph_load( FT_GlyphSlot ttslot, +/* TT_Size */ + FT_Size ttsize, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_GlyphSlot slot = (TT_GlyphSlot)ttslot; + TT_Size size = (TT_Size)ttsize; + FT_Face face = ttslot->face; + FT_Error error; + if ( !slot ) + return TT_Err_Invalid_Slot_Handle; + if ( !size ) + return TT_Err_Invalid_Size_Handle; + if ( !face ) + return TT_Err_Invalid_Argument; + if ( glyph_index >= (FT_UInt)face->num_glyphs && + !face->internal->incremental_interface ) + return TT_Err_Invalid_Argument; + if ( load_flags & FT_LOAD_NO_HINTING ) + { +/* both FT_LOAD_NO_HINTING and FT_LOAD_NO_AUTOHINT */ +/* are necessary to disable hinting for tricky fonts */ + if ( FT_IS_TRICKY( face ) ) + load_flags &= ~FT_LOAD_NO_HINTING; + if ( load_flags & FT_LOAD_NO_AUTOHINT ) + load_flags |= FT_LOAD_NO_HINTING; + } + if ( load_flags & ( FT_LOAD_NO_RECURSE | FT_LOAD_NO_SCALE ) ) + { + load_flags |= FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE; + if ( !FT_IS_TRICKY( face ) ) + load_flags |= FT_LOAD_NO_HINTING; + } +/* now load the glyph outline if necessary */ + error = TT_Load_Glyph( size, slot, glyph_index, load_flags ); +/* force drop-out mode to 2 - irrelevant now */ +/* slot->outline.dropout_mode = 2; */ + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** ****/ +/**** D R I V E R I N T E R F A C E ****/ +/**** ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + FT_DEFINE_SERVICE_MULTIMASTERSREC( + tt_service_gx_multi_masters, + (FT_Get_MM_Func) NULL, + (FT_Set_MM_Design_Func) NULL, + (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, + (FT_Get_MM_Var_Func) TT_Get_MM_Var, + (FT_Set_Var_Design_Func)TT_Set_Var_Design ) + static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = + { + FT_TRUETYPE_ENGINE_TYPE_PATENTED + }; + FT_DEFINE_SERVICE_TTGLYFREC( + tt_service_truetype_glyf, + (TT_Glyf_GetLocationFunc)tt_face_get_location ) + FT_DEFINE_SERVICEDESCREC4( + tt_services, + FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TRUETYPE, + FT_SERVICE_ID_MULTI_MASTERS, &TT_SERVICE_GX_MULTI_MASTERS_GET, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &TT_SERVICE_TRUETYPE_GLYF_GET ) + FT_CALLBACK_DEF( FT_Module_Interface ) +/* TT_Driver */ + tt_get_interface( FT_Module driver, + const char* tt_interface ) + { + FT_Library library; + FT_Module_Interface result; + FT_Module sfntd; + SFNT_Service sfnt; +/* TT_SERVICES_GET derefers `library' in PIC mode */ + result = ft_service_list_lookup( TT_SERVICES_GET, tt_interface ); + if ( result != NULL ) + return result; + if ( !driver ) + return NULL; + library = driver->library; + if ( !library ) + return NULL; +/* only return the default interface from the SFNT module */ + sfntd = FT_Get_Module( library, "sfnt" ); + if ( sfntd ) + { + sfnt = (SFNT_Service)( sfntd->clazz->module_interface ); + if ( sfnt ) + return sfnt->get_interface( driver, tt_interface ); + } + return 0; + } +/* The FT_DriverInterface structure is defined in ftdriver.h. */ +#define TT_HINTER_FLAG FT_MODULE_DRIVER_HAS_HINTER +#define TT_SIZE_SELECT tt_size_select + FT_DEFINE_DRIVER( tt_driver_class, + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + TT_HINTER_FLAG, + sizeof ( TT_DriverRec ), +/* driver name */ + "truetype", +/* driver version == 1.0 */ + 0x10000L, +/* driver requires FreeType 2.0 or above */ + 0x20000L, +/* driver specific interface */ + (void*)0, + tt_driver_init, + tt_driver_done, + tt_get_interface, + sizeof ( TT_FaceRec ), + sizeof ( TT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + tt_face_init, + tt_face_done, + tt_size_init, + tt_size_done, + tt_slot_init, +/* FT_Slot_DoneFunc */ + 0, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + ft_stub_set_char_sizes, +/* FT_CONFIG_OPTION_OLD_INTERNALS */ + ft_stub_set_pixel_sizes, + tt_glyph_load, + tt_get_kerning, +/* FT_Face_AttachFunc */ + 0, + tt_get_advances, + tt_size_request, + TT_SIZE_SELECT + ) +/* END */ +/* tables loader */ +/***************************************************************************/ +/* */ +/* ttpload.c */ +/* */ +/* TrueType-specific tables loader (body). */ +/* */ +/* Copyright 1996-2002, 2004-2012 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 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 trace_ttpload +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_loca */ +/* */ +/* <Description> */ +/* Load the locations table. */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Input> */ +/* stream :: The input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_loca( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + FT_Int shift; +/* we need the size of the `glyf' table for malformed `loca' tables */ + error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); +/* it is possible that a font doesn't have a glyf table at all */ +/* or its size is zero */ + if ( error == TT_Err_Table_Missing ) + face->glyf_len = 0; + else if ( error ) + goto Exit; + FT_TRACE2(( "Locations " )); + error = face->goto_table( face, TTAG_loca, stream, &table_len ); + if ( error ) + { + error = TT_Err_Locations_Missing; + goto Exit; + } + if ( face->header.Index_To_Loc_Format != 0 ) + { + shift = 2; + if ( table_len >= 0x40000L ) + { + FT_TRACE2(( "table too large\n" )); + error = TT_Err_Invalid_Table; + goto Exit; + } + face->num_locations = table_len >> shift; + } + else + { + shift = 1; + if ( table_len >= 0x20000L ) + { + FT_TRACE2(( "table too large\n" )); + error = TT_Err_Invalid_Table; + goto Exit; + } + face->num_locations = table_len >> shift; + } + if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) + { + FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n", + face->num_locations - 1, face->root.num_glyphs )); +/* we only handle the case where `maxp' gives a larger value */ + if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) + { + FT_Long new_loca_len = + ( (FT_Long)( face->root.num_glyphs ) + 1 ) << shift; + TT_Table entry = face->dir_tables; + TT_Table limit = entry + face->num_tables; + FT_Long pos = FT_Stream_Pos( stream ); + FT_Long dist = 0x7FFFFFFFL; +/* compute the distance to next table in font file */ + for ( ; entry < limit; entry++ ) + { + FT_Long diff = entry->Offset - pos; + if ( diff > 0 && diff < dist ) + dist = diff; + } + if ( entry == limit ) + { +/* `loca' is the last table */ + dist = stream->size - pos; + } + if ( new_loca_len <= dist ) + { + face->num_locations = face->root.num_glyphs + 1; + table_len = new_loca_len; + FT_TRACE2(( "adjusting num_locations to %d\n", + face->num_locations )); + } + } + } +/* + * Extract the frame. We don't need to decompress it since + * we are able to parse it directly. + */ + if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) ) + goto Exit; + FT_TRACE2(( "loaded\n" )); + Exit: + return error; + } + FT_LOCAL_DEF( FT_ULong ) + tt_face_get_location( TT_Face face, + FT_UInt gindex, + FT_UInt *asize ) + { + FT_ULong pos1, pos2; + FT_Byte* p; + FT_Byte* p_limit; + pos1 = pos2 = 0; + if ( gindex < face->num_locations ) + { + if ( face->header.Index_To_Loc_Format != 0 ) + { + p = face->glyph_locations + gindex * 4; + p_limit = face->glyph_locations + face->num_locations * 4; + pos1 = FT_NEXT_ULONG( p ); + pos2 = pos1; + if ( p + 4 <= p_limit ) + pos2 = FT_NEXT_ULONG( p ); + } + else + { + p = face->glyph_locations + gindex * 2; + p_limit = face->glyph_locations + face->num_locations * 2; + pos1 = FT_NEXT_USHORT( p ); + pos2 = pos1; + if ( p + 2 <= p_limit ) + pos2 = FT_NEXT_USHORT( p ); + pos1 <<= 1; + pos2 <<= 1; + } + } +/* Check broken location data */ + if ( pos1 > face->glyf_len ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset=0x%08lx found for gid=0x%04lx," + " exceeding the end of glyf table (0x%08lx)\n", + pos1, gindex, face->glyf_len )); + *asize = 0; + return 0; + } + if ( pos2 > face->glyf_len ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset=0x%08lx found for gid=0x%04lx," + " truncate at the end of glyf table (0x%08lx)\n", + pos2, gindex + 1, face->glyf_len )); + pos2 = face->glyf_len; + } +/* The `loca' table must be ordered; it refers to the length of */ +/* an entry as the difference between the current and the next */ +/* position. However, there do exist (malformed) fonts which */ +/* don't obey this rule, so we are only able to provide an */ +/* upper bound for the size. */ +/* */ +/* We get (intentionally) a wrong, non-zero result in case the */ +/* `glyf' table is missing. */ + if ( pos2 >= pos1 ) + *asize = (FT_UInt)( pos2 - pos1 ); + else + *asize = (FT_UInt)( face->glyf_len - pos1 ); + return pos1; + } + FT_LOCAL_DEF( void ) + tt_face_done_loca( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_FRAME_RELEASE( face->glyph_locations ); + face->num_locations = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_cvt */ +/* */ +/* <Description> */ +/* Load the control value table into a face object. */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Input> */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_cvt( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_len; + FT_TRACE2(( "CVT " )); + error = face->goto_table( face, TTAG_cvt, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + face->cvt_size = 0; + face->cvt = NULL; + error = TT_Err_Ok; + goto Exit; + } + face->cvt_size = table_len / 2; + if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) + goto Exit; + if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) + goto Exit; + { + FT_Short* cur = face->cvt; + FT_Short* limit = cur + face->cvt_size; + for ( ; cur < limit; cur++ ) + *cur = FT_GET_SHORT(); + } + FT_FRAME_EXIT(); + FT_TRACE2(( "loaded\n" )); + if ( face->doblend ) + error = tt_face_vary_cvt( face, stream ); + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_fpgm */ +/* */ +/* <Description> */ +/* Load the font program. */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Input> */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_fpgm( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + FT_TRACE2(( "Font program " )); +/* The font program is optional */ + error = face->goto_table( face, TTAG_fpgm, stream, &table_len ); + if ( error ) + { + face->font_program = NULL; + face->font_program_size = 0; + error = TT_Err_Ok; + FT_TRACE2(( "is missing\n" )); + } + else + { + face->font_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) + goto Exit; + FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_prep */ +/* */ +/* <Description> */ +/* Load the cvt program. */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Input> */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_prep( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_len; + FT_TRACE2(( "Prep program " )); + error = face->goto_table( face, TTAG_prep, stream, &table_len ); + if ( error ) + { + face->cvt_program = NULL; + face->cvt_program_size = 0; + error = TT_Err_Ok; + FT_TRACE2(( "is missing\n" )); + } + else + { + face->cvt_program_size = table_len; + if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) + goto Exit; + FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_load_hdmx */ +/* */ +/* <Description> */ +/* Load the `hdmx' table into the face object. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_load_hdmx( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_UInt version, nn, num_records; + FT_ULong table_size, record_size; + FT_Byte* p; + FT_Byte* limit; +/* this table is optional */ + error = face->goto_table( face, TTAG_hdmx, stream, &table_size ); + if ( error || table_size < 8 ) + return TT_Err_Ok; + if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) ) + goto Exit; + p = face->hdmx_table; + limit = p + table_size; + version = FT_NEXT_USHORT( p ); + num_records = FT_NEXT_USHORT( p ); + record_size = FT_NEXT_ULONG( p ); +/* The maximum number of bytes in an hdmx device record is the */ +/* maximum number of glyphs + 2; this is 0xFFFF + 2; this is */ +/* the reason why `record_size' is a long (which we read as */ +/* unsigned long for convenience). In practice, two bytes */ +/* sufficient to hold the size value. */ +/* */ +/* There are at least two fonts, HANNOM-A and HANNOM-B version */ +/* 2.0 (2005), which get this wrong: The upper two bytes of */ +/* the size value are set to 0xFF instead of 0x00. We catch */ +/* and fix this. */ + if ( record_size >= 0xFFFF0000UL ) + record_size &= 0xFFFFU; +/* The limit for `num_records' is a heuristic value. */ + if ( version != 0 || num_records > 255 || record_size > 0x10001L ) + { + error = TT_Err_Invalid_File_Format; + goto Fail; + } + if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) + goto Fail; + for ( nn = 0; nn < num_records; nn++ ) + { + if ( p + record_size > limit ) + break; + face->hdmx_record_sizes[nn] = p[0]; + p += record_size; + } + face->hdmx_record_count = nn; + face->hdmx_table_size = table_size; + face->hdmx_record_size = record_size; + Exit: + return error; + Fail: + FT_FRAME_RELEASE( face->hdmx_table ); + face->hdmx_table_size = 0; + goto Exit; + } + FT_LOCAL_DEF( void ) + tt_face_free_hdmx( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + FT_FREE( face->hdmx_record_sizes ); + FT_FRAME_RELEASE( face->hdmx_table ); + } +/*************************************************************************/ +/* */ +/* Return the advance width table for a given pixel size if it is found */ +/* in the font's `hdmx' table (if any). */ +/* */ + FT_LOCAL_DEF( FT_Byte* ) + tt_face_get_device_metrics( TT_Face face, + FT_UInt ppem, + FT_UInt gindex ) + { + FT_UInt nn; + FT_Byte* result = NULL; + FT_ULong record_size = face->hdmx_record_size; + FT_Byte* record = face->hdmx_table + 8; + for ( nn = 0; nn < face->hdmx_record_count; nn++ ) + if ( face->hdmx_record_sizes[nn] == ppem ) + { + gindex += 2; + if ( gindex < record_size ) + result = record + nn * record_size + gindex; + break; + } + return result; + } +/* END */ +/* glyph loader */ +/***************************************************************************/ +/* */ +/* ttgload.c */ +/* */ +/* TrueType Glyph Loader (body). */ +/* */ +/* Copyright 1996-2012 */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ttsubpix.h */ +/* */ +/* TrueType Subpixel Hinting. */ +/* */ +/* Copyright 2010-2012 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. */ +/* */ +/***************************************************************************/ +#define __TTSUBPIX_H__ +FT_BEGIN_HEADER +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_ttgload +/*************************************************************************/ +/* */ +/* Composite glyph flags. */ +/* */ +#define ARGS_ARE_WORDS 0x0001 +#define ARGS_ARE_XY_VALUES 0x0002 +#define ROUND_XY_TO_GRID 0x0004 +#define WE_HAVE_A_SCALE 0x0008 +/* reserved 0x0010 */ +#define MORE_COMPONENTS 0x0020 +#define WE_HAVE_AN_XY_SCALE 0x0040 +#define WE_HAVE_A_2X2 0x0080 +#define WE_HAVE_INSTR 0x0100 +#define USE_MY_METRICS 0x0200 +#define OVERLAP_COMPOUND 0x0400 +#define SCALED_COMPONENT_OFFSET 0x0800 +#define UNSCALED_COMPONENT_OFFSET 0x1000 +/*************************************************************************/ +/* */ +/* Return the horizontal metrics in font units for a given glyph. */ +/* */ + FT_LOCAL_DEF( void ) + TT_Get_HMetrics( TT_Face face, + FT_UInt idx, + FT_Short* lsb, + FT_UShort* aw ) + { + ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw ); + FT_TRACE5(( " advance width (font units): %d\n", *aw )); + FT_TRACE5(( " left side bearing (font units): %d\n", *lsb )); + } +/*************************************************************************/ +/* */ +/* Return the vertical metrics in font units for a given glyph. */ +/* Greg Hitchcock from Microsoft told us that if there were no `vmtx' */ +/* table, typoAscender/Descender from the `OS/2' table would be used */ +/* instead, and if there were no `OS/2' table, use ascender/descender */ +/* from the `hhea' table. But that is not what Microsoft's rasterizer */ +/* apparently does: It uses the ppem value as the advance height, and */ +/* sets the top side bearing to be zero. */ +/* */ + FT_LOCAL_DEF( void ) + TT_Get_VMetrics( TT_Face face, + FT_UInt idx, + FT_Short* tsb, + FT_UShort* ah ) + { + if ( face->vertical_info ) + ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah ); +/* Empirically determined, at variance with what MS said */ +#if 1 + else + { + *tsb = 0; + *ah = face->root.units_per_EM; + } +/* This is what MS said to do. It isn't what they do, however. */ +#else + else if ( face->os2.version != 0xFFFFU ) + { + *tsb = face->os2.sTypoAscender; + *ah = face->os2.sTypoAscender - face->os2.sTypoDescender; + } + else + { + *tsb = face->horizontal.Ascender; + *ah = face->horizontal.Ascender - face->horizontal.Descender; + } +#endif + FT_TRACE5(( " advance height (font units): %d\n", *ah )); + FT_TRACE5(( " top side bearing (font units): %d\n", *tsb )); + } + static void + tt_get_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = (TT_Face)loader->face; + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + &top_bearing, + &advance_height ); + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + static void + tt_get_metrics_incr_overrides( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = (TT_Face)loader->face; + FT_Short left_bearing = 0, top_bearing = 0; + FT_UShort advance_width = 0, advance_height = 0; +/* If this is an incrementally loaded font check whether there are */ +/* overriding metrics for this glyph. */ + if ( face->root.internal->incremental_interface && + face->root.internal->incremental_interface->funcs->get_glyph_metrics ) + { + FT_Incremental_MetricsRec metrics; + FT_Error error; + metrics.bearing_x = loader->left_bearing; + metrics.bearing_y = 0; + metrics.advance = loader->advance; + metrics.advance_v = 0; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, FALSE, &metrics ); + if ( error ) + goto Exit; + left_bearing = (FT_Short)metrics.bearing_x; + advance_width = (FT_UShort)metrics.advance; +#if 0 +/* GWW: Do I do the same for vertical metrics? */ + metrics.bearing_x = 0; + metrics.bearing_y = loader->top_bearing; + metrics.advance = loader->vadvance; + error = face->root.internal->incremental_interface->funcs->get_glyph_metrics( + face->root.internal->incremental_interface->object, + glyph_index, TRUE, &metrics ); + if ( error ) + goto Exit; + top_bearing = (FT_Short)metrics.bearing_y; + advance_height = (FT_UShort)metrics.advance; +/* 0 */ +#endif + loader->left_bearing = left_bearing; + loader->advance = advance_width; + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } + } + Exit: + return; + } +/*************************************************************************/ +/* */ +/* Translates an array of coordinates. */ +/* */ + static void + translate_array( FT_UInt n, + FT_Vector* coords, + FT_Pos delta_x, + FT_Pos delta_y ) + { + FT_UInt k; + if ( delta_x ) + for ( k = 0; k < n; k++ ) + coords[k].x += delta_x; + if ( delta_y ) + for ( k = 0; k < n; k++ ) + coords[k].y += delta_y; + } +/*************************************************************************/ +/* */ +/* The following functions are used by default with TrueType fonts. */ +/* However, they can be replaced by alternatives if we need to support */ +/* TrueType-compressed formats (like MicroType) in the future. */ +/* */ +/*************************************************************************/ + FT_CALLBACK_DEF( FT_Error ) + TT_Access_Glyph_Frame( TT_Loader loader, + FT_UInt glyph_index, + FT_ULong offset, + FT_UInt byte_count ) + { + FT_Error error; + FT_Stream stream = loader->stream; +/* for non-debug mode */ + FT_UNUSED( glyph_index ); + FT_TRACE4(( "Glyph %ld\n", glyph_index )); +/* the following line sets the `error' variable through macros! */ + if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) ) + return error; + loader->cursor = stream->cursor; + loader->limit = stream->limit; + return TT_Err_Ok; + } + FT_CALLBACK_DEF( void ) + TT_Forget_Glyph_Frame( TT_Loader loader ) + { + FT_Stream stream = loader->stream; + FT_FRAME_EXIT(); + } + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Glyph_Header( TT_Loader loader ) + { + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + if ( p + 10 > limit ) + return TT_Err_Invalid_Outline; + loader->n_contours = FT_NEXT_SHORT( p ); + loader->bbox.xMin = FT_NEXT_SHORT( p ); + loader->bbox.yMin = FT_NEXT_SHORT( p ); + loader->bbox.xMax = FT_NEXT_SHORT( p ); + loader->bbox.yMax = FT_NEXT_SHORT( p ); + FT_TRACE5(( " # of contours: %d\n", loader->n_contours )); + FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, + loader->bbox.xMax )); + FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, + loader->bbox.yMax )); + loader->cursor = p; + return TT_Err_Ok; + } + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Simple_Glyph( TT_Loader load ) + { + FT_Error error; + FT_Byte* p = load->cursor; + FT_Byte* limit = load->limit; + FT_GlyphLoader gloader = load->gloader; + FT_Int n_contours = load->n_contours; + FT_Outline* outline; + TT_Face face = (TT_Face)load->face; + FT_UShort n_ins; + FT_Int n_points; + FT_Byte *flag, *flag_limit; + FT_Byte c, count; + FT_Vector *vec, *vec_limit; + FT_Pos x; + FT_Short *cont, *cont_limit, prev_cont; + FT_Int xy_size = 0; +/* check that we can add the contours to the glyph */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, 0, n_contours ); + if ( error ) + goto Fail; +/* reading the contours' endpoints & number of points */ + cont = gloader->current.outline.contours; + cont_limit = cont + n_contours; +/* check space for contours array + instructions count */ + if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit ) + goto Invalid_Outline; + prev_cont = FT_NEXT_SHORT( p ); + if ( n_contours > 0 ) + cont[0] = prev_cont; + if ( prev_cont < 0 ) + goto Invalid_Outline; + for ( cont++; cont < cont_limit; cont++ ) + { + cont[0] = FT_NEXT_SHORT( p ); + if ( cont[0] <= prev_cont ) + { +/* unordered contours: this is invalid */ + goto Invalid_Outline; + } + prev_cont = cont[0]; + } + n_points = 0; + if ( n_contours > 0 ) + { + n_points = cont[-1] + 1; + if ( n_points < 0 ) + goto Invalid_Outline; + } +/* note that we will add four phantom points later */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 ); + if ( error ) + goto Fail; +/* reading the bytecode instructions */ + load->glyph->control_len = 0; + load->glyph->control_data = 0; + if ( p + 2 > limit ) + goto Invalid_Outline; + n_ins = FT_NEXT_USHORT( p ); + FT_TRACE5(( " Instructions size: %u\n", n_ins )); + if ( n_ins > face->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "TT_Load_Simple_Glyph: too many instructions (%d)\n", + n_ins )); + error = TT_Err_Too_Many_Hints; + goto Fail; + } + if ( ( limit - p ) < n_ins ) + { + FT_TRACE0(( "TT_Load_Simple_Glyph: instruction count mismatch\n" )); + error = TT_Err_Too_Many_Hints; + goto Fail; + } + if ( IS_HINTED( load->load_flags ) ) + { + load->glyph->control_len = n_ins; + load->glyph->control_data = load->exec->glyphIns; + FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); + } + p += n_ins; + outline = &gloader->current.outline; +/* reading the point tags */ + flag = (FT_Byte*)outline->tags; + flag_limit = flag + n_points; + FT_ASSERT( flag != NULL ); + while ( flag < flag_limit ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + *flag++ = c = FT_NEXT_BYTE( p ); + if ( c & 8 ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + count = FT_NEXT_BYTE( p ); + if ( flag + (FT_Int)count > flag_limit ) + goto Invalid_Outline; + for ( ; count > 0; count-- ) + *flag++ = c; + } + } +/* reading the X coordinates */ + vec = outline->points; + vec_limit = vec + n_points; + flag = (FT_Byte*)outline->tags; + x = 0; + if ( p + xy_size > limit ) + goto Invalid_Outline; + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos y = 0; + FT_Byte f = *flag; + if ( f & 2 ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + y = (FT_Pos)FT_NEXT_BYTE( p ); + if ( ( f & 16 ) == 0 ) + y = -y; + } + else if ( ( f & 16 ) == 0 ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + y = (FT_Pos)FT_NEXT_SHORT( p ); + } + x += y; + vec->x = x; +/* the cast is for stupid compilers */ + *flag = (FT_Byte)( f & ~( 2 | 16 ) ); + } +/* reading the Y coordinates */ + vec = gloader->current.outline.points; + vec_limit = vec + n_points; + flag = (FT_Byte*)outline->tags; + x = 0; + for ( ; vec < vec_limit; vec++, flag++ ) + { + FT_Pos y = 0; + FT_Byte f = *flag; + if ( f & 4 ) + { + if ( p + 1 > limit ) + goto Invalid_Outline; + y = (FT_Pos)FT_NEXT_BYTE( p ); + if ( ( f & 32 ) == 0 ) + y = -y; + } + else if ( ( f & 32 ) == 0 ) + { + if ( p + 2 > limit ) + goto Invalid_Outline; + y = (FT_Pos)FT_NEXT_SHORT( p ); + } + x += y; + vec->y = x; +/* the cast is for stupid compilers */ + *flag = (FT_Byte)( f & FT_CURVE_TAG_ON ); + } + outline->n_points = (FT_UShort)n_points; + outline->n_contours = (FT_Short) n_contours; + load->cursor = p; + Fail: + return error; + Invalid_Outline: + error = TT_Err_Invalid_Outline; + goto Fail; + } + FT_CALLBACK_DEF( FT_Error ) + TT_Load_Composite_Glyph( TT_Loader loader ) + { + FT_Error error; + FT_Byte* p = loader->cursor; + FT_Byte* limit = loader->limit; + FT_GlyphLoader gloader = loader->gloader; + FT_SubGlyph subglyph; + FT_UInt num_subglyphs; + num_subglyphs = 0; + do + { + FT_Fixed xx, xy, yy, yx; + FT_UInt count; +/* check that we can load a new subglyph */ + error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 ); + if ( error ) + goto Fail; +/* check space */ + if ( p + 4 > limit ) + goto Invalid_Composite; + subglyph = gloader->current.subglyphs + num_subglyphs; + subglyph->arg1 = subglyph->arg2 = 0; + subglyph->flags = FT_NEXT_USHORT( p ); + subglyph->index = FT_NEXT_USHORT( p ); +/* check space */ + count = 2; + if ( subglyph->flags & ARGS_ARE_WORDS ) + count += 2; + if ( subglyph->flags & WE_HAVE_A_SCALE ) + count += 2; + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + count += 4; + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + count += 8; + if ( p + count > limit ) + goto Invalid_Composite; +/* read arguments */ + if ( subglyph->flags & ARGS_ARE_WORDS ) + { + subglyph->arg1 = FT_NEXT_SHORT( p ); + subglyph->arg2 = FT_NEXT_SHORT( p ); + } + else + { + subglyph->arg1 = FT_NEXT_CHAR( p ); + subglyph->arg2 = FT_NEXT_CHAR( p ); + } +/* read transform */ + xx = yy = 0x10000L; + xy = yx = 0; + if ( subglyph->flags & WE_HAVE_A_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yy = xx; + } + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + } + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + { + xx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yx = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + xy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + yy = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; + } + subglyph->transform.xx = xx; + subglyph->transform.xy = xy; + subglyph->transform.yx = yx; + subglyph->transform.yy = yy; + num_subglyphs++; + } while ( subglyph->flags & MORE_COMPONENTS ); + gloader->current.num_subglyphs = num_subglyphs; + { + FT_Stream stream = loader->stream; +/* we must undo the FT_FRAME_ENTER in order to point */ +/* to the composite instructions, if we find some. */ +/* We will process them later. */ +/* */ + loader->ins_pos = (FT_ULong)( FT_STREAM_POS() + + p - limit ); + } + loader->cursor = p; + Fail: + return error; + Invalid_Composite: + error = TT_Err_Invalid_Composite; + goto Fail; + } + FT_LOCAL_DEF( void ) + TT_Init_Glyph_Loading( TT_Face face ) + { + face->access_glyph_frame = TT_Access_Glyph_Frame; + face->read_glyph_header = TT_Load_Glyph_Header; + face->read_simple_glyph = TT_Load_Simple_Glyph; + face->read_composite_glyph = TT_Load_Composite_Glyph; + face->forget_glyph_frame = TT_Forget_Glyph_Frame; + } + static void + tt_prepare_zone( TT_GlyphZone zone, + FT_GlyphLoad load, + FT_UInt start_point, + FT_UInt start_contour ) + { + zone->n_points = (FT_UShort)( load->outline.n_points - start_point ); + zone->n_contours = (FT_Short) ( load->outline.n_contours - + start_contour ); + zone->org = load->extra_points + start_point; + zone->cur = load->outline.points + start_point; + zone->orus = load->extra_points2 + start_point; + zone->tags = (FT_Byte*)load->outline.tags + start_point; + zone->contours = (FT_UShort*)load->outline.contours + start_contour; + zone->first_point = (FT_UShort)start_point; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Hint_Glyph */ +/* */ +/* <Description> */ +/* Hint the glyph using the zone prepared by the caller. Note that */ +/* the zone is supposed to include four phantom points. */ +/* */ + static FT_Error + TT_Hint_Glyph( TT_Loader loader, + FT_Bool is_composite ) + { + TT_GlyphZone zone = &loader->zone; + FT_Pos origin; + FT_UInt n_ins; + if ( loader->glyph->control_len > 0xFFFFL ) + { + FT_TRACE1(( "TT_Hint_Glyph: too long instructions " )); + FT_TRACE1(( "(0x%lx byte) is truncated\n", + loader->glyph->control_len )); + } + n_ins = (FT_UInt)( loader->glyph->control_len ); + origin = zone->cur[zone->n_points - 4].x; + origin = FT_PIX_ROUND( origin ) - origin; + if ( origin ) + translate_array( zone->n_points, zone->cur, origin, 0 ); +/* save original point position in org */ + if ( n_ins > 0 ) + FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); +/* Reset graphics state. */ + loader->exec->GS = ((TT_Size)loader->size)->GS; +/* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */ +/* completely refer to the (already) hinted subglyphs. */ + if ( is_composite ) + { + loader->exec->metrics.x_scale = 1 << 16; + loader->exec->metrics.y_scale = 1 << 16; + FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points ); + } + else + { + loader->exec->metrics.x_scale = + ((TT_Size)loader->size)->metrics.x_scale; + loader->exec->metrics.y_scale = + ((TT_Size)loader->size)->metrics.y_scale; + } +/* round pp2 and pp4 */ + zone->cur[zone->n_points - 3].x = + FT_PIX_ROUND( zone->cur[zone->n_points - 3].x ); + zone->cur[zone->n_points - 1].y = + FT_PIX_ROUND( zone->cur[zone->n_points - 1].y ); + if ( n_ins > 0 ) + { + FT_Bool debug; + FT_Error error; + FT_GlyphLoader gloader = loader->gloader; + FT_Outline current_outline = gloader->current.outline; + error = TT_Set_CodeRange( loader->exec, tt_coderange_glyph, + loader->exec->glyphIns, n_ins ); + if ( error ) + return error; + loader->exec->is_composite = is_composite; + loader->exec->pts = *zone; + debug = FT_BOOL( !( loader->load_flags & FT_LOAD_NO_SCALE ) && + ((TT_Size)loader->size)->debug ); + error = TT_Run_Context( loader->exec, debug ); + if ( error && loader->exec->pedantic_hinting ) + return error; +/* store drop-out mode in bits 5-7; set bit 2 also as a marker */ + current_outline.tags[0] |= + ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE; + } +/* save glyph phantom points */ + if ( !loader->preserve_pps ) + { + loader->pp1 = zone->cur[zone->n_points - 4]; + loader->pp2 = zone->cur[zone->n_points - 3]; + loader->pp3 = zone->cur[zone->n_points - 2]; + loader->pp4 = zone->cur[zone->n_points - 1]; + } + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Process_Simple_Glyph */ +/* */ +/* <Description> */ +/* Once a simple glyph has been loaded, it needs to be processed. */ +/* Usually, this means scaling and hinting through bytecode */ +/* interpretation. */ +/* */ + static FT_Error + TT_Process_Simple_Glyph( TT_Loader loader ) + { + FT_GlyphLoader gloader = loader->gloader; + FT_Error error = TT_Err_Ok; + FT_Outline* outline; + FT_Int n_points; + outline = &gloader->current.outline; + n_points = outline->n_points; +/* set phantom points */ + outline->points[n_points ] = loader->pp1; + outline->points[n_points + 1] = loader->pp2; + outline->points[n_points + 2] = loader->pp3; + outline->points[n_points + 3] = loader->pp4; + outline->tags[n_points ] = 0; + outline->tags[n_points + 1] = 0; + outline->tags[n_points + 2] = 0; + outline->tags[n_points + 3] = 0; + n_points += 4; + if ( ((TT_Face)loader->face)->doblend ) + { +/* Deltas apply to the unscaled data. */ + FT_Vector* deltas; + FT_Memory memory = loader->face->memory; + FT_Int i; + error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face), + loader->glyph_index, + &deltas, + n_points ); + if ( error ) + return error; + for ( i = 0; i < n_points; ++i ) + { + outline->points[i].x += deltas[i].x; + outline->points[i].y += deltas[i].y; + } + FT_FREE( deltas ); + } + if ( IS_HINTED( loader->load_flags ) ) + { + tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 ); + FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur, + loader->zone.n_points + 4 ); + } +/* scale the glyph */ + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + FT_Vector* vec = outline->points; + FT_Vector* limit = outline->points + n_points; + FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale; + FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale; + for ( ; vec < limit; vec++ ) + { + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); + } + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + } + if ( IS_HINTED( loader->load_flags ) ) + { + loader->zone.n_points += 4; + error = TT_Hint_Glyph( loader, 0 ); + } + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Process_Composite_Component */ +/* */ +/* <Description> */ +/* Once a composite component has been loaded, it needs to be */ +/* processed. Usually, this means transforming and translating. */ +/* */ + static FT_Error + TT_Process_Composite_Component( TT_Loader loader, + FT_SubGlyph subglyph, + FT_UInt start_point, + FT_UInt num_base_points ) + { + FT_GlyphLoader gloader = loader->gloader; + FT_Vector* base_vec = gloader->base.outline.points; + FT_UInt num_points = gloader->base.outline.n_points; + FT_Bool have_scale; + FT_Pos x, y; + have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ); +/* perform the transform required for this subglyph */ + if ( have_scale ) + { + FT_UInt i; + for ( i = num_base_points; i < num_points; i++ ) + FT_Vector_Transform( base_vec + i, &subglyph->transform ); + } +/* get offset */ + if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) + { + FT_UInt k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; +/* match l-th point of the newly loaded component to the k-th point */ +/* of the previously loaded components. */ +/* change to the point numbers used by our outline */ + k += start_point; + l += num_base_points; + if ( k >= num_base_points || + l >= num_points ) + return TT_Err_Invalid_Composite; + p1 = gloader->base.outline.points + k; + p2 = gloader->base.outline.points + l; + x = p1->x - p2->x; + y = p1->y - p2->y; + } + else + { + x = subglyph->arg1; + y = subglyph->arg2; + if ( !x && !y ) + return TT_Err_Ok; +/* Use a default value dependent on */ +/* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old TT */ +/* fonts which don't set the xxx_COMPONENT_OFFSET bit. */ + if ( have_scale && + ( subglyph->flags & SCALED_COMPONENT_OFFSET ) ) + { +#if 0 +/*************************************************************************/ +/* */ +/* This algorithm is what Apple documents. But it doesn't work. */ +/* */ + int a = subglyph->transform.xx > 0 ? subglyph->transform.xx + : -subglyph->transform.xx; + int b = subglyph->transform.yx > 0 ? subglyph->transform.yx + : -subglyph->transform.yx; + int c = subglyph->transform.xy > 0 ? subglyph->transform.xy + : -subglyph->transform.xy; + int d = subglyph->transform.yy > 0 ? subglyph->transform.yy + : -subglyph->transform.yy; + int m = a > b ? a : b; + int n = c > d ? c : d; + if ( a - b <= 33 && a - b >= -33 ) + m *= 2; + if ( c - d <= 33 && c - d >= -33 ) + n *= 2; + x = FT_MulFix( x, m ); + y = FT_MulFix( y, n ); +/* 0 */ +#else +/*************************************************************************/ +/* */ +/* This algorithm is a guess and works much better than the above. */ +/* */ + FT_Fixed mac_xscale = FT_SqrtFixed( + (FT_Int32)FT_MulFix( subglyph->transform.xx, + subglyph->transform.xx ) + + (FT_Int32)FT_MulFix( subglyph->transform.xy, + subglyph->transform.xy ) ); + FT_Fixed mac_yscale = FT_SqrtFixed( + (FT_Int32)FT_MulFix( subglyph->transform.yy, + subglyph->transform.yy ) + + (FT_Int32)FT_MulFix( subglyph->transform.yx, + subglyph->transform.yx ) ); + x = FT_MulFix( x, mac_xscale ); + y = FT_MulFix( y, mac_yscale ); +/* 0 */ +#endif + } + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + FT_Fixed x_scale = ((TT_Size)loader->size)->metrics.x_scale; + FT_Fixed y_scale = ((TT_Size)loader->size)->metrics.y_scale; + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); + if ( subglyph->flags & ROUND_XY_TO_GRID ) + { + x = FT_PIX_ROUND( x ); + y = FT_PIX_ROUND( y ); + } + } + } + if ( x || y ) + translate_array( num_points - num_base_points, + base_vec + num_base_points, + x, y ); + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Process_Composite_Glyph */ +/* */ +/* <Description> */ +/* This is slightly different from TT_Process_Simple_Glyph, in that */ +/* its sole purpose is to hint the glyph. Thus this function is */ +/* only available when bytecode interpreter is enabled. */ +/* */ + static FT_Error + TT_Process_Composite_Glyph( TT_Loader loader, + FT_UInt start_point, + FT_UInt start_contour ) + { + FT_Error error; + FT_Outline* outline; + FT_UInt i; + outline = &loader->gloader->base.outline; +/* make room for phantom points */ + error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, + outline->n_points + 4, + 0 ); + if ( error ) + return error; + outline->points[outline->n_points ] = loader->pp1; + outline->points[outline->n_points + 1] = loader->pp2; + outline->points[outline->n_points + 2] = loader->pp3; + outline->points[outline->n_points + 3] = loader->pp4; + outline->tags[outline->n_points ] = 0; + outline->tags[outline->n_points + 1] = 0; + outline->tags[outline->n_points + 2] = 0; + outline->tags[outline->n_points + 3] = 0; + { + FT_Stream stream = loader->stream; + FT_UShort n_ins, max_ins; + FT_ULong tmp; +/* TT_Load_Composite_Glyph only gives us the offset of instructions */ +/* so we read them here */ + if ( FT_STREAM_SEEK( loader->ins_pos ) || + FT_READ_USHORT( n_ins ) ) + return error; + FT_TRACE5(( " Instructions size = %d\n", n_ins )); +/* check it */ + max_ins = ((TT_Face)loader->face)->max_profile.maxSizeOfInstructions; + if ( n_ins > max_ins ) + { +/* acroread ignores this field, so we only do a rough safety check */ + if ( (FT_Int)n_ins > loader->byte_len ) + { + FT_TRACE1(( "TT_Process_Composite_Glyph: " + "too many instructions (%d) for glyph with length %d\n", + n_ins, loader->byte_len )); + return TT_Err_Too_Many_Hints; + } + tmp = loader->exec->glyphSize; + error = Update_Max( loader->exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void*)&loader->exec->glyphIns, + n_ins ); + loader->exec->glyphSize = (FT_UShort)tmp; + if ( error ) + return error; + } + else if ( n_ins == 0 ) + return TT_Err_Ok; + if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) ) + return error; + loader->glyph->control_data = loader->exec->glyphIns; + loader->glyph->control_len = n_ins; + } + tt_prepare_zone( &loader->zone, &loader->gloader->base, + start_point, start_contour ); +/* Some points are likely touched during execution of */ +/* instructions on components. So let's untouch them. */ + for ( i = start_point; i < loader->zone.n_points; i++ ) + loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH; + loader->zone.n_points += 4; + return TT_Hint_Glyph( loader, 1 ); + } +/* Calculate the four phantom points. */ +/* The first two stand for horizontal origin and advance. */ +/* The last two stand for vertical origin and advance. */ +#define TT_LOADER_SET_PP( loader ) \ + do { \ + (loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \ + (loader)->pp1.y = 0; \ + (loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \ + (loader)->pp2.y = 0; \ + (loader)->pp3.x = 0; \ + (loader)->pp3.y = (loader)->top_bearing + (loader)->bbox.yMax; \ + (loader)->pp4.x = 0; \ + (loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \ + } while ( 0 ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* load_truetype_glyph */ +/* */ +/* <Description> */ +/* Loads a given truetype glyph. Handles composites and uses a */ +/* TT_Loader object. */ +/* */ + static FT_Error + load_truetype_glyph( TT_Loader loader, + FT_UInt glyph_index, + FT_UInt recurse_count, + FT_Bool header_only ) + { + FT_Error error = TT_Err_Ok; + FT_Fixed x_scale, y_scale; + FT_ULong offset; + TT_Face face = (TT_Face)loader->face; + FT_GlyphLoader gloader = loader->gloader; + FT_Bool opened_frame = 0; + FT_Vector* deltas = NULL; + FT_StreamRec inc_stream; + FT_Data glyph_data; + FT_Bool glyph_data_loaded = 0; +/* some fonts have an incorrect value of `maxComponentDepth', */ +/* thus we allow depth 1 to catch the majority of them */ + if ( recurse_count > 1 && + recurse_count > face->max_profile.maxComponentDepth ) + { + error = TT_Err_Invalid_Composite; + goto Exit; + } +/* check glyph index */ + if ( glyph_index >= (FT_UInt)face->root.num_glyphs ) + { + error = TT_Err_Invalid_Glyph_Index; + goto Exit; + } + loader->glyph_index = glyph_index; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + x_scale = ((TT_Size)loader->size)->metrics.x_scale; + y_scale = ((TT_Size)loader->size)->metrics.y_scale; + } + else + { + x_scale = 0x10000L; + y_scale = 0x10000L; + } + tt_get_metrics( loader, glyph_index ); +/* Set `offset' to the start of the glyph relative to the start of */ +/* the `glyf' table, and `byte_len' to the length of the glyph in */ +/* bytes. */ +/* If we are loading glyph data via the incremental interface, set */ +/* the loader stream to a memory stream reading the data returned */ +/* by the interface. */ + if ( face->root.internal->incremental_interface ) + { + error = face->root.internal->incremental_interface->funcs->get_glyph_data( + face->root.internal->incremental_interface->object, + glyph_index, &glyph_data ); + if ( error ) + goto Exit; + glyph_data_loaded = 1; + offset = 0; + loader->byte_len = glyph_data.length; + FT_MEM_ZERO( &inc_stream, sizeof ( inc_stream ) ); + FT_Stream_OpenMemory( &inc_stream, + glyph_data.pointer, glyph_data.length ); + loader->stream = &inc_stream; + } + else + offset = tt_face_get_location( face, glyph_index, + (FT_UInt*)&loader->byte_len ); + if ( loader->byte_len > 0 ) + { +/* for the incremental interface, `glyf_offset' is always zero */ + if ( !loader->glyf_offset && + !face->root.internal->incremental_interface ) + { + FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" )); + error = TT_Err_Invalid_Table; + goto Exit; + } + error = face->access_glyph_frame( loader, glyph_index, + loader->glyf_offset + offset, + loader->byte_len ); + if ( error ) + goto Exit; + opened_frame = 1; +/* read glyph header first */ + error = face->read_glyph_header( loader ); + if ( error || header_only ) + goto Exit; + } + if ( loader->byte_len == 0 || loader->n_contours == 0 ) + { + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; + if ( header_only ) + goto Exit; +/* must initialize points before (possibly) overriding */ +/* glyph metrics from the incremental interface */ + TT_LOADER_SET_PP( loader ); + tt_get_metrics_incr_overrides( loader, glyph_index ); + if ( ((TT_Face)(loader->face))->doblend ) + { +/* this must be done before scaling */ + FT_Memory memory = loader->face->memory; + error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face), + glyph_index, &deltas, 4 ); + if ( error ) + goto Exit; + loader->pp1.x += deltas[0].x; loader->pp1.y += deltas[0].y; + loader->pp2.x += deltas[1].x; loader->pp2.y += deltas[1].y; + loader->pp3.x += deltas[2].x; loader->pp3.y += deltas[2].y; + loader->pp4.x += deltas[3].x; loader->pp4.y += deltas[3].y; + FT_FREE( deltas ); + } + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + error = TT_Err_Ok; + goto Exit; + } +/* must initialize points before (possibly) overriding */ +/* glyph metrics from the incremental interface */ + TT_LOADER_SET_PP( loader ); + tt_get_metrics_incr_overrides( loader, glyph_index ); +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/* if it is a simple glyph, load it */ + if ( loader->n_contours > 0 ) + { + error = face->read_simple_glyph( loader ); + if ( error ) + goto Exit; +/* all data have been read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + error = TT_Process_Simple_Glyph( loader ); + if ( error ) + goto Exit; + FT_GlyphLoader_Add( gloader ); + } +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/* otherwise, load a composite! */ + else if ( loader->n_contours == -1 ) + { + FT_UInt start_point; + FT_UInt start_contour; +/* position of composite instructions, if any */ + FT_ULong ins_pos; + start_point = gloader->base.outline.n_points; + start_contour = gloader->base.outline.n_contours; +/* for each subglyph, read composite header */ + error = face->read_composite_glyph( loader ); + if ( error ) + goto Exit; +/* store the offset of instructions */ + ins_pos = loader->ins_pos; +/* all data we need are read */ + face->forget_glyph_frame( loader ); + opened_frame = 0; + if ( face->doblend ) + { + FT_Int i, limit; + FT_SubGlyph subglyph; + FT_Memory memory = face->root.memory; +/* this provides additional offsets */ +/* for each component's translation */ + if ( ( error = TT_Vary_Get_Glyph_Deltas( + face, + glyph_index, + &deltas, + gloader->current.num_subglyphs + 4 )) != 0 ) + goto Exit; + subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs; + limit = gloader->current.num_subglyphs; + for ( i = 0; i < limit; ++i, ++subglyph ) + { + if ( subglyph->flags & ARGS_ARE_XY_VALUES ) + { +/* XXX: overflow check for subglyph->{arg1,arg2}. */ +/* deltas[i].{x,y} must be within signed 16-bit, */ +/* but the restriction of summed delta is not clear */ + subglyph->arg1 += (FT_Int16)deltas[i].x; + subglyph->arg2 += (FT_Int16)deltas[i].y; + } + } + loader->pp1.x += deltas[i + 0].x; loader->pp1.y += deltas[i + 0].y; + loader->pp2.x += deltas[i + 1].x; loader->pp2.y += deltas[i + 1].y; + loader->pp3.x += deltas[i + 2].x; loader->pp3.y += deltas[i + 2].y; + loader->pp4.x += deltas[i + 3].x; loader->pp4.y += deltas[i + 3].y; + FT_FREE( deltas ); + } + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } +/* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */ +/* `as is' in the glyph slot (the client application will be */ +/* responsible for interpreting these data)... */ + if ( loader->load_flags & FT_LOAD_NO_RECURSE ) + { + FT_GlyphLoader_Add( gloader ); + loader->glyph->format = FT_GLYPH_FORMAT_COMPOSITE; + goto Exit; + } +/*********************************************************************/ +/*********************************************************************/ +/*********************************************************************/ + { + FT_UInt n, num_base_points; + FT_SubGlyph subglyph = 0; + FT_UInt num_points = start_point; + FT_UInt num_subglyphs = gloader->current.num_subglyphs; + FT_UInt num_base_subgs = gloader->base.num_subglyphs; + FT_Stream old_stream = loader->stream; + FT_Int old_byte_len = loader->byte_len; + FT_GlyphLoader_Add( gloader ); +/* read each subglyph independently */ + for ( n = 0; n < num_subglyphs; n++ ) + { + FT_Vector pp[4]; +/* Each time we call load_truetype_glyph in this loop, the */ +/* value of `gloader.base.subglyphs' can change due to table */ +/* reallocations. We thus need to recompute the subglyph */ +/* pointer on each iteration. */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + pp[0] = loader->pp1; + pp[1] = loader->pp2; + pp[2] = loader->pp3; + pp[3] = loader->pp4; + num_base_points = gloader->base.outline.n_points; + error = load_truetype_glyph( loader, subglyph->index, + recurse_count + 1, FALSE ); + if ( error ) + goto Exit; +/* restore subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + n; + if ( !( subglyph->flags & USE_MY_METRICS ) ) + { + loader->pp1 = pp[0]; + loader->pp2 = pp[1]; + loader->pp3 = pp[2]; + loader->pp4 = pp[3]; + } + num_points = gloader->base.outline.n_points; + if ( num_points == num_base_points ) + continue; +/* gloader->base.outline consists of three parts: */ +/* 0 -(1)-> start_point -(2)-> num_base_points -(3)-> n_points. */ +/* */ +/* (1): exists from the beginning */ +/* (2): components that have been loaded so far */ +/* (3): the newly loaded component */ + TT_Process_Composite_Component( loader, subglyph, start_point, + num_base_points ); + } + loader->stream = old_stream; + loader->byte_len = old_byte_len; +/* process the glyph */ + loader->ins_pos = ins_pos; + if ( IS_HINTED( loader->load_flags ) && + subglyph->flags & WE_HAVE_INSTR && + num_points > start_point ) + TT_Process_Composite_Glyph( loader, start_point, start_contour ); + } + } + else + { +/* invalid composite count (negative but not -1) */ + error = TT_Err_Invalid_Outline; + goto Exit; + } +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + Exit: + if ( opened_frame ) + face->forget_glyph_frame( loader ); + if ( glyph_data_loaded ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + return error; + } + static FT_Error + compute_glyph_metrics( TT_Loader loader, + FT_UInt glyph_index ) + { + FT_BBox bbox; + TT_Face face = (TT_Face)loader->face; + FT_Fixed y_scale; + TT_GlyphSlot glyph = loader->glyph; + TT_Size size = (TT_Size)loader->size; + y_scale = 0x10000L; + if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) + y_scale = size->root.metrics.y_scale; + if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE ) + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + else + bbox = loader->bbox; +/* get the device-independent horizontal advance; it is scaled later */ +/* by the base layer. */ + glyph->linearHoriAdvance = loader->linear; + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; +/* adjust advance width to the value contained in the hdmx table */ + if ( !face->postscript.isFixedPitch && + IS_HINTED( loader->load_flags ) ) + { + FT_Byte* widthp; + widthp = tt_face_get_device_metrics( face, + size->root.metrics.x_ppem, + glyph_index ); + if ( widthp ) + glyph->metrics.horiAdvance = *widthp << 6; + } +/* set glyph dimensions */ + glyph->metrics.width = bbox.xMax - bbox.xMin; + glyph->metrics.height = bbox.yMax - bbox.yMin; +/* Now take care of vertical metrics. In the case where there is */ +/* no vertical information within the font (relatively common), */ +/* create some metrics manually */ + { +/* scaled vertical top side bearing */ + FT_Pos top; +/* scaled vertical advance height */ + FT_Pos advance; +/* Get the unscaled top bearing and advance height. */ + if ( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ) + { + top = (FT_Short)FT_DivFix( loader->pp3.y - bbox.yMax, + y_scale ); + if ( loader->pp3.y <= loader->pp4.y ) + advance = 0; + else + advance = (FT_UShort)FT_DivFix( loader->pp3.y - loader->pp4.y, + y_scale ); + } + else + { + FT_Pos height; +/* XXX Compute top side bearing and advance height in */ +/* Get_VMetrics instead of here. */ +/* NOTE: The OS/2 values are the only `portable' ones, */ +/* which is why we use them, if there is an OS/2 */ +/* table in the font. Otherwise, we use the */ +/* values defined in the horizontal header. */ + height = (FT_Short)FT_DivFix( bbox.yMax - bbox.yMin, + y_scale ); + if ( face->os2.version != 0xFFFFU ) + advance = (FT_Pos)( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + advance = (FT_Pos)( face->horizontal.Ascender - + face->horizontal.Descender ); + top = ( advance - height ) / 2; + } + { + FT_Incremental_InterfaceRec* incr; + FT_Incremental_MetricsRec metrics; + FT_Error error; + incr = face->root.internal->incremental_interface; +/* If this is an incrementally loaded font see if there are */ +/* overriding metrics for this glyph. */ + if ( incr && incr->funcs->get_glyph_metrics ) + { + metrics.bearing_x = 0; + metrics.bearing_y = top; + metrics.advance = advance; + error = incr->funcs->get_glyph_metrics( incr->object, + glyph_index, + TRUE, + &metrics ); + if ( error ) + return error; + top = metrics.bearing_y; + advance = metrics.advance; + } + } +/* GWW: Do vertical metrics get loaded incrementally too? */ + glyph->linearVertAdvance = advance; +/* scale the metrics */ + if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) ) + { + top = FT_MulFix( top, y_scale ); + advance = FT_MulFix( advance, y_scale ); + } +/* XXX: for now, we have no better algorithm for the lsb, but it */ +/* should work fine. */ +/* */ + glyph->metrics.vertBearingX = glyph->metrics.horiBearingX - + glyph->metrics.horiAdvance / 2; + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + return 0; + } + static FT_Error + load_sbit_image( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + TT_Face face; + SFNT_Service sfnt; + FT_Stream stream; + FT_Error error; + TT_SBit_MetricsRec metrics; + face = (TT_Face)glyph->face; + sfnt = (SFNT_Service)face->sfnt; + stream = face->root.stream; + error = sfnt->load_sbit_image( face, + size->strike_index, + glyph_index, + (FT_Int)load_flags, + stream, + &glyph->bitmap, + &metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + glyph->metrics.width = (FT_Pos)metrics.width << 6; + glyph->metrics.height = (FT_Pos)metrics.height << 6; + glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6; + glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6; + glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6; + glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6; + glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6; + glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6; + glyph->format = FT_GLYPH_FORMAT_BITMAP; + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + glyph->bitmap_left = metrics.vertBearingX; + glyph->bitmap_top = metrics.vertBearingY; + } + else + { + glyph->bitmap_left = metrics.horiBearingX; + glyph->bitmap_top = metrics.horiBearingY; + } + } + return error; + } + static FT_Error + tt_loader_init( TT_Loader loader, + TT_Size size, + TT_GlyphSlot glyph, + FT_Int32 load_flags, + FT_Bool glyf_table_only ) + { + TT_Face face; + FT_Stream stream; + FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + face = (TT_Face)glyph->face; + stream = face->root.stream; + FT_MEM_ZERO( loader, sizeof ( TT_LoaderRec ) ); +/* load execution context */ + if ( IS_HINTED( load_flags ) && !glyf_table_only ) + { + TT_ExecContext exec; + FT_Bool grayscale; + if ( !size->cvt_ready ) + { + FT_Error error = tt_size_ready_bytecode( size, pedantic ); + if ( error ) + return error; + } +/* query new execution context */ + exec = size->debug ? size->context + : ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + grayscale = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); + TT_Load_Context( exec, face, size ); +/* a change from mono to grayscale rendering (and vice versa) */ +/* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_UInt i; + FT_TRACE4(( "tt_loader_init: grayscale change," + " re-executing `prep' table\n" )); + exec->grayscale = grayscale; + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + tt_size_run_prep( size, pedantic ); + } +/* see whether the cvt program has disabled hinting */ + if ( exec->GS.instruct_control & 1 ) + load_flags |= FT_LOAD_NO_HINTING; +/* load default graphics state -- if needed */ + if ( exec->GS.instruct_control & 2 ) + exec->GS = tt_default_graphics_state; + exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + loader->exec = exec; + loader->instructions = exec->glyphIns; + } +/* seek to the beginning of the glyph table -- for Type 42 fonts */ +/* the table might be accessed from a Postscript stream or something */ +/* else... */ + if ( face->root.internal->incremental_interface ) + loader->glyf_offset = 0; + else + { + FT_Error error = face->goto_table( face, TTAG_glyf, stream, 0 ); + if ( error == TT_Err_Table_Missing ) + loader->glyf_offset = 0; + else if ( error ) + { + FT_ERROR(( "tt_loader_init: could not access glyph table\n" )); + return error; + } + else + loader->glyf_offset = FT_STREAM_POS(); + } +/* get face's glyph loader */ + if ( !glyf_table_only ) + { + FT_GlyphLoader gloader = glyph->internal->loader; + FT_GlyphLoader_Rewind( gloader ); + loader->gloader = gloader; + } + loader->load_flags = load_flags; + loader->face = (FT_Face)face; + loader->size = (FT_Size)size; + loader->glyph = (FT_GlyphSlot)glyph; + loader->stream = stream; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Load_Glyph */ +/* */ +/* <Description> */ +/* A function used to load a single glyph within a given glyph slot, */ +/* for a given size. */ +/* */ +/* <Input> */ +/* glyph :: A handle to a target slot object where the glyph */ +/* will be loaded. */ +/* */ +/* size :: A handle to the source face size at which the glyph */ +/* must be scaled/loaded. */ +/* */ +/* glyph_index :: The index of the glyph in the font file. */ +/* */ +/* load_flags :: A flag indicating what to load for this glyph. The */ +/* FT_LOAD_XXX constants can be used to control the */ +/* glyph loading process (e.g., whether the outline */ +/* should be scaled, whether to load bitmaps or not, */ +/* whether to hint the outline, etc). */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + TT_LoaderRec loader; + error = TT_Err_Ok; +/* try to load embedded bitmap if any */ +/* */ +/* XXX: The convention should be emphasized in */ +/* the documents because it can be confusing. */ + if ( size->strike_index != 0xFFFFFFFFUL && + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + { + error = load_sbit_image( size, glyph, glyph_index, load_flags ); + if ( !error ) + { + if ( FT_IS_SCALABLE( glyph->face ) ) + { +/* for the bbox we need the header only */ + (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); + (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); + glyph->linearHoriAdvance = loader.linear; + glyph->linearVertAdvance = loader.top_bearing + loader.bbox.yMax - + loader.vadvance; + } + return TT_Err_Ok; + } + } +/* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) + return TT_Err_Invalid_Size_Handle; + if ( load_flags & FT_LOAD_SBITS_ONLY ) + return TT_Err_Invalid_Argument; + error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); + if ( error ) + return error; + glyph->format = FT_GLYPH_FORMAT_OUTLINE; + glyph->num_subglyphs = 0; + glyph->outline.flags = 0; +/* main loading loop */ + error = load_truetype_glyph( &loader, glyph_index, 0, FALSE ); + if ( !error ) + { + if ( glyph->format == FT_GLYPH_FORMAT_COMPOSITE ) + { + glyph->num_subglyphs = loader.gloader->base.num_subglyphs; + glyph->subglyphs = loader.gloader->base.subglyphs; + } + else + { + glyph->outline = loader.gloader->base.outline; + glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; +/* Translate array so that (0,0) is the glyph's origin. Note */ +/* that this behaviour is independent on the value of bit 1 of */ +/* the `flags' field in the `head' table -- at least major */ +/* applications like Acroread indicate that. */ + if ( loader.pp1.x ) + FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 ); + } + if ( IS_HINTED( load_flags ) ) + { + if ( loader.exec->GS.scan_control ) + { +/* convert scan conversion mode to FT_OUTLINE_XXX flags */ + switch ( loader.exec->GS.scan_type ) + { +/* simple drop-outs including stubs */ + case 0: + glyph->outline.flags |= FT_OUTLINE_INCLUDE_STUBS; + break; +/* simple drop-outs excluding stubs */ + case 1: +/* nothing; it's the default rendering mode */ + break; +/* smart drop-outs including stubs */ + case 4: + glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS | + FT_OUTLINE_INCLUDE_STUBS; + break; +/* smart drop-outs excluding stubs */ + case 5: + glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS; + break; +/* no drop-out control */ + default: + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; + break; + } + } + else + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; + } + compute_glyph_metrics( &loader, glyph_index ); + } +/* Set the `high precision' bit flag. */ +/* This is _critical_ to get correct output for monochrome */ +/* TrueType glyphs at all sizes using the bytecode interpreter. */ +/* */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && + size->root.metrics.y_ppem < 24 ) + glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + return error; + } +/* END */ +/* object manager */ +/***************************************************************************/ +/* */ +/* ttobjs.c */ +/* */ +/* Objects manager (body). */ +/* */ +/* Copyright 1996-2012 */ +/* 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 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 trace_ttobjs +/*************************************************************************/ +/* */ +/* GLYPH ZONE FUNCTIONS */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_glyphzone_done */ +/* */ +/* <Description> */ +/* Deallocate a glyph zone. */ +/* */ +/* <Input> */ +/* zone :: A pointer to the target glyph zone. */ +/* */ + FT_LOCAL_DEF( void ) + tt_glyphzone_done( TT_GlyphZone zone ) + { + FT_Memory memory = zone->memory; + if ( memory ) + { + FT_FREE( zone->contours ); + FT_FREE( zone->tags ); + FT_FREE( zone->cur ); + FT_FREE( zone->org ); + FT_FREE( zone->orus ); + zone->max_points = zone->n_points = 0; + zone->max_contours = zone->n_contours = 0; + zone->memory = NULL; + } + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_glyphzone_new */ +/* */ +/* <Description> */ +/* Allocate a new glyph zone. */ +/* */ +/* <Input> */ +/* memory :: A handle to the current memory object. */ +/* */ +/* maxPoints :: The capacity of glyph zone in points. */ +/* */ +/* maxContours :: The capacity of glyph zone in contours. */ +/* */ +/* <Output> */ +/* zone :: A pointer to the target glyph zone record. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_glyphzone_new( FT_Memory memory, + FT_UShort maxPoints, + FT_Short maxContours, + TT_GlyphZone zone ) + { + FT_Error error; + FT_MEM_ZERO( zone, sizeof ( *zone ) ); + zone->memory = memory; + if ( FT_NEW_ARRAY( zone->org, maxPoints ) || + FT_NEW_ARRAY( zone->cur, maxPoints ) || + FT_NEW_ARRAY( zone->orus, maxPoints ) || + FT_NEW_ARRAY( zone->tags, maxPoints ) || + FT_NEW_ARRAY( zone->contours, maxContours ) ) + { + tt_glyphzone_done( zone ); + } + else + { + zone->max_points = maxPoints; + zone->max_contours = maxContours; + } + return error; + } +/* Compare the face with a list of well-known `tricky' fonts. */ +/* This list shall be expanded as we find more of them. */ + static FT_Bool + tt_check_trickyness_family( FT_String* name ) + { +#define TRICK_NAMES_MAX_CHARACTERS 16 +#define TRICK_NAMES_COUNT 8 + static const char trick_names[TRICK_NAMES_COUNT] + [TRICK_NAMES_MAX_CHARACTERS + 1] = + { +/* dfkaisb.ttf */ + "DFKaiSho-SB", + "DFKaiShu", +/* kaiu.ttf */ + "DFKai-SB", +/* htkt2.ttf */ + "HuaTianKaiTi?", +/* htst3.ttf */ + "HuaTianSongTi?", +/* mingliu.ttf & mingliu.ttc */ + "MingLiU", +/* mingliu.ttc */ + "PMingLiU", +/* mingli.ttf */ + "MingLi43", + }; + int nn; + for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) + if ( ft_strstr( name, trick_names[nn] ) ) + return TRUE; + return FALSE; + } +/* XXX: This function should be in the `sfnt' module. */ +/* Some PDF generators clear the checksums in the TrueType header table. */ +/* For example, Quartz ContextPDF clears all entries, or Bullzip PDF */ +/* Printer clears the entries for subsetted subtables. We thus have to */ +/* recalculate the checksums where necessary. */ + static FT_UInt32 + tt_synth_sfnt_checksum( FT_Stream stream, + FT_ULong length ) + { + FT_Error error; + FT_UInt32 checksum = 0; + int i; + if ( FT_FRAME_ENTER( length ) ) + return 0; + for ( ; length > 3; length -= 4 ) + checksum += (FT_UInt32)FT_GET_ULONG(); + for ( i = 3; length > 0; length --, i-- ) + checksum += (FT_UInt32)( FT_GET_BYTE() << ( i * 8 ) ); + FT_FRAME_EXIT(); + return checksum; + } +/* XXX: This function should be in the `sfnt' module. */ + static FT_ULong + tt_get_sfnt_checksum( TT_Face face, + FT_UShort i ) + { +/* if we believe the written value, use following part. */ +#if 0 + if ( face->dir_tables[i].CheckSum ) + return face->dir_tables[i].CheckSum; +#endif + if ( !face->goto_table ) + return 0; + if ( face->goto_table( face, + face->dir_tables[i].Tag, + face->root.stream, + NULL ) ) + return 0; + return (FT_ULong)tt_synth_sfnt_checksum( face->root.stream, + face->dir_tables[i].Length ); + } + typedef struct tt_sfnt_id_rec_ + { + FT_ULong CheckSum; + FT_ULong Length; + } tt_sfnt_id_rec; + static FT_Bool + tt_check_trickyness_sfnt_ids( TT_Face face ) + { +#define TRICK_SFNT_IDS_PER_FACE 3 +#define TRICK_SFNT_IDS_NUM_FACES 17 + static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] + [TRICK_SFNT_IDS_PER_FACE] = { +#define TRICK_SFNT_ID_cvt 0 +#define TRICK_SFNT_ID_fpgm 1 +#define TRICK_SFNT_ID_prep 2 +/* MingLiU 1995 */ + { +/* cvt */ + { 0x05bcf058, 0x000002e4 }, +/* fpgm */ + { 0x28233bf1, 0x000087c4 }, +/* prep */ + { 0xa344a1ea, 0x000001e1 } + }, +/* MingLiU 1996- */ + { +/* cvt */ + { 0x05bcf058, 0x000002e4 }, +/* fpgm */ + { 0x28233bf1, 0x000087c4 }, +/* prep */ + { 0xa344a1eb, 0x000001e1 } + }, +/* DFKaiShu */ + { +/* cvt */ + { 0x11e5ead4, 0x00000350 }, +/* fpgm */ + { 0x5a30ca3b, 0x00009063 }, +/* prep */ + { 0x13a42602, 0x0000007e } + }, +/* HuaTianKaiTi */ + { +/* cvt */ + { 0xfffbfffc, 0x00000008 }, +/* fpgm */ + { 0x9c9e48b8, 0x0000bea2 }, +/* prep */ + { 0x70020112, 0x00000008 } + }, +/* HuaTianSongTi */ + { +/* cvt */ + { 0xfffbfffc, 0x00000008 }, +/* fpgm */ + { 0x0a5a0483, 0x00017c39 }, +/* prep */ + { 0x70020112, 0x00000008 } + }, +/* NEC fadpop7.ttf */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x40c92555, 0x000000e5 }, +/* prep */ + { 0xa39b58e3, 0x0000117c } + }, +/* NEC fadrei5.ttf */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x33c41652, 0x000000e5 }, +/* prep */ + { 0x26d6c52a, 0x00000f6a } + }, +/* NEC fangot7.ttf */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x6db1651d, 0x0000019d }, +/* prep */ + { 0x6c6e4b03, 0x00002492 } + }, +/* NEC fangyo5.ttf */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x40c92555, 0x000000e5 }, +/* prep */ + { 0xde51fad0, 0x0000117c } + }, +/* NEC fankyo5.ttf */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x85e47664, 0x000000e5 }, +/* prep */ + { 0xa6c62831, 0x00001caa } + }, +/* NEC fanrgo5.ttf */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x2d891cfd, 0x0000019d }, +/* prep */ + { 0xa0604633, 0x00001de8 } + }, +/* NEC fangot5.ttc */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x40aa774c, 0x000001cb }, +/* prep */ + { 0x9b5caa96, 0x00001f9a } + }, +/* NEC fanmin3.ttc */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x0d3de9cb, 0x00000141 }, +/* prep */ + { 0xd4127766, 0x00002280 } + }, +/* NEC FA-Gothic, 1996 */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x4a692698, 0x000001f0 }, +/* prep */ + { 0x340d4346, 0x00001fca } + }, +/* NEC FA-Minchou, 1996 */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0xcd34c604, 0x00000166 }, +/* prep */ + { 0x6cf31046, 0x000022b0 } + }, +/* NEC FA-RoundGothicB, 1996 */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0x5da75315, 0x0000019d }, +/* prep */ + { 0x40745a5f, 0x000022e0 } + }, +/* NEC FA-RoundGothicM, 1996 */ + { +/* cvt */ + { 0x00000000, 0x00000000 }, +/* fpgm */ + { 0xf055fc48, 0x000001c2 }, +/* prep */ + { 0x3900ded3, 0x00001e18 } + } + }; + FT_ULong checksum; + int num_matched_ids[TRICK_SFNT_IDS_NUM_FACES]; + FT_Bool has_cvt, has_fpgm, has_prep; + FT_UShort i; + int j, k; + FT_MEM_SET( num_matched_ids, 0, + sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); + has_cvt = FALSE; + has_fpgm = FALSE; + has_prep = FALSE; + for ( i = 0; i < face->num_tables; i++ ) + { + checksum = 0; + switch( face->dir_tables[i].Tag ) + { + case TTAG_cvt: + k = TRICK_SFNT_ID_cvt; + has_cvt = TRUE; + break; + case TTAG_fpgm: + k = TRICK_SFNT_ID_fpgm; + has_fpgm = TRUE; + break; + case TTAG_prep: + k = TRICK_SFNT_ID_prep; + has_prep = TRUE; + break; + default: + continue; + } + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + if ( face->dir_tables[i].Length == sfnt_id[j][k].Length ) + { + if ( !checksum ) + checksum = tt_get_sfnt_checksum( face, i ); + if ( sfnt_id[j][k].CheckSum == checksum ) + num_matched_ids[j]++; + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + } + for ( j = 0; j < TRICK_SFNT_IDS_NUM_FACES; j++ ) + { + if ( !has_cvt && !sfnt_id[j][TRICK_SFNT_ID_cvt].Length ) + num_matched_ids[j] ++; + if ( !has_fpgm && !sfnt_id[j][TRICK_SFNT_ID_fpgm].Length ) + num_matched_ids[j] ++; + if ( !has_prep && !sfnt_id[j][TRICK_SFNT_ID_prep].Length ) + num_matched_ids[j] ++; + if ( num_matched_ids[j] == TRICK_SFNT_IDS_PER_FACE ) + return TRUE; + } + return FALSE; + } + static FT_Bool + tt_check_trickyness( FT_Face face ) + { + if ( !face ) + return FALSE; +/* For first, check the face name for quick check. */ + if ( face->family_name && + tt_check_trickyness_family( face->family_name ) ) + return TRUE; +/* Type42 fonts may lack `name' tables, we thus try to identify */ +/* tricky fonts by checking the checksums of Type42-persistent */ +/* sfnt tables (`cvt', `fpgm', and `prep'). */ + if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) + return TRUE; + return FALSE; + } +/* Check whether `.notdef' is the only glyph in the `loca' table. */ + static FT_Bool + tt_check_single_notdef( FT_Face ttface ) + { + FT_Bool result = FALSE; + TT_Face face = (TT_Face)ttface; + FT_UInt asize; + FT_ULong i; + FT_ULong glyph_index = 0; + FT_UInt count = 0; + for( i = 0; i < face->num_locations; i++ ) + { + tt_face_get_location( face, i, &asize ); + if ( asize > 0 ) + { + count += 1; + if ( count > 1 ) + break; + glyph_index = i; + } + } +/* Only have a single outline. */ + if ( count == 1 ) + { + if ( glyph_index == 0 ) + result = TRUE; + else + { +/* FIXME: Need to test glyphname == .notdef ? */ + FT_Error error; + char buf[8]; + error = FT_Get_Glyph_Name( ttface, glyph_index, buf, 8 ); + if ( !error && + buf[0] == '.' && !ft_strncmp( buf, ".notdef", 8 ) ) + result = TRUE; + } + } + return result; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_init */ +/* */ +/* <Description> */ +/* Initialize a given TrueType face object. */ +/* */ +/* <Input> */ +/* stream :: The source font 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 ) + tt_face_init( FT_Stream stream, +/* TT_Face */ + FT_Face ttface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FT_Error error; + FT_Library library; + SFNT_Service sfnt; + TT_Face face = (TT_Face)ttface; + FT_TRACE2(( "TTF driver\n" )); + library = ttface->driver->root.library; + sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); + if ( !sfnt ) + { + FT_ERROR(( "tt_face_init: cannot access `sfnt' module\n" )); + error = TT_Err_Missing_Module; + goto Exit; + } +/* create input stream from resource */ + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; +/* check that we have a valid TrueType file */ + error = sfnt->init_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; +/* We must also be able to accept Mac/GX fonts, as well as OT ones. */ +/* The 0x00020000 tag is completely undocumented; some fonts from */ +/* Arphic made for Chinese Windows 3.1 have this. */ +/* MS fonts */ + if ( face->format_tag != 0x00010000L && +/* CJK fonts for Win 3.1 */ + face->format_tag != 0x00020000L && +/* Mac fonts */ + face->format_tag != TTAG_true ) + { + FT_TRACE2(( " not a TTF font\n" )); + goto Bad_Format; + } + ttface->face_flags |= FT_FACE_FLAG_HINTER; +/* If we are performing a simple font format check, exit immediately. */ + if ( face_index < 0 ) + return TT_Err_Ok; +/* Load font directory */ + error = sfnt->load_face( stream, face, face_index, num_params, params ); + if ( error ) + goto Exit; + if ( tt_check_trickyness( ttface ) ) + ttface->face_flags |= FT_FACE_FLAG_TRICKY; + error = tt_face_load_hdmx( face, stream ); + if ( error ) + goto Exit; + if ( FT_IS_SCALABLE( ttface ) ) + { + if ( !ttface->internal->incremental_interface ) + error = tt_face_load_loca( face, stream ); + if ( !error ) + error = tt_face_load_cvt( face, stream ); + if ( !error ) + error = tt_face_load_fpgm( face, stream ); + if ( !error ) + error = tt_face_load_prep( face, stream ); +/* Check the scalable flag based on `loca'. */ + if ( !ttface->internal->incremental_interface && + ttface->num_fixed_sizes && + face->glyph_locations && + tt_check_single_notdef( ttface ) ) + { + FT_TRACE5(( "tt_face_init:" + " Only the `.notdef' glyph has an outline.\n" + " " + " Resetting scalable flag to FALSE.\n" )); + ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; + } + } +#if defined( TT_CONFIG_OPTION_UNPATENTED_HINTING ) && \ + !defined( TT_CONFIG_OPTION_BYTECODE_INTERPRETER ) + { + FT_Bool unpatented_hinting; + int i; +/* Determine whether unpatented hinting is to be used for this face. */ + unpatented_hinting = FT_BOOL + ( library->debug_hooks[FT_DEBUG_HOOK_UNPATENTED_HINTING] != NULL ); + for ( i = 0; i < num_params && !face->unpatented_hinting; i++ ) + if ( params[i].tag == FT_PARAM_TAG_UNPATENTED_HINTING ) + unpatented_hinting = TRUE; + if ( !unpatented_hinting ) + ttface->internal->ignore_unpatented_hinter = TRUE; + } +/* TT_CONFIG_OPTION_UNPATENTED_HINTING && + !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ +#endif +/* initialize standard glyph loading routines */ + TT_Init_Glyph_Loading( face ); + Exit: + return error; + Bad_Format: + error = TT_Err_Unknown_File_Format; + goto Exit; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_done */ +/* */ +/* <Description> */ +/* Finalize a given face object. */ +/* */ +/* <Input> */ +/* face :: A pointer to the face object to destroy. */ +/* */ + FT_LOCAL_DEF( void ) +/* TT_Face */ + tt_face_done( FT_Face ttface ) + { + TT_Face face = (TT_Face)ttface; + FT_Memory memory; + FT_Stream stream; + SFNT_Service sfnt; + if ( !face ) + return; + memory = ttface->memory; + stream = ttface->stream; + sfnt = (SFNT_Service)face->sfnt; +/* for `extended TrueType formats' (i.e. compressed versions) */ + if ( face->extra.finalizer ) + face->extra.finalizer( face->extra.data ); + if ( sfnt ) + sfnt->done_face( face ); +/* freeing the locations table */ + tt_face_done_loca( face ); + tt_face_free_hdmx( face ); +/* freeing the CVT */ + FT_FREE( face->cvt ); + face->cvt_size = 0; +/* freeing the programs */ + FT_FRAME_RELEASE( face->font_program ); + FT_FRAME_RELEASE( face->cvt_program ); + face->font_program_size = 0; + face->cvt_program_size = 0; + tt_done_blend( memory, face->blend ); + face->blend = NULL; + } +/*************************************************************************/ +/* */ +/* SIZE FUNCTIONS */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_size_run_fpgm */ +/* */ +/* <Description> */ +/* Run the font program. */ +/* */ +/* <Input> */ +/* size :: A handle to the size object. */ +/* */ +/* pedantic :: Set if bytecode execution should be pedantic. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_fpgm( TT_Size size, + FT_Bool pedantic ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; +/* debugging instances have their own context */ + if ( size->debug ) + exec = size->context; + else + exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + TT_Load_Context( exec, face, size ); + exec->callTop = 0; + exec->top = 0; + exec->period = 64; + exec->phase = 0; + exec->threshold = 0; + exec->instruction_trap = FALSE; + exec->F_dot_P = 0x4000L; + exec->pedantic_hinting = pedantic; + { + FT_Size_Metrics* metrics = &exec->metrics; + TT_Size_Metrics* tt_metrics = &exec->tt_metrics; + metrics->x_ppem = 0; + metrics->y_ppem = 0; + metrics->x_scale = 0; + metrics->y_scale = 0; + tt_metrics->ppem = 0; + tt_metrics->scale = 0; + tt_metrics->ratio = 0x10000L; + } +/* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + face->font_program_size ); +/* disable CVT and glyph programs coderange */ + TT_Clear_CodeRange( exec, tt_coderange_cvt ); + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + if ( face->font_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + if ( !error ) + { + FT_TRACE4(( "Executing `fpgm' table.\n" )); + error = face->interpreter( exec ); + } + } + else + error = TT_Err_Ok; + if ( !error ) + TT_Save_Context( exec, size ); + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_size_run_prep */ +/* */ +/* <Description> */ +/* Run the control value program. */ +/* */ +/* <Input> */ +/* size :: A handle to the size object. */ +/* */ +/* pedantic :: Set if bytecode execution should be pedantic. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_run_prep( TT_Size size, + FT_Bool pedantic ) + { + TT_Face face = (TT_Face)size->root.face; + TT_ExecContext exec; + FT_Error error; +/* debugging instances have their own context */ + if ( size->debug ) + exec = size->context; + else + exec = ( (TT_Driver)FT_FACE_DRIVER( face ) )->context; + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + TT_Load_Context( exec, face, size ); + exec->callTop = 0; + exec->top = 0; + exec->instruction_trap = FALSE; + exec->pedantic_hinting = pedantic; + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + face->cvt_program_size ); + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + if ( face->cvt_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + if ( !error && !size->debug ) + { + FT_TRACE4(( "Executing `prep' table.\n" )); + error = face->interpreter( exec ); + } + } + else + error = TT_Err_Ok; +/* save as default graphics state */ + size->GS = exec->GS; + TT_Save_Context( exec, size ); + return error; + } + static void + tt_size_done_bytecode( FT_Size ftsize ) + { + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + if ( size->debug ) + { +/* the debug context must be deleted by the debugger itself */ + size->context = NULL; + size->debug = FALSE; + } + FT_FREE( size->cvt ); + size->cvt_size = 0; +/* free storage area */ + FT_FREE( size->storage ); + size->storage_size = 0; +/* twilight zone */ + tt_glyphzone_done( &size->twilight ); + FT_FREE( size->function_defs ); + FT_FREE( size->instruction_defs ); + size->num_function_defs = 0; + size->max_function_defs = 0; + size->num_instruction_defs = 0; + size->max_instruction_defs = 0; + size->max_func = 0; + size->max_ins = 0; + size->bytecode_ready = 0; + size->cvt_ready = 0; + } +/* Initialize bytecode-related fields in the size object. */ +/* We do this only if bytecode interpretation is really needed. */ + static FT_Error + tt_size_init_bytecode( FT_Size ftsize, + FT_Bool pedantic ) + { + FT_Error error; + TT_Size size = (TT_Size)ftsize; + TT_Face face = (TT_Face)ftsize->face; + FT_Memory memory = face->root.memory; + FT_Int i; + FT_UShort n_twilight; + TT_MaxProfile* maxp = &face->max_profile; + size->bytecode_ready = 1; + size->cvt_ready = 0; + size->max_function_defs = maxp->maxFunctionDefs; + size->max_instruction_defs = maxp->maxInstructionDefs; + size->num_function_defs = 0; + size->num_instruction_defs = 0; + size->max_func = 0; + size->max_ins = 0; + size->cvt_size = face->cvt_size; + size->storage_size = maxp->maxStorage; +/* Set default metrics */ + { + TT_Size_Metrics* metrics = &size->ttmetrics; + metrics->rotated = FALSE; + metrics->stretched = FALSE; +/* set default compensation (all 0) */ + for ( i = 0; i < 4; i++ ) + metrics->compensations[i] = 0; + } +/* allocate function defs, instruction defs, cvt, and storage area */ + if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || + FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || + FT_NEW_ARRAY( size->cvt, size->cvt_size ) || + FT_NEW_ARRAY( size->storage, size->storage_size ) ) + goto Exit; +/* reserve twilight zone */ + n_twilight = maxp->maxTwilightPoints; +/* there are 4 phantom points (do we need this?) */ + n_twilight += 4; + error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight ); + if ( error ) + goto Exit; + size->twilight.n_points = n_twilight; + size->GS = tt_default_graphics_state; +/* set `face->interpreter' according to the debug hook present */ + { + FT_Library library = face->root.driver->root.library; + face->interpreter = (TT_Interpreter) + library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; + if ( !face->interpreter ) + face->interpreter = (TT_Interpreter)TT_RunIns; + } +/* Fine, now run the font program! */ + error = tt_size_run_fpgm( size, pedantic ); + Exit: + if ( error ) + tt_size_done_bytecode( ftsize ); + return error; + } + FT_LOCAL_DEF( FT_Error ) + tt_size_ready_bytecode( TT_Size size, + FT_Bool pedantic ) + { + FT_Error error = TT_Err_Ok; + if ( !size->bytecode_ready ) + { + error = tt_size_init_bytecode( (FT_Size)size, pedantic ); + if ( error ) + goto Exit; + } +/* rescale CVT when needed */ + if ( !size->cvt_ready ) + { + FT_UInt i; + TT_Face face = (TT_Face)size->root.face; +/* Scale the cvt values to the new ppem. */ +/* We use by default the y ppem to scale the CVT. */ + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); +/* all twilight points are originally zero */ + for ( i = 0; i < (FT_UInt)size->twilight.n_points; i++ ) + { + size->twilight.org[i].x = 0; + size->twilight.org[i].y = 0; + size->twilight.cur[i].x = 0; + size->twilight.cur[i].y = 0; + } +/* clear storage area */ + for ( i = 0; i < (FT_UInt)size->storage_size; i++ ) + size->storage[i] = 0; + size->GS = tt_default_graphics_state; + error = tt_size_run_prep( size, pedantic ); + if ( !error ) + size->cvt_ready = 1; + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_size_init */ +/* */ +/* <Description> */ +/* Initialize a new TrueType size object. */ +/* */ +/* <InOut> */ +/* size :: A handle to the size object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) +/* TT_Size */ + tt_size_init( FT_Size ttsize ) + { + TT_Size size = (TT_Size)ttsize; + FT_Error error = TT_Err_Ok; + size->bytecode_ready = 0; + size->cvt_ready = 0; + size->ttmetrics.valid = FALSE; + size->strike_index = 0xFFFFFFFFUL; + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_size_done */ +/* */ +/* <Description> */ +/* The TrueType size object finalizer. */ +/* */ +/* <Input> */ +/* size :: A handle to the target size object. */ +/* */ + FT_LOCAL_DEF( void ) +/* TT_Size */ + tt_size_done( FT_Size ttsize ) + { + TT_Size size = (TT_Size)ttsize; + if ( size->bytecode_ready ) + tt_size_done_bytecode( ttsize ); + size->ttmetrics.valid = FALSE; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_size_reset */ +/* */ +/* <Description> */ +/* Reset a TrueType size when resolutions and character dimensions */ +/* have been changed. */ +/* */ +/* <Input> */ +/* size :: A handle to the target size object. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_size_reset( TT_Size size ) + { + TT_Face face; + FT_Error error = TT_Err_Ok; + FT_Size_Metrics* metrics; + size->ttmetrics.valid = FALSE; + face = (TT_Face)size->root.face; + metrics = &size->metrics; +/* copy the result from base layer */ + *metrics = size->root.metrics; + if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 ) + return TT_Err_Invalid_PPem; +/* This bit flag, if set, indicates that the ppems must be */ +/* rounded to integers. Nearly all TrueType fonts have this bit */ +/* set, as hinting won't work really well otherwise. */ +/* */ + if ( face->header.Flags & 8 ) + { + metrics->x_scale = FT_DivFix( metrics->x_ppem << 6, + face->root.units_per_EM ); + metrics->y_scale = FT_DivFix( metrics->y_ppem << 6, + face->root.units_per_EM ); + metrics->ascender = + FT_PIX_ROUND( FT_MulFix( face->root.ascender, metrics->y_scale ) ); + metrics->descender = + FT_PIX_ROUND( FT_MulFix( face->root.descender, metrics->y_scale ) ); + metrics->height = + FT_PIX_ROUND( FT_MulFix( face->root.height, metrics->y_scale ) ); + metrics->max_advance = + FT_PIX_ROUND( FT_MulFix( face->root.max_advance_width, + metrics->x_scale ) ); + } +/* compute new transformation */ + if ( metrics->x_ppem >= metrics->y_ppem ) + { + size->ttmetrics.scale = metrics->x_scale; + size->ttmetrics.ppem = metrics->x_ppem; + size->ttmetrics.x_ratio = 0x10000L; + size->ttmetrics.y_ratio = FT_DivFix( metrics->y_ppem, + metrics->x_ppem ); + } + else + { + size->ttmetrics.scale = metrics->y_scale; + size->ttmetrics.ppem = metrics->y_ppem; + size->ttmetrics.x_ratio = FT_DivFix( metrics->x_ppem, + metrics->y_ppem ); + size->ttmetrics.y_ratio = 0x10000L; + } + size->cvt_ready = 0; + if ( !error ) + size->ttmetrics.valid = TRUE; + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_driver_init */ +/* */ +/* <Description> */ +/* Initialize a given TrueType driver object. */ +/* */ +/* <Input> */ +/* driver :: A handle to the target driver object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) +/* TT_Driver */ + tt_driver_init( FT_Module ttdriver ) + { + TT_Driver driver = (TT_Driver)ttdriver; + if ( !TT_New_Context( driver ) ) + return TT_Err_Could_Not_Find_Context; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_driver_done */ +/* */ +/* <Description> */ +/* Finalize a given TrueType driver. */ +/* */ +/* <Input> */ +/* driver :: A handle to the target TrueType driver. */ +/* */ + FT_LOCAL_DEF( void ) +/* TT_Driver */ + tt_driver_done( FT_Module ttdriver ) + { + TT_Driver driver = (TT_Driver)ttdriver; +/* destroy the execution context */ + if ( driver->context ) + { + TT_Done_Context( driver->context ); + driver->context = NULL; + } + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_slot_init */ +/* */ +/* <Description> */ +/* Initialize a new slot object. */ +/* */ +/* <InOut> */ +/* slot :: A handle to the slot object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_slot_init( FT_GlyphSlot slot ) + { + return FT_GlyphLoader_CreateExtra( slot->internal->loader ); + } +/* END */ +/***************************************************************************/ +/* */ +/* ttinterp.c */ +/* */ +/* TrueType bytecode interpreter (body). */ +/* */ +/* Copyright 1996-2012 */ +/* 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. */ +/* */ +/***************************************************************************/ +/* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */ +/* issues; many thanks! */ +#define xxxSPH_DEBUG +#define xxxSPH_DEBUG_MORE_VERBOSE +/*************************************************************************/ +/* */ +/* 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 trace_ttinterp +/*************************************************************************/ +/* */ +/* In order to detect infinite loops in the code, we set up a counter */ +/* within the run loop. A single stroke of interpretation is now */ +/* limited to a maximum number of opcodes defined below. */ +/* */ +#define MAX_RUNNABLE_OPCODES 1000000L +/*************************************************************************/ +/* */ +/* There are two kinds of implementations: */ +/* */ +/* a. static implementation */ +/* */ +/* The current execution context is a static variable, which fields */ +/* are accessed directly by the interpreter during execution. The */ +/* context is named `cur'. */ +/* */ +/* This version is non-reentrant, of course. */ +/* */ +/* b. indirect implementation */ +/* */ +/* The current execution context is passed to _each_ function as its */ +/* first argument, and each field is thus accessed indirectly. */ +/* */ +/* This version is fully re-entrant. */ +/* */ +/* The idea is that an indirect implementation may be slower to execute */ +/* on low-end processors that are used in some systems (like 386s or */ +/* even 486s). */ +/* */ +/* As a consequence, the indirect implementation is now the default, as */ +/* its performance costs can be considered negligible in our context. */ +/* Note, however, that we kept the same source with macros because: */ +/* */ +/* - The code is kept very close in design to the Pascal code used for */ +/* development. */ +/* */ +/* - It's much more readable that way! */ +/* */ +/* - It's still open to experimentation and tuning. */ +/* */ +/*************************************************************************/ +/* indirect implementation */ +#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER +/* see ttobjs.h */ +#define CUR (*exc) +/*************************************************************************/ +/* */ +/* This macro is used whenever `exec' is unused in a function, to avoid */ +/* stupid warnings from pedantic compilers. */ +/* */ +#define FT_UNUSED_EXEC FT_UNUSED( exc ) +/* static implementation */ +#else +#define CUR cur +#define FT_UNUSED_EXEC int __dummy = __dummy + static +/* static exec. context variable */ + TT_ExecContextRec cur; +/* apparently, we have a _lot_ of direct indexing when accessing */ +/* the static `cur', which makes the code bigger (due to all the */ +/* four bytes addresses). */ +/* TT_CONFIG_OPTION_STATIC_INTERPRETER */ +#endif +/*************************************************************************/ +/* */ +/* The instruction argument stack. */ +/* */ +/* see ttobjs.h for EXEC_OP_ */ +#define INS_ARG EXEC_OP_ FT_Long* args +/*************************************************************************/ +/* */ +/* This macro is used whenever `args' is unused in a function, to avoid */ +/* stupid warnings from pedantic compilers. */ +/* */ +#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args ) +/*************************************************************************/ +/* */ +/* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */ +/* increase readability of the code. */ +/* */ +/*************************************************************************/ +#define SKIP_Code() \ + SkipCode( EXEC_ARG ) +#define GET_ShortIns() \ + GetShortIns( EXEC_ARG ) +#define NORMalize( x, y, v ) \ + Normalize( EXEC_ARG_ x, y, v ) +#define SET_SuperRound( scale, flags ) \ + SetSuperRound( EXEC_ARG_ scale, flags ) +#define ROUND_None( d, c ) \ + Round_None( EXEC_ARG_ d, c ) +#define INS_Goto_CodeRange( range, ip ) \ + Ins_Goto_CodeRange( EXEC_ARG_ range, ip ) +#define CUR_Func_move( z, p, d ) \ + CUR.func_move( EXEC_ARG_ z, p, d ) +#define CUR_Func_move_orig( z, p, d ) \ + CUR.func_move_orig( EXEC_ARG_ z, p, d ) +#define CUR_Func_round( d, c ) \ + CUR.func_round( EXEC_ARG_ d, c ) +#define CUR_Func_read_cvt( index ) \ + CUR.func_read_cvt( EXEC_ARG_ index ) +#define CUR_Func_write_cvt( index, val ) \ + CUR.func_write_cvt( EXEC_ARG_ index, val ) +#define CUR_Func_move_cvt( index, val ) \ + CUR.func_move_cvt( EXEC_ARG_ index, val ) +#define CURRENT_Ratio() \ + Current_Ratio( EXEC_ARG ) +#define CURRENT_Ppem() \ + Current_Ppem( EXEC_ARG ) +#define CUR_Ppem() \ + Cur_PPEM( EXEC_ARG ) +#define INS_SxVTL( a, b, c, d ) \ + Ins_SxVTL( EXEC_ARG_ a, b, c, d ) +#define COMPUTE_Funcs() \ + Compute_Funcs( EXEC_ARG ) +#define COMPUTE_Round( a ) \ + Compute_Round( EXEC_ARG_ a ) +#define COMPUTE_Point_Displacement( a, b, c, d ) \ + Compute_Point_Displacement( EXEC_ARG_ a, b, c, d ) +#define MOVE_Zp2_Point( a, b, c, t ) \ + Move_Zp2_Point( EXEC_ARG_ a, b, c, t ) +#define CUR_Func_project( v1, v2 ) \ + CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y ) +#define CUR_Func_dualproj( v1, v2 ) \ + CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y ) +#define CUR_fast_project( v ) \ + CUR.func_project( EXEC_ARG_ (v)->x, (v)->y ) +#define CUR_fast_dualproj( v ) \ + CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y ) +/*************************************************************************/ +/* */ +/* Instruction dispatch function, as used by the interpreter. */ +/* */ + typedef void (*TInstruction_Function)( INS_ARG ); +/*************************************************************************/ +/* */ +/* Two simple bounds-checking macros. */ +/* */ +#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) ) +#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) ) +/*************************************************************************/ +/* */ +/* This macro computes (a*2^14)/b and complements TT_MulFix14. */ +/* */ +#define TT_DivFix14( a, b ) \ + FT_DivFix( a, (b) << 2 ) +#undef SUCCESS +#define SUCCESS 0 +#undef FAILURE +#define FAILURE 1 +#define GUESS_VECTOR( V ) +/*************************************************************************/ +/* */ +/* CODERANGE FUNCTIONS */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Goto_CodeRange */ +/* */ +/* <Description> */ +/* Switches to a new code range (updates the code related elements in */ +/* `exec', and `IP'). */ +/* */ +/* <Input> */ +/* range :: The new execution code range. */ +/* */ +/* IP :: The new IP in the new code range. */ +/* */ +/* <InOut> */ +/* exec :: The target execution context. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Goto_CodeRange( TT_ExecContext exec, + FT_Int range, + FT_Long IP ) + { + TT_CodeRange* coderange; + FT_ASSERT( range >= 1 && range <= 3 ); + coderange = &exec->codeRangeTable[range - 1]; + FT_ASSERT( coderange->base != NULL ); +/* NOTE: Because the last instruction of a program may be a CALL */ +/* which will return to the first byte *after* the code */ +/* range, we test for IP <= Size instead of IP < Size. */ +/* */ + FT_ASSERT( (FT_ULong)IP <= coderange->size ); + exec->code = coderange->base; + exec->codeSize = coderange->size; + exec->IP = IP; + exec->curRange = range; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Set_CodeRange */ +/* */ +/* <Description> */ +/* Sets a code range. */ +/* */ +/* <Input> */ +/* range :: The code range index. */ +/* */ +/* base :: The new code base. */ +/* */ +/* length :: The range size in bytes. */ +/* */ +/* <InOut> */ +/* exec :: The target execution context. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_CodeRange( TT_ExecContext exec, + FT_Int range, + void* base, + FT_Long length ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].size = length; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Clear_CodeRange */ +/* */ +/* <Description> */ +/* Clears a code range. */ +/* */ +/* <Input> */ +/* range :: The code range index. */ +/* */ +/* <InOut> */ +/* exec :: The target execution context. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Does not set the Error variable. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Clear_CodeRange( TT_ExecContext exec, + FT_Int range ) + { + FT_ASSERT( range >= 1 && range <= 3 ); + exec->codeRangeTable[range - 1].base = NULL; + exec->codeRangeTable[range - 1].size = 0; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* EXECUTION CONTEXT ROUTINES */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Done_Context */ +/* */ +/* <Description> */ +/* Destroys a given context. */ +/* */ +/* <Input> */ +/* exec :: A handle to the target execution context. */ +/* */ +/* memory :: A handle to the parent memory object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only the glyph loader and debugger should call this function. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Done_Context( TT_ExecContext exec ) + { + FT_Memory memory = exec->memory; +/* points zone */ + exec->maxPoints = 0; + exec->maxContours = 0; +/* free stack */ + FT_FREE( exec->stack ); + exec->stackSize = 0; +/* free call stack */ + FT_FREE( exec->callStack ); + exec->callSize = 0; + exec->callTop = 0; +/* free glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + exec->size = NULL; + exec->face = NULL; + FT_FREE( exec ); + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Init_Context */ +/* */ +/* <Description> */ +/* Initializes a context object. */ +/* */ +/* <Input> */ +/* memory :: A handle to the parent memory object. */ +/* */ +/* <InOut> */ +/* exec :: A handle to the target execution context. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + static FT_Error + Init_Context( TT_ExecContext exec, + FT_Memory memory ) + { + FT_Error error; + FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec )); + exec->memory = memory; + exec->callSize = 32; + if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) ) + goto Fail_Memory; +/* all values in the context are set to 0 already, but this is */ +/* here as a remainder */ + exec->maxPoints = 0; + exec->maxContours = 0; + exec->stackSize = 0; + exec->glyphSize = 0; + exec->stack = NULL; + exec->glyphIns = NULL; + exec->face = NULL; + exec->size = NULL; + return TT_Err_Ok; + Fail_Memory: + FT_ERROR(( "Init_Context: not enough memory for %p\n", exec )); + TT_Done_Context( exec ); + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Update_Max */ +/* */ +/* <Description> */ +/* Checks the size of a buffer and reallocates it if necessary. */ +/* */ +/* <Input> */ +/* memory :: A handle to the parent memory object. */ +/* */ +/* multiplier :: The size in bytes of each element in the buffer. */ +/* */ +/* new_max :: The new capacity (size) of the buffer. */ +/* */ +/* <InOut> */ +/* size :: The address of the buffer's current size expressed */ +/* in elements. */ +/* */ +/* buff :: The address of the buffer base pointer. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + Update_Max( FT_Memory memory, + FT_ULong* size, + FT_Long multiplier, + void* _pbuff, + FT_ULong new_max ) + { + FT_Error error; + void** pbuff = (void**)_pbuff; + if ( *size < new_max ) + { + if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) ) + return error; + *size = new_max; + } + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Load_Context */ +/* */ +/* <Description> */ +/* Prepare an execution context for glyph hinting. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* size :: A handle to the source size object. */ +/* */ +/* <InOut> */ +/* exec :: A handle to the target execution context. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only the glyph loader and debugger should call this function. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Load_Context( TT_ExecContext exec, + TT_Face face, + TT_Size size ) + { + FT_Int i; + FT_ULong tmp; + TT_MaxProfile* maxp; + FT_Error error; + exec->face = face; + maxp = &face->max_profile; + exec->size = size; + if ( size ) + { + exec->numFDefs = size->num_function_defs; + exec->maxFDefs = size->max_function_defs; + exec->numIDefs = size->num_instruction_defs; + exec->maxIDefs = size->max_instruction_defs; + exec->FDefs = size->function_defs; + exec->IDefs = size->instruction_defs; + exec->tt_metrics = size->ttmetrics; + exec->metrics = size->metrics; + exec->maxFunc = size->max_func; + exec->maxIns = size->max_ins; + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + exec->codeRangeTable[i] = size->codeRangeTable[i]; +/* set graphics state */ + exec->GS = size->GS; + exec->cvtSize = size->cvt_size; + exec->cvt = size->cvt; + exec->storeSize = size->storage_size; + exec->storage = size->storage; + exec->twilight = size->twilight; +/* In case of multi-threading it can happen that the old size object */ +/* no longer exists, thus we must clear all glyph zone references. */ + ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) ); + exec->zp1 = exec->zp0; + exec->zp2 = exec->zp0; + } +/* XXX: We reserve a little more elements on the stack to deal safely */ +/* with broken fonts like arialbs, courbs, timesbs, etc. */ + tmp = exec->stackSize; + error = Update_Max( exec->memory, + &tmp, + sizeof ( FT_F26Dot6 ), + (void*)&exec->stack, + maxp->maxStackElements + 32 ); + exec->stackSize = (FT_UInt)tmp; + if ( error ) + return error; + tmp = exec->glyphSize; + error = Update_Max( exec->memory, + &tmp, + sizeof ( FT_Byte ), + (void*)&exec->glyphIns, + maxp->maxSizeOfInstructions ); + exec->glyphSize = (FT_UShort)tmp; + if ( error ) + return error; + exec->pts.n_points = 0; + exec->pts.n_contours = 0; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + exec->zp0 = exec->pts; + exec->instruction_trap = FALSE; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Save_Context */ +/* */ +/* <Description> */ +/* Saves the code ranges in a `size' object. */ +/* */ +/* <Input> */ +/* exec :: A handle to the source execution context. */ +/* */ +/* <InOut> */ +/* size :: A handle to the target size object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only the glyph loader and debugger should call this function. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Save_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_Int i; +/* XXX: Will probably disappear soon with all the code range */ +/* management, which is now rather obsolete. */ +/* */ + size->num_function_defs = exec->numFDefs; + size->num_instruction_defs = exec->numIDefs; + size->max_func = exec->maxFunc; + size->max_ins = exec->maxIns; + for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) + size->codeRangeTable[i] = exec->codeRangeTable[i]; + return TT_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Run_Context */ +/* */ +/* <Description> */ +/* Executes one or more instructions in the execution context. */ +/* */ +/* <Input> */ +/* debug :: A Boolean flag. If set, the function sets some internal */ +/* variables and returns immediately, otherwise TT_RunIns() */ +/* is called. */ +/* */ +/* This is commented out currently. */ +/* */ +/* <Input> */ +/* exec :: A handle to the target execution context. */ +/* */ +/* <Return> */ +/* TrueType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only the glyph loader and debugger should call this function. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Run_Context( TT_ExecContext exec, + FT_Bool debug ) + { + FT_Error error; + if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) ) + != TT_Err_Ok ) + return error; + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + exec->GS.gep0 = 1; + exec->GS.gep1 = 1; + exec->GS.gep2 = 1; + exec->GS.projVector.x = 0x4000; + exec->GS.projVector.y = 0x0000; + exec->GS.freeVector = exec->GS.projVector; + exec->GS.dualVector = exec->GS.projVector; + exec->GS.round_state = 1; + exec->GS.loop = 1; +/* some glyphs leave something on the stack. so we clean it */ +/* before a new execution. */ + exec->top = 0; + exec->callTop = 0; +#if 1 + FT_UNUSED( debug ); + return exec->face->interpreter( exec ); +#else + if ( !debug ) + return TT_RunIns( exec ); + else + return TT_Err_Ok; +#endif + } +/* The default value for `scan_control' is documented as FALSE in the */ +/* TrueType specification. This is confusing since it implies a */ +/* Boolean value. However, this is not the case, thus both the */ +/* default values of our `scan_type' and `scan_control' fields (which */ +/* the documentation's `scan_control' variable is split into) are */ +/* zero. */ + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, + { 0x4000, 0 }, + { 0x4000, 0 }, + { 0x4000, 0 }, + 1, 64, 1, + TRUE, 68, 0, 0, 9, 3, + 0, FALSE, 0, 1, 1, 1 + }; +/* documentation is in ttinterp.h */ + FT_EXPORT_DEF( TT_ExecContext ) + TT_New_Context( TT_Driver driver ) + { + TT_ExecContext exec; + FT_Memory memory; + memory = driver->root.root.memory; + exec = driver->context; + if ( !driver->context ) + { + FT_Error error; +/* allocate object */ + if ( FT_NEW( exec ) ) + goto Fail; +/* initialize it; in case of error this deallocates `exec' too */ + error = Init_Context( exec, memory ); + if ( error ) + goto Fail; +/* store it into the driver */ + driver->context = exec; + } + return driver->context; + Fail: + return NULL; + } +/*************************************************************************/ +/* */ +/* Before an opcode is executed, the interpreter verifies that there are */ +/* enough arguments on the stack, with the help of the `Pop_Push_Count' */ +/* table. */ +/* */ +/* For each opcode, the first column gives the number of arguments that */ +/* are popped from the stack; the second one gives the number of those */ +/* that are pushed in result. */ +/* */ +/* Opcodes which have a varying number of parameters in the data stream */ +/* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */ +/* the `opcode_length' table, and the value in `Pop_Push_Count' is set */ +/* to zero. */ +/* */ +/*************************************************************************/ +#undef PACK +#define PACK( x, y ) ( ( x << 4 ) | y ) + static + const FT_Byte Pop_Push_Count[256] = + { +/* opcodes are gathered in groups of 16 */ +/* please keep the spaces as they are */ +/* SVTCA y */ PACK( 0, 0 ), +/* SVTCA x */ PACK( 0, 0 ), +/* SPvTCA y */ PACK( 0, 0 ), +/* SPvTCA x */ PACK( 0, 0 ), +/* SFvTCA y */ PACK( 0, 0 ), +/* SFvTCA x */ PACK( 0, 0 ), +/* SPvTL // */ PACK( 2, 0 ), +/* SPvTL + */ PACK( 2, 0 ), +/* SFvTL // */ PACK( 2, 0 ), +/* SFvTL + */ PACK( 2, 0 ), +/* SPvFS */ PACK( 2, 0 ), +/* SFvFS */ PACK( 2, 0 ), +/* GPV */ PACK( 0, 2 ), +/* GFV */ PACK( 0, 2 ), +/* SFvTPv */ PACK( 0, 0 ), +/* ISECT */ PACK( 5, 0 ), +/* SRP0 */ PACK( 1, 0 ), +/* SRP1 */ PACK( 1, 0 ), +/* SRP2 */ PACK( 1, 0 ), +/* SZP0 */ PACK( 1, 0 ), +/* SZP1 */ PACK( 1, 0 ), +/* SZP2 */ PACK( 1, 0 ), +/* SZPS */ PACK( 1, 0 ), +/* SLOOP */ PACK( 1, 0 ), +/* RTG */ PACK( 0, 0 ), +/* RTHG */ PACK( 0, 0 ), +/* SMD */ PACK( 1, 0 ), +/* ELSE */ PACK( 0, 0 ), +/* JMPR */ PACK( 1, 0 ), +/* SCvTCi */ PACK( 1, 0 ), +/* SSwCi */ PACK( 1, 0 ), +/* SSW */ PACK( 1, 0 ), +/* DUP */ PACK( 1, 2 ), +/* POP */ PACK( 1, 0 ), +/* CLEAR */ PACK( 0, 0 ), +/* SWAP */ PACK( 2, 2 ), +/* DEPTH */ PACK( 0, 1 ), +/* CINDEX */ PACK( 1, 1 ), +/* MINDEX */ PACK( 1, 0 ), +/* AlignPTS */ PACK( 2, 0 ), +/* INS_$28 */ PACK( 0, 0 ), +/* UTP */ PACK( 1, 0 ), +/* LOOPCALL */ PACK( 2, 0 ), +/* CALL */ PACK( 1, 0 ), +/* FDEF */ PACK( 1, 0 ), +/* ENDF */ PACK( 0, 0 ), +/* MDAP[0] */ PACK( 1, 0 ), +/* MDAP[1] */ PACK( 1, 0 ), +/* IUP[0] */ PACK( 0, 0 ), +/* IUP[1] */ PACK( 0, 0 ), +/* SHP[0] */ PACK( 0, 0 ), +/* SHP[1] */ PACK( 0, 0 ), +/* SHC[0] */ PACK( 1, 0 ), +/* SHC[1] */ PACK( 1, 0 ), +/* SHZ[0] */ PACK( 1, 0 ), +/* SHZ[1] */ PACK( 1, 0 ), +/* SHPIX */ PACK( 1, 0 ), +/* IP */ PACK( 0, 0 ), +/* MSIRP[0] */ PACK( 2, 0 ), +/* MSIRP[1] */ PACK( 2, 0 ), +/* AlignRP */ PACK( 0, 0 ), +/* RTDG */ PACK( 0, 0 ), +/* MIAP[0] */ PACK( 2, 0 ), +/* MIAP[1] */ PACK( 2, 0 ), +/* NPushB */ PACK( 0, 0 ), +/* NPushW */ PACK( 0, 0 ), +/* WS */ PACK( 2, 0 ), +/* RS */ PACK( 1, 1 ), +/* WCvtP */ PACK( 2, 0 ), +/* RCvt */ PACK( 1, 1 ), +/* GC[0] */ PACK( 1, 1 ), +/* GC[1] */ PACK( 1, 1 ), +/* SCFS */ PACK( 2, 0 ), +/* MD[0] */ PACK( 2, 1 ), +/* MD[1] */ PACK( 2, 1 ), +/* MPPEM */ PACK( 0, 1 ), +/* MPS */ PACK( 0, 1 ), +/* FlipON */ PACK( 0, 0 ), +/* FlipOFF */ PACK( 0, 0 ), +/* DEBUG */ PACK( 1, 0 ), +/* LT */ PACK( 2, 1 ), +/* LTEQ */ PACK( 2, 1 ), +/* GT */ PACK( 2, 1 ), +/* GTEQ */ PACK( 2, 1 ), +/* EQ */ PACK( 2, 1 ), +/* NEQ */ PACK( 2, 1 ), +/* ODD */ PACK( 1, 1 ), +/* EVEN */ PACK( 1, 1 ), +/* IF */ PACK( 1, 0 ), +/* EIF */ PACK( 0, 0 ), +/* AND */ PACK( 2, 1 ), +/* OR */ PACK( 2, 1 ), +/* NOT */ PACK( 1, 1 ), +/* DeltaP1 */ PACK( 1, 0 ), +/* SDB */ PACK( 1, 0 ), +/* SDS */ PACK( 1, 0 ), +/* ADD */ PACK( 2, 1 ), +/* SUB */ PACK( 2, 1 ), +/* DIV */ PACK( 2, 1 ), +/* MUL */ PACK( 2, 1 ), +/* ABS */ PACK( 1, 1 ), +/* NEG */ PACK( 1, 1 ), +/* FLOOR */ PACK( 1, 1 ), +/* CEILING */ PACK( 1, 1 ), +/* ROUND[0] */ PACK( 1, 1 ), +/* ROUND[1] */ PACK( 1, 1 ), +/* ROUND[2] */ PACK( 1, 1 ), +/* ROUND[3] */ PACK( 1, 1 ), +/* NROUND[0] */ PACK( 1, 1 ), +/* NROUND[1] */ PACK( 1, 1 ), +/* NROUND[2] */ PACK( 1, 1 ), +/* NROUND[3] */ PACK( 1, 1 ), +/* WCvtF */ PACK( 2, 0 ), +/* DeltaP2 */ PACK( 1, 0 ), +/* DeltaP3 */ PACK( 1, 0 ), +/* DeltaCn[0] */ PACK( 1, 0 ), +/* DeltaCn[1] */ PACK( 1, 0 ), +/* DeltaCn[2] */ PACK( 1, 0 ), +/* SROUND */ PACK( 1, 0 ), +/* S45Round */ PACK( 1, 0 ), +/* JROT */ PACK( 2, 0 ), +/* JROF */ PACK( 2, 0 ), +/* ROFF */ PACK( 0, 0 ), +/* INS_$7B */ PACK( 0, 0 ), +/* RUTG */ PACK( 0, 0 ), +/* RDTG */ PACK( 0, 0 ), +/* SANGW */ PACK( 1, 0 ), +/* AA */ PACK( 1, 0 ), +/* FlipPT */ PACK( 0, 0 ), +/* FlipRgON */ PACK( 2, 0 ), +/* FlipRgOFF */ PACK( 2, 0 ), +/* INS_$83 */ PACK( 0, 0 ), +/* INS_$84 */ PACK( 0, 0 ), +/* ScanCTRL */ PACK( 1, 0 ), +/* SDPVTL[0] */ PACK( 2, 0 ), +/* SDPVTL[1] */ PACK( 2, 0 ), +/* GetINFO */ PACK( 1, 1 ), +/* IDEF */ PACK( 1, 0 ), +/* ROLL */ PACK( 3, 3 ), +/* MAX */ PACK( 2, 1 ), +/* MIN */ PACK( 2, 1 ), +/* ScanTYPE */ PACK( 1, 0 ), +/* InstCTRL */ PACK( 2, 0 ), +/* INS_$8F */ PACK( 0, 0 ), +/* INS_$90 */ PACK( 0, 0 ), +/* INS_$91 */ PACK( 0, 0 ), +/* INS_$92 */ PACK( 0, 0 ), +/* INS_$93 */ PACK( 0, 0 ), +/* INS_$94 */ PACK( 0, 0 ), +/* INS_$95 */ PACK( 0, 0 ), +/* INS_$96 */ PACK( 0, 0 ), +/* INS_$97 */ PACK( 0, 0 ), +/* INS_$98 */ PACK( 0, 0 ), +/* INS_$99 */ PACK( 0, 0 ), +/* INS_$9A */ PACK( 0, 0 ), +/* INS_$9B */ PACK( 0, 0 ), +/* INS_$9C */ PACK( 0, 0 ), +/* INS_$9D */ PACK( 0, 0 ), +/* INS_$9E */ PACK( 0, 0 ), +/* INS_$9F */ PACK( 0, 0 ), +/* INS_$A0 */ PACK( 0, 0 ), +/* INS_$A1 */ PACK( 0, 0 ), +/* INS_$A2 */ PACK( 0, 0 ), +/* INS_$A3 */ PACK( 0, 0 ), +/* INS_$A4 */ PACK( 0, 0 ), +/* INS_$A5 */ PACK( 0, 0 ), +/* INS_$A6 */ PACK( 0, 0 ), +/* INS_$A7 */ PACK( 0, 0 ), +/* INS_$A8 */ PACK( 0, 0 ), +/* INS_$A9 */ PACK( 0, 0 ), +/* INS_$AA */ PACK( 0, 0 ), +/* INS_$AB */ PACK( 0, 0 ), +/* INS_$AC */ PACK( 0, 0 ), +/* INS_$AD */ PACK( 0, 0 ), +/* INS_$AE */ PACK( 0, 0 ), +/* INS_$AF */ PACK( 0, 0 ), +/* PushB[0] */ PACK( 0, 1 ), +/* PushB[1] */ PACK( 0, 2 ), +/* PushB[2] */ PACK( 0, 3 ), +/* PushB[3] */ PACK( 0, 4 ), +/* PushB[4] */ PACK( 0, 5 ), +/* PushB[5] */ PACK( 0, 6 ), +/* PushB[6] */ PACK( 0, 7 ), +/* PushB[7] */ PACK( 0, 8 ), +/* PushW[0] */ PACK( 0, 1 ), +/* PushW[1] */ PACK( 0, 2 ), +/* PushW[2] */ PACK( 0, 3 ), +/* PushW[3] */ PACK( 0, 4 ), +/* PushW[4] */ PACK( 0, 5 ), +/* PushW[5] */ PACK( 0, 6 ), +/* PushW[6] */ PACK( 0, 7 ), +/* PushW[7] */ PACK( 0, 8 ), +/* MDRP[00] */ PACK( 1, 0 ), +/* MDRP[01] */ PACK( 1, 0 ), +/* MDRP[02] */ PACK( 1, 0 ), +/* MDRP[03] */ PACK( 1, 0 ), +/* MDRP[04] */ PACK( 1, 0 ), +/* MDRP[05] */ PACK( 1, 0 ), +/* MDRP[06] */ PACK( 1, 0 ), +/* MDRP[07] */ PACK( 1, 0 ), +/* MDRP[08] */ PACK( 1, 0 ), +/* MDRP[09] */ PACK( 1, 0 ), +/* MDRP[10] */ PACK( 1, 0 ), +/* MDRP[11] */ PACK( 1, 0 ), +/* MDRP[12] */ PACK( 1, 0 ), +/* MDRP[13] */ PACK( 1, 0 ), +/* MDRP[14] */ PACK( 1, 0 ), +/* MDRP[15] */ PACK( 1, 0 ), +/* MDRP[16] */ PACK( 1, 0 ), +/* MDRP[17] */ PACK( 1, 0 ), +/* MDRP[18] */ PACK( 1, 0 ), +/* MDRP[19] */ PACK( 1, 0 ), +/* MDRP[20] */ PACK( 1, 0 ), +/* MDRP[21] */ PACK( 1, 0 ), +/* MDRP[22] */ PACK( 1, 0 ), +/* MDRP[23] */ PACK( 1, 0 ), +/* MDRP[24] */ PACK( 1, 0 ), +/* MDRP[25] */ PACK( 1, 0 ), +/* MDRP[26] */ PACK( 1, 0 ), +/* MDRP[27] */ PACK( 1, 0 ), +/* MDRP[28] */ PACK( 1, 0 ), +/* MDRP[29] */ PACK( 1, 0 ), +/* MDRP[30] */ PACK( 1, 0 ), +/* MDRP[31] */ PACK( 1, 0 ), +/* MIRP[00] */ PACK( 2, 0 ), +/* MIRP[01] */ PACK( 2, 0 ), +/* MIRP[02] */ PACK( 2, 0 ), +/* MIRP[03] */ PACK( 2, 0 ), +/* MIRP[04] */ PACK( 2, 0 ), +/* MIRP[05] */ PACK( 2, 0 ), +/* MIRP[06] */ PACK( 2, 0 ), +/* MIRP[07] */ PACK( 2, 0 ), +/* MIRP[08] */ PACK( 2, 0 ), +/* MIRP[09] */ PACK( 2, 0 ), +/* MIRP[10] */ PACK( 2, 0 ), +/* MIRP[11] */ PACK( 2, 0 ), +/* MIRP[12] */ PACK( 2, 0 ), +/* MIRP[13] */ PACK( 2, 0 ), +/* MIRP[14] */ PACK( 2, 0 ), +/* MIRP[15] */ PACK( 2, 0 ), +/* MIRP[16] */ PACK( 2, 0 ), +/* MIRP[17] */ PACK( 2, 0 ), +/* MIRP[18] */ PACK( 2, 0 ), +/* MIRP[19] */ PACK( 2, 0 ), +/* MIRP[20] */ PACK( 2, 0 ), +/* MIRP[21] */ PACK( 2, 0 ), +/* MIRP[22] */ PACK( 2, 0 ), +/* MIRP[23] */ PACK( 2, 0 ), +/* MIRP[24] */ PACK( 2, 0 ), +/* MIRP[25] */ PACK( 2, 0 ), +/* MIRP[26] */ PACK( 2, 0 ), +/* MIRP[27] */ PACK( 2, 0 ), +/* MIRP[28] */ PACK( 2, 0 ), +/* MIRP[29] */ PACK( 2, 0 ), +/* MIRP[30] */ PACK( 2, 0 ), +/* MIRP[31] */ PACK( 2, 0 ) + }; + static + const FT_Char opcode_length[256] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; +#undef PACK +#if 1 + static FT_Int32 + TT_MulFix14( FT_Int32 a, + FT_Int b ) + { + FT_Int32 sign; + FT_UInt32 ah, al, mid, lo, hi; + sign = a ^ b; + if ( a < 0 ) + a = -a; + if ( b < 0 ) + b = -b; + ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); + al = (FT_UInt32)( a & 0xFFFFU ); + lo = al * b; + mid = ah * b; + hi = mid >> 16; +/* rounding */ + mid = ( mid << 16 ) + ( 1 << 13 ); + lo += mid; + if ( lo < mid ) + hi += 1; + mid = ( lo >> 14 ) | ( hi << 18 ); + return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid; + } +#else +/* compute (a*b)/2^14 with maximum accuracy and rounding */ + static FT_Int32 + TT_MulFix14( FT_Int32 a, + FT_Int b ) + { + FT_Int32 m, s, hi; + FT_UInt32 l, lo; +/* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( ( a & 0xFFFFU ) * b ); + m = ( a >> 16 ) * b; + lo = l + (FT_UInt32)( m << 16 ); + hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l ); +/* divide the result by 2^14 with rounding */ + s = hi >> 31; + l = lo + (FT_UInt32)s; + hi += s + ( l < lo ); + lo = l; + l = lo + 0x2000U; + hi += l < lo; + return ( hi << 18 ) | ( l >> 14 ); + } +#endif +/* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */ + static FT_Int32 + TT_DotFix14( FT_Int32 ax, + FT_Int32 ay, + FT_Int bx, + FT_Int by ) + { + FT_Int32 m, s, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; +/* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); + m = ( ax >> 16 ) * bx; + lo1 = l + (FT_UInt32)( m << 16 ); + hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l ); +/* compute ay*by as 64-bit value */ + l = (FT_UInt32)( ( ay & 0xFFFFU ) * by ); + m = ( ay >> 16 ) * by; + lo2 = l + (FT_UInt32)( m << 16 ); + hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l ); +/* add them */ + lo = lo1 + lo2; + hi = hi1 + hi2 + ( lo < lo1 ); +/* divide the result by 2^14 with rounding */ + s = hi >> 31; + l = lo + (FT_UInt32)s; + hi += s + ( l < lo ); + lo = l; + l = lo + 0x2000U; + hi += ( l < lo ); + return ( hi << 18 ) | ( l >> 14 ); + } +/* return length of given vector */ +#if 0 + static FT_Int32 + TT_VecLen( FT_Int32 x, + FT_Int32 y ) + { + FT_Int32 m, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; +/* compute x*x as 64-bit value */ + lo = (FT_UInt32)( x & 0xFFFFU ); + hi = x >> 16; + l = lo * lo; + m = hi * lo; + hi = hi * hi; + lo1 = l + (FT_UInt32)( m << 17 ); + hi1 = hi + ( m >> 15 ) + ( lo1 < l ); +/* compute y*y as 64-bit value */ + lo = (FT_UInt32)( y & 0xFFFFU ); + hi = y >> 16; + l = lo * lo; + m = hi * lo; + hi = hi * hi; + lo2 = l + (FT_UInt32)( m << 17 ); + hi2 = hi + ( m >> 15 ) + ( lo2 < l ); +/* add them to get 'x*x+y*y' as 64-bit value */ + lo = lo1 + lo2; + hi = hi1 + hi2 + ( lo < lo1 ); +/* compute the square root of this value */ + { + FT_UInt32 root, rem, test_div; + FT_Int count; + root = 0; + { + rem = 0; + count = 32; + do + { + rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 ); + hi = ( hi << 2 ) | ( lo >> 30 ); + lo <<= 2; + root <<= 1; + test_div = ( root << 1 ) + 1; + if ( rem >= test_div ) + { + rem -= test_div; + root += 1; + } + } while ( --count ); + } + return (FT_Int32)root; + } + } +#else +/* this version uses FT_Vector_Length which computes the same value */ +/* much, much faster.. */ +/* */ + static FT_F26Dot6 + TT_VecLen( FT_F26Dot6 X, + FT_F26Dot6 Y ) + { + FT_Vector v; + v.x = X; + v.y = Y; + return FT_Vector_Length( &v ); + } +#endif +/*************************************************************************/ +/* */ +/* <Function> */ +/* Current_Ratio */ +/* */ +/* <Description> */ +/* Returns the current aspect ratio scaling factor depending on the */ +/* projection vector's state and device resolutions. */ +/* */ +/* <Return> */ +/* The aspect ratio in 16.16 format, always <= 1.0 . */ +/* */ + static FT_Long + Current_Ratio( EXEC_OP ) + { + if ( !CUR.tt_metrics.ratio ) + { + { + if ( CUR.GS.projVector.y == 0 ) + CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio; + else if ( CUR.GS.projVector.x == 0 ) + CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio; + else + { + FT_F26Dot6 x, y; + x = TT_MulFix14( CUR.tt_metrics.x_ratio, + CUR.GS.projVector.x ); + y = TT_MulFix14( CUR.tt_metrics.y_ratio, + CUR.GS.projVector.y ); + CUR.tt_metrics.ratio = TT_VecLen( x, y ); + } + } + } + return CUR.tt_metrics.ratio; + } + static FT_Long + Current_Ppem( EXEC_OP ) + { + return FT_MulFix( CUR.tt_metrics.ppem, CURRENT_Ratio() ); + } +/*************************************************************************/ +/* */ +/* Functions related to the control value table (CVT). */ +/* */ +/*************************************************************************/ + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT( EXEC_OP_ FT_ULong idx ) + { + return CUR.cvt[idx]; + } + FT_CALLBACK_DEF( FT_F26Dot6 ) + Read_CVT_Stretched( EXEC_OP_ FT_ULong idx ) + { + return FT_MulFix( CUR.cvt[idx], CURRENT_Ratio() ); + } + FT_CALLBACK_DEF( void ) + Write_CVT( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] = value; + } + FT_CALLBACK_DEF( void ) + Write_CVT_Stretched( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() ); + } + FT_CALLBACK_DEF( void ) + Move_CVT( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] += value; + } + FT_CALLBACK_DEF( void ) + Move_CVT_Stretched( EXEC_OP_ FT_ULong idx, + FT_F26Dot6 value ) + { + CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* GetShortIns */ +/* */ +/* <Description> */ +/* Returns a short integer taken from the instruction stream at */ +/* address IP. */ +/* */ +/* <Return> */ +/* Short read at code[IP]. */ +/* */ +/* <Note> */ +/* This one could become a macro. */ +/* */ + static FT_Short + GetShortIns( EXEC_OP ) + { +/* Reading a byte stream so there is no endianess (DaveP) */ + CUR.IP += 2; + return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) + + CUR.code[CUR.IP - 1] ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Ins_Goto_CodeRange */ +/* */ +/* <Description> */ +/* Goes to a certain code range in the instruction stream. */ +/* */ +/* <Input> */ +/* aRange :: The index of the code range. */ +/* */ +/* aIP :: The new IP address in the code range. */ +/* */ +/* <Return> */ +/* SUCCESS or FAILURE. */ +/* */ + static FT_Bool + Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange, + FT_ULong aIP ) + { + TT_CodeRange* range; + if ( aRange < 1 || aRange > 3 ) + { + CUR.error = TT_Err_Bad_Argument; + return FAILURE; + } + range = &CUR.codeRangeTable[aRange - 1]; +/* invalid coderange */ + if ( range->base == NULL ) + { + CUR.error = TT_Err_Invalid_CodeRange; + return FAILURE; + } +/* NOTE: Because the last instruction of a program may be a CALL */ +/* which will return to the first byte *after* the code */ +/* range, we test for aIP <= Size, instead of aIP < Size. */ + if ( aIP > range->size ) + { + CUR.error = TT_Err_Code_Overflow; + return FAILURE; + } + CUR.code = range->base; + CUR.codeSize = range->size; + CUR.IP = aIP; + CUR.curRange = aRange; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Direct_Move */ +/* */ +/* <Description> */ +/* Moves a point by a given distance along the freedom vector. The */ +/* point will be `touched'. */ +/* */ +/* <Input> */ +/* point :: The index of the point to move. */ +/* */ +/* distance :: The distance to apply. */ +/* */ +/* <InOut> */ +/* zone :: The affected glyph zone. */ +/* */ + static void + Direct_Move( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + v = CUR.GS.freeVector.x; + if ( v != 0 ) + { + zone->cur[point].x += FT_MulDiv( distance, v, CUR.F_dot_P ); + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + v = CUR.GS.freeVector.y; + if ( v != 0 ) + { + zone->cur[point].y += FT_MulDiv( distance, v, CUR.F_dot_P ); + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Direct_Move_Orig */ +/* */ +/* <Description> */ +/* Moves the *original* position of a point by a given distance along */ +/* the freedom vector. Obviously, the point will not be `touched'. */ +/* */ +/* <Input> */ +/* point :: The index of the point to move. */ +/* */ +/* distance :: The distance to apply. */ +/* */ +/* <InOut> */ +/* zone :: The affected glyph zone. */ +/* */ + static void + Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_F26Dot6 v; + v = CUR.GS.freeVector.x; + if ( v != 0 ) + zone->org[point].x += FT_MulDiv( distance, v, CUR.F_dot_P ); + v = CUR.GS.freeVector.y; + if ( v != 0 ) + zone->org[point].y += FT_MulDiv( distance, v, CUR.F_dot_P ); + } +/*************************************************************************/ +/* */ +/* Special versions of Direct_Move() */ +/* */ +/* The following versions are used whenever both vectors are both */ +/* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ +/* */ +/*************************************************************************/ + static void + Direct_Move_X( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + zone->cur[point].x += distance; + zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + static void + Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + zone->cur[point].y += distance; + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } +/*************************************************************************/ +/* */ +/* Special versions of Direct_Move_Orig() */ +/* */ +/* The following versions are used whenever both vectors are both */ +/* along one of the coordinate unit vectors, i.e. in 90% of the cases. */ +/* */ +/*************************************************************************/ + static void + Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + zone->org[point].x += distance; + } + static void + Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone, + FT_UShort point, + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; + zone->org[point].y += distance; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_None */ +/* */ +/* <Description> */ +/* Does not round, but adds engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance (not) to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* The compensated distance. */ +/* */ +/* <Note> */ +/* The TrueType specification says very few about the relationship */ +/* between rounding and engine compensation. However, it seems from */ +/* the description of super round that we should add the compensation */ +/* before rounding. */ +/* */ + static FT_F26Dot6 + Round_None( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + FT_UNUSED_EXEC; + if ( distance >= 0 ) + { + val = distance + compensation; + if ( distance && val < 0 ) + val = 0; + } + else + { + val = distance - compensation; + if ( val > 0 ) + val = 0; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_To_Grid */ +/* */ +/* <Description> */ +/* Rounds value to grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ + static FT_F26Dot6 + Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + FT_UNUSED_EXEC; + if ( distance >= 0 ) + { + val = distance + compensation + 32; + if ( distance && val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -FT_PIX_ROUND( compensation - distance ); + if ( val > 0 ) + val = 0; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_To_Half_Grid */ +/* */ +/* <Description> */ +/* Rounds value to half grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ + static FT_F26Dot6 + Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + FT_UNUSED_EXEC; + if ( distance >= 0 ) + { + val = FT_PIX_FLOOR( distance + compensation ) + 32; + if ( distance && val < 0 ) + val = 0; + } + else + { + val = -( FT_PIX_FLOOR( compensation - distance ) + 32 ); + if ( val > 0 ) + val = 0; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_Down_To_Grid */ +/* */ +/* <Description> */ +/* Rounds value down to grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ + static FT_F26Dot6 + Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + FT_UNUSED_EXEC; + if ( distance >= 0 ) + { + val = distance + compensation; + if ( distance && val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -( ( compensation - distance ) & -64 ); + if ( val > 0 ) + val = 0; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_Up_To_Grid */ +/* */ +/* <Description> */ +/* Rounds value up to grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ + static FT_F26Dot6 + Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + FT_UNUSED_EXEC; + if ( distance >= 0 ) + { + val = distance + compensation + 63; + if ( distance && val > 0 ) + val &= ~63; + else + val = 0; + } + else + { + val = -FT_PIX_CEIL( compensation - distance ); + if ( val > 0 ) + val = 0; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_To_Double_Grid */ +/* */ +/* <Description> */ +/* Rounds value to double grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ + static FT_F26Dot6 + Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + FT_UNUSED_EXEC; + if ( distance >= 0 ) + { + val = distance + compensation + 16; + if ( distance && val > 0 ) + val &= ~31; + else + val = 0; + } + else + { + val = -FT_PAD_ROUND( compensation - distance, 32 ); + if ( val > 0 ) + val = 0; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_Super */ +/* */ +/* <Description> */ +/* Super-rounds value to grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ +/* <Note> */ +/* The TrueType specification says very few about the relationship */ +/* between rounding and engine compensation. However, it seems from */ +/* the description of super round that we should add the compensation */ +/* before rounding. */ +/* */ + static FT_F26Dot6 + Round_Super( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + if ( distance >= 0 ) + { + val = ( distance - CUR.phase + CUR.threshold + compensation ) & + -CUR.period; + if ( distance && val < 0 ) + val = 0; + val += CUR.phase; + } + else + { + val = -( ( CUR.threshold - CUR.phase - distance + compensation ) & + -CUR.period ); + if ( val > 0 ) + val = 0; + val -= CUR.phase; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Round_Super_45 */ +/* */ +/* <Description> */ +/* Super-rounds value to grid after adding engine compensation. */ +/* */ +/* <Input> */ +/* distance :: The distance to round. */ +/* */ +/* compensation :: The engine compensation. */ +/* */ +/* <Return> */ +/* Rounded distance. */ +/* */ +/* <Note> */ +/* There is a separate function for Round_Super_45() as we may need */ +/* greater precision. */ +/* */ + static FT_F26Dot6 + Round_Super_45( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + if ( distance >= 0 ) + { + val = ( ( distance - CUR.phase + CUR.threshold + compensation ) / + CUR.period ) * CUR.period; + if ( distance && val < 0 ) + val = 0; + val += CUR.phase; + } + else + { + val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) / + CUR.period ) * CUR.period ); + if ( val > 0 ) + val = 0; + val -= CUR.phase; + } + return val; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Compute_Round */ +/* */ +/* <Description> */ +/* Sets the rounding mode. */ +/* */ +/* <Input> */ +/* round_mode :: The rounding mode to be used. */ +/* */ + static void + Compute_Round( EXEC_OP_ FT_Byte round_mode ) + { + switch ( round_mode ) + { + case TT_Round_Off: + CUR.func_round = (TT_Round_Func)Round_None; + break; + case TT_Round_To_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Grid; + break; + case TT_Round_Up_To_Grid: + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + break; + case TT_Round_Down_To_Grid: + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + break; + case TT_Round_To_Half_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + break; + case TT_Round_To_Double_Grid: + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + break; + case TT_Round_Super: + CUR.func_round = (TT_Round_Func)Round_Super; + break; + case TT_Round_Super_45: + CUR.func_round = (TT_Round_Func)Round_Super_45; + break; + } + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* SetSuperRound */ +/* */ +/* <Description> */ +/* Sets Super Round parameters. */ +/* */ +/* <Input> */ +/* GridPeriod :: The grid period. */ +/* */ +/* selector :: The SROUND opcode. */ +/* */ + static void + SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod, + FT_Long selector ) + { + switch ( (FT_Int)( selector & 0xC0 ) ) + { + case 0: + CUR.period = GridPeriod / 2; + break; + case 0x40: + CUR.period = GridPeriod; + break; + case 0x80: + CUR.period = GridPeriod * 2; + break; +/* This opcode is reserved, but... */ + case 0xC0: + CUR.period = GridPeriod; + break; + } + switch ( (FT_Int)( selector & 0x30 ) ) + { + case 0: + CUR.phase = 0; + break; + case 0x10: + CUR.phase = CUR.period / 4; + break; + case 0x20: + CUR.phase = CUR.period / 2; + break; + case 0x30: + CUR.phase = CUR.period * 3 / 4; + break; + } + if ( ( selector & 0x0F ) == 0 ) + CUR.threshold = CUR.period - 1; + else + CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8; + CUR.period /= 256; + CUR.phase /= 256; + CUR.threshold /= 256; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Project */ +/* */ +/* <Description> */ +/* Computes the projection of vector given by (v2-v1) along the */ +/* current projection vector. */ +/* */ +/* <Input> */ +/* v1 :: First input vector. */ +/* v2 :: Second input vector. */ +/* */ +/* <Return> */ +/* The distance in F26dot6 format. */ +/* */ + static FT_F26Dot6 + Project( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy, + CUR.GS.projVector.x, + CUR.GS.projVector.y ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Dual_Project */ +/* */ +/* <Description> */ +/* Computes the projection of the vector given by (v2-v1) along the */ +/* current dual vector. */ +/* */ +/* <Input> */ +/* v1 :: First input vector. */ +/* v2 :: Second input vector. */ +/* */ +/* <Return> */ +/* The distance in F26dot6 format. */ +/* */ + static FT_F26Dot6 + Dual_Project( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy, + CUR.GS.dualVector.x, + CUR.GS.dualVector.y ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Project_x */ +/* */ +/* <Description> */ +/* Computes the projection of the vector given by (v2-v1) along the */ +/* horizontal axis. */ +/* */ +/* <Input> */ +/* v1 :: First input vector. */ +/* v2 :: Second input vector. */ +/* */ +/* <Return> */ +/* The distance in F26dot6 format. */ +/* */ + static FT_F26Dot6 + Project_x( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED_EXEC; + FT_UNUSED( dy ); + return dx; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Project_y */ +/* */ +/* <Description> */ +/* Computes the projection of the vector given by (v2-v1) along the */ +/* vertical axis. */ +/* */ +/* <Input> */ +/* v1 :: First input vector. */ +/* v2 :: Second input vector. */ +/* */ +/* <Return> */ +/* The distance in F26dot6 format. */ +/* */ + static FT_F26Dot6 + Project_y( EXEC_OP_ FT_Pos dx, + FT_Pos dy ) + { + FT_UNUSED_EXEC; + FT_UNUSED( dx ); + return dy; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Compute_Funcs */ +/* */ +/* <Description> */ +/* Computes the projection and movement function pointers according */ +/* to the current graphics state. */ +/* */ + static void + Compute_Funcs( EXEC_OP ) + { + if ( CUR.GS.freeVector.x == 0x4000 ) + CUR.F_dot_P = CUR.GS.projVector.x; + else if ( CUR.GS.freeVector.y == 0x4000 ) + CUR.F_dot_P = CUR.GS.projVector.y; + else + CUR.F_dot_P = ( (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x + + (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y ) >> + 14; + if ( CUR.GS.projVector.x == 0x4000 ) + CUR.func_project = (TT_Project_Func)Project_x; + else if ( CUR.GS.projVector.y == 0x4000 ) + CUR.func_project = (TT_Project_Func)Project_y; + else + CUR.func_project = (TT_Project_Func)Project; + if ( CUR.GS.dualVector.x == 0x4000 ) + CUR.func_dualproj = (TT_Project_Func)Project_x; + else if ( CUR.GS.dualVector.y == 0x4000 ) + CUR.func_dualproj = (TT_Project_Func)Project_y; + else + CUR.func_dualproj = (TT_Project_Func)Dual_Project; + CUR.func_move = (TT_Move_Func)Direct_Move; + CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig; + if ( CUR.F_dot_P == 0x4000L ) + { + if ( CUR.GS.freeVector.x == 0x4000 ) + { + CUR.func_move = (TT_Move_Func)Direct_Move_X; + CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; + } + else if ( CUR.GS.freeVector.y == 0x4000 ) + { + CUR.func_move = (TT_Move_Func)Direct_Move_Y; + CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; + } + } +/* at small sizes, F_dot_P can become too small, resulting */ +/* in overflows and `spikes' in a number of glyphs like `w'. */ + if ( FT_ABS( CUR.F_dot_P ) < 0x400L ) + CUR.F_dot_P = 0x4000L; +/* Disable cached aspect ratio */ + CUR.tt_metrics.ratio = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Normalize */ +/* */ +/* <Description> */ +/* Norms a vector. */ +/* */ +/* <Input> */ +/* Vx :: The horizontal input vector coordinate. */ +/* Vy :: The vertical input vector coordinate. */ +/* */ +/* <Output> */ +/* R :: The normed unit vector. */ +/* */ +/* <Return> */ +/* Returns FAILURE if a vector parameter is zero. */ +/* */ +/* <Note> */ +/* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */ +/* R is undefined. */ +/* */ + static FT_Bool + Normalize( EXEC_OP_ FT_F26Dot6 Vx, + FT_F26Dot6 Vy, + FT_UnitVector* R ) + { + FT_F26Dot6 W; + FT_Bool S1, S2; + FT_UNUSED_EXEC; + if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L ) + { + Vx *= 0x100; + Vy *= 0x100; + W = TT_VecLen( Vx, Vy ); + if ( W == 0 ) + { +/* XXX: UNDOCUMENTED! It seems that it is possible to try */ +/* to normalize the vector (0,0). Return immediately. */ + return SUCCESS; + } + R->x = (FT_F2Dot14)TT_DivFix14( Vx, W ); + R->y = (FT_F2Dot14)TT_DivFix14( Vy, W ); + return SUCCESS; + } + W = TT_VecLen( Vx, Vy ); + Vx = TT_DivFix14( Vx, W ); + Vy = TT_DivFix14( Vy, W ); + W = Vx * Vx + Vy * Vy; +/* Now, we want that Sqrt( W ) = 0x4000 */ +/* Or 0x10000000 <= W < 0x10004000 */ + if ( Vx < 0 ) + { + Vx = -Vx; + S1 = TRUE; + } + else + S1 = FALSE; + if ( Vy < 0 ) + { + Vy = -Vy; + S2 = TRUE; + } + else + S2 = FALSE; + while ( W < 0x10000000L ) + { +/* We need to increase W by a minimal amount */ + if ( Vx < Vy ) + Vx++; + else + Vy++; + W = Vx * Vx + Vy * Vy; + } + while ( W >= 0x10004000L ) + { +/* We need to decrease W by a minimal amount */ + if ( Vx < Vy ) + Vx--; + else + Vy--; + W = Vx * Vx + Vy * Vy; + } +/* Note that in various cases, we can only */ +/* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */ + if ( S1 ) + Vx = -Vx; + if ( S2 ) + Vy = -Vy; +/* Type conversion */ + R->x = (FT_F2Dot14)Vx; +/* Type conversion */ + R->y = (FT_F2Dot14)Vy; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* Here we start with the implementation of the various opcodes. */ +/* */ +/*************************************************************************/ + static FT_Bool + Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1, + FT_UShort aIdx2, + FT_Int aOpc, + FT_UnitVector* Vec ) + { + FT_Long A, B, C; + FT_Vector* p1; + FT_Vector* p2; + if ( BOUNDS( aIdx1, CUR.zp2.n_points ) || + BOUNDS( aIdx2, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return FAILURE; + } + p1 = CUR.zp1.cur + aIdx2; + p2 = CUR.zp2.cur + aIdx1; + A = p1->x - p2->x; + B = p1->y - p2->y; +/* If p1 == p2, SPVTL and SFVTL behave the same as */ +/* SPVTCA[X] and SFVTCA[X], respectively. */ +/* */ +/* Confirmed by Greg Hitchcock. */ + if ( A == 0 && B == 0 ) + { + A = 0x4000; + aOpc = 0; + } + if ( ( aOpc & 1 ) != 0 ) + { +/* counter clockwise rotation */ + C = B; + B = A; + A = -C; + } + NORMalize( A, B, Vec ); + return SUCCESS; + } +/* When not using the big switch statements, the interpreter uses a */ +/* call table defined later below in this source. Each opcode must */ +/* thus have a corresponding function, even trivial ones. */ +/* */ +/* They are all defined there. */ +#define DO_SVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.freeVector.x = A; \ + CUR.GS.projVector.x = A; \ + CUR.GS.dualVector.x = A; \ + \ + CUR.GS.freeVector.y = B; \ + CUR.GS.projVector.y = B; \ + CUR.GS.dualVector.y = B; \ + \ + COMPUTE_Funcs(); \ + } +#define DO_SPVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.projVector.x = A; \ + CUR.GS.dualVector.x = A; \ + \ + CUR.GS.projVector.y = B; \ + CUR.GS.dualVector.y = B; \ + \ + GUESS_VECTOR( freeVector ); \ + \ + COMPUTE_Funcs(); \ + } +#define DO_SFVTCA \ + { \ + FT_Short A, B; \ + \ + \ + A = (FT_Short)( CUR.opcode & 1 ) << 14; \ + B = A ^ (FT_Short)0x4000; \ + \ + CUR.GS.freeVector.x = A; \ + CUR.GS.freeVector.y = B; \ + \ + GUESS_VECTOR( projVector ); \ + \ + COMPUTE_Funcs(); \ + } +#define DO_SPVTL \ + if ( INS_SxVTL( (FT_UShort)args[1], \ + (FT_UShort)args[0], \ + CUR.opcode, \ + &CUR.GS.projVector ) == SUCCESS ) \ + { \ + CUR.GS.dualVector = CUR.GS.projVector; \ + GUESS_VECTOR( freeVector ); \ + COMPUTE_Funcs(); \ + } +#define DO_SFVTL \ + if ( INS_SxVTL( (FT_UShort)args[1], \ + (FT_UShort)args[0], \ + CUR.opcode, \ + &CUR.GS.freeVector ) == SUCCESS ) \ + { \ + GUESS_VECTOR( projVector ); \ + COMPUTE_Funcs(); \ + } +#define DO_SFVTPV \ + GUESS_VECTOR( projVector ); \ + CUR.GS.freeVector = CUR.GS.projVector; \ + COMPUTE_Funcs(); +#define DO_SPVFS \ + { \ + FT_Short S; \ + FT_Long X, Y; \ + \ + \ +/* Only use low 16bits, then sign extend */ \ + S = (FT_Short)args[1]; \ + Y = (FT_Long)S; \ + S = (FT_Short)args[0]; \ + X = (FT_Long)S; \ + \ + NORMalize( X, Y, &CUR.GS.projVector ); \ + \ + CUR.GS.dualVector = CUR.GS.projVector; \ + GUESS_VECTOR( freeVector ); \ + COMPUTE_Funcs(); \ + } +#define DO_SFVFS \ + { \ + FT_Short S; \ + FT_Long X, Y; \ + \ + \ +/* Only use low 16bits, then sign extend */ \ + S = (FT_Short)args[1]; \ + Y = (FT_Long)S; \ + S = (FT_Short)args[0]; \ + X = S; \ + \ + NORMalize( X, Y, &CUR.GS.freeVector ); \ + GUESS_VECTOR( projVector ); \ + COMPUTE_Funcs(); \ + } +#define DO_GPV \ + args[0] = CUR.GS.projVector.x; \ + args[1] = CUR.GS.projVector.y; +#define DO_GFV \ + args[0] = CUR.GS.freeVector.x; \ + args[1] = CUR.GS.freeVector.y; +#define DO_SRP0 \ + CUR.GS.rp0 = (FT_UShort)args[0]; +#define DO_SRP1 \ + CUR.GS.rp1 = (FT_UShort)args[0]; +#define DO_SRP2 \ + CUR.GS.rp2 = (FT_UShort)args[0]; +#define DO_RTHG \ + CUR.GS.round_state = TT_Round_To_Half_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; +#define DO_RTG \ + CUR.GS.round_state = TT_Round_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Grid; +#define DO_RTDG \ + CUR.GS.round_state = TT_Round_To_Double_Grid; \ + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; +#define DO_RUTG \ + CUR.GS.round_state = TT_Round_Up_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; +#define DO_RDTG \ + CUR.GS.round_state = TT_Round_Down_To_Grid; \ + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; +#define DO_ROFF \ + CUR.GS.round_state = TT_Round_Off; \ + CUR.func_round = (TT_Round_Func)Round_None; +#define DO_SROUND \ + SET_SuperRound( 0x4000, args[0] ); \ + CUR.GS.round_state = TT_Round_Super; \ + CUR.func_round = (TT_Round_Func)Round_Super; +#define DO_S45ROUND \ + SET_SuperRound( 0x2D41, args[0] ); \ + CUR.GS.round_state = TT_Round_Super_45; \ + CUR.func_round = (TT_Round_Func)Round_Super_45; +#define DO_SLOOP \ + if ( args[0] < 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + else \ + CUR.GS.loop = args[0]; +#define DO_SMD \ + CUR.GS.minimum_distance = args[0]; +#define DO_SCVTCI \ + CUR.GS.control_value_cutin = (FT_F26Dot6)args[0]; +#define DO_SSWCI \ + CUR.GS.single_width_cutin = (FT_F26Dot6)args[0]; +#define DO_SSW \ + CUR.GS.single_width_value = FT_MulFix( args[0], \ + CUR.tt_metrics.scale ); +#define DO_FLIPON \ + CUR.GS.auto_flip = TRUE; +#define DO_FLIPOFF \ + CUR.GS.auto_flip = FALSE; +#define DO_SDB \ + CUR.GS.delta_base = (FT_Short)args[0]; +#define DO_SDS \ + CUR.GS.delta_shift = (FT_Short)args[0]; +/* nothing */ +#define DO_MD +#define DO_MPPEM \ + args[0] = CURRENT_Ppem(); +/* Note: The pointSize should be irrelevant in a given font program; */ +/* we thus decide to return only the ppem. */ +#if 0 +#define DO_MPS \ + args[0] = CUR.metrics.pointSize; +#else +#define DO_MPS \ + args[0] = CURRENT_Ppem(); +/* 0 */ +#endif +#define DO_DUP \ + args[1] = args[0]; +#define DO_CLEAR \ + CUR.new_top = 0; +#define DO_SWAP \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + args[0] = args[1]; \ + args[1] = L; \ + } +#define DO_DEPTH \ + args[0] = CUR.top; +#define DO_CINDEX \ + { \ + FT_Long L; \ + \ + \ + L = args[0]; \ + \ + if ( L <= 0 || L > CUR.args ) \ + { \ + if ( CUR.pedantic_hinting ) \ + CUR.error = TT_Err_Invalid_Reference; \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR.stack[CUR.args - L]; \ + } +#define DO_JROT \ + if ( args[1] != 0 ) \ + { \ + if ( args[0] == 0 && CUR.args == 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.IP += args[0]; \ + if ( CUR.IP < 0 || \ + ( CUR.callTop > 0 && \ + CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.step_ins = FALSE; \ + } +#define DO_JMPR \ + if ( args[0] == 0 && CUR.args == 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.IP += args[0]; \ + if ( CUR.IP < 0 || \ + ( CUR.callTop > 0 && \ + CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.step_ins = FALSE; +#define DO_JROF \ + if ( args[1] == 0 ) \ + { \ + if ( args[0] == 0 && CUR.args == 0 ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.IP += args[0]; \ + if ( CUR.IP < 0 || \ + ( CUR.callTop > 0 && \ + CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \ + CUR.error = TT_Err_Bad_Argument; \ + CUR.step_ins = FALSE; \ + } +#define DO_LT \ + args[0] = ( args[0] < args[1] ); +#define DO_LTEQ \ + args[0] = ( args[0] <= args[1] ); +#define DO_GT \ + args[0] = ( args[0] > args[1] ); +#define DO_GTEQ \ + args[0] = ( args[0] >= args[1] ); +#define DO_EQ \ + args[0] = ( args[0] == args[1] ); +#define DO_NEQ \ + args[0] = ( args[0] != args[1] ); +#define DO_ODD \ + args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 ); +#define DO_EVEN \ + args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 ); +#define DO_AND \ + args[0] = ( args[0] && args[1] ); +#define DO_OR \ + args[0] = ( args[0] || args[1] ); +#define DO_NOT \ + args[0] = !args[0]; +#define DO_ADD \ + args[0] += args[1]; +#define DO_SUB \ + args[0] -= args[1]; +#define DO_DIV \ + if ( args[1] == 0 ) \ + CUR.error = TT_Err_Divide_By_Zero; \ + else \ + args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] ); +#define DO_MUL \ + args[0] = FT_MulDiv( args[0], args[1], 64L ); +#define DO_ABS \ + args[0] = FT_ABS( args[0] ); +#define DO_NEG \ + args[0] = -args[0]; +#define DO_FLOOR \ + args[0] = FT_PIX_FLOOR( args[0] ); +#define DO_CEILING \ + args[0] = FT_PIX_CEIL( args[0] ); +#define DO_RS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDSL( I, CUR.storeSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + else \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR.storage[I]; \ + } +#define DO_WS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDSL( I, CUR.storeSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR.storage[I] = args[1]; \ + } +#define DO_RCVT \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDSL( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + else \ + args[0] = 0; \ + } \ + else \ + args[0] = CUR_Func_read_cvt( I ); \ + } +#define DO_WCVTP \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDSL( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR_Func_write_cvt( I, args[1] ); \ + } +#define DO_WCVTF \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ + \ + \ + if ( BOUNDSL( I, CUR.cvtSize ) ) \ + { \ + if ( CUR.pedantic_hinting ) \ + { \ + ARRAY_BOUND_ERROR; \ + } \ + } \ + else \ + CUR.cvt[I] = FT_MulFix( args[1], CUR.tt_metrics.scale ); \ + } +#define DO_DEBUG \ + CUR.error = TT_Err_Debug_OpCode; +#define DO_ROUND \ + args[0] = CUR_Func_round( \ + args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x68] ); +#define DO_NROUND \ + args[0] = ROUND_None( args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x6C] ); +#define DO_MAX \ + if ( args[1] > args[0] ) \ + args[0] = args[1]; +#define DO_MIN \ + if ( args[1] < args[0] ) \ + args[0] = args[1]; +/*************************************************************************/ +/* */ +/* The following functions are called as is within the switch statement. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* MINDEX[]: Move INDEXed element */ +/* Opcode range: 0x26 */ +/* Stack: int32? --> StkElt */ +/* */ + static void + Ins_MINDEX( INS_ARG ) + { + FT_Long L, K; + L = args[0]; + if ( L <= 0 || L > CUR.args ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + } + else + { + K = CUR.stack[CUR.args - L]; + FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ], + &CUR.stack[CUR.args - L + 1], + ( L - 1 ) ); + CUR.stack[CUR.args - 1] = K; + } + } +/*************************************************************************/ +/* */ +/* ROLL[]: ROLL top three elements */ +/* Opcode range: 0x8A */ +/* Stack: 3 * StkElt --> 3 * StkElt */ +/* */ + static void + Ins_ROLL( INS_ARG ) + { + FT_Long A, B, C; + FT_UNUSED_EXEC; + A = args[2]; + B = args[1]; + C = args[0]; + args[2] = C; + args[1] = A; + args[0] = B; + } +/*************************************************************************/ +/* */ +/* MANAGING THE FLOW OF CONTROL */ +/* */ +/* Instructions appear in the specification's order. */ +/* */ +/*************************************************************************/ + static FT_Bool + SkipCode( EXEC_OP ) + { + CUR.IP += CUR.length; + if ( CUR.IP < CUR.codeSize ) + { + CUR.opcode = CUR.code[CUR.IP]; + CUR.length = opcode_length[CUR.opcode]; + if ( CUR.length < 0 ) + { + if ( CUR.IP + 1 >= CUR.codeSize ) + goto Fail_Overflow; + CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; + } + if ( CUR.IP + CUR.length <= CUR.codeSize ) + return SUCCESS; + } + Fail_Overflow: + CUR.error = TT_Err_Code_Overflow; + return FAILURE; + } +/*************************************************************************/ +/* */ +/* IF[]: IF test */ +/* Opcode range: 0x58 */ +/* Stack: StkElt --> */ +/* */ + static void + Ins_IF( INS_ARG ) + { + FT_Int nIfs; + FT_Bool Out; + if ( args[0] != 0 ) + return; + nIfs = 1; + Out = 0; + do + { + if ( SKIP_Code() == FAILURE ) + return; + switch ( CUR.opcode ) + { +/* IF */ + case 0x58: + nIfs++; + break; +/* ELSE */ + case 0x1B: + Out = FT_BOOL( nIfs == 1 ); + break; +/* EIF */ + case 0x59: + nIfs--; + Out = FT_BOOL( nIfs == 0 ); + break; + } + } while ( Out == 0 ); + } +/*************************************************************************/ +/* */ +/* ELSE[]: ELSE */ +/* Opcode range: 0x1B */ +/* Stack: --> */ +/* */ + static void + Ins_ELSE( INS_ARG ) + { + FT_Int nIfs; + FT_UNUSED_ARG; + nIfs = 1; + do + { + if ( SKIP_Code() == FAILURE ) + return; + switch ( CUR.opcode ) + { +/* IF */ + case 0x58: + nIfs++; + break; +/* EIF */ + case 0x59: + nIfs--; + break; + } + } while ( nIfs != 0 ); + } +/*************************************************************************/ +/* */ +/* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */ +/* */ +/* Instructions appear in the specification's order. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* FDEF[]: Function DEFinition */ +/* Opcode range: 0x2C */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_FDEF( INS_ARG ) + { + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; +/* some font programs are broken enough to redefine functions! */ +/* We will then parse the current table. */ + rec = CUR.FDefs; + limit = rec + CUR.numFDefs; + n = args[0]; + for ( ; rec < limit; rec++ ) + { + if ( rec->opc == n ) + break; + } + if ( rec == limit ) + { +/* check that there is enough room for new functions */ + if ( CUR.numFDefs >= CUR.maxFDefs ) + { + CUR.error = TT_Err_Too_Many_Function_Defs; + return; + } + CUR.numFDefs++; + } +/* Although FDEF takes unsigned 32-bit integer, */ +/* func # must be within unsigned 16-bit integer */ + if ( n > 0xFFFFU ) + { + CUR.error = TT_Err_Too_Many_Function_Defs; + return; + } + rec->range = CUR.curRange; + rec->opc = (FT_UInt16)n; + rec->start = CUR.IP + 1; + rec->active = TRUE; + rec->inline_delta = FALSE; + if ( n > CUR.maxFunc ) + CUR.maxFunc = (FT_UInt16)n; +/* Now skip the whole function definition. */ +/* We don't allow nested IDEFS & FDEFs. */ + while ( SKIP_Code() == SUCCESS ) + { + switch ( CUR.opcode ) + { +/* IDEF */ + case 0x89: +/* FDEF */ + case 0x2C: + CUR.error = TT_Err_Nested_DEFS; + return; +/* ENDF */ + case 0x2D: + rec->end = CUR.IP; + return; + } + } + } +/*************************************************************************/ +/* */ +/* ENDF[]: END Function definition */ +/* Opcode range: 0x2D */ +/* Stack: --> */ +/* */ + static void + Ins_ENDF( INS_ARG ) + { + TT_CallRec* pRec; + FT_UNUSED_ARG; +/* We encountered an ENDF without a call */ + if ( CUR.callTop <= 0 ) + { + CUR.error = TT_Err_ENDF_In_Exec_Stream; + return; + } + CUR.callTop--; + pRec = &CUR.callStack[CUR.callTop]; + pRec->Cur_Count--; + CUR.step_ins = FALSE; + if ( pRec->Cur_Count > 0 ) + { + CUR.callTop++; + CUR.IP = pRec->Cur_Restart; + } + else +/* Loop through the current function */ + INS_Goto_CodeRange( pRec->Caller_Range, + pRec->Caller_IP ); +/* Exit the current call frame. */ +/* NOTE: If the last instruction of a program is a */ +/* CALL or LOOPCALL, the return address is */ +/* always out of the code range. This is a */ +/* valid address, and it is why we do not test */ +/* the result of Ins_Goto_CodeRange() here! */ + } +/*************************************************************************/ +/* */ +/* CALL[]: CALL function */ +/* Opcode range: 0x2B */ +/* Stack: uint32? --> */ +/* */ + static void + Ins_CALL( INS_ARG ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; +/* first of all, check the index */ + F = args[0]; + if ( BOUNDSL( F, CUR.maxFunc + 1 ) ) + goto Fail; +/* Except for some old Apple fonts, all functions in a TrueType */ +/* font are defined in increasing order, starting from 0. This */ +/* means that we normally have */ +/* */ +/* CUR.maxFunc+1 == CUR.numFDefs */ +/* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */ +/* */ +/* If this isn't true, we need to look up the function table. */ + def = CUR.FDefs + F; + if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F ) + { +/* look up the FDefs table */ + TT_DefRecord* limit; + def = CUR.FDefs; + limit = def + CUR.numFDefs; + while ( def < limit && def->opc != F ) + def++; + if ( def == limit ) + goto Fail; + } +/* check that the function is active */ + if ( !def->active ) + goto Fail; +/* check the call stack */ + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + pCrec = CUR.callStack + CUR.callTop; + pCrec->Caller_Range = CUR.curRange; + pCrec->Caller_IP = CUR.IP + 1; + pCrec->Cur_Count = 1; + pCrec->Cur_Restart = def->start; + pCrec->Cur_End = def->end; + CUR.callTop++; + INS_Goto_CodeRange( def->range, + def->start ); + CUR.step_ins = FALSE; + return; + Fail: + CUR.error = TT_Err_Invalid_Reference; + } +/*************************************************************************/ +/* */ +/* LOOPCALL[]: LOOP and CALL function */ +/* Opcode range: 0x2A */ +/* Stack: uint32? Eint16? --> */ +/* */ + static void + Ins_LOOPCALL( INS_ARG ) + { + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; +/* first of all, check the index */ + F = args[1]; + if ( BOUNDSL( F, CUR.maxFunc + 1 ) ) + goto Fail; +/* Except for some old Apple fonts, all functions in a TrueType */ +/* font are defined in increasing order, starting from 0. This */ +/* means that we normally have */ +/* */ +/* CUR.maxFunc+1 == CUR.numFDefs */ +/* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */ +/* */ +/* If this isn't true, we need to look up the function table. */ + def = CUR.FDefs + F; + if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F ) + { +/* look up the FDefs table */ + TT_DefRecord* limit; + def = CUR.FDefs; + limit = def + CUR.numFDefs; + while ( def < limit && def->opc != F ) + def++; + if ( def == limit ) + goto Fail; + } +/* check that the function is active */ + if ( !def->active ) + goto Fail; +/* check stack */ + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + if ( args[0] > 0 ) + { + pCrec = CUR.callStack + CUR.callTop; + pCrec->Caller_Range = CUR.curRange; + pCrec->Caller_IP = CUR.IP + 1; + pCrec->Cur_Count = (FT_Int)args[0]; + pCrec->Cur_Restart = def->start; + pCrec->Cur_End = def->end; + CUR.callTop++; + INS_Goto_CodeRange( def->range, def->start ); + CUR.step_ins = FALSE; + } + return; + Fail: + CUR.error = TT_Err_Invalid_Reference; + } +/*************************************************************************/ +/* */ +/* IDEF[]: Instruction DEFinition */ +/* Opcode range: 0x89 */ +/* Stack: Eint8 --> */ +/* */ + static void + Ins_IDEF( INS_ARG ) + { + TT_DefRecord* def; + TT_DefRecord* limit; +/* First of all, look for the same function in our table */ + def = CUR.IDefs; + limit = def + CUR.numIDefs; + for ( ; def < limit; def++ ) + if ( def->opc == (FT_ULong)args[0] ) + break; + if ( def == limit ) + { +/* check that there is enough room for a new instruction */ + if ( CUR.numIDefs >= CUR.maxIDefs ) + { + CUR.error = TT_Err_Too_Many_Instruction_Defs; + return; + } + CUR.numIDefs++; + } +/* opcode must be unsigned 8-bit integer */ + if ( 0 > args[0] || args[0] > 0x00FF ) + { + CUR.error = TT_Err_Too_Many_Instruction_Defs; + return; + } + def->opc = (FT_Byte)args[0]; + def->start = CUR.IP + 1; + def->range = CUR.curRange; + def->active = TRUE; + if ( (FT_ULong)args[0] > CUR.maxIns ) + CUR.maxIns = (FT_Byte)args[0]; +/* Now skip the whole function definition. */ +/* We don't allow nested IDEFs & FDEFs. */ + while ( SKIP_Code() == SUCCESS ) + { + switch ( CUR.opcode ) + { +/* IDEF */ + case 0x89: +/* FDEF */ + case 0x2C: + CUR.error = TT_Err_Nested_DEFS; + return; +/* ENDF */ + case 0x2D: + return; + } + } + } +/*************************************************************************/ +/* */ +/* PUSHING DATA ONTO THE INTERPRETER STACK */ +/* */ +/* Instructions appear in the specification's order. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* NPUSHB[]: PUSH N Bytes */ +/* Opcode range: 0x40 */ +/* Stack: --> uint32... */ +/* */ + static void + Ins_NPUSHB( INS_ARG ) + { + FT_UShort L, K; + L = (FT_UShort)CUR.code[CUR.IP + 1]; + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + for ( K = 1; K <= L; K++ ) + args[K - 1] = CUR.code[CUR.IP + K + 1]; + CUR.new_top += L; + } +/*************************************************************************/ +/* */ +/* NPUSHW[]: PUSH N Words */ +/* Opcode range: 0x41 */ +/* Stack: --> int32... */ +/* */ + static void + Ins_NPUSHW( INS_ARG ) + { + FT_UShort L, K; + L = (FT_UShort)CUR.code[CUR.IP + 1]; + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + CUR.IP += 2; + for ( K = 0; K < L; K++ ) + args[K] = GET_ShortIns(); + CUR.step_ins = FALSE; + CUR.new_top += L; + } +/*************************************************************************/ +/* */ +/* PUSHB[abc]: PUSH Bytes */ +/* Opcode range: 0xB0-0xB7 */ +/* Stack: --> uint32... */ +/* */ + static void + Ins_PUSHB( INS_ARG ) + { + FT_UShort L, K; + L = (FT_UShort)( CUR.opcode - 0xB0 + 1 ); + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + for ( K = 1; K <= L; K++ ) + args[K - 1] = CUR.code[CUR.IP + K]; + } +/*************************************************************************/ +/* */ +/* PUSHW[abc]: PUSH Words */ +/* Opcode range: 0xB8-0xBF */ +/* Stack: --> int32... */ +/* */ + static void + Ins_PUSHW( INS_ARG ) + { + FT_UShort L, K; + L = (FT_UShort)( CUR.opcode - 0xB8 + 1 ); + if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + CUR.IP++; + for ( K = 0; K < L; K++ ) + args[K] = GET_ShortIns(); + CUR.step_ins = FALSE; + } +/*************************************************************************/ +/* */ +/* MANAGING THE GRAPHICS STATE */ +/* */ +/* Instructions appear in the specs' order. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* GC[a]: Get Coordinate projected onto */ +/* Opcode range: 0x46-0x47 */ +/* Stack: uint32 --> f26.6 */ +/* */ +/* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */ +/* along the dual projection vector! */ +/* */ + static void + Ins_GC( INS_ARG ) + { + FT_ULong L; + FT_F26Dot6 R; + L = (FT_ULong)args[0]; + if ( BOUNDSL( L, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + R = 0; + } + else + { + if ( CUR.opcode & 1 ) + R = CUR_fast_dualproj( &CUR.zp2.org[L] ); + else + R = CUR_fast_project( &CUR.zp2.cur[L] ); + } + args[0] = R; + } +/*************************************************************************/ +/* */ +/* SCFS[]: Set Coordinate From Stack */ +/* Opcode range: 0x48 */ +/* Stack: f26.6 uint32 --> */ +/* */ +/* Formula: */ +/* */ +/* OA := OA + ( value - OA.p )/( f.p ) * f */ +/* */ + static void + Ins_SCFS( INS_ARG ) + { + FT_Long K; + FT_UShort L; + L = (FT_UShort)args[0]; + if ( BOUNDS( L, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + K = CUR_fast_project( &CUR.zp2.cur[L] ); + CUR_Func_move( &CUR.zp2, L, args[1] - K ); +/* UNDOCUMENTED! The MS rasterizer does that with */ +/* twilight points (confirmed by Greg Hitchcock) */ + if ( CUR.GS.gep2 == 0 ) + CUR.zp2.org[L] = CUR.zp2.cur[L]; + } +/*************************************************************************/ +/* */ +/* MD[a]: Measure Distance */ +/* Opcode range: 0x49-0x4A */ +/* Stack: uint32 uint32 --> f26.6 */ +/* */ +/* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */ +/* the dual projection vector. */ +/* */ +/* XXX: UNDOCUMENTED: Flag attributes are inverted! */ +/* 0 => measure distance in original outline */ +/* 1 => measure distance in grid-fitted outline */ +/* */ +/* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */ +/* */ + static void + Ins_MD( INS_ARG ) + { + FT_UShort K, L; + FT_F26Dot6 D; + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + if ( BOUNDS( L, CUR.zp0.n_points ) || + BOUNDS( K, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + D = 0; + } + else + { + if ( CUR.opcode & 1 ) + D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K ); + else + { +/* XXX: UNDOCUMENTED: twilight zone special case */ + if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 ) + { + FT_Vector* vec1 = CUR.zp0.org + L; + FT_Vector* vec2 = CUR.zp1.org + K; + D = CUR_Func_dualproj( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = CUR.zp0.orus + L; + FT_Vector* vec2 = CUR.zp1.orus + K; + if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) + { +/* this should be faster */ + D = CUR_Func_dualproj( vec1, vec2 ); + D = FT_MulFix( D, CUR.metrics.x_scale ); + } + else + { + FT_Vector vec; + vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale ); + vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale ); + D = CUR_fast_dualproj( &vec ); + } + } + } + } + args[0] = D; + } +/*************************************************************************/ +/* */ +/* SDPVTL[a]: Set Dual PVector to Line */ +/* Opcode range: 0x86-0x87 */ +/* Stack: uint32 uint32 --> */ +/* */ + static void + Ins_SDPVTL( INS_ARG ) + { + FT_Long A, B, C; +/* was FT_Int in pas type ERROR */ + FT_UShort p1, p2; + FT_Int aOpc = CUR.opcode; + p1 = (FT_UShort)args[1]; + p2 = (FT_UShort)args[0]; + if ( BOUNDS( p2, CUR.zp1.n_points ) || + BOUNDS( p1, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + { + FT_Vector* v1 = CUR.zp1.org + p2; + FT_Vector* v2 = CUR.zp2.org + p1; + A = v1->x - v2->x; + B = v1->y - v2->y; +/* If v1 == v2, SDPVTL behaves the same as */ +/* SVTCA[X], respectively. */ +/* */ +/* Confirmed by Greg Hitchcock. */ + if ( A == 0 && B == 0 ) + { + A = 0x4000; + aOpc = 0; + } + } + if ( ( aOpc & 1 ) != 0 ) + { +/* counter clockwise rotation */ + C = B; + B = A; + A = -C; + } + NORMalize( A, B, &CUR.GS.dualVector ); + { + FT_Vector* v1 = CUR.zp1.cur + p2; + FT_Vector* v2 = CUR.zp2.cur + p1; + A = v1->x - v2->x; + B = v1->y - v2->y; + } + if ( ( aOpc & 1 ) != 0 ) + { +/* counter clockwise rotation */ + C = B; + B = A; + A = -C; + } + NORMalize( A, B, &CUR.GS.projVector ); + GUESS_VECTOR( freeVector ); + COMPUTE_Funcs(); + } +/*************************************************************************/ +/* */ +/* SZP0[]: Set Zone Pointer 0 */ +/* Opcode range: 0x13 */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_SZP0( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp0 = CUR.twilight; + break; + case 1: + CUR.zp0 = CUR.pts; + break; + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + CUR.GS.gep0 = (FT_UShort)args[0]; + } +/*************************************************************************/ +/* */ +/* SZP1[]: Set Zone Pointer 1 */ +/* Opcode range: 0x14 */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_SZP1( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp1 = CUR.twilight; + break; + case 1: + CUR.zp1 = CUR.pts; + break; + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + CUR.GS.gep1 = (FT_UShort)args[0]; + } +/*************************************************************************/ +/* */ +/* SZP2[]: Set Zone Pointer 2 */ +/* Opcode range: 0x15 */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_SZP2( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp2 = CUR.twilight; + break; + case 1: + CUR.zp2 = CUR.pts; + break; + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + CUR.GS.gep2 = (FT_UShort)args[0]; + } +/*************************************************************************/ +/* */ +/* SZPS[]: Set Zone PointerS */ +/* Opcode range: 0x16 */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_SZPS( INS_ARG ) + { + switch ( (FT_Int)args[0] ) + { + case 0: + CUR.zp0 = CUR.twilight; + break; + case 1: + CUR.zp0 = CUR.pts; + break; + default: + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + CUR.zp1 = CUR.zp0; + CUR.zp2 = CUR.zp0; + CUR.GS.gep0 = (FT_UShort)args[0]; + CUR.GS.gep1 = (FT_UShort)args[0]; + CUR.GS.gep2 = (FT_UShort)args[0]; + } +/*************************************************************************/ +/* */ +/* INSTCTRL[]: INSTruction ConTRoL */ +/* Opcode range: 0x8e */ +/* Stack: int32 int32 --> */ +/* */ + static void + Ins_INSTCTRL( INS_ARG ) + { + FT_Long K, L; + K = args[1]; + L = args[0]; + if ( K < 1 || K > 2 ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + if ( L != 0 ) + L = K; + CUR.GS.instruct_control = FT_BOOL( + ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L ); + } +/*************************************************************************/ +/* */ +/* SCANCTRL[]: SCAN ConTRoL */ +/* Opcode range: 0x85 */ +/* Stack: uint32? --> */ +/* */ + static void + Ins_SCANCTRL( INS_ARG ) + { + FT_Int A; +/* Get Threshold */ + A = (FT_Int)( args[0] & 0xFF ); + if ( A == 0xFF ) + { + CUR.GS.scan_control = TRUE; + return; + } + else if ( A == 0 ) + { + CUR.GS.scan_control = FALSE; + return; + } + if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A ) + CUR.GS.scan_control = TRUE; + if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated ) + CUR.GS.scan_control = TRUE; + if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched ) + CUR.GS.scan_control = TRUE; + if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A ) + CUR.GS.scan_control = FALSE; + if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated ) + CUR.GS.scan_control = FALSE; + if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched ) + CUR.GS.scan_control = FALSE; + } +/*************************************************************************/ +/* */ +/* SCANTYPE[]: SCAN TYPE */ +/* Opcode range: 0x8D */ +/* Stack: uint32? --> */ +/* */ + static void + Ins_SCANTYPE( INS_ARG ) + { + if ( args[0] >= 0 ) + CUR.GS.scan_type = (FT_Int)args[0]; + } +/*************************************************************************/ +/* */ +/* MANAGING OUTLINES */ +/* */ +/* Instructions appear in the specification's order. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* FLIPPT[]: FLIP PoinT */ +/* Opcode range: 0x80 */ +/* Stack: uint32... --> */ +/* */ + static void + Ins_FLIPPT( INS_ARG ) + { + FT_UShort point; + FT_UNUSED_ARG; + if ( CUR.top < CUR.GS.loop ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + goto Fail; + } + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + point = (FT_UShort)CUR.stack[CUR.args]; + if ( BOUNDS( point, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + CUR.pts.tags[point] ^= FT_CURVE_TAG_ON; + CUR.GS.loop--; + } + Fail: + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* FLIPRGON[]: FLIP RanGe ON */ +/* Opcode range: 0x81 */ +/* Stack: uint32 uint32 --> */ +/* */ + static void + Ins_FLIPRGON( INS_ARG ) + { + FT_UShort I, K, L; + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + if ( BOUNDS( K, CUR.pts.n_points ) || + BOUNDS( L, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + for ( I = L; I <= K; I++ ) + CUR.pts.tags[I] |= FT_CURVE_TAG_ON; + } +/*************************************************************************/ +/* */ +/* FLIPRGOFF: FLIP RanGe OFF */ +/* Opcode range: 0x82 */ +/* Stack: uint32 uint32 --> */ +/* */ + static void + Ins_FLIPRGOFF( INS_ARG ) + { + FT_UShort I, K, L; + K = (FT_UShort)args[1]; + L = (FT_UShort)args[0]; + if ( BOUNDS( K, CUR.pts.n_points ) || + BOUNDS( L, CUR.pts.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + for ( I = L; I <= K; I++ ) + CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON; + } + static FT_Bool + Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x, + FT_F26Dot6* y, + TT_GlyphZone zone, + FT_UShort* refp ) + { + TT_GlyphZoneRec zp; + FT_UShort p; + FT_F26Dot6 d; + if ( CUR.opcode & 1 ) + { + zp = CUR.zp0; + p = CUR.GS.rp1; + } + else + { + zp = CUR.zp1; + p = CUR.GS.rp2; + } + if ( BOUNDS( p, zp.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + *refp = 0; + return FAILURE; + } + *zone = zp; + *refp = p; + d = CUR_Func_project( zp.cur + p, zp.org + p ); + { + *x = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.x, CUR.F_dot_P ); + *y = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.y, CUR.F_dot_P ); + } + return SUCCESS; + } + static void + Move_Zp2_Point( EXEC_OP_ FT_UShort point, + FT_F26Dot6 dx, + FT_F26Dot6 dy, + FT_Bool touch ) + { + if ( CUR.GS.freeVector.x != 0 ) + { + CUR.zp2.cur[point].x += dx; + if ( touch ) + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + } + if ( CUR.GS.freeVector.y != 0 ) + { + CUR.zp2.cur[point].y += dy; + if ( touch ) + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + } +/*************************************************************************/ +/* */ +/* SHP[a]: SHift Point by the last point */ +/* Opcode range: 0x32-0x33 */ +/* Stack: uint32... --> */ +/* */ + static void + Ins_SHP( INS_ARG ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + FT_UShort point; + FT_UNUSED_ARG; + if ( CUR.top < CUR.GS.loop ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + point = (FT_UShort)CUR.stack[CUR.args]; + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + MOVE_Zp2_Point( point, dx, dy, TRUE ); + CUR.GS.loop--; + } + Fail: + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* SHC[a]: SHift Contour */ +/* Opcode range: 0x34-35 */ +/* Stack: uint32 --> */ +/* */ +/* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */ +/* contour in the twilight zone, namely contour number */ +/* zero which includes all points of it. */ +/* */ + static void + Ins_SHC( INS_ARG ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, dy; + FT_Short contour, bounds; + FT_UShort start, limit, i; + contour = (FT_UShort)args[0]; + bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours; + if ( BOUNDS( contour, bounds ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; + if ( contour == 0 ) + start = 0; + else + start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 - + CUR.zp2.first_point ); +/* we use the number of points if in the twilight zone */ + if ( CUR.GS.gep2 == 0 ) + limit = CUR.zp2.n_points; + else + limit = (FT_UShort)( CUR.zp2.contours[contour] - + CUR.zp2.first_point + 1 ); + for ( i = start; i < limit; i++ ) + { + if ( zp.cur != CUR.zp2.cur || refp != i ) + MOVE_Zp2_Point( i, dx, dy, TRUE ); + } + } +/*************************************************************************/ +/* */ +/* SHZ[a]: SHift Zone */ +/* Opcode range: 0x36-37 */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_SHZ( INS_ARG ) + { + TT_GlyphZoneRec zp; + FT_UShort refp; + FT_F26Dot6 dx, + dy; + FT_UShort limit, i; + if ( BOUNDS( args[0], 2 ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) ) + return; +/* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ +/* Twilight zone has no real contours, so use `n_points'. */ +/* Normal zone's `n_points' includes phantoms, so must */ +/* use end of last contour. */ + if ( CUR.GS.gep2 == 0 ) + limit = (FT_UShort)CUR.zp2.n_points; + else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 ) + limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 ); + else + limit = 0; +/* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ + for ( i = 0; i < limit; i++ ) + { + if ( zp.cur != CUR.zp2.cur || refp != i ) + MOVE_Zp2_Point( i, dx, dy, FALSE ); + } + } +/*************************************************************************/ +/* */ +/* SHPIX[]: SHift points by a PIXel amount */ +/* Opcode range: 0x38 */ +/* Stack: f26.6 uint32... --> */ +/* */ + static void + Ins_SHPIX( INS_ARG ) + { + FT_F26Dot6 dx, dy; + FT_UShort point; + if ( CUR.top < CUR.GS.loop + 1 ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } + { + dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x ); + dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y ); + } + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + point = (FT_UShort)CUR.stack[CUR.args]; + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + MOVE_Zp2_Point( point, dx, dy, TRUE ); + CUR.GS.loop--; + } + Fail: + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* MSIRP[a]: Move Stack Indirect Relative Position */ +/* Opcode range: 0x3A-0x3B */ +/* Stack: f26.6 uint32 --> */ +/* */ + static void + Ins_MSIRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 distance; + point = (FT_UShort)args[0]; + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } +/* UNDOCUMENTED! The MS rasterizer does that with */ +/* twilight points (confirmed by Greg Hitchcock) */ + if ( CUR.GS.gep1 == 0 ) + { + CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0]; + CUR_Func_move_orig( &CUR.zp1, point, args[1] ); + CUR.zp1.cur[point] = CUR.zp1.org[point]; + } + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + CUR_Func_move( &CUR.zp1, point, args[1] - distance ); + CUR.GS.rp1 = CUR.GS.rp0; + CUR.GS.rp2 = point; + if ( ( CUR.opcode & 1 ) != 0 ) + CUR.GS.rp0 = point; + } +/*************************************************************************/ +/* */ +/* MDAP[a]: Move Direct Absolute Point */ +/* Opcode range: 0x2E-0x2F */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_MDAP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 cur_dist; + FT_F26Dot6 distance; + point = (FT_UShort)args[0]; + if ( BOUNDS( point, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + if ( ( CUR.opcode & 1 ) != 0 ) + { + cur_dist = CUR_fast_project( &CUR.zp0.cur[point] ); + distance = CUR_Func_round( + cur_dist, + CUR.tt_metrics.compensations[0] ) - cur_dist; + } + else + distance = 0; + CUR_Func_move( &CUR.zp0, point, distance ); + CUR.GS.rp0 = point; + CUR.GS.rp1 = point; + } +/*************************************************************************/ +/* */ +/* MIAP[a]: Move Indirect Absolute Point */ +/* Opcode range: 0x3E-0x3F */ +/* Stack: uint32 uint32 --> */ +/* */ + static void + Ins_MIAP( INS_ARG ) + { + FT_ULong cvtEntry; + FT_UShort point; + FT_F26Dot6 distance; + FT_F26Dot6 org_dist; + FT_F26Dot6 control_value_cutin; + control_value_cutin = CUR.GS.control_value_cutin; + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; + if ( BOUNDS( point, CUR.zp0.n_points ) || + BOUNDSL( cvtEntry, CUR.cvtSize ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } +/* UNDOCUMENTED! */ +/* */ +/* The behaviour of an MIAP instruction is quite different when used */ +/* in the twilight zone. */ +/* */ +/* First, no control value cut-in test is performed as it would fail */ +/* anyway. Second, the original point, i.e. (org_x,org_y) of */ +/* zp0.point, is set to the absolute, unrounded distance found in the */ +/* CVT. */ +/* */ +/* This is used in the CVT programs of the Microsoft fonts Arial, */ +/* Times, etc., in order to re-adjust some key font heights. It */ +/* allows the use of the IP instruction in the twilight zone, which */ +/* otherwise would be invalid according to the specification. */ +/* */ +/* We implement it with a special sequence for the twilight zone. */ +/* This is a bad hack, but it seems to work. */ +/* */ +/* Confirmed by Greg Hitchcock. */ + distance = CUR_Func_read_cvt( cvtEntry ); +/* If in twilight zone */ + if ( CUR.GS.gep0 == 0 ) + { + CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance, + CUR.GS.freeVector.x ); + CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance, + CUR.GS.freeVector.y ), + CUR.zp0.cur[point] = CUR.zp0.org[point]; + } + org_dist = CUR_fast_project( &CUR.zp0.cur[point] ); +/* rounding and control cut-in flag */ + if ( ( CUR.opcode & 1 ) != 0 ) + { + if ( FT_ABS( distance - org_dist ) > control_value_cutin ) + distance = org_dist; + distance = CUR_Func_round( distance, + CUR.tt_metrics.compensations[0] ); + } + CUR_Func_move( &CUR.zp0, point, distance - org_dist ); + Fail: + CUR.GS.rp0 = point; + CUR.GS.rp1 = point; + } +/*************************************************************************/ +/* */ +/* MDRP[abcde]: Move Direct Relative Point */ +/* Opcode range: 0xC0-0xDF */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_MDRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 org_dist, distance, minimum_distance; + minimum_distance = CUR.GS.minimum_distance; + point = (FT_UShort)args[0]; + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } +/* XXX: Is there some undocumented feature while in the */ +/* twilight zone? */ +/* XXX: UNDOCUMENTED: twilight zone special case */ + if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 ) + { + FT_Vector* vec1 = &CUR.zp1.org[point]; + FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0]; + org_dist = CUR_Func_dualproj( vec1, vec2 ); + } + else + { + FT_Vector* vec1 = &CUR.zp1.orus[point]; + FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0]; + if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) + { +/* this should be faster */ + org_dist = CUR_Func_dualproj( vec1, vec2 ); + org_dist = FT_MulFix( org_dist, CUR.metrics.x_scale ); + } + else + { + FT_Vector vec; + vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale ); + vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale ); + org_dist = CUR_fast_dualproj( &vec ); + } + } +/* single width cut-in test */ + if ( FT_ABS( org_dist - CUR.GS.single_width_value ) < + CUR.GS.single_width_cutin ) + { + if ( org_dist >= 0 ) + org_dist = CUR.GS.single_width_value; + else + org_dist = -CUR.GS.single_width_value; + } +/* round flag */ + if ( ( CUR.opcode & 4 ) != 0 ) + { + distance = CUR_Func_round( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } + else + distance = ROUND_None( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); +/* minimum distance flag */ + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { + if ( distance < minimum_distance ) + distance = minimum_distance; + } + else + { + if ( distance > -minimum_distance ) + distance = -minimum_distance; + } + } +/* now move the point */ + org_dist = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + CUR_Func_move( &CUR.zp1, point, distance - org_dist ); + Fail: + CUR.GS.rp1 = CUR.GS.rp0; + CUR.GS.rp2 = point; + if ( ( CUR.opcode & 16 ) != 0 ) + CUR.GS.rp0 = point; + } +/*************************************************************************/ +/* */ +/* MIRP[abcde]: Move Indirect Relative Point */ +/* Opcode range: 0xE0-0xFF */ +/* Stack: int32? uint32 --> */ +/* */ + static void + Ins_MIRP( INS_ARG ) + { + FT_UShort point; + FT_ULong cvtEntry; + FT_F26Dot6 cvt_dist, + distance, + cur_dist, + org_dist, + control_value_cutin, + minimum_distance; + minimum_distance = CUR.GS.minimum_distance; + control_value_cutin = CUR.GS.control_value_cutin; + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( args[1] + 1 ); +/* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ + if ( BOUNDS( point, CUR.zp1.n_points ) || + BOUNDSL( cvtEntry, CUR.cvtSize + 1 ) || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } + if ( !cvtEntry ) + cvt_dist = 0; + else + cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 ); +/* single width test */ + if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) < + CUR.GS.single_width_cutin ) + { + if ( cvt_dist >= 0 ) + cvt_dist = CUR.GS.single_width_value; + else + cvt_dist = -CUR.GS.single_width_value; + } +/* UNDOCUMENTED! The MS rasterizer does that with */ +/* twilight points (confirmed by Greg Hitchcock) */ + if ( CUR.GS.gep1 == 0 ) + { + CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x + + TT_MulFix14( (FT_UInt32)cvt_dist, + CUR.GS.freeVector.x ); + CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y + + TT_MulFix14( (FT_UInt32)cvt_dist, + CUR.GS.freeVector.y ); + CUR.zp1.cur[point] = CUR.zp1.org[point]; + } + org_dist = CUR_Func_dualproj( &CUR.zp1.org[point], + &CUR.zp0.org[CUR.GS.rp0] ); + cur_dist = CUR_Func_project ( &CUR.zp1.cur[point], + &CUR.zp0.cur[CUR.GS.rp0] ); +/* auto-flip test */ + if ( CUR.GS.auto_flip ) + { + if ( ( org_dist ^ cvt_dist ) < 0 ) + cvt_dist = -cvt_dist; + } +/* control value cut-in and round */ + if ( ( CUR.opcode & 4 ) != 0 ) + { +/* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ +/* refer to the same zone. */ + if ( CUR.GS.gep0 == CUR.GS.gep1 ) + { +/* XXX: According to Greg Hitchcock, the following wording is */ +/* the right one: */ +/* */ +/* When the absolute difference between the value in */ +/* the table [CVT] and the measurement directly from */ +/* the outline is _greater_ than the cut_in value, the */ +/* outline measurement is used. */ +/* */ +/* This is from `instgly.doc'. The description in */ +/* `ttinst2.doc', version 1.66, is thus incorrect since */ +/* it implies `>=' instead of `>'. */ + if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin ) + cvt_dist = org_dist; + } + distance = CUR_Func_round( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } + else + distance = ROUND_None( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); +/* minimum distance test */ + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { + if ( distance < minimum_distance ) + distance = minimum_distance; + } + else + { + if ( distance > -minimum_distance ) + distance = -minimum_distance; + } + } + CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + Fail: + CUR.GS.rp1 = CUR.GS.rp0; + if ( ( CUR.opcode & 16 ) != 0 ) + CUR.GS.rp0 = point; + CUR.GS.rp2 = point; + } +/*************************************************************************/ +/* */ +/* ALIGNRP[]: ALIGN Relative Point */ +/* Opcode range: 0x3C */ +/* Stack: uint32 uint32... --> */ +/* */ + static void + Ins_ALIGNRP( INS_ARG ) + { + FT_UShort point; + FT_F26Dot6 distance; + FT_UNUSED_ARG; + if ( CUR.top < CUR.GS.loop || + BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } + while ( CUR.GS.loop > 0 ) + { + CUR.args--; + point = (FT_UShort)CUR.stack[CUR.args]; + if ( BOUNDS( point, CUR.zp1.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + CUR_Func_move( &CUR.zp1, point, -distance ); + } + CUR.GS.loop--; + } + Fail: + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* ISECT[]: moves point to InterSECTion */ +/* Opcode range: 0x0F */ +/* Stack: 5 * uint32 --> */ +/* */ + static void + Ins_ISECT( INS_ARG ) + { + FT_UShort point, + a0, a1, + b0, b1; + FT_F26Dot6 discriminant, dotproduct; + FT_F26Dot6 dx, dy, + dax, day, + dbx, dby; + FT_F26Dot6 val; + FT_Vector R; + point = (FT_UShort)args[0]; + a0 = (FT_UShort)args[1]; + a1 = (FT_UShort)args[2]; + b0 = (FT_UShort)args[3]; + b1 = (FT_UShort)args[4]; + if ( BOUNDS( b0, CUR.zp0.n_points ) || + BOUNDS( b1, CUR.zp0.n_points ) || + BOUNDS( a0, CUR.zp1.n_points ) || + BOUNDS( a1, CUR.zp1.n_points ) || + BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } +/* Cramer's rule */ + dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x; + dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y; + dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x; + day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y; + dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x; + dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y; + CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH; + discriminant = FT_MulDiv( dax, -dby, 0x40 ) + + FT_MulDiv( day, dbx, 0x40 ); + dotproduct = FT_MulDiv( dax, dbx, 0x40 ) + + FT_MulDiv( day, dby, 0x40 ); +/* The discriminant above is actually a cross product of vectors */ +/* da and db. Together with the dot product, they can be used as */ +/* surrogates for sine and cosine of the angle between the vectors. */ +/* Indeed, */ +/* dotproduct = |da||db|cos(angle) */ +/* discriminant = |da||db|sin(angle) . */ +/* We use these equations to reject grazing intersections by */ +/* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */ + if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) ) + { + val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 ); + R.x = FT_MulDiv( val, dax, discriminant ); + R.y = FT_MulDiv( val, day, discriminant ); + CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x; + CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y; + } + else + { +/* else, take the middle of the middles of A and B */ + CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x + + CUR.zp1.cur[a1].x + + CUR.zp0.cur[b0].x + + CUR.zp0.cur[b1].x ) / 4; + CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y + + CUR.zp1.cur[a1].y + + CUR.zp0.cur[b0].y + + CUR.zp0.cur[b1].y ) / 4; + } + } +/*************************************************************************/ +/* */ +/* ALIGNPTS[]: ALIGN PoinTS */ +/* Opcode range: 0x27 */ +/* Stack: uint32 uint32 --> */ +/* */ + static void + Ins_ALIGNPTS( INS_ARG ) + { + FT_UShort p1, p2; + FT_F26Dot6 distance; + p1 = (FT_UShort)args[0]; + p2 = (FT_UShort)args[1]; + if ( BOUNDS( p1, CUR.zp1.n_points ) || + BOUNDS( p2, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + distance = CUR_Func_project( CUR.zp0.cur + p2, + CUR.zp1.cur + p1 ) / 2; + CUR_Func_move( &CUR.zp1, p1, distance ); + CUR_Func_move( &CUR.zp0, p2, -distance ); + } +/*************************************************************************/ +/* */ +/* IP[]: Interpolate Point */ +/* Opcode range: 0x39 */ +/* Stack: uint32... --> */ +/* */ +/* SOMETIMES, DUMBER CODE IS BETTER CODE */ + static void + Ins_IP( INS_ARG ) + { + FT_F26Dot6 old_range, cur_range; + FT_Vector* orus_base; + FT_Vector* cur_base; + FT_Int twilight; + FT_UNUSED_ARG; + if ( CUR.top < CUR.GS.loop ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } +/* + * We need to deal in a special way with the twilight zone. + * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0), + * for every n. + */ + twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0; + if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + goto Fail; + } + if ( twilight ) + orus_base = &CUR.zp0.org[CUR.GS.rp1]; + else + orus_base = &CUR.zp0.orus[CUR.GS.rp1]; + cur_base = &CUR.zp0.cur[CUR.GS.rp1]; +/* XXX: There are some glyphs in some braindead but popular */ +/* fonts out there (e.g. [aeu]grave in monotype.ttf) */ +/* calling IP[] with bad values of rp[12]. */ +/* Do something sane when this odd thing happens. */ + if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) || + BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) ) + { + old_range = 0; + cur_range = 0; + } + else + { + if ( twilight ) + old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2], + orus_base ); + else if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) + old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2], + orus_base ); + else + { + FT_Vector vec; + vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x, + CUR.metrics.x_scale ); + vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y, + CUR.metrics.y_scale ); + old_range = CUR_fast_dualproj( &vec ); + } + cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base ); + } + for ( ; CUR.GS.loop > 0; --CUR.GS.loop ) + { + FT_UInt point = (FT_UInt)CUR.stack[--CUR.args]; + FT_F26Dot6 org_dist, cur_dist, new_dist; +/* check point bounds */ + if ( BOUNDS( point, CUR.zp2.n_points ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + continue; + } + if ( twilight ) + org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base ); + else if ( CUR.metrics.x_scale == CUR.metrics.y_scale ) + org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base ); + else + { + FT_Vector vec; + vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x, + CUR.metrics.x_scale ); + vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y, + CUR.metrics.y_scale ); + org_dist = CUR_fast_dualproj( &vec ); + } + cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base ); + if ( org_dist ) + new_dist = ( old_range != 0 ) + ? FT_MulDiv( org_dist, cur_range, old_range ) + : cur_dist; + else + new_dist = 0; + CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist ); + } + Fail: + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* UTP[a]: UnTouch Point */ +/* Opcode range: 0x29 */ +/* Stack: uint32 --> */ +/* */ + static void + Ins_UTP( INS_ARG ) + { + FT_UShort point; + FT_Byte mask; + point = (FT_UShort)args[0]; + if ( BOUNDS( point, CUR.zp0.n_points ) ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + return; + } + mask = 0xFF; + if ( CUR.GS.freeVector.x != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_X; + if ( CUR.GS.freeVector.y != 0 ) + mask &= ~FT_CURVE_TAG_TOUCH_Y; + CUR.zp0.tags[point] &= mask; + } +/* Local variables for Ins_IUP: */ + typedef struct IUP_WorkerRec_ + { +/* original and current coordinate */ + FT_Vector* orgs; +/* arrays */ + FT_Vector* curs; + FT_Vector* orus; + FT_UInt max_points; + } IUP_WorkerRec, *IUP_Worker; + static void + _iup_worker_shift( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt p ) + { + FT_UInt i; + FT_F26Dot6 dx; + dx = worker->curs[p].x - worker->orgs[p].x; + if ( dx != 0 ) + { + for ( i = p1; i < p; i++ ) + worker->curs[i].x += dx; + for ( i = p + 1; i <= p2; i++ ) + worker->curs[i].x += dx; + } + } + static void + _iup_worker_interpolate( IUP_Worker worker, + FT_UInt p1, + FT_UInt p2, + FT_UInt ref1, + FT_UInt ref2 ) + { + FT_UInt i; + FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2; + if ( p1 > p2 ) + return; + if ( BOUNDS( ref1, worker->max_points ) || + BOUNDS( ref2, worker->max_points ) ) + return; + orus1 = worker->orus[ref1].x; + orus2 = worker->orus[ref2].x; + if ( orus1 > orus2 ) + { + FT_F26Dot6 tmp_o; + FT_UInt tmp_r; + tmp_o = orus1; + orus1 = orus2; + orus2 = tmp_o; + tmp_r = ref1; + ref1 = ref2; + ref2 = tmp_r; + } + org1 = worker->orgs[ref1].x; + org2 = worker->orgs[ref2].x; + delta1 = worker->curs[ref1].x - org1; + delta2 = worker->curs[ref2].x - org2; + if ( orus1 == orus2 ) + { +/* simple shift of untouched points */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + if ( x <= org1 ) + x += delta1; + else + x += delta2; + worker->curs[i].x = x; + } + } + else + { + FT_Fixed scale = 0; + FT_Bool scale_valid = 0; +/* interpolation */ + for ( i = p1; i <= p2; i++ ) + { + FT_F26Dot6 x = worker->orgs[i].x; + if ( x <= org1 ) + x += delta1; + else if ( x >= org2 ) + x += delta2; + else + { + if ( !scale_valid ) + { + scale_valid = 1; + scale = FT_DivFix( org2 + delta2 - ( org1 + delta1 ), + orus2 - orus1 ); + } + x = ( org1 + delta1 ) + + FT_MulFix( worker->orus[i].x - orus1, scale ); + } + worker->curs[i].x = x; + } + } + } +/*************************************************************************/ +/* */ +/* IUP[a]: Interpolate Untouched Points */ +/* Opcode range: 0x30-0x31 */ +/* Stack: --> */ +/* */ + static void + Ins_IUP( INS_ARG ) + { + IUP_WorkerRec V; + FT_Byte mask; +/* first point of contour */ + FT_UInt first_point; +/* end point (last+1) of contour */ + FT_UInt end_point; +/* first touched point in contour */ + FT_UInt first_touched; +/* current touched point in contour */ + FT_UInt cur_touched; +/* current point */ + FT_UInt point; +/* current contour */ + FT_Short contour; + FT_UNUSED_ARG; +/* ignore empty outlines */ + if ( CUR.pts.n_contours == 0 ) + return; + if ( CUR.opcode & 1 ) + { + mask = FT_CURVE_TAG_TOUCH_X; + V.orgs = CUR.pts.org; + V.curs = CUR.pts.cur; + V.orus = CUR.pts.orus; + } + else + { + mask = FT_CURVE_TAG_TOUCH_Y; + V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 ); + V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 ); + V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 ); + } + V.max_points = CUR.pts.n_points; + contour = 0; + point = 0; + do + { + end_point = CUR.pts.contours[contour] - CUR.pts.first_point; + first_point = point; + if ( BOUNDS ( end_point, CUR.pts.n_points ) ) + end_point = CUR.pts.n_points - 1; + while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 ) + point++; + if ( point <= end_point ) + { + first_touched = point; + cur_touched = point; + point++; + while ( point <= end_point ) + { + if ( ( CUR.pts.tags[point] & mask ) != 0 ) + { + _iup_worker_interpolate( &V, + cur_touched + 1, + point - 1, + cur_touched, + point ); + cur_touched = point; + } + point++; + } + if ( cur_touched == first_touched ) + _iup_worker_shift( &V, first_point, end_point, cur_touched ); + else + { + _iup_worker_interpolate( &V, + (FT_UShort)( cur_touched + 1 ), + end_point, + cur_touched, + first_touched ); + if ( first_touched > 0 ) + _iup_worker_interpolate( &V, + first_point, + first_touched - 1, + cur_touched, + first_touched ); + } + } + contour++; + } while ( contour < CUR.pts.n_contours ); + } +/*************************************************************************/ +/* */ +/* DELTAPn[]: DELTA exceptions P1, P2, P3 */ +/* Opcode range: 0x5D,0x71,0x72 */ +/* Stack: uint32 (2 * uint32)... --> */ +/* */ + static void + Ins_DELTAP( INS_ARG ) + { + FT_ULong k, nump; + FT_UShort A; + FT_ULong C; + FT_Long B; +/* some points theoretically may occur more + than once, thus UShort isn't enough */ + nump = (FT_ULong)args[0]; + for ( k = 1; k <= nump; k++ ) + { + if ( CUR.args < 2 ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + CUR.args = 0; + goto Fail; + } + CUR.args -= 2; + A = (FT_UShort)CUR.stack[CUR.args + 1]; + B = CUR.stack[CUR.args]; +/* XXX: Because some popular fonts contain some invalid DeltaP */ +/* instructions, we simply ignore them when the stacked */ +/* point reference is off limit, rather than returning an */ +/* error. As a delta instruction doesn't change a glyph */ +/* in great ways, this shouldn't be a problem. */ + if ( !BOUNDS( A, CUR.zp0.n_points ) ) + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + switch ( CUR.opcode ) + { + case 0x5D: + break; + case 0x71: + C += 16; + break; + case 0x72: + C += 32; + break; + } + C += CUR.GS.delta_base; + if ( CURRENT_Ppem() == (FT_Long)C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); + CUR_Func_move( &CUR.zp0, A, B ); + } + } + else + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Invalid_Reference; + } + Fail: + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* DELTACn[]: DELTA exceptions C1, C2, C3 */ +/* Opcode range: 0x73,0x74,0x75 */ +/* Stack: uint32 (2 * uint32)... --> */ +/* */ + static void + Ins_DELTAC( INS_ARG ) + { + FT_ULong nump, k; + FT_ULong A, C; + FT_Long B; + nump = (FT_ULong)args[0]; + for ( k = 1; k <= nump; k++ ) + { + if ( CUR.args < 2 ) + { + if ( CUR.pedantic_hinting ) + CUR.error = TT_Err_Too_Few_Arguments; + CUR.args = 0; + goto Fail; + } + CUR.args -= 2; + A = (FT_ULong)CUR.stack[CUR.args + 1]; + B = CUR.stack[CUR.args]; + if ( BOUNDSL( A, CUR.cvtSize ) ) + { + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Invalid_Reference; + return; + } + } + else + { + C = ( (FT_ULong)B & 0xF0 ) >> 4; + switch ( CUR.opcode ) + { + case 0x73: + break; + case 0x74: + C += 16; + break; + case 0x75: + C += 32; + break; + } + C += CUR.GS.delta_base; + if ( CURRENT_Ppem() == (FT_Long)C ) + { + B = ( (FT_ULong)B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); + CUR_Func_move_cvt( A, B ); + } + } + } + Fail: + CUR.new_top = CUR.args; + } +/*************************************************************************/ +/* */ +/* MISC. INSTRUCTIONS */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* GETINFO[]: GET INFOrmation */ +/* Opcode range: 0x88 */ +/* Stack: uint32 --> uint32 */ +/* */ + static void + Ins_GETINFO( INS_ARG ) + { + FT_Long K; + K = 0; + if ( ( args[0] & 1 ) != 0 ) + K = 35; +/********************************/ +/* GLYPH ROTATED */ +/* Selector Bit: 1 */ +/* Return Bit(s): 8 */ +/* */ + if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated ) + K |= 0x80; +/********************************/ +/* GLYPH STRETCHED */ +/* Selector Bit: 2 */ +/* Return Bit(s): 9 */ +/* */ + if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched ) + K |= 1 << 8; +/********************************/ +/* HINTING FOR GRAYSCALE */ +/* Selector Bit: 5 */ +/* Return Bit(s): 12 */ +/* */ + if ( ( args[0] & 32 ) != 0 && CUR.grayscale ) + K |= 1 << 12; + args[0] = K; + } + static void + Ins_UNKNOWN( INS_ARG ) + { + TT_DefRecord* def = CUR.IDefs; + TT_DefRecord* limit = def + CUR.numIDefs; + FT_UNUSED_ARG; + for ( ; def < limit; def++ ) + { + if ( (FT_Byte)def->opc == CUR.opcode && def->active ) + { + TT_CallRec* call; + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Stack_Overflow; + return; + } + call = CUR.callStack + CUR.callTop++; + call->Caller_Range = CUR.curRange; + call->Caller_IP = CUR.IP + 1; + call->Cur_Count = 1; + call->Cur_Restart = def->start; + call->Cur_End = def->end; + INS_Goto_CodeRange( def->range, def->start ); + CUR.step_ins = FALSE; + return; + } + } + CUR.error = TT_Err_Invalid_Opcode; + } +/*************************************************************************/ +/* */ +/* RUN */ +/* */ +/* This function executes a run of opcodes. It will exit in the */ +/* following cases: */ +/* */ +/* - Errors (in which case it returns FALSE). */ +/* */ +/* - Reaching the end of the main code range (returns TRUE). */ +/* Reaching the end of a code range within a function call is an */ +/* error. */ +/* */ +/* - After executing one single opcode, if the flag `Instruction_Trap' */ +/* is set to TRUE (returns TRUE). */ +/* */ +/* On exit with TRUE, test IP < CodeSize to know whether it comes from */ +/* an instruction trap or a normal termination. */ +/* */ +/* */ +/* Note: The documented DEBUG opcode pops a value from the stack. This */ +/* behaviour is unsupported; here a DEBUG opcode is always an */ +/* error. */ +/* */ +/* */ +/* THIS IS THE INTERPRETER'S MAIN LOOP. */ +/* */ +/* Instructions appear in the specification's order. */ +/* */ +/*************************************************************************/ +/* documentation is in ttinterp.h */ + FT_EXPORT_DEF( FT_Error ) + TT_RunIns( TT_ExecContext exc ) + { +/* executed instructions counter */ + FT_Long ins_counter = 0; +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + cur = *exc; +#endif +/* set CVT functions */ + CUR.tt_metrics.ratio = 0; + if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) + { +/* non-square pixels, use the stretched routines */ + CUR.func_read_cvt = Read_CVT_Stretched; + CUR.func_write_cvt = Write_CVT_Stretched; + CUR.func_move_cvt = Move_CVT_Stretched; + } + else + { +/* square pixels, use normal routines */ + CUR.func_read_cvt = Read_CVT; + CUR.func_write_cvt = Write_CVT; + CUR.func_move_cvt = Move_CVT; + } + COMPUTE_Funcs(); + COMPUTE_Round( (FT_Byte)exc->GS.round_state ); + do + { + CUR.opcode = CUR.code[CUR.IP]; + FT_TRACE7(( " " )); + FT_TRACE7(( opcode_name[CUR.opcode] )); + FT_TRACE7(( "\n" )); + if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 ) + { + if ( CUR.IP + 1 >= CUR.codeSize ) + goto LErrorCodeOverflow_; + CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1]; + } + if ( CUR.IP + CUR.length > CUR.codeSize ) + goto LErrorCodeOverflow_; +/* First, let's check for empty stack and overflow */ + CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 ); +/* `args' is the top of the stack once arguments have been popped. */ +/* One can also interpret it as the index of the last argument. */ + if ( CUR.args < 0 ) + { + FT_UShort i; + if ( CUR.pedantic_hinting ) + { + CUR.error = TT_Err_Too_Few_Arguments; + goto LErrorLabel_; + } +/* push zeroes onto the stack */ + for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ ) + CUR.stack[i] = 0; + CUR.args = 0; + } + CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 ); +/* `new_top' is the new top of the stack, after the instruction's */ +/* execution. `top' will be set to `new_top' after the `switch' */ +/* statement. */ + if ( CUR.new_top > CUR.stackSize ) + { + CUR.error = TT_Err_Stack_Overflow; + goto LErrorLabel_; + } + CUR.step_ins = TRUE; + CUR.error = TT_Err_Ok; + { + FT_Long* args = CUR.stack + CUR.args; + FT_Byte opcode = CUR.opcode; +#undef ARRAY_BOUND_ERROR +#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref + switch ( opcode ) + { +/* SVTCA y */ + case 0x00: +/* SVTCA x */ + case 0x01: +/* SPvTCA y */ + case 0x02: +/* SPvTCA x */ + case 0x03: +/* SFvTCA y */ + case 0x04: +/* SFvTCA x */ + case 0x05: + { + FT_Short AA, BB; + AA = (FT_Short)( ( opcode & 1 ) << 14 ); + BB = (FT_Short)( AA ^ 0x4000 ); + if ( opcode < 4 ) + { + CUR.GS.projVector.x = AA; + CUR.GS.projVector.y = BB; + CUR.GS.dualVector.x = AA; + CUR.GS.dualVector.y = BB; + } + else + { + GUESS_VECTOR( projVector ); + } + if ( ( opcode & 2 ) == 0 ) + { + CUR.GS.freeVector.x = AA; + CUR.GS.freeVector.y = BB; + } + else + { + GUESS_VECTOR( freeVector ); + } + COMPUTE_Funcs(); + } + break; +/* SPvTL // */ + case 0x06: +/* SPvTL + */ + case 0x07: + DO_SPVTL + break; +/* SFvTL // */ + case 0x08: +/* SFvTL + */ + case 0x09: + DO_SFVTL + break; +/* SPvFS */ + case 0x0A: + DO_SPVFS + break; +/* SFvFS */ + case 0x0B: + DO_SFVFS + break; +/* GPV */ + case 0x0C: + DO_GPV + break; +/* GFV */ + case 0x0D: + DO_GFV + break; +/* SFvTPv */ + case 0x0E: + DO_SFVTPV + break; +/* ISECT */ + case 0x0F: + Ins_ISECT( EXEC_ARG_ args ); + break; +/* SRP0 */ + case 0x10: + DO_SRP0 + break; +/* SRP1 */ + case 0x11: + DO_SRP1 + break; +/* SRP2 */ + case 0x12: + DO_SRP2 + break; +/* SZP0 */ + case 0x13: + Ins_SZP0( EXEC_ARG_ args ); + break; +/* SZP1 */ + case 0x14: + Ins_SZP1( EXEC_ARG_ args ); + break; +/* SZP2 */ + case 0x15: + Ins_SZP2( EXEC_ARG_ args ); + break; +/* SZPS */ + case 0x16: + Ins_SZPS( EXEC_ARG_ args ); + break; +/* SLOOP */ + case 0x17: + DO_SLOOP + break; +/* RTG */ + case 0x18: + DO_RTG + break; +/* RTHG */ + case 0x19: + DO_RTHG + break; +/* SMD */ + case 0x1A: + DO_SMD + break; +/* ELSE */ + case 0x1B: + Ins_ELSE( EXEC_ARG_ args ); + break; +/* JMPR */ + case 0x1C: + DO_JMPR + break; +/* SCVTCI */ + case 0x1D: + DO_SCVTCI + break; +/* SSWCI */ + case 0x1E: + DO_SSWCI + break; +/* SSW */ + case 0x1F: + DO_SSW + break; +/* DUP */ + case 0x20: + DO_DUP + break; +/* POP */ + case 0x21: +/* nothing :-) */ + break; +/* CLEAR */ + case 0x22: + DO_CLEAR + break; +/* SWAP */ + case 0x23: + DO_SWAP + break; +/* DEPTH */ + case 0x24: + DO_DEPTH + break; +/* CINDEX */ + case 0x25: + DO_CINDEX + break; +/* MINDEX */ + case 0x26: + Ins_MINDEX( EXEC_ARG_ args ); + break; +/* ALIGNPTS */ + case 0x27: + Ins_ALIGNPTS( EXEC_ARG_ args ); + break; +/* ???? */ + case 0x28: + Ins_UNKNOWN( EXEC_ARG_ args ); + break; +/* UTP */ + case 0x29: + Ins_UTP( EXEC_ARG_ args ); + break; +/* LOOPCALL */ + case 0x2A: + Ins_LOOPCALL( EXEC_ARG_ args ); + break; +/* CALL */ + case 0x2B: + Ins_CALL( EXEC_ARG_ args ); + break; +/* FDEF */ + case 0x2C: + Ins_FDEF( EXEC_ARG_ args ); + break; +/* ENDF */ + case 0x2D: + Ins_ENDF( EXEC_ARG_ args ); + break; +/* MDAP */ + case 0x2E: +/* MDAP */ + case 0x2F: + Ins_MDAP( EXEC_ARG_ args ); + break; +/* IUP */ + case 0x30: +/* IUP */ + case 0x31: + Ins_IUP( EXEC_ARG_ args ); + break; +/* SHP */ + case 0x32: +/* SHP */ + case 0x33: + Ins_SHP( EXEC_ARG_ args ); + break; +/* SHC */ + case 0x34: +/* SHC */ + case 0x35: + Ins_SHC( EXEC_ARG_ args ); + break; +/* SHZ */ + case 0x36: +/* SHZ */ + case 0x37: + Ins_SHZ( EXEC_ARG_ args ); + break; +/* SHPIX */ + case 0x38: + Ins_SHPIX( EXEC_ARG_ args ); + break; +/* IP */ + case 0x39: + Ins_IP( EXEC_ARG_ args ); + break; +/* MSIRP */ + case 0x3A: +/* MSIRP */ + case 0x3B: + Ins_MSIRP( EXEC_ARG_ args ); + break; +/* AlignRP */ + case 0x3C: + Ins_ALIGNRP( EXEC_ARG_ args ); + break; +/* RTDG */ + case 0x3D: + DO_RTDG + break; +/* MIAP */ + case 0x3E: +/* MIAP */ + case 0x3F: + Ins_MIAP( EXEC_ARG_ args ); + break; +/* NPUSHB */ + case 0x40: + Ins_NPUSHB( EXEC_ARG_ args ); + break; +/* NPUSHW */ + case 0x41: + Ins_NPUSHW( EXEC_ARG_ args ); + break; +/* WS */ + case 0x42: + DO_WS + break; + Set_Invalid_Ref: + CUR.error = TT_Err_Invalid_Reference; + break; +/* RS */ + case 0x43: + DO_RS + break; +/* WCVTP */ + case 0x44: + DO_WCVTP + break; +/* RCVT */ + case 0x45: + DO_RCVT + break; +/* GC */ + case 0x46: +/* GC */ + case 0x47: + Ins_GC( EXEC_ARG_ args ); + break; +/* SCFS */ + case 0x48: + Ins_SCFS( EXEC_ARG_ args ); + break; +/* MD */ + case 0x49: +/* MD */ + case 0x4A: + Ins_MD( EXEC_ARG_ args ); + break; +/* MPPEM */ + case 0x4B: + DO_MPPEM + break; +/* MPS */ + case 0x4C: + DO_MPS + break; +/* FLIPON */ + case 0x4D: + DO_FLIPON + break; +/* FLIPOFF */ + case 0x4E: + DO_FLIPOFF + break; +/* DEBUG */ + case 0x4F: + DO_DEBUG + break; +/* LT */ + case 0x50: + DO_LT + break; +/* LTEQ */ + case 0x51: + DO_LTEQ + break; +/* GT */ + case 0x52: + DO_GT + break; +/* GTEQ */ + case 0x53: + DO_GTEQ + break; +/* EQ */ + case 0x54: + DO_EQ + break; +/* NEQ */ + case 0x55: + DO_NEQ + break; +/* ODD */ + case 0x56: + DO_ODD + break; +/* EVEN */ + case 0x57: + DO_EVEN + break; +/* IF */ + case 0x58: + Ins_IF( EXEC_ARG_ args ); + break; +/* EIF */ + case 0x59: +/* do nothing */ + break; +/* AND */ + case 0x5A: + DO_AND + break; +/* OR */ + case 0x5B: + DO_OR + break; +/* NOT */ + case 0x5C: + DO_NOT + break; +/* DELTAP1 */ + case 0x5D: + Ins_DELTAP( EXEC_ARG_ args ); + break; +/* SDB */ + case 0x5E: + DO_SDB + break; +/* SDS */ + case 0x5F: + DO_SDS + break; +/* ADD */ + case 0x60: + DO_ADD + break; +/* SUB */ + case 0x61: + DO_SUB + break; +/* DIV */ + case 0x62: + DO_DIV + break; +/* MUL */ + case 0x63: + DO_MUL + break; +/* ABS */ + case 0x64: + DO_ABS + break; +/* NEG */ + case 0x65: + DO_NEG + break; +/* FLOOR */ + case 0x66: + DO_FLOOR + break; +/* CEILING */ + case 0x67: + DO_CEILING + break; +/* ROUND */ + case 0x68: +/* ROUND */ + case 0x69: +/* ROUND */ + case 0x6A: +/* ROUND */ + case 0x6B: + DO_ROUND + break; +/* NROUND */ + case 0x6C: +/* NROUND */ + case 0x6D: +/* NRRUND */ + case 0x6E: +/* NROUND */ + case 0x6F: + DO_NROUND + break; +/* WCVTF */ + case 0x70: + DO_WCVTF + break; +/* DELTAP2 */ + case 0x71: +/* DELTAP3 */ + case 0x72: + Ins_DELTAP( EXEC_ARG_ args ); + break; +/* DELTAC0 */ + case 0x73: +/* DELTAC1 */ + case 0x74: +/* DELTAC2 */ + case 0x75: + Ins_DELTAC( EXEC_ARG_ args ); + break; +/* SROUND */ + case 0x76: + DO_SROUND + break; +/* S45Round */ + case 0x77: + DO_S45ROUND + break; +/* JROT */ + case 0x78: + DO_JROT + break; +/* JROF */ + case 0x79: + DO_JROF + break; +/* ROFF */ + case 0x7A: + DO_ROFF + break; +/* ???? */ + case 0x7B: + Ins_UNKNOWN( EXEC_ARG_ args ); + break; +/* RUTG */ + case 0x7C: + DO_RUTG + break; +/* RDTG */ + case 0x7D: + DO_RDTG + break; +/* SANGW */ + case 0x7E: +/* AA */ + case 0x7F: +/* nothing - obsolete */ + break; +/* FLIPPT */ + case 0x80: + Ins_FLIPPT( EXEC_ARG_ args ); + break; +/* FLIPRGON */ + case 0x81: + Ins_FLIPRGON( EXEC_ARG_ args ); + break; +/* FLIPRGOFF */ + case 0x82: + Ins_FLIPRGOFF( EXEC_ARG_ args ); + break; +/* UNKNOWN */ + case 0x83: +/* UNKNOWN */ + case 0x84: + Ins_UNKNOWN( EXEC_ARG_ args ); + break; +/* SCANCTRL */ + case 0x85: + Ins_SCANCTRL( EXEC_ARG_ args ); + break; +/* SDPVTL */ + case 0x86: +/* SDPVTL */ + case 0x87: + Ins_SDPVTL( EXEC_ARG_ args ); + break; +/* GETINFO */ + case 0x88: + Ins_GETINFO( EXEC_ARG_ args ); + break; +/* IDEF */ + case 0x89: + Ins_IDEF( EXEC_ARG_ args ); + break; +/* ROLL */ + case 0x8A: + Ins_ROLL( EXEC_ARG_ args ); + break; +/* MAX */ + case 0x8B: + DO_MAX + break; +/* MIN */ + case 0x8C: + DO_MIN + break; +/* SCANTYPE */ + case 0x8D: + Ins_SCANTYPE( EXEC_ARG_ args ); + break; +/* INSTCTRL */ + case 0x8E: + Ins_INSTCTRL( EXEC_ARG_ args ); + break; + case 0x8F: + Ins_UNKNOWN( EXEC_ARG_ args ); + break; + default: + if ( opcode >= 0xE0 ) + Ins_MIRP( EXEC_ARG_ args ); + else if ( opcode >= 0xC0 ) + Ins_MDRP( EXEC_ARG_ args ); + else if ( opcode >= 0xB8 ) + Ins_PUSHW( EXEC_ARG_ args ); + else if ( opcode >= 0xB0 ) + Ins_PUSHB( EXEC_ARG_ args ); + else + Ins_UNKNOWN( EXEC_ARG_ args ); + } + } + if ( CUR.error != TT_Err_Ok ) + { + switch ( CUR.error ) + { +/* looking for redefined instructions */ + case TT_Err_Invalid_Opcode: + { + TT_DefRecord* def = CUR.IDefs; + TT_DefRecord* limit = def + CUR.numIDefs; + for ( ; def < limit; def++ ) + { + if ( def->active && CUR.opcode == (FT_Byte)def->opc ) + { + TT_CallRec* callrec; + if ( CUR.callTop >= CUR.callSize ) + { + CUR.error = TT_Err_Invalid_Reference; + goto LErrorLabel_; + } + callrec = &CUR.callStack[CUR.callTop]; + callrec->Caller_Range = CUR.curRange; + callrec->Caller_IP = CUR.IP + 1; + callrec->Cur_Count = 1; + callrec->Cur_Restart = def->start; + callrec->Cur_End = def->end; + if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE ) + goto LErrorLabel_; + goto LSuiteLabel_; + } + } + } + CUR.error = TT_Err_Invalid_Opcode; + goto LErrorLabel_; +#if 0 +/* Unreachable code warning suppression. */ + break; +/* Leave to remind in case a later change the editor */ +/* to consider break; */ +#endif + default: + goto LErrorLabel_; +#if 0 + break; +#endif + } + } + CUR.top = CUR.new_top; + if ( CUR.step_ins ) + CUR.IP += CUR.length; +/* increment instruction counter and check if we didn't */ +/* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > MAX_RUNNABLE_OPCODES ) + return TT_Err_Execution_Too_Long; + LSuiteLabel_: + if ( CUR.IP >= CUR.codeSize ) + { + if ( CUR.callTop > 0 ) + { + CUR.error = TT_Err_Code_Overflow; + goto LErrorLabel_; + } + else + goto LNo_Error_; + } + } while ( !CUR.instruction_trap ); + LNo_Error_: +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + *exc = cur; +#endif + return TT_Err_Ok; + LErrorCodeOverflow_: + CUR.error = TT_Err_Code_Overflow; + LErrorLabel_: +#ifdef TT_CONFIG_OPTION_STATIC_RASTER + *exc = cur; +#endif +/* If any errors have occurred, function tables may be broken. */ +/* Force a re-execution of `prep' and `fpgm' tables if no */ +/* bytecode debugger is run. */ + if ( CUR.error && !CUR.instruction_trap ) + { + FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error )); + exc->size->cvt_ready = FALSE; + } + return CUR.error; + } +/* END */ +/***************************************************************************/ +/* */ +/* ttsubpix.c */ +/* */ +/* TrueType Subpixel Hinting. */ +/* */ +/* Copyright 2010-2012 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. */ +/* */ +/***************************************************************************/ +/* END */ +/* gx distortable font */ +/***************************************************************************/ +/* */ +/* ttgxvar.c */ +/* */ +/* TrueType GX Font Variation loader */ +/* */ +/* Copyright 2004-2012 by */ +/* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/*************************************************************************/ +/* */ +/* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ +/* */ +/* http://developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */ +/* */ +/* The documentation for `fvar' is inconsistent. At one point it says */ +/* that `countSizePairs' should be 3, at another point 2. It should */ +/* be 2. */ +/* */ +/* The documentation for `gvar' is not intelligible; `cvar' refers you */ +/* to `gvar' and is thus also incomprehensible. */ +/* */ +/* The documentation for `avar' appears correct, but Apple has no fonts */ +/* with an `avar' table, so it is hard to test. */ +/* */ +/* Many thanks to John Jenkins (at Apple) in figuring this out. */ +/* */ +/* */ +/* Apple's `kern' table has some references to tuple indices, but as */ +/* there is no indication where these indices are defined, nor how to */ +/* interpolate the kerning values (different tuples have different */ +/* classes) this issue is ignored. */ +/* */ +/*************************************************************************/ +#define FT_Stream_FTell( stream ) \ + ( (stream)->cursor - (stream)->base ) +#define FT_Stream_SeekSet( stream, off ) \ + ( (stream)->cursor = (stream)->base+(off) ) +/*************************************************************************/ +/* */ +/* 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 trace_ttgxvar +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** Internal Routines *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */ +/* indicates that there is a delta for every point without needing to */ +/* enumerate all of them. */ +/* */ +#define ALL_POINTS (FT_UShort*)( ~0 ) +#define GX_PT_POINTS_ARE_WORDS 0x80 +#define GX_PT_POINT_RUN_COUNT_MASK 0x7F +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_var_readpackedpoints */ +/* */ +/* <Description> */ +/* Read a set of points to which the following deltas will apply. */ +/* Points are packed with a run length encoding. */ +/* */ +/* <Input> */ +/* stream :: The data stream. */ +/* */ +/* <Output> */ +/* point_cnt :: The number of points read. A zero value means that */ +/* all points in the glyph will be affected, without */ +/* enumerating them individually. */ +/* */ +/* <Return> */ +/* An array of FT_UShort containing the affected points or the */ +/* special value ALL_POINTS. */ +/* */ + static FT_UShort* + ft_var_readpackedpoints( FT_Stream stream, + FT_UInt *point_cnt ) + { + FT_UShort *points = NULL; + FT_Int n; + FT_Int runcnt; + FT_Int i; + FT_Int j; + FT_Int first; + FT_Memory memory = stream->memory; + FT_Error error = TT_Err_Ok; + FT_UNUSED( error ); + *point_cnt = n = FT_GET_BYTE(); + if ( n == 0 ) + return ALL_POINTS; + if ( n & GX_PT_POINTS_ARE_WORDS ) + n = FT_GET_BYTE() | ( ( n & GX_PT_POINT_RUN_COUNT_MASK ) << 8 ); + if ( FT_NEW_ARRAY( points, n ) ) + return NULL; + i = 0; + while ( i < n ) + { + runcnt = FT_GET_BYTE(); + if ( runcnt & GX_PT_POINTS_ARE_WORDS ) + { + runcnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; + first = points[i++] = FT_GET_USHORT(); + if ( runcnt < 1 || i + runcnt >= n ) + goto Exit; +/* first point not included in runcount */ + for ( j = 0; j < runcnt; ++j ) + points[i++] = (FT_UShort)( first += FT_GET_USHORT() ); + } + else + { + first = points[i++] = FT_GET_BYTE(); + if ( runcnt < 1 || i + runcnt >= n ) + goto Exit; + for ( j = 0; j < runcnt; ++j ) + points[i++] = (FT_UShort)( first += FT_GET_BYTE() ); + } + } + Exit: + return points; + } + enum + { + GX_DT_DELTAS_ARE_ZERO = 0x80, + GX_DT_DELTAS_ARE_WORDS = 0x40, + GX_DT_DELTA_RUN_COUNT_MASK = 0x3F + }; +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_var_readpackeddeltas */ +/* */ +/* <Description> */ +/* Read a set of deltas. These are packed slightly differently than */ +/* points. In particular there is no overall count. */ +/* */ +/* <Input> */ +/* stream :: The data stream. */ +/* */ +/* delta_cnt :: The number of to be read. */ +/* */ +/* <Return> */ +/* An array of FT_Short containing the deltas for the affected */ +/* points. (This only gets the deltas for one dimension. It will */ +/* generally be called twice, once for x, once for y. When used in */ +/* cvt table, it will only be called once.) */ +/* */ + static FT_Short* + ft_var_readpackeddeltas( FT_Stream stream, + FT_Offset delta_cnt ) + { + FT_Short *deltas = NULL; + FT_UInt runcnt; + FT_Offset i; + FT_UInt j; + FT_Memory memory = stream->memory; + FT_Error error = TT_Err_Ok; + FT_UNUSED( error ); + if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) + return NULL; + i = 0; + while ( i < delta_cnt ) + { + runcnt = FT_GET_BYTE(); + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) + { +/* runcnt zeroes get added */ + for ( j = 0; + j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; + ++j ) + deltas[i++] = 0; + } + else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) + { +/* runcnt shorts from the stack */ + for ( j = 0; + j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; + ++j ) + deltas[i++] = FT_GET_SHORT(); + } + else + { +/* runcnt signed bytes from the stack */ + for ( j = 0; + j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) && i < delta_cnt; + ++j ) + deltas[i++] = FT_GET_CHAR(); + } + if ( j <= ( runcnt & GX_DT_DELTA_RUN_COUNT_MASK ) ) + { +/* Bad format */ + FT_FREE( deltas ); + return NULL; + } + } + return deltas; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_var_load_avar */ +/* */ +/* <Description> */ +/* Parse the `avar' table if present. It need not be, so we return */ +/* nothing. */ +/* */ +/* <InOut> */ +/* face :: The font face. */ +/* */ + static void + ft_var_load_avar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM(face); + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + GX_AVarSegment segment; + FT_Error error = TT_Err_Ok; + FT_ULong version; + FT_Long axisCount; + FT_Int i, j; + FT_ULong table_len; + FT_UNUSED( error ); + blend->avar_checked = TRUE; + if ( (error = face->goto_table( face, TTAG_avar, stream, &table_len )) != 0 ) + return; + if ( FT_FRAME_ENTER( table_len ) ) + return; + version = FT_GET_LONG(); + axisCount = FT_GET_LONG(); + if ( version != 0x00010000L || + axisCount != (FT_Long)blend->mmvar->num_axis ) + goto Exit; + if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) + goto Exit; + segment = &blend->avar_segment[0]; + for ( i = 0; i < axisCount; ++i, ++segment ) + { + segment->pairCount = FT_GET_USHORT(); + if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) + { +/* Failure. Free everything we have done so far. We must do */ +/* it right now since loading the `avar' table is optional. */ + for ( j = i - 1; j >= 0; --j ) + FT_FREE( blend->avar_segment[j].correspondence ); + FT_FREE( blend->avar_segment ); + blend->avar_segment = NULL; + goto Exit; + } + for ( j = 0; j < segment->pairCount; ++j ) + { + segment->correspondence[j].fromCoord = +/* convert to Fixed */ + FT_GET_SHORT() << 2; + segment->correspondence[j].toCoord = +/* convert to Fixed */ + FT_GET_SHORT()<<2; + } + } + Exit: + FT_FRAME_EXIT(); + } + typedef struct GX_GVar_Head_ + { + FT_Long version; + FT_UShort axisCount; + FT_UShort globalCoordCount; + FT_ULong offsetToCoord; + FT_UShort glyphCount; + FT_UShort flags; + FT_ULong offsetToData; + } GX_GVar_Head; +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_var_load_gvar */ +/* */ +/* <Description> */ +/* Parses the `gvar' table if present. If `fvar' is there, `gvar' */ +/* had better be there too. */ +/* */ +/* <InOut> */ +/* face :: The font face. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + static FT_Error + ft_var_load_gvar( TT_Face face ) + { + FT_Stream stream = FT_FACE_STREAM(face); + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + FT_Error error; + FT_UInt i, j; + FT_ULong table_len; + FT_ULong gvar_start; + FT_ULong offsetToData; + GX_GVar_Head gvar_head; + static const FT_Frame_Field gvar_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_GVar_Head + FT_FRAME_START( 20 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( axisCount ), + FT_FRAME_USHORT( globalCoordCount ), + FT_FRAME_ULONG ( offsetToCoord ), + FT_FRAME_USHORT( glyphCount ), + FT_FRAME_USHORT( flags ), + FT_FRAME_ULONG ( offsetToData ), + FT_FRAME_END + }; + if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 ) + goto Exit; + gvar_start = FT_STREAM_POS( ); + if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) + goto Exit; + blend->tuplecount = gvar_head.globalCoordCount; + blend->gv_glyphcnt = gvar_head.glyphCount; + offsetToData = gvar_start + gvar_head.offsetToData; + if ( gvar_head.version != (FT_Long)0x00010000L || + gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) + { + error = TT_Err_Invalid_Table; + goto Exit; + } + if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) + goto Exit; + if ( gvar_head.flags & 1 ) + { +/* long offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) + goto Exit; + for ( i = 0; i <= blend->gv_glyphcnt; ++i ) + blend->glyphoffsets[i] = offsetToData + FT_GET_LONG(); + FT_FRAME_EXIT(); + } + else + { +/* short offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) + goto Exit; + for ( i = 0; i <= blend->gv_glyphcnt; ++i ) + blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; +/* XXX: Undocumented: `*2'! */ + FT_FRAME_EXIT(); + } + if ( blend->tuplecount != 0 ) + { + if ( FT_NEW_ARRAY( blend->tuplecoords, + gvar_head.axisCount * blend->tuplecount ) ) + goto Exit; + if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || + FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) + goto Exit; + for ( i = 0; i < blend->tuplecount; ++i ) + for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j ) + blend->tuplecoords[i * gvar_head.axisCount + j] = +/* convert to FT_Fixed */ + FT_GET_SHORT() << 2; + FT_FRAME_EXIT(); + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* ft_var_apply_tuple */ +/* */ +/* <Description> */ +/* Figure out whether a given tuple (design) applies to the current */ +/* blend, and if so, what is the scaling factor. */ +/* */ +/* <Input> */ +/* blend :: The current blend of the font. */ +/* */ +/* tupleIndex :: A flag saying whether this is an intermediate */ +/* tuple or not. */ +/* */ +/* tuple_coords :: The coordinates of the tuple in normalized axis */ +/* units. */ +/* */ +/* im_start_coords :: The initial coordinates where this tuple starts */ +/* to apply (for intermediate coordinates). */ +/* */ +/* im_end_coords :: The final coordinates after which this tuple no */ +/* longer applies (for intermediate coordinates). */ +/* */ +/* <Return> */ +/* An FT_Fixed value containing the scaling factor. */ +/* */ + static FT_Fixed + ft_var_apply_tuple( GX_Blend blend, + FT_UShort tupleIndex, + FT_Fixed* tuple_coords, + FT_Fixed* im_start_coords, + FT_Fixed* im_end_coords ) + { + FT_UInt i; + FT_Fixed apply = 0x10000L; + for ( i = 0; i < blend->num_axis; ++i ) + { + if ( tuple_coords[i] == 0 ) +/* It's not clear why (for intermediate tuples) we don't need */ +/* to check against start/end -- the documentation says we don't. */ +/* Similarly, it's unclear why we don't need to scale along the */ +/* axis. */ + continue; + else if ( blend->normalizedcoords[i] == 0 || + ( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) || + ( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) ) + { + apply = 0; + break; + } + else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) +/* not an intermediate tuple */ + apply = FT_MulFix( apply, + blend->normalizedcoords[i] > 0 + ? blend->normalizedcoords[i] + : -blend->normalizedcoords[i] ); + else if ( blend->normalizedcoords[i] <= im_start_coords[i] || + blend->normalizedcoords[i] >= im_end_coords[i] ) + { + apply = 0; + break; + } + else if ( blend->normalizedcoords[i] < tuple_coords[i] ) + apply = FT_MulDiv( apply, + blend->normalizedcoords[i] - im_start_coords[i], + tuple_coords[i] - im_start_coords[i] ); + else + apply = FT_MulDiv( apply, + im_end_coords[i] - blend->normalizedcoords[i], + im_end_coords[i] - tuple_coords[i] ); + } + return apply; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct GX_FVar_Head_ + { + FT_Long version; + FT_UShort offsetToData; + FT_UShort countSizePairs; + FT_UShort axisCount; + FT_UShort axisSize; + FT_UShort instanceCount; + FT_UShort instanceSize; + } GX_FVar_Head; + typedef struct fvar_axis_ + { + FT_ULong axisTag; + FT_ULong minValue; + FT_ULong defaultValue; + FT_ULong maxValue; + FT_UShort flags; + FT_UShort nameID; + } GX_FVar_Axis; +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Get_MM_Var */ +/* */ +/* <Description> */ +/* Check that the font's `fvar' table is valid, parse it, and return */ +/* those data. */ +/* */ +/* <InOut> */ +/* face :: The font face. */ +/* TT_Get_MM_Var initializes the blend structure. */ +/* */ +/* <Output> */ +/* master :: The `fvar' data (must be freed by caller). */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_MM_Var( TT_Face face, + FT_MM_Var* *master ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + FT_ULong table_len; + FT_Error error = TT_Err_Ok; + FT_ULong fvar_start; + FT_Int i, j; + FT_MM_Var* mmvar = NULL; + FT_Fixed* next_coords; + FT_String* next_name; + FT_Var_Axis* a; + FT_Var_Named_Style* ns; + GX_FVar_Head fvar_head; + static const FT_Frame_Field fvar_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Head + FT_FRAME_START( 16 ), + FT_FRAME_LONG ( version ), + FT_FRAME_USHORT( offsetToData ), + FT_FRAME_USHORT( countSizePairs ), + FT_FRAME_USHORT( axisCount ), + FT_FRAME_USHORT( axisSize ), + FT_FRAME_USHORT( instanceCount ), + FT_FRAME_USHORT( instanceSize ), + FT_FRAME_END + }; + static const FT_Frame_Field fvaraxis_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE GX_FVar_Axis + FT_FRAME_START( 20 ), + FT_FRAME_ULONG ( axisTag ), + FT_FRAME_ULONG ( minValue ), + FT_FRAME_ULONG ( defaultValue ), + FT_FRAME_ULONG ( maxValue ), + FT_FRAME_USHORT( flags ), + FT_FRAME_USHORT( nameID ), + FT_FRAME_END + }; + if ( face->blend == NULL ) + { +/* both `fvar' and `gvar' must be present */ + if ( (error = face->goto_table( face, TTAG_gvar, + stream, &table_len )) != 0 ) + goto Exit; + if ( (error = face->goto_table( face, TTAG_fvar, + stream, &table_len )) != 0 ) + goto Exit; + fvar_start = FT_STREAM_POS( ); + if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) + goto Exit; + if ( fvar_head.version != (FT_Long)0x00010000L || + fvar_head.countSizePairs != 2 || + fvar_head.axisSize != 20 || +/* axisCount limit implied by 16-bit instanceSize */ + fvar_head.axisCount > 0x3FFE || + fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount || +/* instanceCount limit implied by limited range of name IDs */ + fvar_head.instanceCount > 0x7EFF || + fvar_head.offsetToData + fvar_head.axisCount * 20U + + fvar_head.instanceCount * fvar_head.instanceSize > table_len ) + { + error = TT_Err_Invalid_Table; + goto Exit; + } + if ( FT_NEW( face->blend ) ) + goto Exit; +/* cannot overflow 32-bit arithmetic because of limits above */ + face->blend->mmvar_len = + sizeof ( FT_MM_Var ) + + fvar_head.axisCount * sizeof ( FT_Var_Axis ) + + fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + + fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + + 5 * fvar_head.axisCount; + if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) + goto Exit; + face->blend->mmvar = mmvar; + mmvar->num_axis = + fvar_head.axisCount; + mmvar->num_designs = +/* meaningless in this context; each glyph */ + ~0; +/* may have a different number of designs */ +/* (or tuples, as called by Apple) */ + mmvar->num_namedstyles = + fvar_head.instanceCount; + mmvar->axis = + (FT_Var_Axis*)&(mmvar[1]); + mmvar->namedstyle = + (FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]); + next_coords = + (FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]); + for ( i = 0; i < fvar_head.instanceCount; ++i ) + { + mmvar->namedstyle[i].coords = next_coords; + next_coords += fvar_head.axisCount; + } + next_name = (FT_String*)next_coords; + for ( i = 0; i < fvar_head.axisCount; ++i ) + { + mmvar->axis[i].name = next_name; + next_name += 5; + } + if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) ) + goto Exit; + a = mmvar->axis; + for ( i = 0; i < fvar_head.axisCount; ++i ) + { + GX_FVar_Axis axis_rec; + if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) ) + goto Exit; + a->tag = axis_rec.axisTag; +/* A Fixed */ + a->minimum = axis_rec.minValue; +/* A Fixed */ + a->def = axis_rec.defaultValue; +/* A Fixed */ + a->maximum = axis_rec.maxValue; + a->strid = axis_rec.nameID; + a->name[0] = (FT_String)( a->tag >> 24 ); + a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF ); + a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF ); + a->name[3] = (FT_String)( ( a->tag ) & 0xFF ); + a->name[4] = 0; + ++a; + } + ns = mmvar->namedstyle; + for ( i = 0; i < fvar_head.instanceCount; ++i, ++ns ) + { + if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) ) + goto Exit; + ns->strid = FT_GET_USHORT(); +/* flags = */ (void) FT_GET_USHORT(); + for ( j = 0; j < fvar_head.axisCount; ++j ) +/* A Fixed */ + ns->coords[j] = FT_GET_ULONG(); + FT_FRAME_EXIT(); + } + } + if ( master != NULL ) + { + FT_UInt n; + if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) + goto Exit; + FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); + mmvar->axis = + (FT_Var_Axis*)&(mmvar[1]); + mmvar->namedstyle = + (FT_Var_Named_Style*)&(mmvar->axis[mmvar->num_axis]); + next_coords = + (FT_Fixed*)&(mmvar->namedstyle[mmvar->num_namedstyles]); + for ( n = 0; n < mmvar->num_namedstyles; ++n ) + { + mmvar->namedstyle[n].coords = next_coords; + next_coords += mmvar->num_axis; + } + a = mmvar->axis; + next_name = (FT_String*)next_coords; + for ( n = 0; n < mmvar->num_axis; ++n ) + { + a->name = next_name; +/* standard PostScript names for some standard apple tags */ + if ( a->tag == TTAG_wght ) + a->name = (char *)"Weight"; + else if ( a->tag == TTAG_wdth ) + a->name = (char *)"Width"; + else if ( a->tag == TTAG_opsz ) + a->name = (char *)"OpticalSize"; + else if ( a->tag == TTAG_slnt ) + a->name = (char *)"Slant"; + next_name += 5; + ++a; + } + *master = mmvar; + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Set_MM_Blend */ +/* */ +/* <Description> */ +/* Set the blend (normalized) coordinates for this instance of the */ +/* font. Check that the `gvar' table is reasonable and does some */ +/* initial preparation. */ +/* */ +/* <InOut> */ +/* face :: The font. */ +/* Initialize the blend structure with `gvar' data. */ +/* */ +/* <Input> */ +/* num_coords :: Must be the axis count of the font. */ +/* */ +/* coords :: An array of num_coords, each between [-1,1]. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_MM_Blend( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error = TT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i; + FT_Memory memory = face->root.memory; + enum + { + mcvt_retain, + mcvt_modify, + mcvt_load + } manageCvt; + face->doblend = FALSE; + if ( face->blend == NULL ) + { + if ( (error = TT_Get_MM_Var( face, NULL)) != 0 ) + goto Exit; + } + blend = face->blend; + mmvar = blend->mmvar; + if ( num_coords != mmvar->num_axis ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + for ( i = 0; i < num_coords; ++i ) + if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + if ( blend->glyphoffsets == NULL ) + if ( (error = ft_var_load_gvar( face )) != 0 ) + goto Exit; + if ( blend->normalizedcoords == NULL ) + { + if ( FT_NEW_ARRAY( blend->normalizedcoords, num_coords ) ) + goto Exit; + manageCvt = mcvt_modify; +/* If we have not set the blend coordinates before this, then the */ +/* cvt table will still be what we read from the `cvt ' table and */ +/* we don't need to reload it. We may need to change it though... */ + } + else + { + manageCvt = mcvt_retain; + for ( i = 0; i < num_coords; ++i ) + { + if ( blend->normalizedcoords[i] != coords[i] ) + { + manageCvt = mcvt_load; + break; + } + } +/* If we don't change the blend coords then we don't need to do */ +/* anything to the cvt table. It will be correct. Otherwise we */ +/* no longer have the original cvt (it was modified when we set */ +/* the blend last time), so we must reload and then modify it. */ + } + blend->num_axis = num_coords; + FT_MEM_COPY( blend->normalizedcoords, + coords, + num_coords * sizeof ( FT_Fixed ) ); + face->doblend = TRUE; + if ( face->cvt != NULL ) + { + switch ( manageCvt ) + { + case mcvt_load: +/* The cvt table has been loaded already; every time we change the */ +/* blend we may need to reload and remodify the cvt table. */ + FT_FREE( face->cvt ); + face->cvt = NULL; + tt_face_load_cvt( face, face->root.stream ); + break; + case mcvt_modify: +/* The original cvt table is in memory. All we need to do is */ +/* apply the `cvar' table (if any). */ + tt_face_vary_cvt( face, face->root.stream ); + break; + case mcvt_retain: +/* The cvt table is correct for this set of coordinates. */ + break; + } + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Set_Var_Design */ +/* */ +/* <Description> */ +/* Set the coordinates for the instance, measured in the user */ +/* coordinate system. Parse the `avar' table (if present) to convert */ +/* from user to normalized coordinates. */ +/* */ +/* <InOut> */ +/* face :: The font face. */ +/* Initialize the blend struct with `gvar' data. */ +/* */ +/* <Input> */ +/* num_coords :: This must be the axis count of the font. */ +/* */ +/* coords :: A coordinate array with `num_coords' elements. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Set_Var_Design( TT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + FT_Error error = TT_Err_Ok; + FT_Fixed* normalized = NULL; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_UInt i, j; + FT_Var_Axis* a; + GX_AVarSegment av; + FT_Memory memory = face->root.memory; + if ( face->blend == NULL ) + { + if ( (error = TT_Get_MM_Var( face, NULL )) != 0 ) + goto Exit; + } + blend = face->blend; + mmvar = blend->mmvar; + if ( num_coords != mmvar->num_axis ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } +/* Axis normalization is a two stage process. First we normalize */ +/* based on the [min,def,max] values for the axis to be [-1,0,1]. */ +/* Then, if there's an `avar' table, we renormalize this range. */ + if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) + goto Exit; + a = mmvar->axis; + for ( i = 0; i < mmvar->num_axis; ++i, ++a ) + { + if ( coords[i] > a->maximum || coords[i] < a->minimum ) + { + error = TT_Err_Invalid_Argument; + goto Exit; + } + if ( coords[i] < a->def ) + normalized[i] = -FT_DivFix( coords[i] - a->def, a->minimum - a->def ); + else if ( a->maximum == a->def ) + normalized[i] = 0; + else + normalized[i] = FT_DivFix( coords[i] - a->def, a->maximum - a->def ); + } + if ( !blend->avar_checked ) + ft_var_load_avar( face ); + if ( blend->avar_segment != NULL ) + { + av = blend->avar_segment; + for ( i = 0; i < mmvar->num_axis; ++i, ++av ) + { + for ( j = 1; j < (FT_UInt)av->pairCount; ++j ) + if ( normalized[i] < av->correspondence[j].fromCoord ) + { + normalized[i] = + FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord ) + + av->correspondence[j - 1].toCoord; + break; + } + } + } + error = TT_Set_MM_Blend( face, num_coords, normalized ); + Exit: + FT_FREE( normalized ); + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** GX VAR PARSING ROUTINES *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_face_vary_cvt */ +/* */ +/* <Description> */ +/* Modify the loaded cvt table according to the `cvar' table and the */ +/* font's blend. */ +/* */ +/* <InOut> */ +/* face :: A handle to the target face object. */ +/* */ +/* <Input> */ +/* stream :: A handle to the input stream. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* Most errors are ignored. It is perfectly valid not to have a */ +/* `cvar' table even if there is a `gvar' and `fvar' table. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_vary_cvt( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + FT_ULong table_start; + FT_ULong table_len; + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong here; + FT_UInt i, j; + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + GX_Blend blend = face->blend; + FT_UInt point_count; + FT_UShort* localpoints; + FT_Short* deltas; + FT_TRACE2(( "CVAR " )); + if ( blend == NULL ) + { + FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); + error = TT_Err_Ok; + goto Exit; + } + if ( face->cvt == NULL ) + { + FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); + error = TT_Err_Ok; + goto Exit; + } + error = face->goto_table( face, TTAG_cvar, stream, &table_len ); + if ( error ) + { + FT_TRACE2(( "is missing\n" )); + error = TT_Err_Ok; + goto Exit; + } + if ( FT_FRAME_ENTER( table_len ) ) + { + error = TT_Err_Ok; + goto Exit; + } + table_start = FT_Stream_FTell( stream ); + if ( FT_GET_LONG() != 0x00010000L ) + { + FT_TRACE2(( "bad table version\n" )); + error = TT_Err_Ok; + goto FExit; + } + if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) + goto FExit; + tupleCount = FT_GET_USHORT(); + offsetToData = table_start + FT_GET_USHORT(); +/* The documentation implies there are flags packed into the */ +/* tuplecount, but John Jenkins says that shared points don't apply */ +/* to `cvar', and no other flags are defined. */ + for ( i = 0; i < ( tupleCount & 0xFFF ); ++i ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); +/* There is no provision here for a global tuple coordinate section, */ +/* so John says. There are no tuple indices, just embedded tuples. */ + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; ++j ) +/* convert from */ + tuple_coords[j] = FT_GET_SHORT() << 2; +/* short frac to fixed */ + } + else + { +/* skip this tuple; it makes no sense */ + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + for ( j = 0; j < 2 * blend->num_axis; ++j ) + (void)FT_GET_SHORT(); + offsetToData += tupleDataSize; + continue; + } + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; ++j ) + im_start_coords[j] = FT_GET_SHORT() << 2; + for ( j = 0; j < blend->num_axis; ++j ) + im_end_coords[j] = FT_GET_SHORT() << 2; + } + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); +/* tuple isn't active for our blend */ + if ( + apply == 0 || +/* global points not allowed, */ +/* if they aren't local, makes no sense */ + !( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) ) + { + offsetToData += tupleDataSize; + continue; + } + here = FT_Stream_FTell( stream ); + FT_Stream_SeekSet( stream, offsetToData ); + localpoints = ft_var_readpackedpoints( stream, &point_count ); + deltas = ft_var_readpackeddeltas( stream, + point_count == 0 ? face->cvt_size + : point_count ); + if ( localpoints == NULL || deltas == NULL ) +/* failure, ignore it */ ; + else if ( localpoints == ALL_POINTS ) + { +/* this means that there are deltas for every entry in cvt */ + for ( j = 0; j < face->cvt_size; ++j ) + face->cvt[j] = (FT_Short)( face->cvt[j] + + FT_MulFix( deltas[j], apply ) ); + } + else + { + for ( j = 0; j < point_count; ++j ) + { + int pindex = localpoints[j]; + face->cvt[pindex] = (FT_Short)( face->cvt[pindex] + + FT_MulFix( deltas[j], apply ) ); + } + } + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas ); + offsetToData += tupleDataSize; + FT_Stream_SeekSet( stream, here ); + } + FExit: + FT_FRAME_EXIT(); + Exit: + FT_FREE( tuple_coords ); + FT_FREE( im_start_coords ); + FT_FREE( im_end_coords ); + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* TT_Vary_Get_Glyph_Deltas */ +/* */ +/* <Description> */ +/* Load the appropriate deltas for the current glyph. */ +/* */ +/* <Input> */ +/* face :: A handle to the target face object. */ +/* */ +/* glyph_index :: The index of the glyph being modified. */ +/* */ +/* n_points :: The number of the points in the glyph, including */ +/* phantom points. */ +/* */ +/* <Output> */ +/* deltas :: The array of points to change. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + TT_Vary_Get_Glyph_Deltas( TT_Face face, + FT_UInt glyph_index, + FT_Vector* *deltas, + FT_UInt n_points ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + GX_Blend blend = face->blend; + FT_Vector* delta_xy = NULL; + FT_Error error; + FT_ULong glyph_start; + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong here; + FT_UInt i, j; + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + FT_UInt point_count, spoint_count = 0; + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; + FT_UShort* points; + FT_Short *deltas_x, *deltas_y; + if ( !face->doblend || blend == NULL ) + return TT_Err_Invalid_Argument; +/* to be freed by the caller */ + if ( FT_NEW_ARRAY( delta_xy, n_points ) ) + goto Exit; + *deltas = delta_xy; + if ( glyph_index >= blend->gv_glyphcnt || + blend->glyphoffsets[glyph_index] == + blend->glyphoffsets[glyph_index + 1] ) +/* no variation data for this glyph */ + return TT_Err_Ok; + if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || + FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - + blend->glyphoffsets[glyph_index] ) ) + goto Fail1; + glyph_start = FT_Stream_FTell( stream ); +/* each set of glyph variation data is formatted similarly to `cvar' */ +/* (except we get shared points and global tuples) */ + if ( FT_NEW_ARRAY( tuple_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_start_coords, blend->num_axis ) || + FT_NEW_ARRAY( im_end_coords, blend->num_axis ) ) + goto Fail2; + tupleCount = FT_GET_USHORT(); + offsetToData = glyph_start + FT_GET_USHORT(); + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + FT_Stream_SeekSet( stream, offsetToData ); + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); + FT_Stream_SeekSet( stream, here ); + } + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); ++i ) + { + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + tupleDataSize = FT_GET_USHORT(); + tupleIndex = FT_GET_USHORT(); + if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) + { + for ( j = 0; j < blend->num_axis; ++j ) +/* convert from */ + tuple_coords[j] = FT_GET_SHORT() << 2; +/* short frac to fixed */ + } + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + { + error = TT_Err_Invalid_Table; + goto Fail3; + } + else + { + FT_MEM_COPY( + tuple_coords, + &blend->tuplecoords[(tupleIndex & 0xFFF) * blend->num_axis], + blend->num_axis * sizeof ( FT_Fixed ) ); + } + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + { + for ( j = 0; j < blend->num_axis; ++j ) + im_start_coords[j] = FT_GET_SHORT() << 2; + for ( j = 0; j < blend->num_axis; ++j ) + im_end_coords[j] = FT_GET_SHORT() << 2; + } + apply = ft_var_apply_tuple( blend, + (FT_UShort)tupleIndex, + tuple_coords, + im_start_coords, + im_end_coords ); +/* tuple isn't active for our blend */ + if ( apply == 0 ) + { + offsetToData += tupleDataSize; + continue; + } + here = FT_Stream_FTell( stream ); + if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) + { + FT_Stream_SeekSet( stream, offsetToData ); + localpoints = ft_var_readpackedpoints( stream, &point_count ); + points = localpoints; + } + else + { + points = sharedpoints; + point_count = spoint_count; + } + deltas_x = ft_var_readpackeddeltas( stream, + point_count == 0 ? n_points + : point_count ); + deltas_y = ft_var_readpackeddeltas( stream, + point_count == 0 ? n_points + : point_count ); + if ( points == NULL || deltas_y == NULL || deltas_x == NULL ) +/* failure, ignore it */ + ; + else if ( points == ALL_POINTS ) + { +/* this means that there are deltas for every point in the glyph */ + for ( j = 0; j < n_points; ++j ) + { + delta_xy[j].x += FT_MulFix( deltas_x[j], apply ); + delta_xy[j].y += FT_MulFix( deltas_y[j], apply ); + } + } + else + { + for ( j = 0; j < point_count; ++j ) + { + if ( localpoints[j] >= n_points ) + continue; + delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply ); + delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply ); + } + } + if ( localpoints != ALL_POINTS ) + FT_FREE( localpoints ); + FT_FREE( deltas_x ); + FT_FREE( deltas_y ); + offsetToData += tupleDataSize; + FT_Stream_SeekSet( stream, here ); + } + Fail3: + FT_FREE( tuple_coords ); + FT_FREE( im_start_coords ); + FT_FREE( im_end_coords ); + Fail2: + FT_FRAME_EXIT(); + Fail1: + if ( error ) + { + FT_FREE( delta_xy ); + *deltas = NULL; + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* tt_done_blend */ +/* */ +/* <Description> */ +/* Frees the blend internal data structure. */ +/* */ + FT_LOCAL_DEF( void ) + tt_done_blend( FT_Memory memory, + GX_Blend blend ) + { + if ( blend != NULL ) + { + FT_UInt i; + FT_FREE( blend->normalizedcoords ); + FT_FREE( blend->mmvar ); + if ( blend->avar_segment != NULL ) + { + for ( i = 0; i < blend->num_axis; ++i ) + FT_FREE( blend->avar_segment[i].correspondence ); + FT_FREE( blend->avar_segment ); + } + FT_FREE( blend->tuplecoords ); + FT_FREE( blend->glyphoffsets ); + FT_FREE( blend ); + } + } +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* type1.c */ +/* */ +/* FreeType Type 1 driver component (body only). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* t1parse.c */ +/* */ +/* Type 1 parser (body). */ +/* */ +/* Copyright 1996-2005, 2008, 2009, 2012 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 Type 1 parser is in charge of the following: */ +/* */ +/* - provide an implementation of a growing sequence of objects called */ +/* a `T1_Table' (used to build various tables needed by the loader). */ +/* */ +/* - opening .pfb and .pfa files to extract their top-level and private */ +/* dictionaries. */ +/* */ +/* - read numbers, arrays & strings from any dictionary. */ +/* */ +/* See `t1load.c' to see how data is loaded from the font file. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* t1parse.h */ +/* */ +/* Type 1 parser (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2008 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. */ +/* */ +/***************************************************************************/ +#define __T1PARSE_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* <Struct> */ +/* T1_ParserRec */ +/* */ +/* <Description> */ +/* A PS_ParserRec is an object used to parse a Type 1 fonts very */ +/* quickly. */ +/* */ +/* <Fields> */ +/* root :: The root parser. */ +/* */ +/* stream :: The current input stream. */ +/* */ +/* base_dict :: A pointer to the top-level dictionary. */ +/* */ +/* base_len :: The length in bytes of the top dictionary. */ +/* */ +/* private_dict :: A pointer to the private dictionary. */ +/* */ +/* private_len :: The length in bytes of the private dictionary. */ +/* */ +/* in_pfb :: A boolean. Indicates that we are handling a PFB */ +/* file. */ +/* */ +/* in_memory :: A boolean. Indicates a memory-based stream. */ +/* */ +/* single_block :: A boolean. Indicates that the private dictionary */ +/* is stored in lieu of the base dictionary. */ +/* */ + typedef struct T1_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + FT_Byte* base_dict; + FT_ULong base_len; + FT_Byte* private_dict; + FT_ULong private_len; + FT_Bool in_pfb; + FT_Bool in_memory; + FT_Bool single_block; + } T1_ParserRec, *T1_Parser; +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Done_Table( p ) \ + do \ + { \ + if ( (p)->funcs.done ) \ + (p)->funcs.done( p ); \ + } while ( 0 ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) +#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t ) +#define T1_ToCoordArray( p, m, c ) \ + (p)->root.funcs.to_coord_array( &(p)->root, m, c ) +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define T1_ToTokenArray( p, t, m, c ) \ + (p)->root.funcs.to_token_array( &(p)->root, t, m, c ) +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) + FT_LOCAL( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + FT_LOCAL( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ); + FT_LOCAL( void ) + T1_Finalize_Parser( T1_Parser parser ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* t1errors.h */ +/* */ +/* Type 1 error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 Type 1 error enumeration constants. */ +/* */ +/*************************************************************************/ +#define __T1ERRORS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX T1_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type1 +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_t1parse +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** INPUT STREAM PARSER *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* see Adobe Technical Note 5040.Download_Fonts.pdf */ + static FT_Error + read_pfb_tag( FT_Stream stream, + FT_UShort *atag, + FT_ULong *asize ) + { + FT_Error error; + FT_UShort tag; + FT_ULong size; + *atag = 0; + *asize = 0; + if ( !FT_READ_USHORT( tag ) ) + { + if ( tag == 0x8001U || tag == 0x8002U ) + { + if ( !FT_READ_ULONG_LE( size ) ) + *asize = size; + } + *atag = tag; + } + return error; + } + static FT_Error + check_type1_format( FT_Stream stream, + const char* header_string, + size_t header_length ) + { + FT_Error error; + FT_UShort tag; + FT_ULong dummy; + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + error = read_pfb_tag( stream, &tag, &dummy ); + if ( error ) + goto Exit; +/* We assume that the first segment in a PFB is always encoded as */ +/* text. This might be wrong (and the specification doesn't insist */ +/* on that), but we have never seen a counterexample. */ + if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) ) + goto Exit; + if ( !FT_FRAME_ENTER( header_length ) ) + { + error = T1_Err_Ok; + if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 ) + error = T1_Err_Unknown_File_Format; + FT_FRAME_EXIT(); + } + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + T1_New_Parser( T1_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error; + FT_UShort tag; + FT_ULong size; + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = 0; + parser->private_len = 0; + parser->private_dict = 0; + parser->in_pfb = 0; + parser->in_memory = 0; + parser->single_block = 0; +/* check the header format */ + error = check_type1_format( stream, "%!PS-AdobeFont", 14 ); + if ( error ) + { + if ( error != T1_Err_Unknown_File_Format ) + goto Exit; + error = check_type1_format( stream, "%!FontType", 10 ); + if ( error ) + { + FT_TRACE2(( " not a Type 1 font\n" )); + goto Exit; + } + } +/******************************************************************/ +/* */ +/* Here a short summary of what is going on: */ +/* */ +/* When creating a new Type 1 parser, we try to locate and load */ +/* the base dictionary if this is possible (i.e., for PFB */ +/* files). Otherwise, we load the whole font into memory. */ +/* */ +/* When `loading' the base dictionary, we only setup pointers */ +/* in the case of a memory-based stream. Otherwise, we */ +/* allocate and load the base dictionary in it. */ +/* */ +/* parser->in_pfb is set if we are in a binary (`.pfb') font. */ +/* parser->in_memory is set if we have a memory stream. */ +/* */ +/* try to compute the size of the base dictionary; */ +/* look for a Postscript binary file tag, i.e., 0x8001 */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Exit; + if ( tag != 0x8001U ) + { +/* assume that this is a PFA file for now; an error will */ +/* be produced later when more things are checked */ + if ( FT_STREAM_SEEK( 0L ) ) + goto Exit; + size = stream->size; + } + else + parser->in_pfb = 1; +/* now, try to load `size' bytes of the `base' dictionary we */ +/* found previously */ +/* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; +/* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { +/* read segment in memory -- this is clumsy, but so does the format */ + if ( FT_ALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + parser->base_len = size; + } + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + return error; + } + FT_LOCAL_DEF( void ) + T1_Finalize_Parser( T1_Parser parser ) + { + FT_Memory memory = parser->root.memory; +/* always free the private dictionary */ + FT_FREE( parser->private_dict ); +/* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + parser->root.funcs.done( &parser->root ); + } + FT_LOCAL_DEF( FT_Error ) + T1_Get_Private_Dict( T1_Parser parser, + PSAux_Service psaux ) + { + FT_Stream stream = parser->stream; + FT_Memory memory = parser->root.memory; + FT_Error error = T1_Err_Ok; + FT_ULong size; + if ( parser->in_pfb ) + { +/* in the case of the PFB format, the private dictionary can be */ +/* made of several segments. We thus first read the number of */ +/* segments to compute the total size of the private dictionary */ +/* then re-read them into memory. */ + FT_Long start_pos = FT_STREAM_POS(); + FT_UShort tag; + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error ) + goto Fail; + if ( tag != 0x8002U ) + break; + parser->private_len += size; + if ( FT_STREAM_SKIP( size ) ) + goto Fail; + } +/* Check that we have a private dictionary there */ +/* and allocate private dictionary buffer */ + if ( parser->private_len == 0 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " invalid private dictionary section\n" )); + error = T1_Err_Invalid_File_Format; + goto Fail; + } + if ( FT_STREAM_SEEK( start_pos ) || + FT_ALLOC( parser->private_dict, parser->private_len ) ) + goto Fail; + parser->private_len = 0; + for (;;) + { + error = read_pfb_tag( stream, &tag, &size ); + if ( error || tag != 0x8002U ) + { + error = T1_Err_Ok; + break; + } + if ( FT_STREAM_READ( parser->private_dict + parser->private_len, + size ) ) + goto Fail; + parser->private_len += size; + } + } + else + { +/* We have already `loaded' the whole PFA font file into memory; */ +/* if this is a memory resource, allocate a new block to hold */ +/* the private dict. Otherwise, simply overwrite into the base */ +/* dictionary block in the heap. */ +/* first of all, look at the `eexec' keyword */ + FT_Byte* cur = parser->base_dict; + FT_Byte* limit = cur + parser->base_len; + FT_Byte c; + Again: + for (;;) + { + c = cur[0]; +/* 9 = 5 letters for `eexec' + */ + if ( c == 'e' && cur + 9 < limit ) +/* whitespace + 4 chars */ + { + if ( cur[1] == 'e' && + cur[2] == 'x' && + cur[3] == 'e' && + cur[4] == 'c' ) + break; + } + cur++; + if ( cur >= limit ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " could not find `eexec' keyword\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + } +/* check whether `eexec' was real -- it could be in a comment */ +/* or string (as e.g. in u003043t.gsf from ghostscript) */ + parser->root.cursor = parser->base_dict; +/* set limit to `eexec' + whitespace + 4 characters */ + parser->root.limit = cur + 10; + cur = parser->root.cursor; + limit = parser->root.limit; + while ( cur < limit ) + { + if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 ) + goto Found; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + break; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } +/* we haven't found the correct `eexec'; go back and continue */ +/* searching */ + cur = limit; + limit = parser->base_dict + parser->base_len; + goto Again; +/* now determine where to write the _encrypted_ binary private */ +/* dictionary. We overwrite the base dictionary for disk-based */ +/* resources and allocate a new block otherwise */ + Found: + parser->root.limit = parser->base_dict + parser->base_len; + T1_Skip_PS_Token( parser ); + cur = parser->root.cursor; + limit = parser->root.limit; +/* according to the Type1 spec, the first cipher byte must not be */ +/* an ASCII whitespace character code (blank, tab, carriage return */ +/* or line feed). We have seen Type 1 fonts with two line feed */ +/* characters... So skip now all whitespace character codes. */ + while ( cur < limit && + ( *cur == ' ' || + *cur == '\t' || + *cur == '\r' || + *cur == '\n' ) ) + ++cur; + if ( cur >= limit ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " `eexec' not properly terminated\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + size = parser->base_len - ( cur - parser->base_dict ); + if ( parser->in_memory ) + { +/* note that we allocate one more byte to put a terminating `0' */ + if ( FT_ALLOC( parser->private_dict, size + 1 ) ) + goto Fail; + parser->private_len = size; + } + else + { + parser->single_block = 1; + parser->private_dict = parser->base_dict; + parser->private_len = size; + parser->base_dict = 0; + parser->base_len = 0; + } +/* now determine whether the private dictionary is encoded in binary */ +/* or hexadecimal ASCII format -- decode it accordingly */ +/* we need to access the next 4 bytes (after the final whitespace */ +/* following the `eexec' keyword); if they all are hexadecimal */ +/* digits, then we have a case of ASCII storage */ + if ( cur + 3 < limit && + ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) && + ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) ) + { +/* ASCII hexadecimal encoding */ + FT_Long len; + parser->root.cursor = cur; + (void)psaux->ps_parser_funcs->to_bytes( &parser->root, + parser->private_dict, + parser->private_len, + &len, + 0 ); + parser->private_len = len; +/* put a safeguard */ + parser->private_dict[len] = '\0'; + } + else +/* binary encoding -- copy the private dict */ + FT_MEM_MOVE( parser->private_dict, cur, size ); + } +/* we now decrypt the encoded binary private dictionary */ + psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U ); + if ( parser->private_len < 4 ) + { + FT_ERROR(( "T1_Get_Private_Dict:" + " invalid private dictionary section\n" )); + error = T1_Err_Invalid_File_Format; + goto Fail; + } +/* replace the four random bytes at the beginning with whitespace */ + parser->private_dict[0] = ' '; + parser->private_dict[1] = ' '; + parser->private_dict[2] = ' '; + parser->private_dict[3] = ' '; + parser->root.base = parser->private_dict; + parser->root.cursor = parser->private_dict; + parser->root.limit = parser->root.cursor + parser->private_len; + Fail: + Exit: + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* t1load.c */ +/* */ +/* Type 1 font loader (body). */ +/* */ +/* Copyright 1996-2012 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 is the new and improved Type 1 data loader for FreeType 2. The */ +/* old loader has several problems: it is slow, complex, difficult to */ +/* maintain, and contains incredible hacks to make it accept some */ +/* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ +/* the Type 1 fonts on my machine still aren't loaded correctly by it. */ +/* */ +/* This version is much simpler, much faster and also easier to read and */ +/* maintain by a great order of magnitude. The idea behind it is to */ +/* _not_ try to read the Type 1 token stream with a state machine (i.e. */ +/* a Postscript-like interpreter) but rather to perform simple pattern */ +/* matching. */ +/* */ +/* Indeed, nearly all data definitions follow a simple pattern like */ +/* */ +/* ... /Field <data> ... */ +/* */ +/* where <data> can be a number, a boolean, a string, or an array of */ +/* numbers. There are a few exceptions, namely the encoding, font name, */ +/* charstrings, and subrs; they are handled with a special pattern */ +/* matching routine. */ +/* */ +/* All other common cases are handled very simply. The matching rules */ +/* are defined in the file `t1tokens.h' through the use of several */ +/* macros calls PARSE_XXX. This file is included twice here; the first */ +/* time to generate parsing callback functions, the second time to */ +/* generate a table of keywords (with pointers to the associated */ +/* callback functions). */ +/* */ +/* The function `parse_dict' simply scans *linearly* a given dictionary */ +/* (either the top-level or private one) and calls the appropriate */ +/* callback when it encounters an immediate keyword. */ +/* */ +/* This is by far the fastest way one can find to parse and read all */ +/* data. */ +/* */ +/* This led to tremendous code size reduction. Note that later, the */ +/* glyph loader will also be _greatly_ simplified, and the automatic */ +/* hinter will replace the clumsy `t1hinter'. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* t1load.h */ +/* */ +/* Type 1 font loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2006, 2007 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. */ +/* */ +/***************************************************************************/ +#define __T1LOAD_H__ +FT_BEGIN_HEADER + typedef struct T1_Loader_ + { +/* parser used to read the stream */ + T1_ParserRec parser; +/* number of characters in encoding */ + FT_Int num_chars; +/* PS_Table used to store the */ + PS_TableRec encoding_table; +/* encoding character names */ + FT_Int num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; +/* For moving .notdef glyph to index 0. */ + PS_TableRec swap_table; + FT_Int num_subrs; + PS_TableRec subrs; + FT_Bool fontdata; +/* T1_LOADER_ENCOUNTERED_XXX */ + FT_UInt keywords_encountered; + } T1_LoaderRec, *T1_Loader; +/* treatment of some keywords differs depending on whether */ +/* they precede or follow certain other keywords */ +#define T1_PRIVATE ( 1 << 0 ) +#define T1_FONTDIR_AFTER_PRIVATE ( 1 << 1 ) + FT_LOCAL( FT_Error ) + T1_Open_Face( T1_Face face ); + FT_LOCAL( FT_Error ) + T1_Get_Multi_Master( T1_Face face, + FT_Multi_Master* master ); + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Var( T1_Face face, + FT_MM_Var* *master ); + FT_LOCAL( FT_Error ) + T1_Set_MM_Blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + FT_LOCAL( FT_Error ) + T1_Set_MM_Design( T1_Face face, + FT_UInt num_coords, + FT_Long* coords ); + FT_LOCAL_DEF( FT_Error ) + T1_Set_Var_Design( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); + FT_LOCAL( void ) + T1_Done_Blend( T1_Face face ); +FT_END_HEADER +/* END */ +#define IS_INCREMENTAL ( face->root.internal->incremental_interface != 0 ) +/*************************************************************************/ +/* */ +/* 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 trace_t1load +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** MULTIPLE MASTERS SUPPORT *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + t1_allocate_blend( T1_Face face, + FT_UInt num_designs, + FT_UInt num_axis ) + { + PS_Blend blend; + FT_Memory memory = face->root.memory; + FT_Error error = T1_Err_Ok; + blend = face->blend; + if ( !blend ) + { + if ( FT_NEW( blend ) ) + goto Exit; + blend->num_default_design_vector = 0; + face->blend = blend; + } +/* allocate design data if needed */ + if ( num_designs > 0 ) + { + if ( blend->num_designs == 0 ) + { + FT_UInt nn; +/* allocate the blend `private' and `font_info' dictionaries */ + if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || + FT_NEW_ARRAY( blend->privates[1], num_designs ) || + FT_NEW_ARRAY( blend->bboxes[1], num_designs ) || + FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + goto Exit; + blend->default_weight_vector = blend->weight_vector + num_designs; + blend->font_infos[0] = &face->type1.font_info; + blend->privates [0] = &face->type1.private_dict; + blend->bboxes [0] = &face->type1.font_bbox; + for ( nn = 2; nn <= num_designs; nn++ ) + { + blend->privates[nn] = blend->privates [nn - 1] + 1; + blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; + blend->bboxes[nn] = blend->bboxes [nn - 1] + 1; + } + blend->num_designs = num_designs; + } + else if ( blend->num_designs != num_designs ) + goto Fail; + } +/* allocate axis data if needed */ + if ( num_axis > 0 ) + { + if ( blend->num_axis != 0 && blend->num_axis != num_axis ) + goto Fail; + blend->num_axis = num_axis; + } +/* allocate the blend design pos table if needed */ + num_designs = blend->num_designs; + num_axis = blend->num_axis; + if ( num_designs && num_axis && blend->design_pos[0] == 0 ) + { + FT_UInt n; + if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) + goto Exit; + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = blend->design_pos[0] + num_axis * n; + } + Exit: + return error; + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + FT_LOCAL_DEF( FT_Error ) + T1_Get_Multi_Master( T1_Face face, + FT_Multi_Master* master ) + { + PS_Blend blend = face->blend; + FT_UInt n; + FT_Error error; + error = T1_Err_Invalid_Argument; + if ( blend ) + { + master->num_axis = blend->num_axis; + master->num_designs = blend->num_designs; + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_MM_Axis* axis = master->axis + n; + PS_DesignMap map = blend->design_map + n; + axis->name = blend->axis_names[n]; + axis->minimum = map->design_points[0]; + axis->maximum = map->design_points[map->num_points - 1]; + } + error = T1_Err_Ok; + } + return error; + } +/*************************************************************************/ +/* */ +/* Given a normalized (blend) coordinate, figure out the design */ +/* coordinate appropriate for that value. */ +/* */ + FT_LOCAL_DEF( FT_Fixed ) + mm_axis_unmap( PS_DesignMap axismap, + FT_Fixed ncv ) + { + int j; + if ( ncv <= axismap->blend_points[0] ) + return INT_TO_FIXED( axismap->design_points[0] ); + for ( j = 1; j < axismap->num_points; ++j ) + { + if ( ncv <= axismap->blend_points[j] ) + return INT_TO_FIXED( axismap->design_points[j - 1] ) + + ( axismap->design_points[j] - axismap->design_points[j - 1] ) * + FT_DivFix( ncv - axismap->blend_points[j - 1], + axismap->blend_points[j] - + axismap->blend_points[j - 1] ); + } + return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); + } +/*************************************************************************/ +/* */ +/* Given a vector of weights, one for each design, figure out the */ +/* normalized axis coordinates which gave rise to those weights. */ +/* */ + FT_LOCAL_DEF( void ) + mm_weights_unmap( FT_Fixed* weights, + FT_Fixed* axiscoords, + FT_UInt axis_count ) + { + FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); + if ( axis_count == 1 ) + axiscoords[0] = weights[1]; + else if ( axis_count == 2 ) + { + axiscoords[0] = weights[3] + weights[1]; + axiscoords[1] = weights[3] + weights[2]; + } + else if ( axis_count == 3 ) + { + axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; + } + else + { + axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + + weights[7] + weights[5] + weights[3] + weights[1]; + axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + + weights[7] + weights[6] + weights[3] + weights[2]; + axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[7] + weights[6] + weights[5] + weights[4]; + axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + + weights[11] + weights[10] + weights[9] + weights[8]; + } + } +/*************************************************************************/ +/* */ +/* Just a wrapper around T1_Get_Multi_Master to support the different */ +/* arguments needed by the GX var distortable fonts. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_Var( T1_Face face, + FT_MM_Var* *master ) + { + FT_Memory memory = face->root.memory; + FT_MM_Var *mmvar = NULL; + FT_Multi_Master mmaster; + FT_Error error; + FT_UInt i; + FT_Fixed axiscoords[T1_MAX_MM_AXIS]; + PS_Blend blend = face->blend; + error = T1_Get_Multi_Master( face, &mmaster ); + if ( error ) + goto Exit; + if ( FT_ALLOC( mmvar, + sizeof ( FT_MM_Var ) + + mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) + goto Exit; + mmvar->num_axis = mmaster.num_axis; + mmvar->num_designs = mmaster.num_designs; +/* Does not apply */ + mmvar->num_namedstyles = ~0; + mmvar->axis = (FT_Var_Axis*)&mmvar[1]; +/* Point to axes after MM_Var struct */ + mmvar->namedstyle = NULL; + for ( i = 0 ; i < mmaster.num_axis; ++i ) + { + mmvar->axis[i].name = mmaster.axis[i].name; + mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum); + mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum); + mmvar->axis[i].def = ( mmvar->axis[i].minimum + + mmvar->axis[i].maximum ) / 2; +/* Does not apply. But this value is in range */ +/* Does not apply */ + mmvar->axis[i].strid = ~0; +/* Does not apply */ + mmvar->axis[i].tag = ~0; + if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); + else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); + } + if ( blend->num_designs == ( 1U << blend->num_axis ) ) + { + mm_weights_unmap( blend->default_weight_vector, + axiscoords, + blend->num_axis ); + for ( i = 0; i < mmaster.num_axis; ++i ) + mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], + axiscoords[i] ); + } + *master = mmvar; + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Blend( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { + PS_Blend blend = face->blend; + FT_Error error; + FT_UInt n, m; + error = T1_Err_Invalid_Argument; + if ( blend && blend->num_axis == num_coords ) + { +/* recompute the weight vector from the blend coordinates */ + error = T1_Err_Ok; + for ( n = 0; n < blend->num_designs; n++ ) + { +/* 1.0 fixed */ + FT_Fixed result = 0x10000L; + for ( m = 0; m < blend->num_axis; m++ ) + { + FT_Fixed factor; +/* get current blend axis position */ + factor = coords[m]; + if ( factor < 0 ) factor = 0; + if ( factor > 0x10000L ) factor = 0x10000L; + if ( ( n & ( 1 << m ) ) == 0 ) + factor = 0x10000L - factor; + result = FT_MulFix( result, factor ); + } + blend->weight_vector[n] = result; + } + error = T1_Err_Ok; + } + return error; + } + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_Design( T1_Face face, + FT_UInt num_coords, + FT_Long* coords ) + { + PS_Blend blend = face->blend; + FT_Error error; + FT_UInt n, p; + error = T1_Err_Invalid_Argument; + if ( blend && blend->num_axis == num_coords ) + { +/* compute the blend coordinates through the blend design map */ + FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; + for ( n = 0; n < blend->num_axis; n++ ) + { + FT_Long design = coords[n]; + FT_Fixed the_blend; + PS_DesignMap map = blend->design_map + n; + FT_Long* designs = map->design_points; + FT_Fixed* blends = map->blend_points; + FT_Int before = -1, after = -1; + for ( p = 0; p < (FT_UInt)map->num_points; p++ ) + { + FT_Long p_design = designs[p]; +/* exact match? */ + if ( design == p_design ) + { + the_blend = blends[p]; + goto Found; + } + if ( design < p_design ) + { + after = p; + break; + } + before = p; + } +/* now interpolate if necessary */ + if ( before < 0 ) + the_blend = blends[0]; + else if ( after < 0 ) + the_blend = blends[map->num_points - 1]; + else + the_blend = FT_MulDiv( design - designs[before], + blends [after] - blends [before], + designs[after] - designs[before] ); + Found: + final_blends[n] = the_blend; + } + error = T1_Set_MM_Blend( face, num_coords, final_blends ); + } + return error; + } +/*************************************************************************/ +/* */ +/* Just a wrapper around T1_Set_MM_Design to support the different */ +/* arguments needed by the GX var distortable fonts. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + T1_Set_Var_Design( T1_Face face, + FT_UInt num_coords, + FT_Fixed* coords ) + { +/* maximum axis count is 4 */ + FT_Long lcoords[4]; + FT_UInt i; + FT_Error error; + error = T1_Err_Invalid_Argument; + if ( num_coords <= 4 && num_coords > 0 ) + { + for ( i = 0; i < num_coords; ++i ) + lcoords[i] = FIXED_TO_INT( coords[i] ); + error = T1_Set_MM_Design( face, num_coords, lcoords ); + } + return error; + } + FT_LOCAL_DEF( void ) + T1_Done_Blend( T1_Face face ) + { + FT_Memory memory = face->root.memory; + PS_Blend blend = face->blend; + if ( blend ) + { + FT_UInt num_designs = blend->num_designs; + FT_UInt num_axis = blend->num_axis; + FT_UInt n; +/* release design pos table */ + FT_FREE( blend->design_pos[0] ); + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = 0; +/* release blend `private' and `font info' dictionaries */ + FT_FREE( blend->privates[1] ); + FT_FREE( blend->font_infos[1] ); + FT_FREE( blend->bboxes[1] ); + for ( n = 0; n < num_designs; n++ ) + { + blend->privates [n] = 0; + blend->font_infos[n] = 0; + blend->bboxes [n] = 0; + } +/* release weight vectors */ + FT_FREE( blend->weight_vector ); + blend->default_weight_vector = 0; +/* release axis names */ + for ( n = 0; n < num_axis; n++ ) + FT_FREE( blend->axis_names[n] ); +/* release design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap dmap = blend->design_map + n; + FT_FREE( dmap->design_points ); + dmap->num_points = 0; + } + FT_FREE( face->blend ); + } + } + static void + parse_blend_axis_types( T1_Face face, + T1_Loader loader ) + { + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Error error = T1_Err_Ok; + PS_Blend blend; + FT_Memory memory; +/* take an array of objects */ + T1_ToTokenArray( &loader->parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", + num_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } +/* allocate blend if necessary */ + error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); + if ( error ) + goto Exit; + blend = face->blend; + memory = face->root.memory; +/* each token is an immediate containing the name of the axis */ + for ( n = 0; n < num_axis; n++ ) + { + T1_Token token = axis_tokens + n; + FT_Byte* name; + FT_PtrDist len; +/* skip first slash, if any */ + if ( token->start[0] == '/' ) + token->start++; + len = token->limit - token->start; + if ( len == 0 ) + { + error = T1_Err_Invalid_File_Format; + goto Exit; + } + if ( FT_ALLOC( blend->axis_names[n], (FT_Long)( len + 1 ) ) ) + goto Exit; + name = (FT_Byte*)blend->axis_names[n]; + FT_MEM_COPY( name, token->start, len ); + name[len] = 0; + } + Exit: + loader->parser.root.error = error; + } + static void + parse_blend_design_positions( T1_Face face, + T1_Loader loader ) + { + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Int num_axis; + T1_Parser parser = &loader->parser; + FT_Error error = T1_Err_Ok; + PS_Blend blend; +/* get the array of design tokens -- compute number of designs */ + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_blend_design_positions:" + " incorrect number of designs: %d\n", + num_designs )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + { + FT_Byte* old_cursor = parser->root.cursor; + FT_Byte* old_limit = parser->root.limit; + FT_Int n; + blend = face->blend; +/* make compiler happy */ + num_axis = 0; + for ( n = 0; n < num_designs; n++ ) + { + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + T1_Token token; + FT_Int axis, n_axis; +/* read axis/coordinates tokens */ + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); + if ( n == 0 ) + { + if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_positions:" + " invalid number of axes: %d\n", + n_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + num_axis = n_axis; + error = t1_allocate_blend( face, num_designs, num_axis ); + if ( error ) + goto Exit; + blend = face->blend; + } + else if ( n_axis != num_axis ) + { + FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } +/* now read each axis token into the design position */ + for ( axis = 0; axis < n_axis; axis++ ) + { + T1_Token token2 = axis_tokens + axis; + parser->root.cursor = token2->start; + parser->root.limit = token2->limit; + blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); + } + } + loader->parser.root.cursor = old_cursor; + loader->parser.root.limit = old_limit; + } + Exit: + loader->parser.root.error = error; + } + static void + parse_blend_design_map( T1_Face face, + T1_Loader loader ) + { + FT_Error error = T1_Err_Ok; + T1_Parser parser = &loader->parser; + PS_Blend blend; + T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; + FT_Int n, num_axis; + FT_Byte* old_cursor; + FT_Byte* old_limit; + FT_Memory memory = face->root.memory; + T1_ToTokenArray( parser, axis_tokens, + T1_MAX_MM_AXIS, &num_axis ); + if ( num_axis < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", + num_axis )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + error = t1_allocate_blend( face, 0, num_axis ); + if ( error ) + goto Exit; + blend = face->blend; +/* now read each axis design map */ + for ( n = 0; n < num_axis; n++ ) + { + PS_DesignMap map = blend->design_map + n; + T1_Token axis_token; + T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; + FT_Int p, num_points; + axis_token = axis_tokens + n; + parser->root.cursor = axis_token->start; + parser->root.limit = axis_token->limit; + T1_ToTokenArray( parser, point_tokens, + T1_MAX_MM_MAP_POINTS, &num_points ); + if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) + { + FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } +/* allocate design map data */ + if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) + goto Exit; + map->blend_points = map->design_points + num_points; + map->num_points = (FT_Byte)num_points; + for ( p = 0; p < num_points; p++ ) + { + T1_Token point_token; + point_token = point_tokens + p; +/* don't include delimiting brackets */ + parser->root.cursor = point_token->start + 1; + parser->root.limit = point_token->limit - 1; + map->design_points[p] = T1_ToInt( parser ); + map->blend_points [p] = T1_ToFixed( parser, 0 ); + } + } + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + Exit: + parser->root.error = error; + } + static void + parse_weight_vector( T1_Face face, + T1_Loader loader ) + { + T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; + FT_Int num_designs; + FT_Error error = T1_Err_Ok; + T1_Parser parser = &loader->parser; + PS_Blend blend = face->blend; + T1_Token token; + FT_Int n; + FT_Byte* old_cursor; + FT_Byte* old_limit; + T1_ToTokenArray( parser, design_tokens, + T1_MAX_MM_DESIGNS, &num_designs ); + if ( num_designs < 0 ) + { + error = T1_Err_Ignore; + goto Exit; + } + if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) + { + FT_ERROR(( "parse_weight_vector:" + " incorrect number of designs: %d\n", + num_designs )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + if ( !blend || !blend->num_designs ) + { + error = t1_allocate_blend( face, num_designs, 0 ); + if ( error ) + goto Exit; + blend = face->blend; + } + else if ( blend->num_designs != (FT_UInt)num_designs ) + { + FT_ERROR(( "parse_weight_vector:" + " /BlendDesignPosition and /WeightVector have\n" + " " + " different number of elements\n" )); + error = T1_Err_Invalid_File_Format; + goto Exit; + } + old_cursor = parser->root.cursor; + old_limit = parser->root.limit; + for ( n = 0; n < num_designs; n++ ) + { + token = design_tokens + n; + parser->root.cursor = token->start; + parser->root.limit = token->limit; + blend->default_weight_vector[n] = + blend->weight_vector[n] = T1_ToFixed( parser, 0 ); + } + parser->root.cursor = old_cursor; + parser->root.limit = old_limit; + Exit: + parser->root.error = error; + } +/* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ +/* we're only interested in the number of array elements */ + static void + parse_buildchar( T1_Face face, + T1_Loader loader ) + { + face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 ); + return; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** TYPE 1 SYMBOL PARSING *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + t1_load_keyword( T1_Face face, + T1_Loader loader, + const T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects; + PS_Blend blend = face->blend; + if ( blend && blend->num_designs == 0 ) + blend = NULL; +/* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } +/* now, the keyword is either a simple field, or a table of fields; */ +/* we are now going to take care of it */ + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + objects = &dummy_object; + max_objects = 0; + if ( blend ) + { + objects = (void**)blend->font_infos; + max_objects = blend->num_designs; + } + break; + case T1_FIELD_LOCATION_FONT_EXTRA: + dummy_object = &face->type1.font_extra; + objects = &dummy_object; + max_objects = 0; + break; + case T1_FIELD_LOCATION_PRIVATE: + dummy_object = &face->type1.private_dict; + objects = &dummy_object; + max_objects = 0; + if ( blend ) + { + objects = (void**)blend->privates; + max_objects = blend->num_designs; + } + break; + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + objects = &dummy_object; + max_objects = 0; + if ( blend ) + { + objects = (void**)blend->bboxes; + max_objects = blend->num_designs; + } + break; + case T1_FIELD_LOCATION_LOADER: + dummy_object = loader; + objects = &dummy_object; + max_objects = 0; + break; + case T1_FIELD_LOCATION_FACE: + dummy_object = face; + objects = &dummy_object; + max_objects = 0; + break; + case T1_FIELD_LOCATION_BLEND: + dummy_object = face->blend; + objects = &dummy_object; + max_objects = 0; + break; + default: + dummy_object = &face->type1; + objects = &dummy_object; + max_objects = 0; + } + if ( *objects ) + { + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + } + else + { + FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" + " which is not valid at this point\n" + " (probably due to missing keywords)\n", + field->ident )); + error = T1_Err_Ok; + } + Exit: + return error; + } + static void + parse_private( T1_Face face, + T1_Loader loader ) + { + FT_UNUSED( face ); + loader->keywords_encountered |= T1_PRIVATE; + } + static int + read_binary_data( T1_Parser parser, + FT_Long* size, + FT_Byte** base, + FT_Bool incremental ) + { + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; +/* the binary data has one of the following formats */ +/* */ +/* `size' [white*] RD white ....... ND */ +/* `size' [white*] -| white ....... |- */ +/* */ + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur < limit && ft_isdigit( *cur ) ) + { + FT_Long s = T1_ToInt( parser ); +/* `RD' or `-|' or something else */ + T1_Skip_PS_Token( parser ); +/* there is only one whitespace char after the */ +/* `RD' or `-|' token */ + *base = parser->root.cursor + 1; + if ( s >= 0 && s < limit - *base ) + { + parser->root.cursor += s + 1; + *size = s; + return !parser->root.error; + } + } + if( !incremental ) + { + FT_ERROR(( "read_binary_data: invalid size field\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + } + return 0; + } +/* We now define the routines to handle the `/Encoding', `/Subrs', */ +/* and `/CharStrings' dictionaries. */ + static void + t1_parse_font_matrix( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + FT_Matrix* matrix = &face->type1.font_matrix; + FT_Vector* offset = &face->type1.font_offset; + FT_Face root = (FT_Face)&face->root; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + FT_Int result; + result = T1_ToFixedArray( parser, 6, temp, 3 ); + if ( result < 0 ) + { + parser->root.error = T1_Err_Invalid_File_Format; + return; + } + temp_scale = FT_ABS( temp[3] ); + if ( temp_scale == 0 ) + { + FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + return; + } +/* Set Units per EM based on FontMatrix values. We set the value to */ +/* 1000 / temp_scale, because temp_scale was already multiplied by */ +/* 1000 (in t1_tofixed, from psobjs.c). */ + root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); +/* we need to scale the values by 1.0/temp_scale */ + if ( temp_scale != 0x10000L ) + { + 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]; +/* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + static void + parse_encoding( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + PSAux_Service psaux = (PSAux_Service)face->psaux; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "parse_encoding: out of bounds\n" )); + parser->root.error = T1_Err_Invalid_File_Format; + return; + } +/* if we have a number or `[', the encoding is an array, */ +/* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &face->type1.encoding; + FT_Int count, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; +/* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; +/* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = count; + if ( FT_NEW_ARRAY( encode->char_index, count ) || + FT_NEW_ARRAY( encode->char_name, count ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, count, memory ) ) ) + { + parser->root.error = error; + return; + } +/* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < count; n++ ) + { + char* notdef = (char *)".notdef"; + T1_Add_Table( char_table, n, notdef, 8 ); + } +/* Now we need to read records of the form */ +/* */ +/* ... charcode /charname ... */ +/* */ +/* for each entry in our table. */ +/* */ +/* We simply look for a number followed by an immediate */ +/* name. Note that this ignores correctly the sequence */ +/* that is often seen in type1 fonts: */ +/* */ +/* 0 1 255 { 1 index exch /.notdef put } for dup */ +/* */ +/* used to clean the encoding array before anything else. */ +/* */ +/* Alternatively, if the array is directly given as */ +/* */ +/* /Encoding [ ... ] */ +/* */ +/* we only read immediates. */ + n = 0; + T1_Skip_Spaces( parser ); + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; +/* we stop when we encounter a `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + IS_PS_DELIM( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } +/* check whether we've found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + } + cur = parser->root.cursor; + if ( cur + 2 < limit && *cur == '/' && n < count ) + { + FT_PtrDist len; + cur++; + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.cursor >= limit ) + return; + if ( parser->root.error ) + return; + len = parser->root.cursor - cur; + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + n++; + } + else if ( only_immediates ) + { +/* Since the current position is not updated for */ +/* immediates-only mode we would get an infinite loop if */ +/* we don't do anything here. */ +/* */ +/* This encoding array is not valid according to the type1 */ +/* specification (it might be an encoding for a CID type1 */ +/* font, however), so we conclude that this font is NOT a */ +/* type1 font. */ + parser->root.error = FT_Err_Unknown_File_Format; + return; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + T1_Skip_Spaces( parser ); + } + face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } +/* Otherwise, we should have either `StandardEncoding', */ +/* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + else + parser->root.error = T1_Err_Ignore; + } + } + static void + parse_subrs( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + PS_Table table = &loader->subrs; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Int num_subrs; + PSAux_Service psaux = (PSAux_Service)face->psaux; + T1_Skip_Spaces( parser ); +/* test for empty array */ + if ( parser->root.cursor < parser->root.limit && + *parser->root.cursor == '[' ) + { + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + if ( parser->root.cursor >= parser->root.limit || + *parser->root.cursor != ']' ) + parser->root.error = T1_Err_Invalid_File_Format; + return; + } + num_subrs = (FT_Int)T1_ToInt( parser ); +/* position the parser right before the `dup' of the first subr */ +/* `array' */ + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); +/* initialize subrs array -- with synthetic fonts it is possible */ +/* we get here twice */ + if ( !loader->num_subrs ) + { + error = psaux->ps_table_funcs->init( table, num_subrs, memory ); + if ( error ) + goto Fail; + } +/* the format is simple: */ +/* */ +/* `index' + binary data */ +/* */ + for (;;) + { + FT_Long idx, size; + FT_Byte* base; +/* If we are out of data, or if the next token isn't `dup', */ +/* we are done. */ + if ( parser->root.cursor + 4 >= parser->root.limit || + ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) + break; +/* `dup' */ + T1_Skip_PS_Token( parser ); + idx = T1_ToInt( parser ); + if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) + return; +/* The binary string is followed by one token, e.g. `NP' */ +/* (bound to `noaccess put') or by two separate tokens: */ +/* `noaccess' & `put'. We position the parser right */ +/* before the next `dup', if any. */ +/* `NP' or `|' or `noaccess' */ + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces ( parser ); + if ( parser->root.cursor + 4 < parser->root.limit && + ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) + { +/* skip `put' */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + } +/* with synthetic fonts it is possible we get here twice */ + if ( loader->num_subrs ) + continue; +/* some fonts use a value of -1 for lenIV to indicate that */ +/* the charstrings are unencoded */ +/* */ +/* thanks to Tom Kacvinsky for pointing this out */ +/* */ + if ( face->type1.private_dict.lenIV >= 0 ) + { + FT_Byte* temp; +/* some fonts define empty subr records -- this is not totally */ +/* compliant to the specification (which says they should at */ +/* least contain a `return'), but we support them anyway */ + if ( size < face->type1.private_dict.lenIV ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } +/* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_ALLOC( temp, size ) ) + goto Fail; + FT_MEM_COPY( temp, base, size ); + psaux->t1_decrypt( temp, size, 4330 ); + size -= face->type1.private_dict.lenIV; + error = T1_Add_Table( table, (FT_Int)idx, + temp + face->type1.private_dict.lenIV, size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( table, (FT_Int)idx, base, size ); + if ( error ) + goto Fail; + } + if ( !loader->num_subrs ) + loader->num_subrs = num_subrs; + return; + Fail: + parser->root.error = error; + } +#define TABLE_EXTEND 5 + static void + parse_charstrings( T1_Face face, + T1_Loader loader ) + { + T1_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Int n, num_glyphs; + FT_UInt notdef_index = 0; + FT_Byte notdef_found = 0; + num_glyphs = (FT_Int)T1_ToInt( parser ); + if ( num_glyphs < 0 ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } +/* some fonts like Optima-Oblique not only define the /CharStrings */ +/* array but access it also */ + if ( num_glyphs == 0 || parser->root.error ) + return; +/* initialize tables, leaving space for addition of .notdef, */ +/* if necessary, and a few other glyphs to handle buggy */ +/* fonts which have more glyphs than specified. */ +/* for some non-standard fonts like `Optima' which provides */ +/* different outlines depending on the resolution it is */ +/* possible to get here twice */ + if ( !loader->num_glyphs ) + { + error = psaux->ps_table_funcs->init( + code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; + error = psaux->ps_table_funcs->init( + name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); + if ( error ) + goto Fail; +/* Initialize table for swapping index notdef_index and */ +/* index 0 names and codes (if necessary). */ + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + } + n = 0; + for (;;) + { + FT_Long size; + FT_Byte* base; +/* the format is simple: */ +/* `/glyphname' + binary data */ + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + break; +/* we stop when we find a `def' or `end' keyword */ + if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) + { + if ( cur[0] == 'd' && + cur[1] == 'e' && + cur[2] == 'f' ) + { +/* There are fonts which have this: */ +/* */ +/* /CharStrings 118 dict def */ +/* Private begin */ +/* CharStrings begin */ +/* ... */ +/* */ +/* To catch this we ignore `def' if */ +/* no charstring has actually been */ +/* seen. */ + if ( n ) + break; + } + if ( cur[0] == 'e' && + cur[1] == 'n' && + cur[2] == 'd' ) + break; + } + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + if ( *cur == '/' ) + { + FT_PtrDist len; + if ( cur + 1 >= limit ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } +/* skip `/' */ + cur++; + len = parser->root.cursor - cur; + if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) + return; +/* for some non-standard fonts like `Optima' which provides */ +/* different outlines depending on the resolution it is */ +/* possible to get here twice */ + if ( loader->num_glyphs ) + continue; + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; +/* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; +/* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)(name_table->elements[n]) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + if ( face->type1.private_dict.lenIV >= 0 && + n < num_glyphs + TABLE_EXTEND ) + { + FT_Byte* temp; + if ( size <= face->type1.private_dict.lenIV ) + { + error = T1_Err_Invalid_File_Format; + goto Fail; + } +/* t1_decrypt() shouldn't write to base -- make temporary copy */ + if ( FT_ALLOC( temp, size ) ) + goto Fail; + FT_MEM_COPY( temp, base, size ); + psaux->t1_decrypt( temp, size, 4330 ); + size -= face->type1.private_dict.lenIV; + error = T1_Add_Table( code_table, n, + temp + face->type1.private_dict.lenIV, size ); + FT_FREE( temp ); + } + else + error = T1_Add_Table( code_table, n, base, size ); + if ( error ) + goto Fail; + n++; + } + } + loader->num_glyphs = n; +/* if /.notdef is found but does not occupy index 0, do our magic. */ + if ( notdef_found && + ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) + { +/* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ +/* name and code entries to swap_table. Then place notdef_index */ +/* name and code entries into swap_table. Then swap name and code */ +/* entries at indices notdef_index and 0 using values stored in */ +/* swap_table. */ +/* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; +/* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; +/* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; +/* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + } + else if ( !notdef_found ) + { +/* notdef_index is already 0, or /.notdef is undefined in */ +/* charstrings dictionary. Worry about /.notdef undefined. */ +/* We take index 0 and add it to the end of the table(s) */ +/* and add our own /.notdef glyph to index 0. */ +/* 0 333 hsbw endchar */ + FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; + char* notdef_name = (char *)".notdef"; + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; + error = T1_Add_Table( name_table, 0, notdef_name, 8 ); + if ( error ) + goto Fail; + error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); + if ( error ) + goto Fail; + error = T1_Add_Table( name_table, n, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + error = T1_Add_Table( code_table, n, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; +/* we added a glyph. */ + loader->num_glyphs += 1; + } + return; + Fail: + parser->root.error = error; + } +/*************************************************************************/ +/* */ +/* Define the token field static variables. This is a set of */ +/* T1_FieldRec variables. */ +/* */ +/*************************************************************************/ + static + const T1_FieldRec t1_keywords[] = + { +/***************************************************************************/ +/* */ +/* t1tokens.h */ +/* */ +/* Type 1 tokenizer (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2008, 2009 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 PS_FontInfoRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_INFO + T1_FIELD_STRING( "version", version, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Notice", notice, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FullName", full_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "FamilyName", family_name, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_STRING( "Weight", weight, + T1_FIELD_DICT_FONTDICT ) +/* we use pointers to detect modifications made by synthetic fonts */ + T1_FIELD_NUM ( "ItalicAngle", italic_angle, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlinePosition", underline_position, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, + T1_FIELD_DICT_FONTDICT ) +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_FontExtraRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_EXTRA + T1_FIELD_NUM ( "FSType", fs_type, + T1_FIELD_DICT_FONTDICT ) +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_PrivateRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_PRIVATE + T1_FIELD_NUM ( "UniqueID", unique_id, + T1_FIELD_DICT_FONTDICT | T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "lenIV", lenIV, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "LanguageGroup", language_group, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "password", password, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_FIXED_1000( "BlueScale", blue_scale, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueShift", blue_shift, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM ( "BlueFuzz", blue_fuzz, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_FIXED ( "ExpansionFactor", expansion_factor, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_BOOL ( "ForceBold", force_bold, + T1_FIELD_DICT_PRIVATE ) +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + T1_FIELD_KEY ( "FontName", font_name, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "PaintType", paint_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_NUM ( "FontType", font_type, T1_FIELD_DICT_FONTDICT ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, T1_FIELD_DICT_FONTDICT ) +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + T1_FIELD_BBOX( "FontBBox", xMin, T1_FIELD_DICT_FONTDICT ) +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FaceRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FACE + T1_FIELD_NUM( "NDV", ndv_idx, T1_FIELD_DICT_PRIVATE ) + T1_FIELD_NUM( "CDV", cdv_idx, T1_FIELD_DICT_PRIVATE ) +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_BlendRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BLEND + T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, + T1_MAX_MM_DESIGNS, T1_FIELD_DICT_FONTDICT ) +/* END */ +/* now add the special functions... */ + T1_FIELD_CALLBACK( "FontMatrix", t1_parse_font_matrix, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Encoding", parse_encoding, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "Subrs", parse_subrs, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, + T1_FIELD_DICT_PRIVATE ) + T1_FIELD_CALLBACK( "Private", parse_private, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, + T1_FIELD_DICT_FONTDICT ) + T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, + T1_FIELD_DICT_PRIVATE ) + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; +#define T1_FIELD_COUNT \ + ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) ) + static FT_Error + parse_dict( T1_Face face, + T1_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T1_Parser parser = &loader->parser; + FT_Byte *limit, *start_binary = NULL; + FT_Bool have_integer = 0; + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = T1_Err_Ok; + limit = parser->root.limit; + T1_Skip_Spaces( parser ); + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + cur = parser->root.cursor; +/* look for `eexec' */ + if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) + break; +/* look for `closefile' which ends the eexec section */ + else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) + break; +/* in a synthetic font the base font starts after a */ +/* `FontDictionary' token that is placed after a Private dict */ + else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) + { + if ( loader->keywords_encountered & T1_PRIVATE ) + loader->keywords_encountered |= + T1_FONTDIR_AFTER_PRIVATE; + parser->root.cursor += 13; + } +/* check whether we have an integer */ + else if ( ft_isdigit( *cur ) ) + { + start_binary = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 1; + } +/* in valid Type 1 fonts we don't see `RD' or `-|' directly */ +/* since those tokens are handled by parse_subrs and */ +/* parse_charstrings */ + else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' && + have_integer ) + { + FT_Long s; + FT_Byte* b; + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) + return T1_Err_Invalid_File_Format; + have_integer = 0; + } + else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && + have_integer ) + { + FT_Long s; + FT_Byte* b; + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) + return T1_Err_Invalid_File_Format; + have_integer = 0; + } +/* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_PtrDist len; + cur++; + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + len = parser->root.cursor - cur; + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { +/* now compare the immediate name to the keyword table */ + T1_Field keyword = (T1_Field)t1_keywords; + for (;;) + { + FT_Byte* name; + name = (FT_Byte*)keyword->ident; + if ( !name ) + break; + if ( cur[0] == name[0] && + len == (FT_PtrDist)ft_strlen( (const char *)name ) && + ft_memcmp( cur, name, len ) == 0 ) + { +/* We found it -- run the parsing callback! */ +/* We record every instance of every field */ +/* (until we reach the base font of a */ +/* synthetic font) to deal adequately with */ +/* multiple master fonts; this is also */ +/* necessary because later PostScript */ +/* definitions override earlier ones. */ +/* Once we encounter `FontDirectory' after */ +/* `/Private', we know that this is a synthetic */ +/* font; except for `/CharStrings' we are not */ +/* interested in anything that follows this */ +/* `FontDirectory'. */ +/* MM fonts have more than one /Private token at */ +/* the top level; let's hope that all the junk */ +/* that follows the first /Private token is not */ +/* interesting to us. */ +/* According to Adobe Tech Note #5175 (CID-Keyed */ +/* Font Installation for ATM Software) a `begin' */ +/* must be followed by exactly one `end', and */ +/* `begin' -- `end' pairs must be accurately */ +/* paired. We could use this to distinguish */ +/* between the global Private and the Private */ +/* dict that is a member of the Blend dict. */ + const FT_UInt dict = + ( loader->keywords_encountered & T1_PRIVATE ) + ? T1_FIELD_DICT_PRIVATE + : T1_FIELD_DICT_FONTDICT; + if ( !( dict & keyword->dict ) ) + { + FT_TRACE1(( "parse_dict: found `%s' but ignoring it" + " since it is in the wrong dictionary\n", + keyword->ident )); + break; + } + if ( !( loader->keywords_encountered & + T1_FONTDIR_AFTER_PRIVATE ) || + ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) + { + parser->root.error = t1_load_keyword( face, + loader, + keyword ); + if ( parser->root.error != T1_Err_Ok ) + { + if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore ) + parser->root.error = T1_Err_Ok; + else + return parser->root.error; + } + } + break; + } + keyword++; + } + } + have_integer = 0; + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + have_integer = 0; + } + T1_Skip_Spaces( parser ); + } + Exit: + return parser->root.error; + } + static void + t1_init_loader( T1_Loader loader, + T1_Face face ) + { + FT_UNUSED( face ); + FT_MEM_ZERO( loader, sizeof ( *loader ) ); + loader->num_glyphs = 0; + loader->num_chars = 0; +/* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + loader->subrs.init = 0; + loader->swap_table.init = 0; + loader->fontdata = 0; + loader->keywords_encountered = 0; + } + static void + t1_done_loader( T1_Loader loader ) + { + T1_Parser parser = &loader->parser; +/* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); + T1_Release_Table( &loader->subrs ); +/* finalize parser */ + T1_Finalize_Parser( parser ); + } + FT_LOCAL_DEF( FT_Error ) + T1_Open_Face( T1_Face face ) + { + T1_LoaderRec loader; + T1_Parser parser; + T1_Font type1 = &face->type1; + PS_Private priv = &type1->private_dict; + FT_Error error; + PSAux_Service psaux = (PSAux_Service)face->psaux; + t1_init_loader( &loader, face ); +/* default values */ + face->ndv_idx = -1; + face->cdv_idx = -1; + face->len_buildchar = 0; + priv->blue_shift = 7; + priv->blue_fuzz = 1; + priv->lenIV = 4; + priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); + priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); + parser = &loader.parser; + error = T1_New_Parser( parser, + face->root.stream, + face->root.memory, + psaux ); + if ( error ) + goto Exit; + error = parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + error = T1_Get_Private_Dict( parser, psaux ); + if ( error ) + goto Exit; + error = parse_dict( face, &loader, + parser->private_dict, parser->private_len ); + if ( error ) + goto Exit; +/* ensure even-ness of `num_blue_values' */ + priv->num_blue_values &= ~1; + if ( face->blend && + face->blend->num_default_design_vector != 0 && + face->blend->num_default_design_vector != face->blend->num_axis ) + { +/* we don't use it currently so just warn, reset, and ignore */ + FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " + "while there are %u axes.\n", + face->blend->num_default_design_vector, + face->blend->num_axis )); + face->blend->num_default_design_vector = 0; + } +/* the following can happen for MM instances; we then treat the */ +/* font as a normal PS font */ + if ( face->blend && + ( !face->blend->num_designs || !face->blend->num_axis ) ) + T1_Done_Blend( face ); +/* another safety check */ + if ( face->blend ) + { + FT_UInt i; + for ( i = 0; i < face->blend->num_axis; i++ ) + if ( !face->blend->design_map[i].num_points ) + { + T1_Done_Blend( face ); + break; + } + } + if ( face->blend ) + { + if ( face->len_buildchar > 0 ) + { + FT_Memory memory = face->root.memory; + if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) + { + FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); + face->len_buildchar = 0; + goto Exit; + } + } + } + else + face->len_buildchar = 0; +/* now, propagate the subrs, charstrings, and glyphnames tables */ +/* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + if ( loader.subrs.init ) + { + loader.subrs.init = 0; + type1->num_subrs = loader.num_subrs; + type1->subrs_block = loader.subrs.block; + type1->subrs = loader.subrs.elements; + type1->subrs_len = loader.subrs.lengths; + } + if ( !IS_INCREMENTAL ) + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); + error = T1_Err_Invalid_File_Format; + } + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; +/* we copy the glyph names `block' and `elements' fields; */ +/* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; +/* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; +/* OK, we do the following: for each element in the encoding */ +/* table, look up the index of the glyph having the same name */ +/* the index is then stored in type1.encoding.char_index, and */ +/* the name to type1.encoding.char_name */ + min_char = 0; + max_char = 0; + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = (char *)".notdef"; + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[idx]; + if ( ft_strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = (char*)glyph_name; +/* Change min/max encoded char only if glyph name is */ +/* not /.notdef */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode >= max_char ) + max_char = charcode + 1; + } + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + Exit: + t1_done_loader( &loader ); + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* t1objs.c */ +/* */ +/* Type 1 objects manager (body). */ +/* */ +/* Copyright 1996-2009, 2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* t1gload.h */ +/* */ +/* Type 1 Glyph Loader (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2008, 2011 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. */ +/* */ +/***************************************************************************/ +#define __T1GLOAD_H__ +/***************************************************************************/ +/* */ +/* t1objs.h */ +/* */ +/* Type 1 objects manager (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2006, 2011 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. */ +/* */ +/***************************************************************************/ +#define __T1OBJS_H__ +FT_BEGIN_HEADER +/* The following structures must be defined by the hinter */ + typedef struct T1_Size_Hints_ T1_Size_Hints; + typedef struct T1_Glyph_Hints_ T1_Glyph_Hints; +/*************************************************************************/ +/* */ +/* <Type> */ +/* T1_Size */ +/* */ +/* <Description> */ +/* A handle to a Type 1 size object. */ +/* */ + typedef struct T1_SizeRec_* T1_Size; +/*************************************************************************/ +/* */ +/* <Type> */ +/* T1_GlyphSlot */ +/* */ +/* <Description> */ +/* A handle to a Type 1 glyph slot object. */ +/* */ + typedef struct T1_GlyphSlotRec_* T1_GlyphSlot; +/*************************************************************************/ +/* */ +/* <Type> */ +/* T1_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 T1_CharMapRec_* T1_CharMap; +/*************************************************************************/ +/* */ +/* HERE BEGINS THE TYPE1 SPECIFIC STUFF */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Type> */ +/* T1_SizeRec */ +/* */ +/* <Description> */ +/* Type 1 size record. */ +/* */ + typedef struct T1_SizeRec_ + { + FT_SizeRec root; + } T1_SizeRec; + FT_LOCAL( void ) + T1_Size_Done( FT_Size size ); + FT_LOCAL( FT_Error ) + T1_Size_Request( FT_Size size, + FT_Size_Request req ); + FT_LOCAL( FT_Error ) + T1_Size_Init( FT_Size size ); +/*************************************************************************/ +/* */ +/* <Type> */ +/* T1_GlyphSlotRec */ +/* */ +/* <Description> */ +/* Type 1 glyph slot record. */ +/* */ + typedef struct T1_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_Bool hint; + FT_Bool scaled; + FT_Int max_points; + FT_Int max_contours; + FT_Fixed x_scale; + FT_Fixed y_scale; + } T1_GlyphSlotRec; + FT_LOCAL( FT_Error ) + T1_Face_Init( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) + T1_Face_Done( FT_Face face ); + FT_LOCAL( FT_Error ) + T1_GlyphSlot_Init( FT_GlyphSlot slot ); + FT_LOCAL( void ) + T1_GlyphSlot_Done( FT_GlyphSlot slot ); + FT_LOCAL( FT_Error ) + T1_Driver_Init( FT_Module driver ); + FT_LOCAL( void ) + T1_Driver_Done( FT_Module driver ); +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ); + FT_LOCAL( FT_Error ) + T1_Get_Advances( FT_Face face, + FT_UInt first, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed* advances ); + FT_LOCAL( FT_Error ) + T1_Load_Glyph( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* t1afm.h */ +/* */ +/* AFM support for Type 1 fonts (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2006 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. */ +/* */ +/***************************************************************************/ +#define __T1AFM_H__ +FT_BEGIN_HEADER + FT_LOCAL( FT_Error ) + T1_Read_Metrics( FT_Face face, + FT_Stream stream ); + FT_LOCAL( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ); + FT_LOCAL( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ); + FT_LOCAL( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ); +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_t1objs +/*************************************************************************/ +/* */ +/* SIZE FUNCTIONS */ +/* */ +/* note that we store the global hints in the size's "internal" root */ +/* field */ +/* */ +/*************************************************************************/ + static PSH_Globals_Funcs + T1_Size_Get_Globals_Funcs( T1_Size size ) + { + T1_Face face = (T1_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 ) +/* T1_Size */ + T1_Size_Done( FT_Size t1size ) + { + T1_Size size = (T1_Size)t1size; + if ( size->root.internal ) + { + PSH_Globals_Funcs funcs; + funcs = T1_Size_Get_Globals_Funcs( size ); + if ( funcs ) + funcs->destroy( (PSH_Globals)size->root.internal ); + size->root.internal = 0; + } + } + FT_LOCAL_DEF( FT_Error ) +/* T1_Size */ + T1_Size_Init( FT_Size t1size ) + { + T1_Size size = (T1_Size)t1size; + FT_Error error = T1_Err_Ok; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + if ( funcs ) + { + PSH_Globals globals; + T1_Face face = (T1_Face)size->root.face; + error = funcs->create( size->root.face->memory, + &face->type1.private_dict, &globals ); + if ( !error ) + size->root.internal = (FT_Size_Internal)(void*)globals; + } + return error; + } + FT_LOCAL_DEF( FT_Error ) +/* T1_Size */ + T1_Size_Request( FT_Size t1size, + FT_Size_Request req ) + { + T1_Size size = (T1_Size)t1size; + PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); + FT_Request_Metrics( size->root.face, req ); + if ( funcs ) + funcs->set_scale( (PSH_Globals)size->root.internal, + size->root.metrics.x_scale, + size->root.metrics.y_scale, + 0, 0 ); + return T1_Err_Ok; + } +/*************************************************************************/ +/* */ +/* SLOT FUNCTIONS */ +/* */ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + T1_GlyphSlot_Done( FT_GlyphSlot slot ) + { + slot->internal->glyph_hints = 0; + } + FT_LOCAL_DEF( FT_Error ) + T1_GlyphSlot_Init( FT_GlyphSlot slot ) + { + T1_Face face; + PSHinter_Service pshinter; + face = (T1_Face)slot->face; + pshinter = (PSHinter_Service)face->pshinter; + if ( pshinter ) + { + FT_Module module; + module = FT_Get_Module( slot->face->driver->root.library, + "pshinter" ); + if ( module ) + { + T1_Hints_Funcs funcs; + funcs = pshinter->get_t1_funcs( module ); + slot->internal->glyph_hints = (void*)funcs; + } + } + return 0; + } +/*************************************************************************/ +/* */ +/* FACE FUNCTIONS */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* T1_Face_Done */ +/* */ +/* <Description> */ +/* The face object destructor. */ +/* */ +/* <Input> */ +/* face :: A typeless pointer to the face object to destroy. */ +/* */ + FT_LOCAL_DEF( void ) +/* T1_Face */ + T1_Face_Done( FT_Face t1face ) + { + T1_Face face = (T1_Face)t1face; + FT_Memory memory; + T1_Font type1; + if ( !face ) + return; + memory = face->root.memory; + type1 = &face->type1; +/* release multiple masters information */ + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + if ( face->buildchar ) + { + FT_FREE( face->buildchar ); + face->buildchar = NULL; + face->len_buildchar = 0; + } + T1_Done_Blend( face ); + face->blend = 0; +/* release font info strings */ + { + PS_FontInfo info = &type1->font_info; + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); + } +/* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + FT_FREE( type1->subrs ); + FT_FREE( type1->subrs_len ); + FT_FREE( type1->subrs_block ); + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); +/* release afm data if present */ + if ( face->afm_data ) + T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); +/* release unicode map, if any */ +#if 0 + FT_FREE( face->unicode_map_rec.maps ); + face->unicode_map_rec.num_maps = 0; + face->unicode_map = NULL; +#endif + face->root.family_name = NULL; + face->root.style_name = NULL; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* T1_Face_Init */ +/* */ +/* <Description> */ +/* The face object constructor. */ +/* */ +/* <Input> */ +/* stream :: input stream where to load font data. */ +/* */ +/* 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 face record to build. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + T1_Face_Init( FT_Stream stream, +/* T1_Face */ + FT_Face t1face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T1_Face face = (T1_Face)t1face; + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( stream ); + face->root.num_faces = 1; + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + FT_ERROR(( "T1_Face_Init: cannot access `psaux' module\n" )); + error = T1_Err_Missing_Module; + goto Exit; + } + face->pshinter = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "pshinter" ); + FT_TRACE2(( "Type 1 driver\n" )); +/* open the tokenizer; this will also check the font format */ + error = T1_Open_Face( face ); + 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 */ + if ( face_index > 0 ) + { + FT_ERROR(( "T1_Face_Init: invalid face index\n" )); + error = T1_Err_Invalid_Argument; + goto Exit; + } +/* now load the font program into the face object */ +/* initialize the face object fields */ +/* set up root face fields */ + { + FT_Face root = (FT_Face)&face->root; + root->num_glyphs = type1->num_glyphs; + root->face_index = 0; + root->face_flags = FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES | + FT_FACE_FLAG_HINTER; + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + if ( face->blend ) + root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; +/* XXX: TODO -- add kerning with .afm support */ +/* The following code to extract the family and the style is very */ +/* simplistic and might get some things wrong. For a full-featured */ +/* algorithm you might have a look at the whitepaper given at */ +/* */ +/* http://blogs.msdn.com/text/archive/2007/04/23/wpf-font-selection-model.aspx */ +/* get style name -- be careful, some broken fonts only */ +/* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; + root->style_name = NULL; + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + if ( full ) + { + FT_Bool the_same = TRUE; + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + the_same = FALSE; + if ( !*family ) + root->style_name = full; + break; + } + } + } + if ( the_same ) + root->style_name = (char *)"Regular"; + } + } + else + { +/* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } + if ( !root->style_name ) + { + if ( info->weight ) + root->style_name = info->weight; + else +/* assume `Regular' style because we don't know better */ + root->style_name = (char *)"Regular"; + } +/* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( info->weight ) + { + if ( !ft_strcmp( info->weight, "Bold" ) || + !ft_strcmp( info->weight, "Black" ) ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + } +/* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; + root->bbox.xMin = type1->font_bbox.xMin >> 16; + root->bbox.yMin = type1->font_bbox.yMin >> 16; +/* no `U' suffix here to 0xFFFF! */ + root->bbox.xMax = ( type1->font_bbox.xMax + 0xFFFF ) >> 16; + root->bbox.yMax = ( type1->font_bbox.yMax + 0xFFFF ) >> 16; +/* Set units_per_EM if we didn't set it in t1_parse_font_matrix. */ + if ( !root->units_per_EM ) + root->units_per_EM = 1000; + root->ascender = (FT_Short)( root->bbox.yMax ); + root->descender = (FT_Short)( root->bbox.yMin ); + root->height = (FT_Short)( ( root->units_per_EM * 12 ) / 10 ); + if ( root->height < root->ascender - root->descender ) + root->height = (FT_Short)( root->ascender - root->descender ); +/* now compute the maximum advance width */ + root->max_advance_width = + (FT_Short)( root->bbox.xMax ); + { + FT_Pos max_advance; + error = T1_Compute_Max_Advance( face, &max_advance ); +/* in case of error, keep the standard width */ + if ( !error ) + root->max_advance_width = (FT_Short)FIXED_TO_INT( max_advance ); + else +/* clear error */ + error = T1_Err_Ok; + } + root->max_advance_height = root->height; + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; + } + { + FT_Face root = &face->root; + if ( psnames ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + charmap.face = root; +/* first of all, try to synthesize a Unicode charmap */ + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + if ( error && FT_Err_No_Unicode_Glyph_Name != error ) + goto Exit; + error = FT_Err_Ok; +/* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = TT_PLATFORM_ADOBE; + clazz = NULL; + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + default: + ; + } + if ( clazz ) + error = FT_CMap_New( clazz, NULL, &charmap, NULL ); +#if 0 +/* Select default charmap */ + if (root->num_charmaps) + root->charmap = root->charmaps[0]; +#endif + } + } + Exit: + return error; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* T1_Driver_Init */ +/* */ +/* <Description> */ +/* Initializes a given Type 1 driver object. */ +/* */ +/* <Input> */ +/* driver :: A handle to the target driver object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + T1_Driver_Init( FT_Module driver ) + { + FT_UNUSED( driver ); + return T1_Err_Ok; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* T1_Driver_Done */ +/* */ +/* <Description> */ +/* Finalizes a given Type 1 driver. */ +/* */ +/* <Input> */ +/* driver :: A handle to the target Type 1 driver. */ +/* */ + FT_LOCAL_DEF( void ) + T1_Driver_Done( FT_Module driver ) + { + FT_UNUSED( driver ); + } +/* END */ +/***************************************************************************/ +/* */ +/* t1driver.c */ +/* */ +/* Type 1 driver interface (body). */ +/* */ +/* Copyright 1996-2004, 2006, 2007, 2009, 2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* t1driver.h */ +/* */ +/* High-level Type 1 driver interface (specification). */ +/* */ +/* Copyright 1996-2001, 2002 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. */ +/* */ +/***************************************************************************/ +#define __T1DRIVER_H__ +FT_BEGIN_HEADER + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t1_driver_class; +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_t1driver +/* + * GLYPH DICT SERVICE + * + */ + static FT_Error + t1_get_glyph_name( T1_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max ); + return T1_Err_Ok; + } + static FT_UInt + t1_get_name_index( T1_Face face, + FT_String* glyph_name ) + { + FT_Int i; + FT_String* gname; + for ( i = 0; i < face->type1.num_glyphs; i++ ) + { + gname = face->type1.glyph_names[i]; + if ( !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)i; + } + return 0; + } + static const FT_Service_GlyphDictRec t1_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) t1_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)t1_get_name_index + }; +/* + * POSTSCRIPT NAME SERVICE + * + */ + static const char* + t1_get_ps_name( T1_Face face ) + { + return (const char*) face->type1.font_name; + } + static const FT_Service_PsFontNameRec t1_service_ps_name = + { + (FT_PsName_GetFunc)t1_get_ps_name + }; +/* + * MULTIPLE MASTERS SERVICE + * + */ + static const FT_Service_MultiMastersRec t1_service_multi_masters = + { + (FT_Get_MM_Func) T1_Get_Multi_Master, + (FT_Set_MM_Design_Func) T1_Set_MM_Design, + (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, + (FT_Get_MM_Var_Func) T1_Get_MM_Var, + (FT_Set_Var_Design_Func)T1_Set_Var_Design + }; +/* + * POSTSCRIPT INFO SERVICE + * + */ + static FT_Error + t1_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T1_Face)face)->type1.font_info; + return T1_Err_Ok; + } + static FT_Error + t1_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((T1_Face)face)->type1.font_extra; + return T1_Err_Ok; + } + static FT_Int + t1_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + return 1; + } + static FT_Error + t1_ps_get_font_private( FT_Face face, + PS_PrivateRec* afont_private ) + { + *afont_private = ((T1_Face)face)->type1.private_dict; + return T1_Err_Ok; + } + static FT_Long + t1_ps_get_font_value( FT_Face face, + PS_Dict_Keys key, + FT_UInt idx, + void *value, + FT_Long value_len ) + { + FT_Long retval = -1; + T1_Face t1face = (T1_Face)face; + T1_Font type1 = &t1face->type1; + switch ( key ) + { + case PS_DICT_FONT_TYPE: + retval = sizeof ( type1->font_type ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->font_type; + break; + case PS_DICT_FONT_MATRIX: + if ( idx < sizeof ( type1->font_matrix ) / + sizeof ( type1->font_matrix.xx ) ) + { + FT_Fixed val = 0; + retval = sizeof ( val ); + if ( value && value_len >= retval ) + { + switch ( idx ) + { + case 0: + val = type1->font_matrix.xx; + break; + case 1: + val = type1->font_matrix.xy; + break; + case 2: + val = type1->font_matrix.yx; + break; + case 3: + val = type1->font_matrix.yy; + break; + } + *((FT_Fixed *)value) = val; + } + } + break; + case PS_DICT_FONT_BBOX: + if ( idx < sizeof ( type1->font_bbox ) / + sizeof ( type1->font_bbox.xMin ) ) + { + FT_Fixed val = 0; + retval = sizeof ( val ); + if ( value && value_len >= retval ) + { + switch ( idx ) + { + case 0: + val = type1->font_bbox.xMin; + break; + case 1: + val = type1->font_bbox.yMin; + break; + case 2: + val = type1->font_bbox.xMax; + break; + case 3: + val = type1->font_bbox.yMax; + break; + } + *((FT_Fixed *)value) = val; + } + } + break; + case PS_DICT_PAINT_TYPE: + retval = sizeof ( type1->paint_type ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->paint_type; + break; + case PS_DICT_FONT_NAME: + retval = ft_strlen( type1->font_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_name ), retval ); + break; + case PS_DICT_UNIQUE_ID: + retval = sizeof ( type1->private_dict.unique_id ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.unique_id; + break; + case PS_DICT_NUM_CHAR_STRINGS: + retval = sizeof ( type1->num_glyphs ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->num_glyphs; + break; + case PS_DICT_CHAR_STRING_KEY: + if ( idx < (FT_UInt)type1->num_glyphs ) + { + retval = ft_strlen( type1->glyph_names[idx] ) + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->glyph_names[idx] ), retval ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + case PS_DICT_CHAR_STRING: + if ( idx < (FT_UInt)type1->num_glyphs ) + { + retval = type1->charstrings_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->charstrings[idx] ), + retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + case PS_DICT_ENCODING_TYPE: + retval = sizeof ( type1->encoding_type ); + if ( value && value_len >= retval ) + *((T1_EncodingType *)value) = type1->encoding_type; + break; + case PS_DICT_ENCODING_ENTRY: + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY && + idx < (FT_UInt)type1->encoding.num_chars ) + { + retval = ft_strlen( type1->encoding.char_name[idx] ) + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->encoding.char_name[idx] ), + retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + case PS_DICT_NUM_SUBRS: + retval = sizeof ( type1->num_subrs ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->num_subrs; + break; + case PS_DICT_SUBR: + if ( idx < (FT_UInt)type1->num_subrs ) + { + retval = type1->subrs_len[idx] + 1; + if ( value && value_len >= retval ) + { + ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 ); + ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; + } + } + break; + case PS_DICT_STD_HW: + retval = sizeof ( type1->private_dict.standard_width[0] ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->private_dict.standard_width[0]; + break; + case PS_DICT_STD_VW: + retval = sizeof ( type1->private_dict.standard_height[0] ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->private_dict.standard_height[0]; + break; + case PS_DICT_NUM_BLUE_VALUES: + retval = sizeof ( type1->private_dict.num_blue_values ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_blue_values; + break; + case PS_DICT_BLUE_VALUE: + if ( idx < type1->private_dict.num_blue_values ) + { + retval = sizeof ( type1->private_dict.blue_values[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.blue_values[idx]; + } + break; + case PS_DICT_BLUE_SCALE: + retval = sizeof ( type1->private_dict.blue_scale ); + if ( value && value_len >= retval ) + *((FT_Fixed *)value) = type1->private_dict.blue_scale; + break; + case PS_DICT_BLUE_FUZZ: + retval = sizeof ( type1->private_dict.blue_fuzz ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.blue_fuzz; + break; + case PS_DICT_BLUE_SHIFT: + retval = sizeof ( type1->private_dict.blue_shift ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.blue_shift; + break; + case PS_DICT_NUM_OTHER_BLUES: + retval = sizeof ( type1->private_dict.num_other_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_other_blues; + break; + case PS_DICT_OTHER_BLUE: + if ( idx < type1->private_dict.num_other_blues ) + { + retval = sizeof ( type1->private_dict.other_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.other_blues[idx]; + } + break; + case PS_DICT_NUM_FAMILY_BLUES: + retval = sizeof ( type1->private_dict.num_family_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_family_blues; + break; + case PS_DICT_FAMILY_BLUE: + if ( idx < type1->private_dict.num_family_blues ) + { + retval = sizeof ( type1->private_dict.family_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.family_blues[idx]; + } + break; + case PS_DICT_NUM_FAMILY_OTHER_BLUES: + retval = sizeof ( type1->private_dict.num_family_other_blues ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_family_other_blues; + break; + case PS_DICT_FAMILY_OTHER_BLUE: + if ( idx < type1->private_dict.num_family_other_blues ) + { + retval = sizeof ( type1->private_dict.family_other_blues[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.family_other_blues[idx]; + } + break; + case PS_DICT_NUM_STEM_SNAP_H: + retval = sizeof ( type1->private_dict.num_snap_widths ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_snap_widths; + break; + case PS_DICT_STEM_SNAP_H: + if ( idx < type1->private_dict.num_snap_widths ) + { + retval = sizeof ( type1->private_dict.snap_widths[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.snap_widths[idx]; + } + break; + case PS_DICT_NUM_STEM_SNAP_V: + retval = sizeof ( type1->private_dict.num_snap_heights ); + if ( value && value_len >= retval ) + *((FT_Byte *)value) = type1->private_dict.num_snap_heights; + break; + case PS_DICT_STEM_SNAP_V: + if ( idx < type1->private_dict.num_snap_heights ) + { + retval = sizeof ( type1->private_dict.snap_heights[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.snap_heights[idx]; + } + break; + case PS_DICT_RND_STEM_UP: + retval = sizeof ( type1->private_dict.round_stem_up ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->private_dict.round_stem_up; + break; + case PS_DICT_FORCE_BOLD: + retval = sizeof ( type1->private_dict.force_bold ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->private_dict.force_bold; + break; + case PS_DICT_MIN_FEATURE: + if ( idx < sizeof ( type1->private_dict.min_feature ) / + sizeof ( type1->private_dict.min_feature[0] ) ) + { + retval = sizeof ( type1->private_dict.min_feature[idx] ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->private_dict.min_feature[idx]; + } + break; + case PS_DICT_LEN_IV: + retval = sizeof ( type1->private_dict.lenIV ); + if ( value && value_len >= retval ) + *((FT_Int *)value) = type1->private_dict.lenIV; + break; + case PS_DICT_PASSWORD: + retval = sizeof ( type1->private_dict.password ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->private_dict.password; + break; + case PS_DICT_LANGUAGE_GROUP: + retval = sizeof ( type1->private_dict.language_group ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->private_dict.language_group; + break; + case PS_DICT_IS_FIXED_PITCH: + retval = sizeof ( type1->font_info.is_fixed_pitch ); + if ( value && value_len >= retval ) + *((FT_Bool *)value) = type1->font_info.is_fixed_pitch; + break; + case PS_DICT_UNDERLINE_POSITION: + retval = sizeof ( type1->font_info.underline_position ); + if ( value && value_len >= retval ) + *((FT_Short *)value) = type1->font_info.underline_position; + break; + case PS_DICT_UNDERLINE_THICKNESS: + retval = sizeof ( type1->font_info.underline_thickness ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->font_info.underline_thickness; + break; + case PS_DICT_FS_TYPE: + retval = sizeof ( type1->font_extra.fs_type ); + if ( value && value_len >= retval ) + *((FT_UShort *)value) = type1->font_extra.fs_type; + break; + case PS_DICT_VERSION: + retval = ft_strlen( type1->font_info.version ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.version ), retval ); + break; + case PS_DICT_NOTICE: + retval = ft_strlen( type1->font_info.notice ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.notice ), retval ); + break; + case PS_DICT_FULL_NAME: + retval = ft_strlen( type1->font_info.full_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.full_name ), retval ); + break; + case PS_DICT_FAMILY_NAME: + retval = ft_strlen( type1->font_info.family_name ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.family_name ), retval ); + break; + case PS_DICT_WEIGHT: + retval = ft_strlen( type1->font_info.weight ) + 1; + if ( value && value_len >= retval ) + ft_memcpy( value, (void *)( type1->font_info.weight ), retval ); + break; + case PS_DICT_ITALIC_ANGLE: + retval = sizeof ( type1->font_info.italic_angle ); + if ( value && value_len >= retval ) + *((FT_Long *)value) = type1->font_info.italic_angle; + break; + default: + break; + } + return retval; + } + static const FT_Service_PsInfoRec t1_service_ps_info = + { + (PS_GetFontInfoFunc) t1_ps_get_font_info, + (PS_GetFontExtraFunc) t1_ps_get_font_extra, + (PS_HasGlyphNamesFunc) t1_ps_has_glyph_names, + (PS_GetFontPrivateFunc)t1_ps_get_font_private, + (PS_GetFontValueFunc) t1_ps_get_font_value, + }; + static const FT_Service_KerningRec t1_service_kerning = + { + T1_Get_Track_Kerning, + }; +/* + * SERVICE LIST + * + */ + static const FT_ServiceDescRec t1_services[] = + { + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t1_service_ps_name }, + { FT_SERVICE_ID_GLYPH_DICT, &t1_service_glyph_dict }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TYPE_1 }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t1_service_ps_info }, + { FT_SERVICE_ID_KERNING, &t1_service_kerning }, + { FT_SERVICE_ID_MULTI_MASTERS, &t1_service_multi_masters }, + { NULL, NULL } + }; + FT_CALLBACK_DEF( FT_Module_Interface ) + Get_Interface( FT_Module module, + const FT_String* t1_interface ) + { + FT_UNUSED( module ); + return ft_service_list_lookup( t1_services, t1_interface ); + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Get_Kerning */ +/* */ +/* <Description> */ +/* A driver method used to return the kerning vector between two */ +/* glyphs of the same face. */ +/* */ +/* <Input> */ +/* face :: A handle to the source face object. */ +/* */ +/* left_glyph :: The index of the left glyph in the kern pair. */ +/* */ +/* right_glyph :: The index of the right glyph in the kern pair. */ +/* */ +/* <Output> */ +/* kerning :: The kerning vector. This is in font units for */ +/* scalable formats, and in pixels for fixed-sizes */ +/* formats. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ +/* <Note> */ +/* Only horizontal layouts (left-to-right & right-to-left) are */ +/* supported by this function. Other layouts, or more sophisticated */ +/* kernings are out of scope of this method (the basic driver */ +/* interface is meant to be simple). */ +/* */ +/* They can be implemented by format-specific interfaces. */ +/* */ + static FT_Error +/* T1_Face */ + Get_Kerning( FT_Face t1face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_Vector* kerning ) + { + T1_Face face = (T1_Face)t1face; + kerning->x = 0; + kerning->y = 0; + if ( face->afm_data ) + T1_Get_Kerning( (AFM_FontInfo)face->afm_data, + left_glyph, + right_glyph, + kerning ); + return T1_Err_Ok; + } + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec t1_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + sizeof ( FT_DriverRec ), + "type1", + 0x10000L, + 0x20000L, +/* format interface */ + 0, + T1_Driver_Init, + T1_Driver_Done, + Get_Interface, + }, + sizeof ( T1_FaceRec ), + sizeof ( T1_SizeRec ), + sizeof ( T1_GlyphSlotRec ), + T1_Face_Init, + T1_Face_Done, + T1_Size_Init, + T1_Size_Done, + T1_GlyphSlot_Init, + T1_GlyphSlot_Done, + T1_Load_Glyph, + Get_Kerning, + T1_Read_Metrics, + T1_Get_Advances, + T1_Size_Request, +/* FT_Size_SelectFunc */ + 0 + }; +/* END */ +/***************************************************************************/ +/* */ +/* t1gload.c */ +/* */ +/* Type 1 Glyph Loader (body). */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 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 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 trace_t1gload +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/********** *********/ +/********** 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 ) + T1_Parse_Glyph_And_Get_Char_String( T1_Decoder decoder, + FT_UInt glyph_index, + FT_Data* char_string ) + { + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font type1 = &face->type1; + FT_Error error = T1_Err_Ok; + FT_Incremental_InterfaceRec *inc = + face->root.internal->incremental_interface; + decoder->font_matrix = type1->font_matrix; + decoder->font_offset = type1->font_offset; +/* For incremental fonts get the character data using the */ +/* callback function. */ + if ( inc ) + error = inc->funcs->get_glyph_data( inc->object, + glyph_index, char_string ); + else +/* For ordinary fonts get the character data stored in the face record. */ + { + char_string->pointer = type1->charstrings[glyph_index]; + char_string->length = (FT_Int)type1->charstrings_len[glyph_index]; + } + if ( !error ) + error = decoder->funcs.parse_charstrings( + decoder, (FT_Byte*)char_string->pointer, + char_string->length ); +/* 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 ); + } + return error; + } + FT_CALLBACK_DEF( FT_Error ) + T1_Parse_Glyph( T1_Decoder decoder, + FT_UInt glyph_index ) + { + FT_Data glyph_data; + FT_Error error = T1_Parse_Glyph_And_Get_Char_String( + decoder, glyph_index, &glyph_data ); + if ( !error ) + { + T1_Face face = (T1_Face)decoder->builder.face; + if ( face->root.internal->incremental_interface ) + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); + } + return error; + } + FT_LOCAL_DEF( FT_Error ) + T1_Compute_Max_Advance( T1_Face face, + FT_Pos* max_advance ) + { + FT_Error error; + T1_DecoderRec decoder; + FT_Int glyph_index; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + *max_advance = 0; +/* initialize load decoder */ + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, +/* size */ + 0, +/* glyph slot */ + 0, + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + *max_advance = 0; +/* for each glyph, parse the glyph charstring and extract */ +/* the advance width */ + for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) + { +/* now get load the unscaled outline */ + error = T1_Parse_Glyph( &decoder, glyph_index ); + if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance ) + *max_advance = decoder.builder.advance.x; +/* ignore the error if one occurred - skip to next glyph */ + } + psaux->t1_decoder_funcs->done( &decoder ); + return T1_Err_Ok; + } + FT_LOCAL_DEF( FT_Error ) +/* T1_Face */ + T1_Get_Advances( FT_Face t1face, + FT_UInt first, + FT_UInt count, + FT_Int32 load_flags, + FT_Fixed* advances ) + { + T1_Face face = (T1_Face)t1face; + T1_DecoderRec decoder; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_UInt nn; + FT_Error error; + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + for ( nn = 0; nn < count; nn++ ) + advances[nn] = 0; + return T1_Err_Ok; + } + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, +/* size */ + 0, +/* glyph slot */ + 0, + (FT_Byte**)type1->glyph_names, + face->blend, + 0, + FT_RENDER_MODE_NORMAL, + T1_Parse_Glyph ); + if ( error ) + return error; + decoder.builder.metrics_only = 1; + decoder.builder.load_points = 0; + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; + for ( nn = 0; nn < count; nn++ ) + { + error = T1_Parse_Glyph( &decoder, first + nn ); + if ( !error ) + advances[nn] = FIXED_TO_INT( decoder.builder.advance.x ); + else + advances[nn] = 0; + } + return T1_Err_Ok; + } + FT_LOCAL_DEF( FT_Error ) +/* T1_GlyphSlot */ + T1_Load_Glyph( FT_GlyphSlot t1glyph, +/* T1_Size */ + FT_Size t1size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + T1_GlyphSlot glyph = (T1_GlyphSlot)t1glyph; + FT_Error error; + T1_DecoderRec decoder; + T1_Face face = (T1_Face)t1glyph->face; + FT_Bool hinting; + T1_Font type1 = &face->type1; + PSAux_Service psaux = (PSAux_Service)face->psaux; + const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs; + FT_Matrix font_matrix; + FT_Vector font_offset; + FT_Data glyph_data; + FT_Bool must_finish_decoder = FALSE; + FT_Bool glyph_data_loaded = 0; + if ( glyph_index >= (FT_UInt)face->root.num_glyphs && + !face->root.internal->incremental_interface ) + { + error = T1_Err_Invalid_Argument; + goto Exit; + } + FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); + if ( load_flags & FT_LOAD_NO_RECURSE ) + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; + if ( t1size ) + { + glyph->x_scale = t1size->metrics.x_scale; + glyph->y_scale = t1size->metrics.y_scale; + } + else + { + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + } + t1glyph->outline.n_points = 0; + t1glyph->outline.n_contours = 0; + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && + ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + error = decoder_funcs->init( &decoder, + t1glyph->face, + t1size, + t1glyph, + (FT_Byte**)type1->glyph_names, + face->blend, + FT_BOOL( hinting ), + FT_LOAD_TARGET_MODE( load_flags ), + T1_Parse_Glyph ); + if ( error ) + goto Exit; + must_finish_decoder = TRUE; + decoder.builder.no_recurse = FT_BOOL( + ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + decoder.buildchar = face->buildchar; + decoder.len_buildchar = face->len_buildchar; +/* now load the unscaled outline */ + error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index, + &glyph_data ); + if ( error ) + goto Exit; + glyph_data_loaded = 1; + font_matrix = decoder.font_matrix; + font_offset = decoder.font_offset; +/* save new glyph tables */ + 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 */ + if ( !error ) + { + t1glyph->outline.flags &= FT_OUTLINE_OWNER; + t1glyph->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 = t1glyph->internal; + t1glyph->metrics.horiBearingX = + FIXED_TO_INT( decoder.builder.left_bearing.x ); + t1glyph->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 = &t1glyph->metrics; + FT_Vector advance; +/* copy the _unscaled_ advance width */ + metrics->horiAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + t1glyph->linearHoriAdvance = + FIXED_TO_INT( decoder.builder.advance.x ); + t1glyph->internal->glyph_transformed = 0; + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { +/* make up vertical ones */ + metrics->vertAdvance = ( face->type1.font_bbox.yMax - + face->type1.font_bbox.yMin ) >> 16; + t1glyph->linearVertAdvance = metrics->vertAdvance; + } + else + { + metrics->vertAdvance = + FIXED_TO_INT( decoder.builder.advance.y ); + t1glyph->linearVertAdvance = + FIXED_TO_INT( decoder.builder.advance.y ); + } + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + if ( t1size && t1size->metrics.y_ppem < 24 ) + t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; +#if 1 +/* apply the font matrix, if any */ + if ( font_matrix.xx != 0x10000L || font_matrix.yy != font_matrix.xx || + font_matrix.xy != 0 || font_matrix.yx != 0 ) + FT_Outline_Transform( &t1glyph->outline, &font_matrix ); + if ( font_offset.x || font_offset.y ) + FT_Outline_Translate( &t1glyph->outline, + font_offset.x, + font_offset.y ); + advance.x = metrics->horiAdvance; + advance.y = 0; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->horiAdvance = advance.x + font_offset.x; + advance.x = 0; + advance.y = metrics->vertAdvance; + FT_Vector_Transform( &advance, &font_matrix ); + metrics->vertAdvance = advance.y + font_offset.y; +#endif + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + { +/* 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 we are not hinting */ + 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( &t1glyph->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 ); + } + } +/* Set control data to the glyph charstrings. Note that this is */ +/* _not_ zero-terminated. */ + t1glyph->control_data = (FT_Byte*)glyph_data.pointer; + t1glyph->control_len = glyph_data.length; + } + Exit: + if ( glyph_data_loaded && face->root.internal->incremental_interface ) + { + face->root.internal->incremental_interface->funcs->free_glyph_data( + face->root.internal->incremental_interface->object, + &glyph_data ); +/* Set the control data to null - it is no longer available if */ +/* loaded incrementally. */ + t1glyph->control_data = 0; + t1glyph->control_len = 0; + } + if ( must_finish_decoder ) + decoder_funcs->done( &decoder ); + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* t1afm.c */ +/* */ +/* AFM support for Type 1 fonts (body). */ +/* */ +/* Copyright 1996-2011 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 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 trace_t1afm + FT_LOCAL_DEF( void ) + T1_Done_Metrics( FT_Memory memory, + AFM_FontInfo fi ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + FT_FREE( fi->TrackKerns ); + fi->NumTrackKern = 0; + FT_FREE( fi ); + } +/* read a glyph name and return the equivalent glyph index */ + static FT_Int + t1_get_index( const char* name, + FT_Offset len, + void* user_data ) + { + T1_Font type1 = (T1_Font)user_data; + FT_Int n; +/* PS string/name length must be < 16-bit */ + if ( len > 0xFFFFU ) + return 0; + for ( n = 0; n < type1->num_glyphs; n++ ) + { + char* gname = (char*)type1->glyph_names[n]; + if ( gname && gname[0] == name[0] && + ft_strlen( gname ) == len && + ft_strncmp( gname, name, len ) == 0 ) + return n; + } + return 0; + } +#undef KERN_INDEX +#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) +/* compare two kerning pairs */ + FT_CALLBACK_DEF( int ) + compare_kern_pairs( const void* a, + const void* b ) + { + AFM_KernPair pair1 = (AFM_KernPair)a; + AFM_KernPair pair2 = (AFM_KernPair)b; + FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 ); + FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 ); + if ( index1 > index2 ) + return 1; + else if ( index1 < index2 ) + return -1; + else + return 0; + } +/* parse a PFM file -- for now, only read the kerning pairs */ + static FT_Error + T1_Read_PFM( FT_Face t1_face, + FT_Stream stream, + AFM_FontInfo fi ) + { + FT_Error error = T1_Err_Ok; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + AFM_KernPair kp; + FT_Int width_table_length; + FT_CharMap oldcharmap; + FT_CharMap charmap; + FT_Int n; + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; +/* Figure out how long the width table is. */ +/* This info is a little-endian short at offset 99. */ + p = start + 99; + if ( p + 2 > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + width_table_length = FT_PEEK_USHORT_LE( p ); + p += 18 + width_table_length; + if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) +/* extension table is probably optional */ + goto Exit; +/* Kerning offset is 14 bytes from start of extensions table. */ + p += 14; + p = start + FT_PEEK_ULONG_LE( p ); + if ( p == start ) +/* zero offset means no table */ + goto Exit; + if ( p + 2 > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + fi->NumKernPair = FT_PEEK_USHORT_LE( p ); + p += 2; + if ( p + 4 * fi->NumKernPair > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } +/* Actually, kerning pairs are simply optional! */ + if ( fi->NumKernPair == 0 ) + goto Exit; +/* allocate the pairs */ + if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) + goto Exit; +/* now, read each kern pair */ + kp = fi->KernPairs; + limit = p + 4 * fi->NumKernPair; +/* PFM kerning data are stored by encoding rather than glyph index, */ +/* so find the PostScript charmap of this font and install it */ +/* temporarily. If we find no PostScript charmap, then just use */ +/* the default and hope it is the right one. */ + oldcharmap = t1_face->charmap; + charmap = NULL; + for ( n = 0; n < t1_face->num_charmaps; n++ ) + { + charmap = t1_face->charmaps[n]; +/* check against PostScript pseudo platform */ + if ( charmap->platform_id == 7 ) + { + error = FT_Set_Charmap( t1_face, charmap ); + if ( error ) + goto Exit; + break; + } + } +/* Kerning info is stored as: */ +/* */ +/* encoding of first glyph (1 byte) */ +/* encoding of second glyph (1 byte) */ +/* offset (little-endian short) */ + for ( ; p < limit ; p += 4 ) + { + kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); + kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); + kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2); + kp->y = 0; + kp++; + } + if ( oldcharmap != NULL ) + error = FT_Set_Charmap( t1_face, oldcharmap ); + if ( error ) + goto Exit; +/* now, sort the kern pairs according to their glyph indices */ + ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), + compare_kern_pairs ); + Exit: + if ( error ) + { + FT_FREE( fi->KernPairs ); + fi->NumKernPair = 0; + } + return error; + } +/* parse a metrics file -- either AFM or PFM depending on what */ +/* it turns out to be */ + FT_LOCAL_DEF( FT_Error ) + T1_Read_Metrics( FT_Face t1_face, + FT_Stream stream ) + { + PSAux_Service psaux; + FT_Memory memory = stream->memory; + AFM_ParserRec parser; + AFM_FontInfo fi = NULL; + FT_Error error = T1_Err_Unknown_File_Format; + T1_Font t1_font = &( (T1_Face)t1_face )->type1; + if ( FT_NEW( fi ) || + FT_FRAME_ENTER( stream->size ) ) + goto Exit; + fi->FontBBox = t1_font->font_bbox; + fi->Ascender = t1_font->font_bbox.yMax; + fi->Descender = t1_font->font_bbox.yMin; + psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux; + if ( psaux->afm_parser_funcs ) + { + error = psaux->afm_parser_funcs->init( &parser, + stream->memory, + stream->cursor, + stream->limit ); + if ( !error ) + { + parser.FontInfo = fi; + parser.get_index = t1_get_index; + parser.user_data = t1_font; + error = psaux->afm_parser_funcs->parse( &parser ); + psaux->afm_parser_funcs->done( &parser ); + } + } + if ( error == T1_Err_Unknown_File_Format ) + { + FT_Byte* start = stream->cursor; +/* MS Windows allows versions up to 0x3FF without complaining */ + if ( stream->size > 6 && + start[1] < 4 && + FT_PEEK_ULONG_LE( start + 2 ) == stream->size ) + error = T1_Read_PFM( t1_face, stream, fi ); + } + if ( !error ) + { + t1_font->font_bbox = fi->FontBBox; + t1_face->bbox.xMin = fi->FontBBox.xMin >> 16; + t1_face->bbox.yMin = fi->FontBBox.yMin >> 16; +/* no `U' suffix here to 0xFFFF! */ + t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16; + t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16; +/* no `U' suffix here to 0x8000! */ + t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); + t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); + if ( fi->NumKernPair ) + { + t1_face->face_flags |= FT_FACE_FLAG_KERNING; + ( (T1_Face)t1_face )->afm_data = fi; + fi = NULL; + } + } + FT_FRAME_EXIT(); + Exit: + if ( fi != NULL ) + T1_Done_Metrics( memory, fi ); + return error; + } +/* find the kerning for a given glyph pair */ + FT_LOCAL_DEF( void ) + T1_Get_Kerning( AFM_FontInfo fi, + FT_UInt glyph1, + FT_UInt glyph2, + FT_Vector* kerning ) + { + AFM_KernPair min, mid, max; + FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); +/* simple binary search */ + min = fi->KernPairs; + max = min + fi->NumKernPair - 1; + while ( min <= max ) + { + FT_ULong midi; + mid = min + ( max - min ) / 2; + midi = KERN_INDEX( mid->index1, mid->index2 ); + if ( midi == idx ) + { + kerning->x = mid->x; + kerning->y = mid->y; + return; + } + if ( midi < idx ) + min = mid + 1; + else + max = mid - 1; + } + kerning->x = 0; + kerning->y = 0; + } + FT_LOCAL_DEF( FT_Error ) + T1_Get_Track_Kerning( FT_Face face, + FT_Fixed ptsize, + FT_Int degree, + FT_Fixed* kerning ) + { + AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data; + FT_Int i; + if ( !fi ) + return T1_Err_Invalid_Argument; + for ( i = 0; i < fi->NumTrackKern; i++ ) + { + AFM_TrackKern tk = fi->TrackKerns + i; + if ( tk->degree != degree ) + continue; + if ( ptsize < tk->min_ptsize ) + *kerning = tk->min_kern; + else if ( ptsize > tk->max_ptsize ) + *kerning = tk->max_kern; + else + { + *kerning = FT_MulDiv( ptsize - tk->min_ptsize, + tk->max_kern - tk->min_kern, + tk->max_ptsize - tk->min_ptsize ) + + tk->min_kern; + } + } + return T1_Err_Ok; + } +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* type42.c */ +/* */ +/* FreeType Type 42 driver component. */ +/* */ +/* Copyright 2002 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* t42objs.c */ +/* */ +/* Type 42 objects manager (body). */ +/* */ +/* Copyright 2002-2009, 2011 */ +/* by Roberto Alameda. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* t42objs.h */ +/* */ +/* Type 42 objects manager (specification). */ +/* */ +/* Copyright 2002, 2003, 2006, 2007, 2011 by Roberto Alameda. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __T42OBJS_H__ +/***************************************************************************/ +/* */ +/* t42types.h */ +/* */ +/* Type 42 font data types (specification only). */ +/* */ +/* Copyright 2002, 2003, 2006, 2008 by Roberto Alameda. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __T42TYPES_H__ +FT_BEGIN_HEADER + typedef struct T42_FaceRec_ + { + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; +#if 0 + const void* afm_data; +#endif + FT_Byte* ttf_data; + FT_ULong ttf_size; + FT_Face ttf_face; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; + PS_UnicodesRec unicode_map; + } T42_FaceRec, *T42_Face; +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/* Type42 size */ + typedef struct T42_SizeRec_ + { + FT_SizeRec root; + FT_Size ttsize; + } T42_SizeRec, *T42_Size; +/* Type42 slot */ + typedef struct T42_GlyphSlotRec_ + { + FT_GlyphSlotRec root; + FT_GlyphSlot ttslot; + } T42_GlyphSlotRec, *T42_GlyphSlot; +/* Type 42 driver */ + typedef struct T42_DriverRec_ + { + FT_DriverRec root; + FT_Driver_Class ttclazz; + void* extension_component; + } T42_DriverRec, *T42_Driver; +/* */ + FT_LOCAL( FT_Error ) + T42_Face_Init( FT_Stream stream, + FT_Face face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ); + FT_LOCAL( void ) + T42_Face_Done( FT_Face face ); + FT_LOCAL( FT_Error ) + T42_Size_Init( FT_Size size ); + FT_LOCAL( FT_Error ) + T42_Size_Request( FT_Size size, + FT_Size_Request req ); + FT_LOCAL( FT_Error ) + T42_Size_Select( FT_Size size, + FT_ULong strike_index ); + FT_LOCAL( void ) + T42_Size_Done( FT_Size size ); + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Init( FT_GlyphSlot slot ); + FT_LOCAL( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ); + FT_LOCAL( void ) + T42_GlyphSlot_Done( FT_GlyphSlot slot ); + FT_LOCAL( FT_Error ) + T42_Driver_Init( FT_Module module ); + FT_LOCAL( void ) + T42_Driver_Done( FT_Module module ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* t42parse.h */ +/* */ +/* Type 42 font parser (specification). */ +/* */ +/* Copyright 2002, 2003 by Roberto Alameda. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __T42PARSE_H__ +FT_BEGIN_HEADER + typedef struct T42_ParserRec_ + { + PS_ParserRec root; + FT_Stream stream; + FT_Byte* base_dict; + FT_Long base_len; + FT_Bool in_memory; + } T42_ParserRec, *T42_Parser; + typedef struct T42_Loader_ + { +/* parser used to read the stream */ + T42_ParserRec parser; +/* number of characters in encoding */ + FT_UInt num_chars; +/* PS_Table used to store the */ + PS_TableRec encoding_table; +/* encoding character names */ + FT_UInt num_glyphs; + PS_TableRec glyph_names; + PS_TableRec charstrings; +/* For moving .notdef glyph to index 0. */ + PS_TableRec swap_table; + } T42_LoaderRec, *T42_Loader; + FT_LOCAL( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ); + FT_LOCAL( void ) + t42_parser_done( T42_Parser parser ); + FT_LOCAL( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ); + FT_LOCAL( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ); + FT_LOCAL( void ) + t42_loader_done( T42_Loader loader ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* t42error.h */ +/* */ +/* Type 42 error codes (specification only). */ +/* */ +/* Copyright 2002, 2003, 2012 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 Type 42 error enumeration constants. */ +/* */ +/*************************************************************************/ +#define __T42ERROR_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX T42_Err_ +#define FT_ERR_BASE FT_Mod_Err_Type42 +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t42 + static FT_Error + T42_Open_Face( T42_Face face ) + { + T42_LoaderRec loader; + T42_Parser parser; + T1_Font type1 = &face->type1; + FT_Memory memory = face->root.memory; + FT_Error error; + PSAux_Service psaux = (PSAux_Service)face->psaux; + t42_loader_init( &loader, face ); + parser = &loader.parser; + if ( FT_ALLOC( face->ttf_data, 12 ) ) + goto Exit; + error = t42_parser_init( parser, + face->root.stream, + memory, + psaux); + if ( error ) + goto Exit; + error = t42_parse_dict( face, &loader, + parser->base_dict, parser->base_len ); + if ( error ) + goto Exit; + if ( type1->font_type != 42 ) + { + FT_ERROR(( "T42_Open_Face: cannot handle FontType %d\n", + type1->font_type )); + error = T42_Err_Unknown_File_Format; + goto Exit; + } +/* now, propagate the charstrings and glyphnames tables */ +/* to the Type1 data */ + type1->num_glyphs = loader.num_glyphs; + if ( !loader.charstrings.init ) + { + FT_ERROR(( "T42_Open_Face: no charstrings array in face\n" )); + error = T42_Err_Invalid_File_Format; + } + loader.charstrings.init = 0; + type1->charstrings_block = loader.charstrings.block; + type1->charstrings = loader.charstrings.elements; + type1->charstrings_len = loader.charstrings.lengths; +/* we copy the glyph names `block' and `elements' fields; */ +/* the `lengths' field must be released later */ + type1->glyph_names_block = loader.glyph_names.block; + type1->glyph_names = (FT_String**)loader.glyph_names.elements; + loader.glyph_names.block = 0; + loader.glyph_names.elements = 0; +/* we must now build type1.encoding when we have a custom array */ + if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) + { + FT_Int charcode, idx, min_char, max_char; + FT_Byte* char_name; + FT_Byte* glyph_name; +/* OK, we do the following: for each element in the encoding */ +/* table, look up the index of the glyph having the same name */ +/* as defined in the CharStrings array. */ +/* The index is then stored in type1.encoding.char_index, and */ +/* the name in type1.encoding.char_name */ + min_char = 0; + max_char = 0; + charcode = 0; + for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) + { + type1->encoding.char_index[charcode] = 0; + type1->encoding.char_name [charcode] = (char *)".notdef"; + char_name = loader.encoding_table.elements[charcode]; + if ( char_name ) + for ( idx = 0; idx < type1->num_glyphs; idx++ ) + { + glyph_name = (FT_Byte*)type1->glyph_names[idx]; + if ( ft_strcmp( (const char*)char_name, + (const char*)glyph_name ) == 0 ) + { + type1->encoding.char_index[charcode] = (FT_UShort)idx; + type1->encoding.char_name [charcode] = (char*)glyph_name; +/* Change min/max encoded char only if glyph name is */ +/* not /.notdef */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)glyph_name ) != 0 ) + { + if ( charcode < min_char ) + min_char = charcode; + if ( charcode >= max_char ) + max_char = charcode + 1; + } + break; + } + } + } + type1->encoding.code_first = min_char; + type1->encoding.code_last = max_char; + type1->encoding.num_chars = loader.num_chars; + } + Exit: + t42_loader_done( &loader ); + return error; + } +/***************** Driver Functions *************/ + FT_LOCAL_DEF( FT_Error ) + T42_Face_Init( FT_Stream stream, +/* T42_Face */ + FT_Face t42face, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + T42_Face face = (T42_Face)t42face; + FT_Error error; + FT_Service_PsCMaps psnames; + PSAux_Service psaux; + FT_Face root = (FT_Face)&face->root; + T1_Font type1 = &face->type1; + PS_FontInfo info = &type1->font_info; + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_UNUSED( face_index ); + FT_UNUSED( stream ); + face->ttf_face = NULL; + face->root.num_faces = 1; + FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); + face->psnames = psnames; + face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), + "psaux" ); + psaux = (PSAux_Service)face->psaux; + if ( !psaux ) + { + FT_ERROR(( "T42_Face_Init: cannot access `psaux' module\n" )); + error = T42_Err_Missing_Module; + goto Exit; + } + FT_TRACE2(( "Type 42 driver\n" )); +/* open the tokenizer, this will also check the font format */ + error = T42_Open_Face( face ); + 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 */ + if ( face_index > 0 ) + { + FT_ERROR(( "T42_Face_Init: invalid face index\n" )); + error = T42_Err_Invalid_Argument; + goto Exit; + } +/* Now load the font program into the face object */ +/* Init the face object fields */ +/* Now set up root face fields */ + root->num_glyphs = type1->num_glyphs; + root->num_charmaps = 0; + root->face_index = 0; + root->face_flags = FT_FACE_FLAG_SCALABLE | + FT_FACE_FLAG_HORIZONTAL | + FT_FACE_FLAG_GLYPH_NAMES; + if ( info->is_fixed_pitch ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; +/* We only set this flag if we have the patented bytecode interpreter. */ +/* There are no known `tricky' Type42 fonts that could be loaded with */ +/* the unpatented interpreter. */ + root->face_flags |= FT_FACE_FLAG_HINTER; +/* XXX: TODO -- add kerning with .afm support */ +/* get style name -- be careful, some broken fonts only */ +/* have a `/FontName' dictionary entry! */ + root->family_name = info->family_name; +/* assume "Regular" style if we don't know better */ + root->style_name = (char *)"Regular"; + if ( root->family_name ) + { + char* full = info->full_name; + char* family = root->family_name; + if ( full ) + { + while ( *full ) + { + if ( *full == *family ) + { + family++; + full++; + } + else + { + if ( *full == ' ' || *full == '-' ) + full++; + else if ( *family == ' ' || *family == '-' ) + family++; + else + { + if ( !*family ) + root->style_name = full; + break; + } + } + } + } + } + else + { +/* do we have a `/FontName'? */ + if ( type1->font_name ) + root->family_name = type1->font_name; + } +/* no embedded bitmap support */ + root->num_fixed_sizes = 0; + root->available_sizes = 0; +/* Load the TTF font embedded in the T42 font */ + { + FT_Open_Args args; + args.flags = FT_OPEN_MEMORY; + args.memory_base = face->ttf_data; + args.memory_size = face->ttf_size; + if ( num_params ) + { + args.flags |= FT_OPEN_PARAMS; + args.num_params = num_params; + args.params = params; + } + error = FT_Open_Face( FT_FACE_LIBRARY( face ), + &args, 0, &face->ttf_face ); + } + if ( error ) + goto Exit; + FT_Done_Size( face->ttf_face->size ); +/* Ignore info in FontInfo dictionary and use the info from the */ +/* loaded TTF font. The PostScript interpreter also ignores it. */ + root->bbox = face->ttf_face->bbox; + root->units_per_EM = face->ttf_face->units_per_EM; + root->ascender = face->ttf_face->ascender; + root->descender = face->ttf_face->descender; + root->height = face->ttf_face->height; + root->max_advance_width = face->ttf_face->max_advance_width; + root->max_advance_height = face->ttf_face->max_advance_height; + root->underline_position = (FT_Short)info->underline_position; + root->underline_thickness = (FT_Short)info->underline_thickness; +/* compute style flags */ + root->style_flags = 0; + if ( info->italic_angle ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD ) + root->style_flags |= FT_STYLE_FLAG_BOLD; + if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL ) + root->face_flags |= FT_FACE_FLAG_VERTICAL; + { + if ( psnames ) + { + FT_CharMapRec charmap; + T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes; + FT_CMap_Class clazz; + charmap.face = root; +/* first of all, try to synthesize a Unicode charmap */ + charmap.platform_id = TT_PLATFORM_MICROSOFT; + charmap.encoding_id = TT_MS_ID_UNICODE_CS; + charmap.encoding = FT_ENCODING_UNICODE; + error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL ); + if ( error && FT_Err_No_Unicode_Glyph_Name != error ) + goto Exit; + error = FT_Err_Ok; +/* now, generate an Adobe Standard encoding when appropriate */ + charmap.platform_id = TT_PLATFORM_ADOBE; + clazz = NULL; + switch ( type1->encoding_type ) + { + case T1_ENCODING_TYPE_STANDARD: + charmap.encoding = FT_ENCODING_ADOBE_STANDARD; + charmap.encoding_id = TT_ADOBE_ID_STANDARD; + clazz = cmap_classes->standard; + break; + case T1_ENCODING_TYPE_EXPERT: + charmap.encoding = FT_ENCODING_ADOBE_EXPERT; + charmap.encoding_id = TT_ADOBE_ID_EXPERT; + clazz = cmap_classes->expert; + break; + case T1_ENCODING_TYPE_ARRAY: + charmap.encoding = FT_ENCODING_ADOBE_CUSTOM; + charmap.encoding_id = TT_ADOBE_ID_CUSTOM; + clazz = cmap_classes->custom; + break; + case T1_ENCODING_TYPE_ISOLATIN1: + charmap.encoding = FT_ENCODING_ADOBE_LATIN_1; + charmap.encoding_id = TT_ADOBE_ID_LATIN_1; + clazz = cmap_classes->unicode; + break; + default: + ; + } + if ( clazz ) + error = FT_CMap_New( clazz, NULL, &charmap, NULL ); +#if 0 +/* Select default charmap */ + if ( root->num_charmaps ) + root->charmap = root->charmaps[0]; +#endif + } + } + Exit: + return error; + } + FT_LOCAL_DEF( void ) + T42_Face_Done( FT_Face t42face ) + { + T42_Face face = (T42_Face)t42face; + T1_Font type1; + PS_FontInfo info; + FT_Memory memory; + if ( !face ) + return; + type1 = &face->type1; + info = &type1->font_info; + memory = face->root.memory; +/* delete internal ttf face prior to freeing face->ttf_data */ + if ( face->ttf_face ) + FT_Done_Face( face->ttf_face ); +/* release font info strings */ + FT_FREE( info->version ); + FT_FREE( info->notice ); + FT_FREE( info->full_name ); + FT_FREE( info->family_name ); + FT_FREE( info->weight ); +/* release top dictionary */ + FT_FREE( type1->charstrings_len ); + FT_FREE( type1->charstrings ); + FT_FREE( type1->glyph_names ); + FT_FREE( type1->charstrings_block ); + FT_FREE( type1->glyph_names_block ); + FT_FREE( type1->encoding.char_index ); + FT_FREE( type1->encoding.char_name ); + FT_FREE( type1->font_name ); + FT_FREE( face->ttf_data ); +#if 0 +/* release afm data if present */ + if ( face->afm_data ) + T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); +#endif +/* release unicode map, if any */ + FT_FREE( face->unicode_map.maps ); + face->unicode_map.num_maps = 0; + face->root.family_name = 0; + face->root.style_name = 0; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* T42_Driver_Init */ +/* */ +/* <Description> */ +/* Initializes a given Type 42 driver object. */ +/* */ +/* <Input> */ +/* driver :: A handle to the target driver object. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) +/* T42_Driver */ + T42_Driver_Init( FT_Module module ) + { + T42_Driver driver = (T42_Driver)module; + FT_Module ttmodule; + ttmodule = FT_Get_Module( module->library, "truetype" ); + if ( !ttmodule ) + { + FT_ERROR(( "T42_Driver_Init: cannot access `truetype' module\n" )); + return T42_Err_Missing_Module; + } + driver->ttclazz = (FT_Driver_Class)ttmodule->clazz; + return T42_Err_Ok; + } + FT_LOCAL_DEF( void ) + T42_Driver_Done( FT_Module module ) + { + FT_UNUSED( module ); + } + FT_LOCAL_DEF( FT_Error ) +/* T42_Size */ + T42_Size_Init( FT_Size size ) + { + T42_Size t42size = (T42_Size)size; + FT_Face face = size->face; + T42_Face t42face = (T42_Face)face; + FT_Size ttsize; + FT_Error error = T42_Err_Ok; + error = FT_New_Size( t42face->ttf_face, &ttsize ); + t42size->ttsize = ttsize; + FT_Activate_Size( ttsize ); + return error; + } + FT_LOCAL_DEF( FT_Error ) +/* T42_Size */ + T42_Size_Request( FT_Size t42size, + FT_Size_Request req ) + { + T42_Size size = (T42_Size)t42size; + T42_Face face = (T42_Face)t42size->face; + FT_Error error; + FT_Activate_Size( size->ttsize ); + error = FT_Request_Size( face->ttf_face, req ); + if ( !error ) + t42size->metrics = face->ttf_face->size->metrics; + return error; + } + FT_LOCAL_DEF( FT_Error ) +/* T42_Size */ + T42_Size_Select( FT_Size t42size, + FT_ULong strike_index ) + { + T42_Size size = (T42_Size)t42size; + T42_Face face = (T42_Face)t42size->face; + FT_Error error; + FT_Activate_Size( size->ttsize ); + error = FT_Select_Size( face->ttf_face, (FT_Int)strike_index ); + if ( !error ) + t42size->metrics = face->ttf_face->size->metrics; + return error; + } + FT_LOCAL_DEF( void ) +/* T42_Size */ + T42_Size_Done( FT_Size t42size ) + { + T42_Size size = (T42_Size)t42size; + FT_Face face = t42size->face; + T42_Face t42face = (T42_Face)face; + FT_ListNode node; + node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize ); + if ( node ) + { + FT_Done_Size( size->ttsize ); + size->ttsize = NULL; + } + } + FT_LOCAL_DEF( FT_Error ) +/* T42_GlyphSlot */ + T42_GlyphSlot_Init( FT_GlyphSlot t42slot ) + { + T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + FT_Face face = t42slot->face; + T42_Face t42face = (T42_Face)face; + FT_GlyphSlot ttslot; + FT_Error error = T42_Err_Ok; + if ( face->glyph == NULL ) + { +/* First glyph slot for this face */ + slot->ttslot = t42face->ttf_face->glyph; + } + else + { + error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); + slot->ttslot = ttslot; + } + return error; + } + FT_LOCAL_DEF( void ) +/* T42_GlyphSlot */ + T42_GlyphSlot_Done( FT_GlyphSlot t42slot ) + { + T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + FT_Done_GlyphSlot( slot->ttslot ); + } + static void + t42_glyphslot_clear( FT_GlyphSlot slot ) + { +/* free bitmap if needed */ + ft_glyphslot_free_bitmap( slot ); +/* clear all public fields in the glyph slot */ + FT_ZERO( &slot->metrics ); + FT_ZERO( &slot->outline ); + FT_ZERO( &slot->bitmap ); + slot->bitmap_left = 0; + slot->bitmap_top = 0; + slot->num_subglyphs = 0; + slot->subglyphs = 0; + slot->control_data = 0; + slot->control_len = 0; + slot->other = 0; + slot->format = FT_GLYPH_FORMAT_NONE; + slot->linearHoriAdvance = 0; + slot->linearVertAdvance = 0; + } + FT_LOCAL_DEF( FT_Error ) + T42_GlyphSlot_Load( FT_GlyphSlot glyph, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_Error error; + T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph; + T42_Size t42size = (T42_Size)size; + FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; + t42_glyphslot_clear( t42slot->ttslot ); + error = ttclazz->load_glyph( t42slot->ttslot, + t42size->ttsize, + glyph_index, + load_flags | FT_LOAD_NO_BITMAP ); + if ( !error ) + { + glyph->metrics = t42slot->ttslot->metrics; + glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance; + glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance; + glyph->format = t42slot->ttslot->format; + glyph->outline = t42slot->ttslot->outline; + glyph->bitmap = t42slot->ttslot->bitmap; + glyph->bitmap_left = t42slot->ttslot->bitmap_left; + glyph->bitmap_top = t42slot->ttslot->bitmap_top; + glyph->num_subglyphs = t42slot->ttslot->num_subglyphs; + glyph->subglyphs = t42slot->ttslot->subglyphs; + glyph->control_data = t42slot->ttslot->control_data; + glyph->control_len = t42slot->ttslot->control_len; + } + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* t42parse.c */ +/* */ +/* Type 42 font parser (body). */ +/* */ +/* Copyright 2002-2012 by */ +/* Roberto Alameda. */ +/* */ +/* 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 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 trace_t42 + static void + t42_parse_font_matrix( T42_Face face, + T42_Loader loader ); + static void + t42_parse_encoding( T42_Face face, + T42_Loader loader ); + static void + t42_parse_charstrings( T42_Face face, + T42_Loader loader ); + static void + t42_parse_sfnts( T42_Face face, + T42_Loader loader ); +/* as Type42 fonts have no Private dict, */ +/* we set the last argument of T1_FIELD_XXX to 0 */ + static const + T1_FieldRec t42_keywords[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FontInfo +#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 T1_FontRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FONT_DICT + T1_FIELD_KEY ( "FontName", font_name, 0 ) + T1_FIELD_NUM ( "PaintType", paint_type, 0 ) + T1_FIELD_NUM ( "FontType", font_type, 0 ) + T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_BBox +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BBOX + T1_FIELD_BBOX("FontBBox", xMin, 0 ) + T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 ) + T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 ) + T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 ) + T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 ) + { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + }; +#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) +#define T1_Done_Table( p ) \ + do \ + { \ + if ( (p)->funcs.done ) \ + (p)->funcs.done( p ); \ + } while ( 0 ) +#define T1_Release_Table( p ) \ + do \ + { \ + if ( (p)->funcs.release ) \ + (p)->funcs.release( p ); \ + } while ( 0 ) +#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) +#define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) +#define T1_ToInt( p ) \ + (p)->root.funcs.to_int( &(p)->root ) +#define T1_ToBytes( p, b, m, n, d ) \ + (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) +#define T1_ToFixedArray( p, m, f, t ) \ + (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) +#define T1_ToToken( p, t ) \ + (p)->root.funcs.to_token( &(p)->root, t ) +#define T1_Load_Field( p, f, o, m, pf ) \ + (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) +#define T1_Load_Field_Table( p, f, o, m, pf ) \ + (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) +/********************* Parsing Functions ******************/ + FT_LOCAL_DEF( FT_Error ) + t42_parser_init( T42_Parser parser, + FT_Stream stream, + FT_Memory memory, + PSAux_Service psaux ) + { + FT_Error error = T42_Err_Ok; + FT_Long size; + psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); + parser->stream = stream; + parser->base_len = 0; + parser->base_dict = 0; + parser->in_memory = 0; +/*******************************************************************/ +/* */ +/* Here a short summary of what is going on: */ +/* */ +/* When creating a new Type 42 parser, we try to locate and load */ +/* the base dictionary, loading the whole font into memory. */ +/* */ +/* When `loading' the base dictionary, we only set up pointers */ +/* in the case of a memory-based stream. Otherwise, we allocate */ +/* and load the base dictionary in it. */ +/* */ +/* parser->in_memory is set if we have a memory stream. */ +/* */ + if ( FT_STREAM_SEEK( 0L ) || + FT_FRAME_ENTER( 17 ) ) + goto Exit; + if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) + { + FT_TRACE2(( " not a Type42 font\n" )); + error = T42_Err_Unknown_File_Format; + } + FT_FRAME_EXIT(); + if ( error || FT_STREAM_SEEK( 0 ) ) + goto Exit; + size = stream->size; +/* now, try to load `size' bytes of the `base' dictionary we */ +/* found previously */ +/* if it is a memory-based resource, set up pointers */ + if ( !stream->read ) + { + parser->base_dict = (FT_Byte*)stream->base + stream->pos; + parser->base_len = size; + parser->in_memory = 1; +/* check that the `size' field is valid */ + if ( FT_STREAM_SKIP( size ) ) + goto Exit; + } + else + { +/* read segment in memory */ + if ( FT_ALLOC( parser->base_dict, size ) || + FT_STREAM_READ( parser->base_dict, size ) ) + goto Exit; + parser->base_len = size; + } + parser->root.base = parser->base_dict; + parser->root.cursor = parser->base_dict; + parser->root.limit = parser->root.cursor + parser->base_len; + Exit: + if ( error && !parser->in_memory ) + FT_FREE( parser->base_dict ); + return error; + } + FT_LOCAL_DEF( void ) + t42_parser_done( T42_Parser parser ) + { + FT_Memory memory = parser->root.memory; +/* free the base dictionary only when we have a disk stream */ + if ( !parser->in_memory ) + FT_FREE( parser->base_dict ); + parser->root.funcs.done( &parser->root ); + } + static int + t42_is_space( FT_Byte c ) + { + return ( c == ' ' || c == '\t' || + c == '\r' || c == '\n' || c == '\f' || + c == '\0' ); + } + static void + t42_parse_font_matrix( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Matrix* matrix = &face->type1.font_matrix; + FT_Vector* offset = &face->type1.font_offset; + FT_Face root = (FT_Face)&face->root; + FT_Fixed temp[6]; + FT_Fixed temp_scale; + (void)T1_ToFixedArray( parser, 6, temp, 3 ); + temp_scale = FT_ABS( temp[3] ); +/* Set Units per EM based on FontMatrix values. We set the value to */ +/* 1000 / temp_scale, because temp_scale was already multiplied by */ +/* 1000 (in t1_tofixed, from psobjs.c). */ + root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); +/* we need to scale the values by 1.0/temp_scale */ + if ( temp_scale != 0x10000L ) + { + 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] = 0x10000L; + } + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; +/* note that the offsets must be expressed in integer font units */ + offset->x = temp[4] >> 16; + offset->y = temp[5] >> 16; + } + static void + t42_parse_encoding( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + PSAux_Service psaux = (PSAux_Service)face->psaux; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + { + FT_ERROR(( "t42_parse_encoding: out of bounds\n" )); + parser->root.error = T42_Err_Invalid_File_Format; + return; + } +/* if we have a number or `[', the encoding is an array, */ +/* and we must load it now */ + if ( ft_isdigit( *cur ) || *cur == '[' ) + { + T1_Encoding encode = &face->type1.encoding; + FT_UInt count, n; + PS_Table char_table = &loader->encoding_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + FT_Bool only_immediates = 0; +/* read the number of entries in the encoding; should be 256 */ + if ( *cur == '[' ) + { + count = 256; + only_immediates = 1; + parser->root.cursor++; + } + else + count = (FT_UInt)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + return; +/* we use a T1_Table to store our charnames */ + loader->num_chars = encode->num_chars = count; + if ( FT_NEW_ARRAY( encode->char_index, count ) || + FT_NEW_ARRAY( encode->char_name, count ) || + FT_SET_ERROR( psaux->ps_table_funcs->init( + char_table, count, memory ) ) ) + { + parser->root.error = error; + return; + } +/* We need to `zero' out encoding_table.elements */ + for ( n = 0; n < count; n++ ) + { + char* notdef = (char *)".notdef"; + T1_Add_Table( char_table, n, notdef, 8 ); + } +/* Now we need to read records of the form */ +/* */ +/* ... charcode /charname ... */ +/* */ +/* for each entry in our table. */ +/* */ +/* We simply look for a number followed by an immediate */ +/* name. Note that this ignores correctly the sequence */ +/* that is often seen in type42 fonts: */ +/* */ +/* 0 1 255 { 1 index exch /.notdef put } for dup */ +/* */ +/* used to clean the encoding array before anything else. */ +/* */ +/* Alternatively, if the array is directly given as */ +/* */ +/* /Encoding [ ... ] */ +/* */ +/* we only read immediates. */ + n = 0; + T1_Skip_Spaces( parser ); + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; +/* we stop when we encounter `def' or `]' */ + if ( *cur == 'd' && cur + 3 < limit ) + { + if ( cur[1] == 'e' && + cur[2] == 'f' && + t42_is_space( cur[3] ) ) + { + FT_TRACE6(( "encoding end\n" )); + cur += 3; + break; + } + } + if ( *cur == ']' ) + { + FT_TRACE6(( "encoding end\n" )); + cur++; + break; + } +/* check whether we have found an entry */ + if ( ft_isdigit( *cur ) || only_immediates ) + { + FT_Int charcode; + if ( only_immediates ) + charcode = n; + else + { + charcode = (FT_Int)T1_ToInt( parser ); + T1_Skip_Spaces( parser ); + } + cur = parser->root.cursor; + if ( *cur == '/' && cur + 2 < limit && n < count ) + { + FT_PtrDist len; + cur++; + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + len = parser->root.cursor - cur; + parser->root.error = T1_Add_Table( char_table, charcode, + cur, len + 1 ); + if ( parser->root.error ) + return; + char_table->elements[charcode][len] = '\0'; + n++; + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + } + T1_Skip_Spaces( parser ); + } + face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; + } +/* Otherwise, we should have either `StandardEncoding', */ +/* `ExpertEncoding', or `ISOLatin1Encoding' */ + else + { + if ( cur + 17 < limit && + ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + else if ( cur + 15 < limit && + ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + else if ( cur + 18 < limit && + ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) + face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + else + { + FT_ERROR(( "t42_parse_encoding: invalid token\n" )); + parser->root.error = T42_Err_Invalid_File_Format; + } + } + } + typedef enum T42_Load_Status_ + { + BEFORE_START, + BEFORE_TABLE_DIR, + OTHER_TABLES + } T42_Load_Status; + static void + t42_parse_sfnts( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + FT_Memory memory = parser->root.memory; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_Error error; + FT_Int num_tables = 0; + FT_ULong count, ttf_size = 0; + FT_Long n, string_size, old_string_size, real_size; + FT_Byte* string_buf = NULL; + FT_Bool allocated = 0; + T42_Load_Status status; +/* The format is */ +/* */ +/* /sfnts [ <hexstring> <hexstring> ... ] def */ +/* */ +/* or */ +/* */ +/* /sfnts [ */ +/* <num_bin_bytes> RD <binary data> */ +/* <num_bin_bytes> RD <binary data> */ +/* ... */ +/* ] def */ +/* */ +/* with exactly one space after the `RD' token. */ + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) + { + FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + T1_Skip_Spaces( parser ); + status = BEFORE_START; + string_size = 0; + old_string_size = 0; + count = 0; + while ( parser->root.cursor < limit ) + { + cur = parser->root.cursor; + if ( *cur == ']' ) + { + parser->root.cursor++; + goto Exit; + } + else if ( *cur == '<' ) + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; +/* don't include delimiters */ + string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); + if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) + goto Fail; + allocated = 1; + parser->root.cursor = cur; + (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); + old_string_size = string_size; + string_size = real_size; + } + else if ( ft_isdigit( *cur ) ) + { + if ( allocated ) + { + FT_ERROR(( "t42_parse_sfnts: " + "can't handle mixed binary and hex strings\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + string_size = T1_ToInt( parser ); + if ( string_size < 0 ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } +/* `RD' */ + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; +/* one space after `RD' */ + string_buf = parser->root.cursor + 1; + if ( limit - parser->root.cursor < string_size ) + { + FT_ERROR(( "t42_parse_sfnts: too many binary data\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + else + parser->root.cursor += string_size + 1; + } + if ( !string_buf ) + { + FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } +/* A string can have a trailing zero (odd) byte for padding. */ +/* Ignore it. */ + if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 ) + string_size--; + if ( !string_size ) + { + FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + for ( n = 0; n < string_size; n++ ) + { + switch ( status ) + { + case BEFORE_START: +/* load offset table, 12 bytes */ + if ( count < 12 ) + { + face->ttf_data[count++] = string_buf[n]; + continue; + } + else + { + num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; + status = BEFORE_TABLE_DIR; + ttf_size = 12 + 16 * num_tables; + if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) + goto Fail; + } +/* fall through */ + case BEFORE_TABLE_DIR: +/* the offset table is read; read the table directory */ + if ( count < ttf_size ) + { + face->ttf_data[count++] = string_buf[n]; + continue; + } + else + { + int i; + FT_ULong len; + for ( i = 0; i < num_tables; i++ ) + { + FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; + len = FT_PEEK_ULONG( p ); +/* Pad to a 4-byte boundary length */ + ttf_size += ( len + 3 ) & ~3; + } + status = OTHER_TABLES; + face->ttf_size = ttf_size; +/* there are no more than 256 tables, so no size check here */ + if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, + ttf_size + 1 ) ) + goto Fail; + } +/* fall through */ + case OTHER_TABLES: +/* all other tables are just copied */ + if ( count >= ttf_size ) + { + FT_ERROR(( "t42_parse_sfnts: too many binary data\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + face->ttf_data[count++] = string_buf[n]; + } + } + T1_Skip_Spaces( parser ); + } +/* if control reaches this point, the format was not valid */ + error = T42_Err_Invalid_File_Format; + Fail: + parser->root.error = error; + Exit: + if ( allocated ) + FT_FREE( string_buf ); + } + static void + t42_parse_charstrings( T42_Face face, + T42_Loader loader ) + { + T42_Parser parser = &loader->parser; + PS_Table code_table = &loader->charstrings; + PS_Table name_table = &loader->glyph_names; + PS_Table swap_table = &loader->swap_table; + FT_Memory memory = parser->root.memory; + FT_Error error; + PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_Byte* cur; + FT_Byte* limit = parser->root.limit; + FT_UInt n; + FT_UInt notdef_index = 0; + FT_Byte notdef_found = 0; + T1_Skip_Spaces( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + if ( ft_isdigit( *parser->root.cursor ) ) + { + loader->num_glyphs = (FT_UInt)T1_ToInt( parser ); + if ( parser->root.error ) + return; + } + else if ( *parser->root.cursor == '<' ) + { +/* We have `<< ... >>'. Count the number of `/' in the dictionary */ +/* to get its size. */ + FT_UInt count = 0; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + while ( parser->root.cursor < limit ) + { + if ( *parser->root.cursor == '/' ) + count++; + else if ( *parser->root.cursor == '>' ) + { + loader->num_glyphs = count; +/* rewind */ + parser->root.cursor = cur; + break; + } + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + T1_Skip_Spaces( parser ); + } + } + else + { + FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } +/* initialize tables */ + error = psaux->ps_table_funcs->init( code_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; + error = psaux->ps_table_funcs->init( name_table, + loader->num_glyphs, + memory ); + if ( error ) + goto Fail; +/* Initialize table for swapping index notdef_index and */ +/* index 0 names and codes (if necessary). */ + error = psaux->ps_table_funcs->init( swap_table, 4, memory ); + if ( error ) + goto Fail; + n = 0; + for (;;) + { +/* The format is simple: */ +/* `/glyphname' + index [+ def] */ + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + if ( cur >= limit ) + break; +/* We stop when we find an `end' keyword or '>' */ + if ( *cur == 'e' && + cur + 3 < limit && + cur[1] == 'n' && + cur[2] == 'd' && + t42_is_space( cur[3] ) ) + break; + if ( *cur == '>' ) + break; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + return; + if ( *cur == '/' ) + { + FT_PtrDist len; + if ( cur + 1 >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } +/* skip `/' */ + cur++; + len = parser->root.cursor - cur; + error = T1_Add_Table( name_table, n, cur, len + 1 ); + if ( error ) + goto Fail; +/* add a trailing zero to the name table */ + name_table->elements[n][len] = '\0'; +/* record index of /.notdef */ + if ( *cur == '.' && + ft_strcmp( ".notdef", + (const char*)(name_table->elements[n]) ) == 0 ) + { + notdef_index = n; + notdef_found = 1; + } + T1_Skip_Spaces( parser ); + cur = parser->root.cursor; + (void)T1_ToInt( parser ); + if ( parser->root.cursor >= limit ) + { + FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } + len = parser->root.cursor - cur; + error = T1_Add_Table( code_table, n, cur, len + 1 ); + if ( error ) + goto Fail; + code_table->elements[n][len] = '\0'; + n++; + if ( n >= loader->num_glyphs ) + break; + } + } + loader->num_glyphs = n; + if ( !notdef_found ) + { + FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); + error = T42_Err_Invalid_File_Format; + goto Fail; + } +/* if /.notdef does not occupy index 0, do our magic. */ + if ( ft_strcmp( (const char*)".notdef", + (const char*)name_table->elements[0] ) ) + { +/* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ +/* name and code entries to swap_table. Then place notdef_index */ +/* name and code entries into swap_table. Then swap name and code */ +/* entries at indices notdef_index and 0 using values stored in */ +/* swap_table. */ +/* Index 0 name */ + error = T1_Add_Table( swap_table, 0, + name_table->elements[0], + name_table->lengths [0] ); + if ( error ) + goto Fail; +/* Index 0 code */ + error = T1_Add_Table( swap_table, 1, + code_table->elements[0], + code_table->lengths [0] ); + if ( error ) + goto Fail; +/* Index notdef_index name */ + error = T1_Add_Table( swap_table, 2, + name_table->elements[notdef_index], + name_table->lengths [notdef_index] ); + if ( error ) + goto Fail; +/* Index notdef_index code */ + error = T1_Add_Table( swap_table, 3, + code_table->elements[notdef_index], + code_table->lengths [notdef_index] ); + if ( error ) + goto Fail; + error = T1_Add_Table( name_table, notdef_index, + swap_table->elements[0], + swap_table->lengths [0] ); + if ( error ) + goto Fail; + error = T1_Add_Table( code_table, notdef_index, + swap_table->elements[1], + swap_table->lengths [1] ); + if ( error ) + goto Fail; + error = T1_Add_Table( name_table, 0, + swap_table->elements[2], + swap_table->lengths [2] ); + if ( error ) + goto Fail; + error = T1_Add_Table( code_table, 0, + swap_table->elements[3], + swap_table->lengths [3] ); + if ( error ) + goto Fail; + } + return; + Fail: + parser->root.error = error; + } + static FT_Error + t42_load_keyword( T42_Face face, + T42_Loader loader, + T1_Field field ) + { + FT_Error error; + void* dummy_object; + void** objects; + FT_UInt max_objects = 0; +/* if the keyword has a dedicated callback, call it */ + if ( field->type == T1_FIELD_TYPE_CALLBACK ) + { + field->reader( (FT_Face)face, loader ); + error = loader->parser.root.error; + goto Exit; + } +/* now the keyword is either a simple field or a table of fields; */ +/* we are now going to take care of it */ + switch ( field->location ) + { + case T1_FIELD_LOCATION_FONT_INFO: + dummy_object = &face->type1.font_info; + break; + case T1_FIELD_LOCATION_FONT_EXTRA: + dummy_object = &face->type1.font_extra; + break; + case T1_FIELD_LOCATION_BBOX: + dummy_object = &face->type1.font_bbox; + break; + default: + dummy_object = &face->type1; + } + objects = &dummy_object; + if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || + field->type == T1_FIELD_TYPE_FIXED_ARRAY ) + error = T1_Load_Field_Table( &loader->parser, field, + objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, field, + objects, max_objects, 0 ); + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + t42_parse_dict( T42_Face face, + T42_Loader loader, + FT_Byte* base, + FT_Long size ) + { + T42_Parser parser = &loader->parser; + FT_Byte* limit; + FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / + sizeof ( t42_keywords[0] ) ); + parser->root.cursor = base; + parser->root.limit = base + size; + parser->root.error = T42_Err_Ok; + limit = parser->root.limit; + T1_Skip_Spaces( parser ); + while ( parser->root.cursor < limit ) + { + FT_Byte* cur; + cur = parser->root.cursor; +/* look for `FontDirectory' which causes problems for some fonts */ + if ( *cur == 'F' && cur + 25 < limit && + ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + FT_Byte* cur2; +/* skip the `FontDirectory' keyword */ + T1_Skip_PS_Token( parser ); + T1_Skip_Spaces ( parser ); + cur = cur2 = parser->root.cursor; +/* look up the `known' keyword */ + while ( cur < limit ) + { + if ( *cur == 'k' && cur + 5 < limit && + ft_strncmp( (char*)cur, "known", 5 ) == 0 ) + break; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + T1_Skip_Spaces ( parser ); + cur = parser->root.cursor; + } + if ( cur < limit ) + { + T1_TokenRec token; +/* skip the `known' keyword and the token following it */ + T1_Skip_PS_Token( parser ); + T1_ToToken( parser, &token ); +/* if the last token was an array, skip it! */ + if ( token.type == T1_TOKEN_TYPE_ARRAY ) + cur2 = parser->root.cursor; + } + parser->root.cursor = cur2; + } +/* look for immediates */ + else if ( *cur == '/' && cur + 2 < limit ) + { + FT_PtrDist len; + cur++; + parser->root.cursor = cur; + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + len = parser->root.cursor - cur; + if ( len > 0 && len < 22 && parser->root.cursor < limit ) + { + int i; +/* now compare the immediate name to the keyword table */ +/* loop through all known keywords */ + for ( i = 0; i < n_keywords; i++ ) + { + T1_Field keyword = (T1_Field)&t42_keywords[i]; + FT_Byte *name = (FT_Byte*)keyword->ident; + if ( !name ) + continue; + if ( cur[0] == name[0] && + len == (FT_PtrDist)ft_strlen( (const char *)name ) && + ft_memcmp( cur, name, len ) == 0 ) + { +/* we found it -- run the parsing callback! */ + parser->root.error = t42_load_keyword( face, + loader, + keyword ); + if ( parser->root.error ) + return parser->root.error; + break; + } + } + } + } + else + { + T1_Skip_PS_Token( parser ); + if ( parser->root.error ) + goto Exit; + } + T1_Skip_Spaces( parser ); + } + Exit: + return parser->root.error; + } + FT_LOCAL_DEF( void ) + t42_loader_init( T42_Loader loader, + T42_Face face ) + { + FT_UNUSED( face ); + FT_MEM_ZERO( loader, sizeof ( *loader ) ); + loader->num_glyphs = 0; + loader->num_chars = 0; +/* initialize the tables -- simply set their `init' field to 0 */ + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + } + FT_LOCAL_DEF( void ) + t42_loader_done( T42_Loader loader ) + { + T42_Parser parser = &loader->parser; +/* finalize tables */ + T1_Release_Table( &loader->encoding_table ); + T1_Release_Table( &loader->charstrings ); + T1_Release_Table( &loader->glyph_names ); + T1_Release_Table( &loader->swap_table ); +/* finalize parser */ + t42_parser_done( parser ); + } +/* END */ +/***************************************************************************/ +/* */ +/* t42drivr.c */ +/* */ +/* High-level Type 42 driver interface (body). */ +/* */ +/* Copyright 2002-2004, 2006, 2007, 2009, 2011 by Roberto Alameda. */ +/* */ +/* 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 driver implements Type42 fonts as described in the */ +/* Technical Note #5012 from Adobe, with these limitations: */ +/* */ +/* 1) CID Fonts are not currently supported. */ +/* 2) Incremental fonts making use of the GlyphDirectory keyword */ +/* will be loaded, but the rendering will be using the TrueType */ +/* tables. */ +/* 3) As for Type1 fonts, CDevProc is not supported. */ +/* 4) The Metrics dictionary is not supported. */ +/* 5) AFM metrics are not supported. */ +/* */ +/* In other words, this driver supports Type42 fonts derived from */ +/* TrueType fonts in a non-CID manner, as done by usual conversion */ +/* programs. */ +/* */ +/*************************************************************************/ +/***************************************************************************/ +/* */ +/* t42drivr.h */ +/* */ +/* High-level Type 42 driver interface (specification). */ +/* */ +/* Copyright 2002 by Roberto Alameda. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __T42DRIVR_H__ +FT_BEGIN_HEADER + FT_EXPORT_VAR( const FT_Driver_ClassRec ) t42_driver_class; +FT_END_HEADER +/* END */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t42 +/* + * + * GLYPH DICT SERVICE + * + */ + static FT_Error + t42_get_glyph_name( T42_Face face, + FT_UInt glyph_index, + FT_Pointer buffer, + FT_UInt buffer_max ) + { + FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max ); + return T42_Err_Ok; + } + static FT_UInt + t42_get_name_index( T42_Face face, + FT_String* glyph_name ) + { + FT_Int i; + FT_String* gname; + for ( i = 0; i < face->type1.num_glyphs; i++ ) + { + gname = face->type1.glyph_names[i]; + if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) ) + return (FT_UInt)ft_atol( (const char *)face->type1.charstrings[i] ); + } + return 0; + } + static const FT_Service_GlyphDictRec t42_service_glyph_dict = + { + (FT_GlyphDict_GetNameFunc) t42_get_glyph_name, + (FT_GlyphDict_NameIndexFunc)t42_get_name_index + }; +/* + * + * POSTSCRIPT NAME SERVICE + * + */ + static const char* + t42_get_ps_font_name( T42_Face face ) + { + return (const char*)face->type1.font_name; + } + static const FT_Service_PsFontNameRec t42_service_ps_font_name = + { + (FT_PsName_GetFunc)t42_get_ps_font_name + }; +/* + * + * POSTSCRIPT INFO SERVICE + * + */ + static FT_Error + t42_ps_get_font_info( FT_Face face, + PS_FontInfoRec* afont_info ) + { + *afont_info = ((T42_Face)face)->type1.font_info; + return T42_Err_Ok; + } + static FT_Error + t42_ps_get_font_extra( FT_Face face, + PS_FontExtraRec* afont_extra ) + { + *afont_extra = ((T42_Face)face)->type1.font_extra; + return T42_Err_Ok; + } + static FT_Int + t42_ps_has_glyph_names( FT_Face face ) + { + FT_UNUSED( face ); + return 1; + } + static FT_Error + t42_ps_get_font_private( FT_Face face, + PS_PrivateRec* afont_private ) + { + *afont_private = ((T42_Face)face)->type1.private_dict; + return T42_Err_Ok; + } + static const FT_Service_PsInfoRec t42_service_ps_info = + { + (PS_GetFontInfoFunc) t42_ps_get_font_info, + (PS_GetFontExtraFunc) t42_ps_get_font_extra, + (PS_HasGlyphNamesFunc) t42_ps_has_glyph_names, + (PS_GetFontPrivateFunc)t42_ps_get_font_private, +/* not implemented */ + (PS_GetFontValueFunc) NULL + }; +/* + * + * SERVICE LIST + * + */ + static const FT_ServiceDescRec t42_services[] = + { + { FT_SERVICE_ID_GLYPH_DICT, &t42_service_glyph_dict }, + { FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &t42_service_ps_font_name }, + { FT_SERVICE_ID_POSTSCRIPT_INFO, &t42_service_ps_info }, + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TYPE_42 }, + { NULL, NULL } + }; + FT_CALLBACK_DEF( FT_Module_Interface ) + T42_Get_Interface( FT_Module module, + const FT_String* t42_interface ) + { + FT_UNUSED( module ); + return ft_service_list_lookup( t42_services, t42_interface ); + } + const FT_Driver_ClassRec t42_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_SCALABLE | + FT_MODULE_DRIVER_HAS_HINTER, + sizeof ( T42_DriverRec ), + "type42", + 0x10000L, + 0x20000L, +/* format interface */ + 0, + T42_Driver_Init, + T42_Driver_Done, + T42_Get_Interface, + }, + sizeof ( T42_FaceRec ), + sizeof ( T42_SizeRec ), + sizeof ( T42_GlyphSlotRec ), + T42_Face_Init, + T42_Face_Done, + T42_Size_Init, + T42_Size_Done, + T42_GlyphSlot_Init, + T42_GlyphSlot_Done, + T42_GlyphSlot_Load, +/* FT_Face_GetKerningFunc */ + 0, +/* FT_Face_AttachFunc */ + 0, +/* FT_Face_GetAdvancesFunc */ + 0, + T42_Size_Request, + T42_Size_Select + }; +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* winfnt.c */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2004, 2006-2012 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* Copyright 2003 Huw D M Davies for Codeweavers */ +/* Copyright 2007 Dmitry Timoshkov for Codeweavers */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* winfnt.h */ +/* */ +/* FreeType font driver for Windows FNT/FON files */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2007 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* Copyright 2007 Dmitry Timoshkov for Codeweavers */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __WINFNT_H__ +FT_BEGIN_HEADER + typedef struct WinMZ_HeaderRec_ + { + FT_UShort magic; +/* skipped content */ + FT_UShort lfanew; + } WinMZ_HeaderRec; + typedef struct WinNE_HeaderRec_ + { + FT_UShort magic; +/* skipped content */ + FT_UShort resource_tab_offset; + FT_UShort rname_tab_offset; + } WinNE_HeaderRec; + typedef struct WinPE32_HeaderRec_ + { + FT_ULong magic; + FT_UShort machine; + FT_UShort number_of_sections; +/* skipped content */ + FT_UShort size_of_optional_header; +/* skipped content */ + FT_UShort magic32; +/* skipped content */ + FT_ULong rsrc_virtual_address; + FT_ULong rsrc_size; +/* skipped content */ + } WinPE32_HeaderRec; + typedef struct WinPE32_SectionRec_ + { + FT_Byte name[8]; +/* skipped content */ + FT_ULong virtual_address; + FT_ULong size_of_raw_data; + FT_ULong pointer_to_raw_data; +/* skipped content */ + } WinPE32_SectionRec; + typedef struct WinPE_RsrcDirRec_ + { + FT_ULong characteristics; + FT_ULong time_date_stamp; + FT_UShort major_version; + FT_UShort minor_version; + FT_UShort number_of_named_entries; + FT_UShort number_of_id_entries; + } WinPE_RsrcDirRec; + typedef struct WinPE_RsrcDirEntryRec_ + { + FT_ULong name; + FT_ULong offset; + } WinPE_RsrcDirEntryRec; + typedef struct WinPE_RsrcDataEntryRec_ + { + FT_ULong offset_to_data; + FT_ULong size; + FT_ULong code_page; + FT_ULong reserved; + } WinPE_RsrcDataEntryRec; + typedef struct WinNameInfoRec_ + { + FT_UShort offset; + FT_UShort length; + FT_UShort flags; + FT_UShort id; + FT_UShort handle; + FT_UShort usage; + } WinNameInfoRec; + typedef struct WinResourceInfoRec_ + { + FT_UShort type_id; + FT_UShort count; + } WinResourceInfoRec; +#define WINFNT_MZ_MAGIC 0x5A4D +#define WINFNT_NE_MAGIC 0x454E +#define WINFNT_PE_MAGIC 0x4550 + typedef struct FNT_FontRec_ + { + FT_ULong offset; + FT_WinFNT_HeaderRec header; + FT_Byte* fnt_frame; + FT_ULong fnt_size; + FT_String* family_name; + } FNT_FontRec, *FNT_Font; + typedef struct FNT_FaceRec_ + { + FT_FaceRec root; + FNT_Font font; + FT_CharMap charmap_handle; +/* a single charmap per face */ + FT_CharMapRec charmap; + } FNT_FaceRec, *FNT_Face; + FT_EXPORT_VAR( const FT_Driver_ClassRec ) winfnt_driver_class; +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* fnterrs.h */ +/* */ +/* Win FNT/FON error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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. */ +/* */ +/*************************************************************************/ +#define __FNTERRS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX FNT_Err_ +#define FT_ERR_BASE FT_Mod_Err_Winfonts +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_winfnt + static const FT_Frame_Field winmz_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinMZ_HeaderRec + FT_FRAME_START( 64 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 29 * 2 ), + FT_FRAME_ULONG_LE ( lfanew ), + FT_FRAME_END + }; + static const FT_Frame_Field winne_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinNE_HeaderRec + FT_FRAME_START( 40 ), + FT_FRAME_USHORT_LE ( magic ), + FT_FRAME_SKIP_BYTES( 34 ), + FT_FRAME_USHORT_LE ( resource_tab_offset ), + FT_FRAME_USHORT_LE ( rname_tab_offset ), + FT_FRAME_END + }; + static const FT_Frame_Field winpe32_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_HeaderRec + FT_FRAME_START( 248 ), +/* PE00 */ + FT_FRAME_ULONG_LE ( magic ), +/* 0x014c - i386 */ + FT_FRAME_USHORT_LE ( machine ), + FT_FRAME_USHORT_LE ( number_of_sections ), + FT_FRAME_SKIP_BYTES( 12 ), + FT_FRAME_USHORT_LE ( size_of_optional_header ), + FT_FRAME_SKIP_BYTES( 2 ), +/* 0x10b */ + FT_FRAME_USHORT_LE ( magic32 ), + FT_FRAME_SKIP_BYTES( 110 ), + FT_FRAME_ULONG_LE ( rsrc_virtual_address ), + FT_FRAME_ULONG_LE ( rsrc_size ), + FT_FRAME_SKIP_BYTES( 104 ), + FT_FRAME_END + }; + static const FT_Frame_Field winpe32_section_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE32_SectionRec + FT_FRAME_START( 40 ), + FT_FRAME_BYTES ( name, 8 ), + FT_FRAME_SKIP_BYTES( 4 ), + FT_FRAME_ULONG_LE ( virtual_address ), + FT_FRAME_ULONG_LE ( size_of_raw_data ), + FT_FRAME_ULONG_LE ( pointer_to_raw_data ), + FT_FRAME_SKIP_BYTES( 16 ), + FT_FRAME_END + }; + static const FT_Frame_Field winpe_rsrc_dir_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirRec + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE ( characteristics ), + FT_FRAME_ULONG_LE ( time_date_stamp ), + FT_FRAME_USHORT_LE( major_version ), + FT_FRAME_USHORT_LE( minor_version ), + FT_FRAME_USHORT_LE( number_of_named_entries ), + FT_FRAME_USHORT_LE( number_of_id_entries ), + FT_FRAME_END + }; + static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDirEntryRec + FT_FRAME_START( 8 ), + FT_FRAME_ULONG_LE( name ), + FT_FRAME_ULONG_LE( offset ), + FT_FRAME_END + }; + static const FT_Frame_Field winpe_rsrc_data_entry_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WinPE_RsrcDataEntryRec + FT_FRAME_START( 16 ), + FT_FRAME_ULONG_LE( offset_to_data ), + FT_FRAME_ULONG_LE( size ), + FT_FRAME_ULONG_LE( code_page ), + FT_FRAME_ULONG_LE( reserved ), + FT_FRAME_END + }; + static const FT_Frame_Field winfnt_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE FT_WinFNT_HeaderRec + FT_FRAME_START( 148 ), + FT_FRAME_USHORT_LE( version ), + FT_FRAME_ULONG_LE ( file_size ), + FT_FRAME_BYTES ( copyright, 60 ), + FT_FRAME_USHORT_LE( file_type ), + FT_FRAME_USHORT_LE( nominal_point_size ), + FT_FRAME_USHORT_LE( vertical_resolution ), + FT_FRAME_USHORT_LE( horizontal_resolution ), + FT_FRAME_USHORT_LE( ascent ), + FT_FRAME_USHORT_LE( internal_leading ), + FT_FRAME_USHORT_LE( external_leading ), + FT_FRAME_BYTE ( italic ), + FT_FRAME_BYTE ( underline ), + FT_FRAME_BYTE ( strike_out ), + FT_FRAME_USHORT_LE( weight ), + FT_FRAME_BYTE ( charset ), + FT_FRAME_USHORT_LE( pixel_width ), + FT_FRAME_USHORT_LE( pixel_height ), + FT_FRAME_BYTE ( pitch_and_family ), + FT_FRAME_USHORT_LE( avg_width ), + FT_FRAME_USHORT_LE( max_width ), + FT_FRAME_BYTE ( first_char ), + FT_FRAME_BYTE ( last_char ), + FT_FRAME_BYTE ( default_char ), + FT_FRAME_BYTE ( break_char ), + FT_FRAME_USHORT_LE( bytes_per_row ), + FT_FRAME_ULONG_LE ( device_offset ), + FT_FRAME_ULONG_LE ( face_name_offset ), + FT_FRAME_ULONG_LE ( bits_pointer ), + FT_FRAME_ULONG_LE ( bits_offset ), + FT_FRAME_BYTE ( reserved ), + FT_FRAME_ULONG_LE ( flags ), + FT_FRAME_USHORT_LE( A_space ), + FT_FRAME_USHORT_LE( B_space ), + FT_FRAME_USHORT_LE( C_space ), + FT_FRAME_ULONG_LE ( color_table_offset ), + FT_FRAME_BYTES ( reserved1, 16 ), + FT_FRAME_END + }; + static void + fnt_font_done( FNT_Face face ) + { + FT_Memory memory = FT_FACE( face )->memory; + FT_Stream stream = FT_FACE( face )->stream; + FNT_Font font = face->font; + if ( !font ) + return; + if ( font->fnt_frame ) + FT_FRAME_RELEASE( font->fnt_frame ); + FT_FREE( font->family_name ); + FT_FREE( font ); + face->font = 0; + } + static FT_Error + fnt_font_load( FNT_Font font, + FT_Stream stream ) + { + FT_Error error; + FT_WinFNT_Header header = &font->header; + FT_Bool new_format; + FT_UInt size; +/* first of all, read the FNT header */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) + goto Exit; +/* check header */ + if ( header->version != 0x200 && + header->version != 0x300 ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FNT_Err_Unknown_File_Format; + goto Exit; + } + new_format = FT_BOOL( font->header.version == 0x300 ); + size = new_format ? 148 : 118; + if ( header->file_size < size ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FNT_Err_Unknown_File_Format; + goto Exit; + } +/* Version 2 doesn't have these fields */ + if ( header->version == 0x200 ) + { + header->flags = 0; + header->A_space = 0; + header->B_space = 0; + header->C_space = 0; + header->color_table_offset = 0; + } + if ( header->file_type & 1 ) + { + FT_TRACE2(( "[can't handle vector FNT fonts]\n" )); + error = FNT_Err_Unknown_File_Format; + goto Exit; + } +/* this is a FNT file/table; extract its frame */ + if ( FT_STREAM_SEEK( font->offset ) || + FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) ) + goto Exit; + Exit: + return error; + } + static FT_Error + fnt_face_get_dll_font( FNT_Face face, + FT_Int face_index ) + { + FT_Error error; + FT_Stream stream = FT_FACE( face )->stream; + FT_Memory memory = FT_FACE( face )->memory; + WinMZ_HeaderRec mz_header; + face->font = 0; +/* does it begin with an MZ header? */ + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) + goto Exit; + error = FNT_Err_Unknown_File_Format; + if ( mz_header.magic == WINFNT_MZ_MAGIC ) + { +/* yes, now look for an NE header in the file */ + WinNE_HeaderRec ne_header; + FT_TRACE2(( "MZ signature found\n" )); + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) + goto Exit; + error = FNT_Err_Unknown_File_Format; + if ( ne_header.magic == WINFNT_NE_MAGIC ) + { +/* good, now look into the resource table for each FNT resource */ + FT_ULong res_offset = mz_header.lfanew + + ne_header.resource_tab_offset; + FT_UShort size_shift; + FT_UShort font_count = 0; + FT_ULong font_offset = 0; + FT_TRACE2(( "NE signature found\n" )); + if ( FT_STREAM_SEEK( res_offset ) || + FT_FRAME_ENTER( ne_header.rname_tab_offset - + ne_header.resource_tab_offset ) ) + goto Exit; + size_shift = FT_GET_USHORT_LE(); + for (;;) + { + FT_UShort type_id, count; + type_id = FT_GET_USHORT_LE(); + if ( !type_id ) + break; + count = FT_GET_USHORT_LE(); + if ( type_id == 0x8008U ) + { + font_count = count; + font_offset = (FT_ULong)( FT_STREAM_POS() + 4 + + ( stream->cursor - stream->limit ) ); + break; + } + stream->cursor += 4 + count * 12; + } + FT_FRAME_EXIT(); + if ( !font_count || !font_offset ) + { + FT_TRACE2(( "this file doesn't contain any FNT resources\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } +/* loading `winfnt_header_fields' needs at least 118 bytes; */ +/* use this as a rough measure to check the expected font size */ + if ( font_count * 118UL > stream->size ) + { + FT_TRACE2(( "invalid number of faces\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + face->root.num_faces = font_count; + if ( face_index >= font_count ) + { + error = FNT_Err_Invalid_Argument; + goto Exit; + } + else if ( face_index < 0 ) + goto Exit; + if ( FT_NEW( face->font ) ) + goto Exit; + if ( FT_STREAM_SEEK( font_offset + face_index * 12 ) || + FT_FRAME_ENTER( 12 ) ) + goto Fail; + face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; + stream->cursor += 8; + FT_FRAME_EXIT(); + error = fnt_font_load( face->font, stream ); + } + else if ( ne_header.magic == WINFNT_PE_MAGIC ) + { + WinPE32_HeaderRec pe32_header; + WinPE32_SectionRec pe32_section; + WinPE_RsrcDirRec root_dir, name_dir, lang_dir; + WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; + WinPE_RsrcDataEntryRec data_entry; + FT_Long root_dir_offset, name_dir_offset, lang_dir_offset; + FT_UShort i, j, k; + FT_TRACE2(( "PE signature found\n" )); + if ( FT_STREAM_SEEK( mz_header.lfanew ) || + FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) + goto Exit; + FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " + "size_of_optional_header %02x\n" + "magic32 %02x, rsrc_virtual_address %04lx, " + "rsrc_size %04lx\n", + pe32_header.magic, pe32_header.machine, + pe32_header.number_of_sections, + pe32_header.size_of_optional_header, + pe32_header.magic32, pe32_header.rsrc_virtual_address, + pe32_header.rsrc_size )); +/* check full signature */ if ( pe32_header.magic != WINFNT_PE_MAGIC || +/* i386 */ pe32_header.machine != 0x014c || +/* FIXME */ pe32_header.size_of_optional_header != 0xe0 || + pe32_header.magic32 != 0x10b ) + { + FT_TRACE2(( "this file has an invalid PE header\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + face->root.num_faces = 0; + for ( i = 0; i < pe32_header.number_of_sections; i++ ) + { + if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, + &pe32_section ) ) + goto Exit; + FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", + pe32_section.name, pe32_section.virtual_address, + pe32_section.size_of_raw_data, + pe32_section.pointer_to_raw_data )); + if ( pe32_header.rsrc_virtual_address == + pe32_section.virtual_address ) + goto Found_rsrc_section; + } + FT_TRACE2(( "this file doesn't contain any resources\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + Found_rsrc_section: + FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) + goto Exit; + root_dir_offset = pe32_section.pointer_to_raw_data; + for ( i = 0; i < root_dir.number_of_named_entries + + root_dir.number_of_id_entries; i++ ) + { + if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry1 ) ) + goto Exit; +/* DataIsDirectory */ if ( !(dir_entry1.offset & 0x80000000UL ) ) + { + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + dir_entry1.offset &= ~0x80000000UL; + name_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry1.offset; + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry1.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) + goto Exit; + for ( j = 0; j < name_dir.number_of_named_entries + + name_dir.number_of_id_entries; j++ ) + { + if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry2 ) ) + goto Exit; +/* DataIsDirectory */ if ( !(dir_entry2.offset & 0x80000000UL ) ) + { + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + dir_entry2.offset &= ~0x80000000UL; + lang_dir_offset = pe32_section.pointer_to_raw_data + + dir_entry2.offset; + if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + + dir_entry2.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) + goto Exit; + for ( k = 0; k < lang_dir.number_of_named_entries + + lang_dir.number_of_id_entries; k++ ) + { + if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, + &dir_entry3 ) ) + goto Exit; +/* DataIsDirectory */ if ( dir_entry2.offset & 0x80000000UL ) + { + error = FNT_Err_Invalid_File_Format; + goto Exit; + } +/* RT_FONT */ if ( dir_entry1.name == 8 ) + { + if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || + FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, + &data_entry ) ) + goto Exit; + FT_TRACE2(( "found font #%lu, offset %04lx, " + "size %04lx, cp %lu\n", + dir_entry2.name, + pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address, + data_entry.size, data_entry.code_page )); + if ( face_index == face->root.num_faces ) + { + if ( FT_NEW( face->font ) ) + goto Exit; + face->font->offset = pe32_section.pointer_to_raw_data + + data_entry.offset_to_data - + pe32_section.virtual_address; + face->font->fnt_size = data_entry.size; + error = fnt_font_load( face->font, stream ); + if ( error ) + { + FT_TRACE2(( "font #%lu load error %d\n", + dir_entry2.name, error )); + goto Fail; + } + else + FT_TRACE2(( "font #%lu successfully loaded\n", + dir_entry2.name )); + } + face->root.num_faces++; + } + } + } + } + } + if ( !face->root.num_faces ) + { + FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } + if ( face_index >= face->root.num_faces ) + { + error = FNT_Err_Invalid_Argument; + goto Exit; + } + } + Fail: + if ( error ) + fnt_font_done( face ); + Exit: + return error; + } + typedef struct FNT_CMapRec_ + { + FT_CMapRec cmap; + FT_UInt32 first; + FT_UInt32 count; + } FNT_CMapRec, *FNT_CMap; + static FT_Error + fnt_cmap_init( FNT_CMap cmap ) + { + FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); + FNT_Font font = face->font; + cmap->first = (FT_UInt32) font->header.first_char; + cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 ); + return 0; + } + static FT_UInt + fnt_cmap_char_index( FNT_CMap cmap, + FT_UInt32 char_code ) + { + FT_UInt gindex = 0; + char_code -= cmap->first; + if ( char_code < cmap->count ) +/* we artificially increase the glyph index; */ +/* FNT_Load_Glyph reverts to the right one */ + gindex = (FT_UInt)( char_code + 1 ); + return gindex; + } + static FT_UInt32 + fnt_cmap_char_next( FNT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + if ( char_code <= cmap->first ) + { + result = cmap->first; + gindex = 1; + } + else + { + char_code -= cmap->first; + if ( char_code < cmap->count ) + { + result = cmap->first + char_code; + gindex = (FT_UInt)( char_code + 1 ); + } + } + *pchar_code = result; + return gindex; + } + static const FT_CMap_ClassRec fnt_cmap_class_rec = + { + sizeof ( FNT_CMapRec ), + (FT_CMap_InitFunc) fnt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)fnt_cmap_char_index, + (FT_CMap_CharNextFunc) fnt_cmap_char_next, + NULL, NULL, NULL, NULL, NULL + }; + static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec; + static void +/* FNT_Face */ + FNT_Face_Done( FT_Face fntface ) + { + FNT_Face face = (FNT_Face)fntface; + FT_Memory memory; + if ( !face ) + return; + memory = FT_FACE_MEMORY( face ); + fnt_font_done( face ); + FT_FREE( fntface->available_sizes ); + fntface->num_fixed_sizes = 0; + } + static FT_Error + FNT_Face_Init( FT_Stream stream, +/* FNT_Face */ + FT_Face fntface, + FT_Int face_index, + FT_Int num_params, + FT_Parameter* params ) + { + FNT_Face face = (FNT_Face)fntface; + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_UNUSED( num_params ); + FT_UNUSED( params ); + FT_TRACE2(( "Windows FNT driver\n" )); +/* try to load font from a DLL */ + error = fnt_face_get_dll_font( face, face_index ); + if ( !error && face_index < 0 ) + goto Exit; + if ( error == FNT_Err_Unknown_File_Format ) + { +/* this didn't work; try to load a single FNT font */ + FNT_Font font; + if ( FT_NEW( face->font ) ) + goto Exit; + fntface->num_faces = 1; + font = face->font; + font->offset = 0; + font->fnt_size = stream->size; + error = fnt_font_load( font, stream ); + if ( !error ) + { + if ( face_index > 0 ) + error = FNT_Err_Invalid_Argument; + else if ( face_index < 0 ) + goto Exit; + } + } + if ( error ) + goto Fail; +/* we now need to fill the root FT_Face fields */ +/* with relevant information */ + { + FT_Face root = FT_FACE( face ); + FNT_Font font = face->font; + FT_PtrDist family_size; + root->face_index = face_index; + root->face_flags = FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; + if ( font->header.avg_width == font->header.max_width ) + root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + if ( font->header.italic ) + root->style_flags |= FT_STYLE_FLAG_ITALIC; + if ( font->header.weight >= 800 ) + root->style_flags |= FT_STYLE_FLAG_BOLD; +/* set up the `fixed_sizes' array */ + if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) + goto Fail; + root->num_fixed_sizes = 1; + { + FT_Bitmap_Size* bsize = root->available_sizes; + FT_UShort x_res, y_res; + bsize->width = font->header.avg_width; + bsize->height = (FT_Short)( + font->header.pixel_height + font->header.external_leading ); + bsize->size = font->header.nominal_point_size << 6; + x_res = font->header.horizontal_resolution; + if ( !x_res ) + x_res = 72; + y_res = font->header.vertical_resolution; + if ( !y_res ) + y_res = 72; + bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 ); + bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem ); +/* + * this reads: + * + * the nominal height is larger than the bbox's height + * + * => nominal_point_size contains incorrect value; + * use pixel_height as the nominal height + */ + if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) ) + { + FT_TRACE2(( "use pixel_height as the nominal height\n" )); + bsize->y_ppem = font->header.pixel_height << 6; + bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res ); + } + bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 ); + bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem ); + } + { + FT_CharMapRec charmap; + charmap.encoding = FT_ENCODING_NONE; +/* initial platform/encoding should indicate unset status? */ + charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; + charmap.encoding_id = TT_APPLE_ID_DEFAULT; + charmap.face = root; + if ( font->header.charset == FT_WinFNT_ID_MAC ) + { + charmap.encoding = FT_ENCODING_APPLE_ROMAN; + charmap.platform_id = TT_PLATFORM_MACINTOSH; +/* charmap.encoding_id = TT_MAC_ID_ROMAN; */ + } + error = FT_CMap_New( fnt_cmap_class, + NULL, + &charmap, + NULL ); + if ( error ) + goto Fail; +/* Select default charmap */ + if ( root->num_charmaps ) + root->charmap = root->charmaps[0]; + } +/* set up remaining flags */ + if ( font->header.last_char < font->header.first_char ) + { + FT_TRACE2(( "invalid number of glyphs\n" )); + error = FNT_Err_Invalid_File_Format; + goto Fail; + } +/* reserve one slot for the .notdef glyph at index 0 */ + root->num_glyphs = font->header.last_char - + font->header.first_char + 1 + 1; + if ( font->header.face_name_offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid family name offset\n" )); + error = FNT_Err_Invalid_File_Format; + goto Fail; + } + family_size = font->header.file_size - font->header.face_name_offset; +/* Some broken fonts don't delimit the face name with a final */ +/* NULL byte -- the frame is erroneously one byte too small. */ +/* We thus allocate one more byte, setting it explicitly to */ +/* zero. */ + if ( FT_ALLOC( font->family_name, family_size + 1 ) ) + goto Fail; + FT_MEM_COPY( font->family_name, + font->fnt_frame + font->header.face_name_offset, + family_size ); + font->family_name[family_size] = '\0'; + if ( FT_REALLOC( font->family_name, + family_size, + ft_strlen( font->family_name ) + 1 ) ) + goto Fail; + root->family_name = font->family_name; + root->style_name = (char *)"Regular"; + if ( root->style_flags & FT_STYLE_FLAG_BOLD ) + { + if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Bold Italic"; + else + root->style_name = (char *)"Bold"; + } + else if ( root->style_flags & FT_STYLE_FLAG_ITALIC ) + root->style_name = (char *)"Italic"; + } + goto Exit; + Fail: + FNT_Face_Done( fntface ); + Exit: + return error; + } + static FT_Error + FNT_Size_Select( FT_Size size, + FT_ULong strike_index ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + FT_UNUSED( strike_index ); + FT_Select_Metrics( size->face, 0 ); + size->metrics.ascender = header->ascent * 64; + size->metrics.descender = -( header->pixel_height - + header->ascent ) * 64; + size->metrics.max_advance = header->max_width * 64; + return FNT_Err_Ok; + } + static FT_Error + FNT_Size_Request( FT_Size size, + FT_Size_Request req ) + { + FNT_Face face = (FNT_Face)size->face; + FT_WinFNT_Header header = &face->font->header; + FT_Bitmap_Size* bsize = size->face->available_sizes; + FT_Error error = FNT_Err_Invalid_Pixel_Size; + FT_Long height; + height = FT_REQUEST_HEIGHT( req ); + height = ( height + 32 ) >> 6; + switch ( req->type ) + { + case FT_SIZE_REQUEST_TYPE_NOMINAL: + if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) + error = FNT_Err_Ok; + break; + case FT_SIZE_REQUEST_TYPE_REAL_DIM: + if ( height == header->pixel_height ) + error = FNT_Err_Ok; + break; + default: + error = FNT_Err_Unimplemented_Feature; + break; + } + if ( error ) + return error; + else + return FNT_Size_Select( size, 0 ); + } + static FT_Error + FNT_Load_Glyph( FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); + FNT_Font font; + FT_Error error = FNT_Err_Ok; + FT_Byte* p; + FT_Int len; + FT_Bitmap* bitmap = &slot->bitmap; + FT_ULong offset; + FT_Bool new_format; + FT_UNUSED( load_flags ); + if ( !face ) + { + error = FNT_Err_Invalid_Argument; + goto Exit; + } + font = face->font; + if ( !font || + glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ) + { + error = FNT_Err_Invalid_Argument; + goto Exit; + } + if ( glyph_index > 0 ) +/* revert to real index */ + glyph_index--; + else +/* the .notdef glyph */ + glyph_index = font->header.default_char; + new_format = FT_BOOL( font->header.version == 0x300 ); + len = new_format ? 6 : 4; +/* jump to glyph entry */ + p = font->fnt_frame + ( new_format ? 148 : 118 ) + len * glyph_index; + bitmap->width = FT_NEXT_SHORT_LE( p ); + if ( new_format ) + offset = FT_NEXT_ULONG_LE( p ); + else + offset = FT_NEXT_USHORT_LE( p ); + if ( offset >= font->header.file_size ) + { + FT_TRACE2(( "invalid FNT offset\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } +/* jump to glyph data */ +/* font->header.bits_offset */ p = font->fnt_frame + + offset; +/* allocate and build bitmap */ + { + FT_Memory memory = FT_FACE_MEMORY( slot->face ); + FT_Int pitch = ( bitmap->width + 7 ) >> 3; + FT_Byte* column; + FT_Byte* write; + bitmap->pitch = pitch; + bitmap->rows = font->header.pixel_height; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + if ( offset + pitch * bitmap->rows >= font->header.file_size ) + { + FT_TRACE2(( "invalid bitmap width\n" )); + error = FNT_Err_Invalid_File_Format; + goto Exit; + } +/* note: since glyphs are stored in columns and not in rows we */ +/* can't use ft_glyphslot_set_bitmap */ + if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) ) + goto Exit; + column = (FT_Byte*)bitmap->buffer; + for ( ; pitch > 0; pitch--, column++ ) + { + FT_Byte* limit = p + bitmap->rows; + for ( write = column; p < limit; p++, write += bitmap->pitch ) + *write = *p; + } + } + slot->internal->flags = FT_GLYPH_OWN_BITMAP; + slot->bitmap_left = 0; + slot->bitmap_top = font->header.ascent; + slot->format = FT_GLYPH_FORMAT_BITMAP; +/* now set up metrics */ + slot->metrics.width = bitmap->width << 6; + slot->metrics.height = bitmap->rows << 6; + slot->metrics.horiAdvance = bitmap->width << 6; + slot->metrics.horiBearingX = 0; + slot->metrics.horiBearingY = slot->bitmap_top << 6; + ft_synthesize_vertical_metrics( &slot->metrics, + bitmap->rows << 6 ); + Exit: + return error; + } + static FT_Error + winfnt_get_header( FT_Face face, + FT_WinFNT_HeaderRec *aheader ) + { + FNT_Font font = ((FNT_Face)face)->font; + *aheader = font->header; + return 0; + } + static const FT_Service_WinFntRec winfnt_service_rec = + { + winfnt_get_header + }; +/* + * SERVICE LIST + * + */ + static const FT_ServiceDescRec winfnt_services[] = + { + { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_WINFNT }, + { FT_SERVICE_ID_WINFNT, &winfnt_service_rec }, + { NULL, NULL } + }; + static FT_Module_Interface + winfnt_get_service( FT_Module module, + const FT_String* service_id ) + { + FT_UNUSED( module ); + return ft_service_list_lookup( winfnt_services, service_id ); + } + FT_CALLBACK_TABLE_DEF + const FT_Driver_ClassRec winfnt_driver_class = + { + { + FT_MODULE_FONT_DRIVER | + FT_MODULE_DRIVER_NO_OUTLINES, + sizeof ( FT_DriverRec ), + "winfonts", + 0x10000L, + 0x20000L, + 0, +/* FT_Module_Constructor */ + 0, +/* FT_Module_Destructor */ + 0, + winfnt_get_service + }, + sizeof ( FNT_FaceRec ), + sizeof ( FT_SizeRec ), + sizeof ( FT_GlyphSlotRec ), + FNT_Face_Init, + FNT_Face_Done, +/* FT_Size_InitFunc */ + 0, +/* FT_Size_DoneFunc */ + 0, +/* FT_Slot_InitFunc */ + 0, +/* FT_Slot_DoneFunc */ + 0, + FNT_Load_Glyph, +/* FT_Face_GetKerningFunc */ + 0, +/* FT_Face_AttachFunc */ + 0, +/* FT_Face_GetAdvancesFunc */ + 0, + FNT_Size_Request, + FNT_Size_Select + }; +/* END */ +/***************************************************************************/ +/* */ +/* raster.c */ +/* */ +/* FreeType monochrome rasterer module component (body only). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* rastpic.c */ +/* */ +/* The FreeType position independent code services for raster module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* rastpic.h */ +/* */ +/* The FreeType position independent code services for raster module. */ +/* */ +/* Copyright 2009 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __RASTPIC_H__ +FT_BEGIN_HEADER +#define FT_STANDARD_RASTER_GET ft_standard_raster +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* rasterrs.h */ +/* */ +/* monochrome renderer error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 monochrome renderer error enumeration */ +/* constants. */ +/* */ +/*************************************************************************/ +#define __RASTERRS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Raster_Err_ +#define FT_ERR_BASE FT_Mod_Err_Raster +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* ftraster.c */ +/* */ +/* The FreeType glyph rasterizer (body). */ +/* */ +/* Copyright 1996-2003, 2005, 2007-2012 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 can be compiled without the rest of the FreeType engine, by */ +/* defining the _STANDALONE_ macro when compiling it. You also need to */ +/* put the files `ftimage.h' and `ftmisc.h' into the $(incdir) */ +/* directory. Typically, you should do something like */ +/* */ +/* - copy `src/raster/ftraster.c' (this file) to your current directory */ +/* */ +/* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' */ +/* to your current directory */ +/* */ +/* - compile `ftraster' with the _STANDALONE_ macro defined, as in */ +/* */ +/* cc -c -D_STANDALONE_ ftraster.c */ +/* */ +/* The renderer can be initialized with a call to */ +/* `ft_standard_raster.raster_new'; a bitmap can be generated */ +/* with a call to `ft_standard_raster.raster_render'. */ +/* */ +/* See the comments and documentation in the file `ftimage.h' for more */ +/* details on how the raster works. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* This is a rewrite of the FreeType 1.x scan-line converter */ +/* */ +/*************************************************************************/ +#ifdef _STANDALONE_ +#define FT_CONFIG_STANDARD_LIBRARY_H <stdlib.h> +/* for memset */ +#include <string.h> +/***************************************************************************/ +/* */ +/* ftmisc.h */ +/* */ +/* Miscellaneous macros for stand-alone rasterizer (specification */ +/* only). */ +/* */ +/* Copyright 2005, 2009, 2010 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 *not* portable! You have to adapt */ +/* its definitions to your platform. */ +/* */ +/***************************************************/ +#define __FTMISC_H__ +/* memset */ +#define FT_BEGIN_HEADER +#define FT_END_HEADER +#define FT_LOCAL_DEF( x ) static x +/* from include/freetype2/fttypes.h */ + typedef unsigned char FT_Byte; + typedef signed int FT_Int; + typedef unsigned int FT_UInt; + typedef signed long FT_Long; + typedef unsigned long FT_ULong; + typedef signed long FT_F26Dot6; + typedef int FT_Error; +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) +/* from include/freetype2/ftsystem.h */ + typedef struct FT_MemoryRec_* FT_Memory; + typedef void* (*FT_Alloc_Func)( FT_Memory memory, + long size ); + typedef void (*FT_Free_Func)( FT_Memory memory, + void* block ); + typedef void* (*FT_Realloc_Func)( FT_Memory memory, + long cur_size, + long new_size, + void* block ); + typedef struct FT_MemoryRec_ + { + void* user; + FT_Alloc_Func alloc; + FT_Free_Func free; + FT_Realloc_Func realloc; + } FT_MemoryRec; +/* from src/ftcalc.c */ +#if ( defined _WIN32 || defined _WIN64 ) + typedef __int64 FT_Int64; +#else +#include "inttypes.h" + typedef int64_t FT_Int64; +#endif + static FT_Long + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFL ); + return ( s > 0 ) ? d : -d; + } + static FT_Long + FT_MulDiv_No_Round( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + d = (FT_Long)( c > 0 ? (FT_Int64)a * b / c + : 0x7FFFFFFFL ); + return ( s > 0 ) ? d : -d; + } +/* END */ +#include "ftimage.h" +/* !_STANDALONE_ */ +#else +/***************************************************************************/ +/* */ +/* ftraster.h */ +/* */ +/* The FreeType glyph rasterizer (specification). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define __FTRASTER_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/* */ +/* Uncomment the following line if you are using ftraster.c as a */ +/* standalone module, fully independent of FreeType. */ +/* */ +/* #define _STANDALONE_ */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster; +FT_END_HEADER +/* END */ +/* for FT_MulDiv and FT_MulDiv_No_Round */ +/* !_STANDALONE_ */ +#endif +/*************************************************************************/ +/* */ +/* A simple technical note on how the raster works */ +/* ----------------------------------------------- */ +/* */ +/* Converting an outline into a bitmap is achieved in several steps: */ +/* */ +/* 1 - Decomposing the outline into successive `profiles'. Each */ +/* profile is simply an array of scanline intersections on a given */ +/* dimension. A profile's main attributes are */ +/* */ +/* o its scanline position boundaries, i.e. `Ymin' and `Ymax' */ +/* */ +/* o an array of intersection coordinates for each scanline */ +/* between `Ymin' and `Ymax' */ +/* */ +/* o a direction, indicating whether it was built going `up' or */ +/* `down', as this is very important for filling rules */ +/* */ +/* o its drop-out mode */ +/* */ +/* 2 - Sweeping the target map's scanlines in order to compute segment */ +/* `spans' which are then filled. Additionally, this pass */ +/* performs drop-out control. */ +/* */ +/* The outline data is parsed during step 1 only. The profiles are */ +/* built from the bottom of the render pool, used as a stack. The */ +/* following graphics shows the profile list under construction: */ +/* */ +/* __________________________________________________________ _ _ */ +/* | | | | | */ +/* | profile | coordinates for | profile | coordinates for |--> */ +/* | 1 | profile 1 | 2 | profile 2 |--> */ +/* |_________|_________________|_________|_________________|__ _ _ */ +/* */ +/* ^ ^ */ +/* | | */ +/* start of render pool top */ +/* */ +/* The top of the profile stack is kept in the `top' variable. */ +/* */ +/* As you can see, a profile record is pushed on top of the render */ +/* pool, which is then followed by its coordinates/intersections. If */ +/* a change of direction is detected in the outline, a new profile is */ +/* generated until the end of the outline. */ +/* */ +/* Note that when all profiles have been generated, the function */ +/* Finalize_Profile_Table() is used to record, for each profile, its */ +/* bottom-most scanline as well as the scanline above its upmost */ +/* boundary. These positions are called `y-turns' because they (sort */ +/* of) correspond to local extrema. They are stored in a sorted list */ +/* built from the top of the render pool as a downwards stack: */ +/* */ +/* _ _ _______________________________________ */ +/* | | */ +/* <--| sorted list of | */ +/* <--| extrema scanlines | */ +/* _ _ __________________|____________________| */ +/* */ +/* ^ ^ */ +/* | | */ +/* maxBuff sizeBuff = end of pool */ +/* */ +/* This list is later used during the sweep phase in order to */ +/* optimize performance (see technical note on the sweep below). */ +/* */ +/* Of course, the raster detects whether the two stacks collide and */ +/* handles the situation properly. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/** **/ +/** CONFIGURATION MACROS **/ +/** **/ +/*************************************************************************/ +/*************************************************************************/ +/* define DEBUG_RASTER if you want to compile a debugging version */ +/* #define DEBUG_RASTER */ +/* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */ +/* 5-levels anti-aliasing */ +/* #define FT_RASTER_OPTION_ANTI_ALIASING */ +/* The size of the two-lines intermediate bitmap used */ +/* for anti-aliasing, in bytes. */ +#define RASTER_GRAY_LINES 2048 +/*************************************************************************/ +/*************************************************************************/ +/** **/ +/** OTHER MACROS (do not change) **/ +/** **/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* 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 trace_raster +#ifdef _STANDALONE_ +/* This macro is used to indicate that a function parameter is unused. */ +/* Its purpose is simply to reduce compiler warnings. Note also that */ +/* simply defining it as `(void)x' doesn't avoid warnings with certain */ +/* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) +/* Disable the tracing mechanism for simplicity -- developers can */ +/* activate it easily by redefining these two macros. */ +#ifndef FT_ERROR +/* nothing */ +#define FT_ERROR( x ) do { } while ( 0 ) +#endif +#ifndef FT_TRACE +/* nothing */ +#define FT_TRACE( x ) do { } while ( 0 ) +/* nothing */ +#define FT_TRACE1( x ) do { } while ( 0 ) +/* nothing */ +#define FT_TRACE6( x ) do { } while ( 0 ) +#endif +#define Raster_Err_None 0 +#define Raster_Err_Not_Ini -1 +#define Raster_Err_Overflow -2 +#define Raster_Err_Neg_Height -3 +#define Raster_Err_Invalid -4 +#define Raster_Err_Unsupported -5 +#define ft_memset memset +#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \ + raster_reset_, raster_set_mode_, \ + raster_render_, raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; +/* !_STANDALONE_ */ +#else +/* for FT_TRACE() and FT_ERROR() */ +#define Raster_Err_None Raster_Err_Ok +#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized +#define Raster_Err_Overflow Raster_Err_Raster_Overflow +#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height +#define Raster_Err_Invalid Raster_Err_Invalid_Outline +#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph +/* !_STANDALONE_ */ +#endif +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif +/* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ +/* typically a small value and the result of a*b is known to fit into */ +/* 32 bits. */ +#define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) +/* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ +/* for clipping computations. It simply uses the FT_MulDiv() function */ +/* defined in `ftcalc.h'. */ +#define SMulDiv FT_MulDiv +#define SMulDiv_No_Round FT_MulDiv_No_Round +/* The rasterizer is a very general purpose component; please leave */ +/* the following redefinitions there (you never know your target */ +/* environment). */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef NULL +#define NULL (void*)0 +#endif +#ifndef SUCCESS +#define SUCCESS 0 +#endif +#ifndef FAILURE +#define FAILURE 1 +#endif +/* The maximum number of stacked Bezier curves. */ +#define MaxBezier 32 +/* Setting this constant to more than 32 is a */ +/* pure waste of space. */ +/* fractional bits of *input* coordinates */ +#define Pixel_Bits 6 +/*************************************************************************/ +/*************************************************************************/ +/** **/ +/** SIMPLE TYPE DECLARATIONS **/ +/** **/ +/*************************************************************************/ +/*************************************************************************/ + typedef int Int; + typedef unsigned int UInt; + typedef short Short; + typedef unsigned short UShort, *PUShort; + typedef long Long, *PLong; + typedef unsigned char Byte, *PByte; + typedef char Bool; + typedef union Alignment_ + { + long l; + void* p; + void (*f)(void); + } Alignment, *PAlignment; + typedef struct TPoint_ + { + Long x; + Long y; + } TPoint; +/* values for the `flags' bit field */ +#define Flow_Up 0x8 +#define Overshoot_Top 0x10 +#define Overshoot_Bottom 0x20 +/* States of each line, arc, and profile */ + typedef enum TStates_ + { + Unknown_State, + Ascending_State, + Descending_State, + Flat_State + } TStates; + typedef struct TProfile_ TProfile; + typedef TProfile* PProfile; + struct TProfile_ + { +/* current coordinate during sweep */ + FT_F26Dot6 X; +/* link to next profile (various purposes) */ + PProfile link; +/* start of profile's data in render pool */ + PLong offset; +/* Bit 0-2: drop-out mode */ + unsigned flags; +/* Bit 3: profile orientation (up/down) */ +/* Bit 4: is top profile? */ +/* Bit 5: is bottom profile? */ +/* profile's height in scanlines */ + long height; +/* profile's starting scanline */ + long start; +/* number of lines to step before this */ + unsigned countL; +/* profile becomes drawable */ +/* next profile in same contour, used */ + PProfile next; +/* during drop-out control */ + }; + typedef PProfile TProfileList; + typedef PProfile* PProfileList; +/* Simple record used to implement a stack of bands, required */ +/* by the sub-banding mechanism */ + typedef struct black_TBand_ + { +/* band's minimum */ + Short y_min; +/* band's maximum */ + Short y_max; + } black_TBand; +#define AlignProfileSize \ + ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) ) +#undef RAS_ARG +#undef RAS_ARGS +#undef RAS_VAR +#undef RAS_VARS +#ifdef FT_STATIC_RASTER +/* void */ +#define RAS_ARGS +/* void */ +#define RAS_ARG +/* void */ +#define RAS_VARS +/* void */ +#define RAS_VAR +#define FT_UNUSED_RASTER do { } while ( 0 ) +/* !FT_STATIC_RASTER */ +#else +#define RAS_ARGS black_PWorker worker, +#define RAS_ARG black_PWorker worker +#define RAS_VARS worker, +#define RAS_VAR worker +#define FT_UNUSED_RASTER FT_UNUSED( worker ) +/* !FT_STATIC_RASTER */ +#endif + typedef struct black_TWorker_ black_TWorker, *black_PWorker; +/* prototypes used for sweep function dispatch */ + typedef void + Function_Sweep_Init( RAS_ARGS Short* min, + Short* max ); + typedef void + Function_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ); + typedef void + Function_Sweep_Step( RAS_ARG ); +/* NOTE: These operations are only valid on 2's complement processors */ +#undef FLOOR +#undef CEILING +#undef TRUNC +#undef SCALED +#define FLOOR( x ) ( (x) & -ras.precision ) +#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) +#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) +#define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) +#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) +#define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half ) +#define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half ) +/* The most used variables are positioned at the top of the structure. */ +/* Thus, their offset can be coded with less opcodes, resulting in a */ +/* smaller executable. */ + struct black_TWorker_ + { +/* precision related variables */ + Int precision_bits; + Int precision; + Int precision_half; + Int precision_shift; + Int precision_step; + Int precision_jitter; +/* == precision_shift for bitmaps */ + Int scale_shift; +/* == precision_shift+1 for pixmaps */ +/* The profiles buffer */ + PLong buff; +/* Render pool size */ + PLong sizeBuff; +/* Profiles buffer size */ + PLong maxBuff; +/* Current cursor in buffer */ + PLong top; + FT_Error error; +/* number of Y-turns in outline */ + Int numTurns; +/* current Bezier arc pointer */ + TPoint* arc; +/* target bitmap width */ + UShort bWidth; +/* target bitmap buffer */ + PByte bTarget; +/* target pixmap buffer */ + PByte gTarget; + Long lastX, lastY; + Long minY, maxY; +/* current number of profiles */ + UShort num_Profs; +/* signals a fresh new profile which */ + Bool fresh; +/* `start' field must be completed */ +/* signals that the last arc ended */ + Bool joint; +/* exactly on a scanline. Allows */ +/* removal of doublets */ +/* current profile */ + PProfile cProfile; +/* head of linked list of profiles */ + PProfile fProfile; +/* contour's first profile in case */ + PProfile gProfile; +/* of impact */ +/* rendering state */ + TStates state; +/* description of target bit/pixmap */ + FT_Bitmap target; + FT_Outline outline; +/* current offset in target bitmap */ + Long traceOfs; +/* current offset in target pixmap */ + Long traceG; +/* sweep's increment in target bitmap */ + Short traceIncr; +/* current min x during gray rendering */ + Short gray_min_x; +/* current max x during gray rendering */ + Short gray_max_x; +/* dispatch variables */ + Function_Sweep_Init* Proc_Sweep_Init; + Function_Sweep_Span* Proc_Sweep_Span; + Function_Sweep_Span* Proc_Sweep_Drop; + Function_Sweep_Step* Proc_Sweep_Step; +/* current drop_out control method */ + Byte dropOutControl; +/* indicates whether a horizontal pass */ + Bool second_pass; +/* should be performed to control */ +/* drop-out accurately when calling */ +/* Render_Glyph. Note that there is */ +/* no horizontal pass during gray */ +/* rendering. */ +/* The Bezier stack */ + TPoint arcs[3 * MaxBezier + 1]; +/* band stack used for sub-banding */ + black_TBand band_stack[16]; +/* band stack top */ + Int band_top; +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + Byte* grays; + Byte gray_lines[RASTER_GRAY_LINES]; +/* Intermediate table used to render the */ +/* graylevels pixmaps. */ +/* gray_lines is a buffer holding two */ +/* monochrome scanlines */ +/* width in bytes of one monochrome */ + Short gray_width; +/* intermediate scanline of gray_lines. */ +/* Each gray pixel takes 2 bits long there */ +/* The gray_lines must hold 2 lines, thus with size */ +/* in bytes of at least `gray_width*2'. */ +/* FT_RASTER_ANTI_ALIASING */ +#endif + }; + typedef struct black_TRaster_ + { + char* buffer; + long buffer_size; + void* memory; + black_PWorker worker; + Byte grays[5]; + Short gray_width; + } black_TRaster, *black_PRaster; +#ifdef FT_STATIC_RASTER + static black_TWorker cur_ras; +#define ras cur_ras +/* !FT_STATIC_RASTER */ +#else +#define ras (*worker) +/* !FT_STATIC_RASTER */ +#endif +#ifdef FT_RASTER_OPTION_ANTI_ALIASING +/* A lookup table used to quickly count set bits in four gray 2x2 */ +/* cells. The values of the table have been produced with the */ +/* following code: */ +/* */ +/* for ( i = 0; i < 256; i++ ) */ +/* { */ +/* l = 0; */ +/* j = i; */ +/* */ +/* for ( c = 0; c < 4; c++ ) */ +/* { */ +/* l <<= 4; */ +/* */ +/* if ( j & 0x80 ) l++; */ +/* if ( j & 0x40 ) l++; */ +/* */ +/* j = ( j << 2 ) & 0xFF; */ +/* } */ +/* printf( "0x%04X", l ); */ +/* } */ +/* */ + static const short count_table[256] = + { + 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012, + 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022, + 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112, + 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122, + 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112, + 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122, + 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212, + 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222, + 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012, + 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022, + 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, + 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, + 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, + 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, + 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212, + 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222, + 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012, + 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022, + 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, + 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, + 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, + 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, + 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212, + 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222, + 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012, + 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022, + 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112, + 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122, + 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112, + 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122, + 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212, + 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222 + }; +/* FT_RASTER_OPTION_ANTI_ALIASING */ +#endif +/*************************************************************************/ +/*************************************************************************/ +/** **/ +/** PROFILES COMPUTATION **/ +/** **/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* Set_High_Precision */ +/* */ +/* <Description> */ +/* Set precision variables according to param flag. */ +/* */ +/* <Input> */ +/* High :: Set to True for high precision (typically for ppem < 18), */ +/* false otherwise. */ +/* */ + static void + Set_High_Precision( RAS_ARGS Int High ) + { +/* + * `precision_step' is used in `Bezier_Up' to decide when to split a + * given y-monotonous Bezier arc that crosses a scanline before + * approximating it as a straight segment. The default value of 32 (for + * low accuracy) corresponds to + * + * 32 / 64 == 0.5 pixels , + * + * while for the high accuracy case we have + * + * 256/ (1 << 12) = 0.0625 pixels . + * + * `precision_jitter' is an epsilon threshold used in + * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier + * decomposition (after all, we are working with approximations only); + * it avoids switching on additional pixels which would cause artifacts + * otherwise. + * + * The value of `precision_jitter' has been determined heuristically. + * + */ + if ( High ) + { + ras.precision_bits = 12; + ras.precision_step = 256; + ras.precision_jitter = 30; + } + else + { + ras.precision_bits = 6; + ras.precision_step = 32; + ras.precision_jitter = 2; + } + FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); + ras.precision = 1 << ras.precision_bits; + ras.precision_half = ras.precision / 2; + ras.precision_shift = ras.precision_bits - Pixel_Bits; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* New_Profile */ +/* */ +/* <Description> */ +/* Create a new profile in the render pool. */ +/* */ +/* <Input> */ +/* aState :: The state/orientation of the new profile. */ +/* */ +/* overshoot :: Whether the profile's unrounded start position */ +/* differs by at least a half pixel. */ +/* */ +/* <Return> */ +/* SUCCESS on success. FAILURE in case of overflow or of incoherent */ +/* profile. */ +/* */ + static Bool + New_Profile( RAS_ARGS TStates aState, + Bool overshoot ) + { + if ( !ras.fProfile ) + { + ras.cProfile = (PProfile)ras.top; + ras.fProfile = ras.cProfile; + ras.top += AlignProfileSize; + } + if ( ras.top >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + ras.cProfile->flags = 0; + ras.cProfile->start = 0; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + ras.cProfile->link = (PProfile)0; + ras.cProfile->next = (PProfile)0; + ras.cProfile->flags = ras.dropOutControl; + switch ( aState ) + { + case Ascending_State: + ras.cProfile->flags |= Flow_Up; + if ( overshoot ) + ras.cProfile->flags |= Overshoot_Bottom; + FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile )); + break; + case Descending_State: + if ( overshoot ) + ras.cProfile->flags |= Overshoot_Top; + FT_TRACE6(( "New descending profile = %p\n", ras.cProfile )); + break; + default: + FT_ERROR(( "New_Profile: invalid profile direction\n" )); + ras.error = Raster_Err_Invalid; + return FAILURE; + } + if ( !ras.gProfile ) + ras.gProfile = ras.cProfile; + ras.state = aState; + ras.fresh = TRUE; + ras.joint = FALSE; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* End_Profile */ +/* */ +/* <Description> */ +/* Finalize the current profile. */ +/* */ +/* <Input> */ +/* overshoot :: Whether the profile's unrounded end position differs */ +/* by at least a half pixel. */ +/* */ +/* <Return> */ +/* SUCCESS on success. FAILURE in case of overflow or incoherency. */ +/* */ + static Bool + End_Profile( RAS_ARGS Bool overshoot ) + { + Long h; + PProfile oldProfile; + h = (Long)( ras.top - ras.cProfile->offset ); + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered\n" )); + ras.error = Raster_Err_Neg_Height; + return FAILURE; + } + if ( h > 0 ) + { + FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n", + ras.cProfile, ras.cProfile->start, h )); + ras.cProfile->height = h; + if ( overshoot ) + { + if ( ras.cProfile->flags & Flow_Up ) + ras.cProfile->flags |= Overshoot_Top; + else + ras.cProfile->flags |= Overshoot_Bottom; + } + oldProfile = ras.cProfile; + ras.cProfile = (PProfile)ras.top; + ras.top += AlignProfileSize; + ras.cProfile->height = 0; + ras.cProfile->offset = ras.top; + oldProfile->next = ras.cProfile; + ras.num_Profs++; + } + if ( ras.top >= ras.maxBuff ) + { + FT_TRACE1(( "overflow in End_Profile\n" )); + ras.error = Raster_Err_Overflow; + return FAILURE; + } + ras.joint = FALSE; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Insert_Y_Turn */ +/* */ +/* <Description> */ +/* Insert a salient into the sorted list placed on top of the render */ +/* pool. */ +/* */ +/* <Input> */ +/* New y scanline position. */ +/* */ +/* <Return> */ +/* SUCCESS on success. FAILURE in case of overflow. */ +/* */ + static Bool + Insert_Y_Turn( RAS_ARGS Int y ) + { + PLong y_turns; + Int y2, n; + n = ras.numTurns - 1; + y_turns = ras.sizeBuff - ras.numTurns; +/* look for first y value that is <= */ + while ( n >= 0 && y < y_turns[n] ) + n--; +/* if it is <, simply insert it, ignore if == */ + if ( n >= 0 && y > y_turns[n] ) + while ( n >= 0 ) + { + y2 = (Int)y_turns[n]; + y_turns[n] = y; + y = y2; + n--; + } + if ( n < 0 ) + { + ras.maxBuff--; + if ( ras.maxBuff <= ras.top ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + ras.numTurns++; + ras.sizeBuff[-ras.numTurns] = y; + } + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Finalize_Profile_Table */ +/* */ +/* <Description> */ +/* Adjust all links in the profiles list. */ +/* */ +/* <Return> */ +/* SUCCESS on success. FAILURE in case of overflow. */ +/* */ + static Bool + Finalize_Profile_Table( RAS_ARG ) + { + Int bottom, top; + UShort n; + PProfile p; + n = ras.num_Profs; + p = ras.fProfile; + if ( n > 1 && p ) + { + while ( n > 0 ) + { + if ( n > 1 ) + p->link = (PProfile)( p->offset + p->height ); + else + p->link = NULL; + if ( p->flags & Flow_Up ) + { + bottom = (Int)p->start; + top = (Int)( p->start + p->height - 1 ); + } + else + { + bottom = (Int)( p->start - p->height + 1 ); + top = (Int)p->start; + p->start = bottom; + p->offset += p->height - 1; + } + if ( Insert_Y_Turn( RAS_VARS bottom ) || + Insert_Y_Turn( RAS_VARS top + 1 ) ) + return FAILURE; + p = p->link; + n--; + } + } + else + ras.fProfile = NULL; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Split_Conic */ +/* */ +/* <Description> */ +/* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */ +/* stack. */ +/* */ +/* <Input> */ +/* None (subdivided Bezier is taken from the top of the stack). */ +/* */ +/* <Note> */ +/* This routine is the `beef' of this component. It is _the_ inner */ +/* loop that should be optimized to hell to get the best performance. */ +/* */ + static void + Split_Conic( TPoint* base ) + { + Long a, b; + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; +/* hand optimized. gcc doesn't seem to be too good at common */ +/* expression substitution and instruction scheduling ;-) */ + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Split_Cubic */ +/* */ +/* <Description> */ +/* Subdivide a third-order Bezier arc into two joint sub-arcs in the */ +/* Bezier stack. */ +/* */ +/* <Note> */ +/* This routine is the `beef' of the component. It is one of _the_ */ +/* inner loops that should be optimized like hell to get the best */ +/* performance. */ +/* */ + static void + Split_Cubic( TPoint* base ) + { + Long a, b, c, d; + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c + 1 ) >> 1; + base[5].x = b = ( base[3].x + d + 1 ) >> 1; + c = ( c + d + 1 ) >> 1; + base[2].x = a = ( a + c + 1 ) >> 1; + base[4].x = b = ( b + c + 1 ) >> 1; + base[3].x = ( a + b + 1 ) >> 1; + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c + 1 ) >> 1; + base[5].y = b = ( base[3].y + d + 1 ) >> 1; + c = ( c + d + 1 ) >> 1; + base[2].y = a = ( a + c + 1 ) >> 1; + base[4].y = b = ( b + c + 1 ) >> 1; + base[3].y = ( a + b + 1 ) >> 1; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Line_Up */ +/* */ +/* <Description> */ +/* Compute the x-coordinates of an ascending line segment and store */ +/* them in the render pool. */ +/* */ +/* <Input> */ +/* x1 :: The x-coordinate of the segment's start point. */ +/* */ +/* y1 :: The y-coordinate of the segment's start point. */ +/* */ +/* x2 :: The x-coordinate of the segment's end point. */ +/* */ +/* y2 :: The y-coordinate of the segment's end point. */ +/* */ +/* miny :: A lower vertical clipping bound value. */ +/* */ +/* maxy :: An upper vertical clipping bound value. */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow. */ +/* */ + static Bool + Line_Up( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Long Dx, Dy; +/* XXX: is `Short' sufficient? */ + Int e1, e2, f1, f2, size; + Long Ix, Rx, Ax; + PLong top; + Dx = x2 - x1; + Dy = y2 - y1; + if ( Dy <= 0 || y2 < miny || y1 > maxy ) + return SUCCESS; + if ( y1 < miny ) + { +/* Take care: miny-y1 can be a very large value; we use */ +/* a slow MulDiv function to avoid clipping bugs */ + x1 += SMulDiv( Dx, miny - y1, Dy ); + e1 = (Int)TRUNC( miny ); + f1 = 0; + } + else + { + e1 = (Int)TRUNC( y1 ); + f1 = (Int)FRAC( y1 ); + } + if ( y2 > maxy ) + { +/* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ + e2 = (Int)TRUNC( maxy ); + f2 = 0; + } + else + { + e2 = (Int)TRUNC( y2 ); + f2 = (Int)FRAC( y2 ); + } + if ( f1 > 0 ) + { + if ( e1 == e2 ) + return SUCCESS; + else + { + x1 += SMulDiv( Dx, ras.precision - f1, Dy ); + e1 += 1; + } + } + else + if ( ras.joint ) + { + ras.top--; + ras.joint = FALSE; + } + ras.joint = (char)( f2 == 0 ); + if ( ras.fresh ) + { + ras.cProfile->start = e1; + ras.fresh = FALSE; + } + size = e2 - e1 + 1; + if ( ras.top + size >= ras.maxBuff ) + { + ras.error = Raster_Err_Overflow; + return FAILURE; + } + if ( Dx > 0 ) + { + Ix = SMulDiv_No_Round( ras.precision, Dx, Dy ); + Rx = ( ras.precision * Dx ) % Dy; + Dx = 1; + } + else + { + Ix = -SMulDiv_No_Round( ras.precision, -Dx, Dy ); + Rx = ( ras.precision * -Dx ) % Dy; + Dx = -1; + } + Ax = -Dy; + top = ras.top; + while ( size > 0 ) + { + *top++ = x1; + x1 += Ix; + Ax += Rx; + if ( Ax >= 0 ) + { + Ax -= Dy; + x1 += Dx; + } + size--; + } + ras.top = top; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Line_Down */ +/* */ +/* <Description> */ +/* Compute the x-coordinates of an descending line segment and store */ +/* them in the render pool. */ +/* */ +/* <Input> */ +/* x1 :: The x-coordinate of the segment's start point. */ +/* */ +/* y1 :: The y-coordinate of the segment's start point. */ +/* */ +/* x2 :: The x-coordinate of the segment's end point. */ +/* */ +/* y2 :: The y-coordinate of the segment's end point. */ +/* */ +/* miny :: A lower vertical clipping bound value. */ +/* */ +/* maxy :: An upper vertical clipping bound value. */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow. */ +/* */ + static Bool + Line_Down( RAS_ARGS Long x1, + Long y1, + Long x2, + Long y2, + Long miny, + Long maxy ) + { + Bool result, fresh; + fresh = ras.fresh; + result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + return result; + } +/* A function type describing the functions used to split Bezier arcs */ + typedef void (*TSplitter)( TPoint* base ); +/*************************************************************************/ +/* */ +/* <Function> */ +/* Bezier_Up */ +/* */ +/* <Description> */ +/* Compute the x-coordinates of an ascending Bezier arc and store */ +/* them in the render pool. */ +/* */ +/* <Input> */ +/* degree :: The degree of the Bezier arc (either 2 or 3). */ +/* */ +/* splitter :: The function to split Bezier arcs. */ +/* */ +/* miny :: A lower vertical clipping bound value. */ +/* */ +/* maxy :: An upper vertical clipping bound value. */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow. */ +/* */ + static Bool + Bezier_Up( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + Long y1, y2, e, e2, e0; + Short f1; + TPoint* arc; + TPoint* start_arc; + PLong top; + arc = ras.arc; + y1 = arc[degree].y; + y2 = arc[0].y; + top = ras.top; + if ( y2 < miny || y1 > maxy ) + goto Fin; + e2 = FLOOR( y2 ); + if ( e2 > maxy ) + e2 = maxy; + e0 = miny; + if ( y1 < miny ) + e = miny; + else + { + e = CEILING( y1 ); + f1 = (Short)( FRAC( y1 ) ); + e0 = e; + if ( f1 == 0 ) + { + if ( ras.joint ) + { + top--; + ras.joint = FALSE; + } + *top++ = arc[degree].x; + e += ras.precision; + } + } + if ( ras.fresh ) + { + ras.cProfile->start = TRUNC( e0 ); + ras.fresh = FALSE; + } + if ( e2 < e ) + goto Fin; + if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) + { + ras.top = top; + ras.error = Raster_Err_Overflow; + return FAILURE; + } + start_arc = arc; + while ( arc >= start_arc && e <= e2 ) + { + ras.joint = FALSE; + y2 = arc[0].y; + if ( y2 > e ) + { + y1 = arc[degree].y; + if ( y2 - y1 >= ras.precision_step ) + { + splitter( arc ); + arc += degree; + } + else + { + *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x, + e - y1, y2 - y1 ); + arc -= degree; + e += ras.precision; + } + } + else + { + if ( y2 == e ) + { + ras.joint = TRUE; + *top++ = arc[0].x; + e += ras.precision; + } + arc -= degree; + } + } + Fin: + ras.top = top; + ras.arc -= degree; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Bezier_Down */ +/* */ +/* <Description> */ +/* Compute the x-coordinates of an descending Bezier arc and store */ +/* them in the render pool. */ +/* */ +/* <Input> */ +/* degree :: The degree of the Bezier arc (either 2 or 3). */ +/* */ +/* splitter :: The function to split Bezier arcs. */ +/* */ +/* miny :: A lower vertical clipping bound value. */ +/* */ +/* maxy :: An upper vertical clipping bound value. */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow. */ +/* */ + static Bool + Bezier_Down( RAS_ARGS Int degree, + TSplitter splitter, + Long miny, + Long maxy ) + { + TPoint* arc = ras.arc; + Bool result, fresh; + arc[0].y = -arc[0].y; + arc[1].y = -arc[1].y; + arc[2].y = -arc[2].y; + if ( degree > 2 ) + arc[3].y = -arc[3].y; + fresh = ras.fresh; + result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); + if ( fresh && !ras.fresh ) + ras.cProfile->start = -ras.cProfile->start; + arc[0].y = -arc[0].y; + return result; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Line_To */ +/* */ +/* <Description> */ +/* Inject a new line segment and adjust the Profiles list. */ +/* */ +/* <Input> */ +/* x :: The x-coordinate of the segment's end point (its start point */ +/* is stored in `lastX'). */ +/* */ +/* y :: The y-coordinate of the segment's end point (its start point */ +/* is stored in `lastY'). */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow or incorrect */ +/* profile. */ +/* */ + static Bool + Line_To( RAS_ARGS Long x, + Long y ) + { +/* First, detect a change of direction */ + switch ( ras.state ) + { + case Unknown_State: + if ( y > ras.lastY ) + { + if ( New_Profile( RAS_VARS Ascending_State, + IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + else + { + if ( y < ras.lastY ) + if ( New_Profile( RAS_VARS Descending_State, + IS_TOP_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + break; + case Ascending_State: + if ( y < ras.lastY ) + { + if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) || + New_Profile( RAS_VARS Descending_State, + IS_TOP_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + break; + case Descending_State: + if ( y > ras.lastY ) + { + if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) || + New_Profile( RAS_VARS Ascending_State, + IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) + return FAILURE; + } + break; + default: + ; + } +/* Then compute the lines */ + switch ( ras.state ) + { + case Ascending_State: + if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + case Descending_State: + if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, + x, y, ras.minY, ras.maxY ) ) + return FAILURE; + break; + default: + ; + } + ras.lastX = x; + ras.lastY = y; + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Conic_To */ +/* */ +/* <Description> */ +/* Inject a new conic arc and adjust the profile list. */ +/* */ +/* <Input> */ +/* cx :: The x-coordinate of the arc's new control point. */ +/* */ +/* cy :: The y-coordinate of the arc's new control point. */ +/* */ +/* x :: The x-coordinate of the arc's end point (its start point is */ +/* stored in `lastX'). */ +/* */ +/* y :: The y-coordinate of the arc's end point (its start point is */ +/* stored in `lastY'). */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow or incorrect */ +/* profile. */ +/* */ + static Bool + Conic_To( RAS_ARGS Long cx, + Long cy, + Long x, + Long y ) + { + Long y1, y2, y3, x3, ymin, ymax; + TStates state_bez; + ras.arc = ras.arcs; + ras.arc[2].x = ras.lastX; + ras.arc[2].y = ras.lastY; + ras.arc[1].x = cx; + ras.arc[1].y = cy; + ras.arc[0].x = x; + ras.arc[0].y = y; + do + { + y1 = ras.arc[2].y; + y2 = ras.arc[1].y; + y3 = ras.arc[0].y; + x3 = ras.arc[0].x; +/* first, categorize the Bezier arc */ + if ( y1 <= y3 ) + { + ymin = y1; + ymax = y3; + } + else + { + ymin = y3; + ymax = y1; + } + if ( y2 < ymin || y2 > ymax ) + { +/* this arc has no given direction, split it! */ + Split_Conic( ras.arc ); + ras.arc += 2; + } + else if ( y1 == y3 ) + { +/* this arc is flat, ignore it and pop it from the Bezier stack */ + ras.arc -= 2; + } + else + { +/* the arc is y-monotonous, either ascending or descending */ +/* detect a change of direction */ + state_bez = y1 < y3 ? Ascending_State : Descending_State; + if ( ras.state != state_bez ) + { + Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 ) + : IS_TOP_OVERSHOOT( y1 ); +/* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VARS o ) ) + goto Fail; +/* create a new profile */ + if ( New_Profile( RAS_VARS state_bez, o ) ) + goto Fail; + } +/* now call the appropriate routine */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + goto Fail; + } + } while ( ras.arc >= ras.arcs ); + ras.lastX = x3; + ras.lastY = y3; + return SUCCESS; + Fail: + return FAILURE; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Cubic_To */ +/* */ +/* <Description> */ +/* Inject a new cubic arc and adjust the profile list. */ +/* */ +/* <Input> */ +/* cx1 :: The x-coordinate of the arc's first new control point. */ +/* */ +/* cy1 :: The y-coordinate of the arc's first new control point. */ +/* */ +/* cx2 :: The x-coordinate of the arc's second new control point. */ +/* */ +/* cy2 :: The y-coordinate of the arc's second new control point. */ +/* */ +/* x :: The x-coordinate of the arc's end point (its start point is */ +/* stored in `lastX'). */ +/* */ +/* y :: The y-coordinate of the arc's end point (its start point is */ +/* stored in `lastY'). */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on render pool overflow or incorrect */ +/* profile. */ +/* */ + static Bool + Cubic_To( RAS_ARGS Long cx1, + Long cy1, + Long cx2, + Long cy2, + Long x, + Long y ) + { + Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; + TStates state_bez; + ras.arc = ras.arcs; + ras.arc[3].x = ras.lastX; + ras.arc[3].y = ras.lastY; + ras.arc[2].x = cx1; + ras.arc[2].y = cy1; + ras.arc[1].x = cx2; + ras.arc[1].y = cy2; + ras.arc[0].x = x; + ras.arc[0].y = y; + do + { + y1 = ras.arc[3].y; + y2 = ras.arc[2].y; + y3 = ras.arc[1].y; + y4 = ras.arc[0].y; + x4 = ras.arc[0].x; +/* first, categorize the Bezier arc */ + if ( y1 <= y4 ) + { + ymin1 = y1; + ymax1 = y4; + } + else + { + ymin1 = y4; + ymax1 = y1; + } + if ( y2 <= y3 ) + { + ymin2 = y2; + ymax2 = y3; + } + else + { + ymin2 = y3; + ymax2 = y2; + } + if ( ymin2 < ymin1 || ymax2 > ymax1 ) + { +/* this arc has no given direction, split it! */ + Split_Cubic( ras.arc ); + ras.arc += 3; + } + else if ( y1 == y4 ) + { +/* this arc is flat, ignore it and pop it from the Bezier stack */ + ras.arc -= 3; + } + else + { + state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; +/* detect a change of direction */ + if ( ras.state != state_bez ) + { + Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 ) + : IS_TOP_OVERSHOOT( y1 ); +/* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VARS o ) ) + goto Fail; + if ( New_Profile( RAS_VARS state_bez, o ) ) + goto Fail; + } +/* compute intersections */ + if ( state_bez == Ascending_State ) + { + if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; + } + else + if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + goto Fail; + } + } while ( ras.arc >= ras.arcs ); + ras.lastX = x4; + ras.lastY = y4; + return SUCCESS; + Fail: + return FAILURE; + } +#undef SWAP_ +#define SWAP_( x, y ) do \ + { \ + Long swap = x; \ + \ + \ + x = y; \ + y = swap; \ + } while ( 0 ) +/*************************************************************************/ +/* */ +/* <Function> */ +/* Decompose_Curve */ +/* */ +/* <Description> */ +/* Scan the outline arrays in order to emit individual segments and */ +/* Beziers by calling Line_To() and Bezier_To(). It handles all */ +/* weird cases, like when the first point is off the curve, or when */ +/* there are simply no `on' points in the contour! */ +/* */ +/* <Input> */ +/* first :: The index of the first point in the contour. */ +/* */ +/* last :: The index of the last point in the contour. */ +/* */ +/* flipped :: If set, flip the direction of the curve. */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE on error. */ +/* */ + static Bool + Decompose_Curve( RAS_ARGS UShort first, + UShort last, + int flipped ) + { + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + FT_Vector* points; + FT_Vector* point; + FT_Vector* limit; + char* tags; +/* current point's state */ + unsigned tag; + points = ras.outline.points; + limit = points + last; + v_start.x = SCALED( points[first].x ); + v_start.y = SCALED( points[first].y ); + v_last.x = SCALED( points[last].x ); + v_last.y = SCALED( points[last].y ); + if ( flipped ) + { + SWAP_( v_start.x, v_start.y ); + SWAP_( v_last.x, v_last.y ); + } + v_control = v_start; + point = points + first; + tags = ras.outline.tags + first; +/* set scan mode if necessary */ + if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE ) + ras.dropOutControl = (Byte)tags[0] >> 5; + tag = FT_CURVE_TAG( tags[0] ); +/* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; +/* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { +/* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) + { +/* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { +/* if both first and last points are conic, */ +/* start at their middle and record its position */ +/* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + v_last = v_start; + } + point--; + tags--; + } + ras.lastX = v_start.x; + ras.lastY = v_start.y; + while ( point < limit ) + { + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { +/* emit a single line_to */ + case FT_CURVE_TAG_ON: + { + Long x, y; + x = SCALED( point->x ); + y = SCALED( point->y ); + if ( flipped ) + SWAP_( x, y ); + if ( Line_To( RAS_VARS x, y ) ) + goto Fail; + continue; + } +/* consume conic arcs */ + case FT_CURVE_TAG_CONIC: + v_control.x = SCALED( point[0].x ); + v_control.y = SCALED( point[0].y ); + if ( flipped ) + SWAP_( v_control.x, v_control.y ); + Do_Conic: + if ( point < limit ) + { + FT_Vector v_middle; + Long x, y; + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + x = SCALED( point[0].x ); + y = SCALED( point[0].y ); + if ( flipped ) + SWAP_( x, y ); + if ( tag == FT_CURVE_TAG_ON ) + { + if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) + goto Fail; + continue; + } + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + v_middle.x = ( v_control.x + x ) / 2; + v_middle.y = ( v_control.y + y ) / 2; + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_middle.x, v_middle.y ) ) + goto Fail; + v_control.x = x; + v_control.y = y; + goto Do_Conic; + } + if ( Conic_To( RAS_VARS v_control.x, v_control.y, + v_start.x, v_start.y ) ) + goto Fail; + goto Close; +/* FT_CURVE_TAG_CUBIC */ + default: + { + Long x1, y1, x2, y2, x3, y3; + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + point += 2; + tags += 2; + x1 = SCALED( point[-2].x ); + y1 = SCALED( point[-2].y ); + x2 = SCALED( point[-1].x ); + y2 = SCALED( point[-1].y ); + if ( flipped ) + { + SWAP_( x1, y1 ); + SWAP_( x2, y2 ); + } + if ( point <= limit ) + { + x3 = SCALED( point[0].x ); + y3 = SCALED( point[0].y ); + if ( flipped ) + SWAP_( x3, y3 ); + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) + goto Fail; + continue; + } + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) + goto Fail; + goto Close; + } + } + } +/* close the contour with a line segment */ + if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) + goto Fail; + Close: + return SUCCESS; + Invalid_Outline: + ras.error = Raster_Err_Invalid; + Fail: + return FAILURE; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Convert_Glyph */ +/* */ +/* <Description> */ +/* Convert a glyph into a series of segments and arcs and make a */ +/* profiles list with them. */ +/* */ +/* <Input> */ +/* flipped :: If set, flip the direction of curve. */ +/* */ +/* <Return> */ +/* SUCCESS on success, FAILURE if any error was encountered during */ +/* rendering. */ +/* */ + static Bool + Convert_Glyph( RAS_ARGS int flipped ) + { + int i; + unsigned start; + PProfile lastProfile; + ras.fProfile = NULL; + ras.joint = FALSE; + ras.fresh = FALSE; + ras.maxBuff = ras.sizeBuff - AlignProfileSize; + ras.numTurns = 0; + ras.cProfile = (PProfile)ras.top; + ras.cProfile->offset = ras.top; + ras.num_Profs = 0; + start = 0; + for ( i = 0; i < ras.outline.n_contours; i++ ) + { + Bool o; + ras.state = Unknown_State; + ras.gProfile = NULL; + if ( Decompose_Curve( RAS_VARS (unsigned short)start, + ras.outline.contours[i], + flipped ) ) + return FAILURE; + start = ras.outline.contours[i] + 1; +/* we must now check whether the extreme arcs join or not */ + if ( FRAC( ras.lastY ) == 0 && + ras.lastY >= ras.minY && + ras.lastY <= ras.maxY ) + if ( ras.gProfile && + ( ras.gProfile->flags & Flow_Up ) == + ( ras.cProfile->flags & Flow_Up ) ) + ras.top--; +/* Note that ras.gProfile can be nil if the contour was too small */ +/* to be drawn. */ + lastProfile = ras.cProfile; + if ( ras.cProfile->flags & Flow_Up ) + o = IS_TOP_OVERSHOOT( ras.lastY ); + else + o = IS_BOTTOM_OVERSHOOT( ras.lastY ); + if ( End_Profile( RAS_VARS o ) ) + return FAILURE; +/* close the `next profile in contour' linked list */ + if ( ras.gProfile ) + lastProfile->next = ras.gProfile; + } + if ( Finalize_Profile_Table( RAS_VAR ) ) + return FAILURE; + return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); + } +/*************************************************************************/ +/*************************************************************************/ +/** **/ +/** SCAN-LINE SWEEPS AND DRAWING **/ +/** **/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* Init_Linked */ +/* */ +/* Initializes an empty linked list. */ +/* */ + static void + Init_Linked( TProfileList* l ) + { + *l = NULL; + } +/*************************************************************************/ +/* */ +/* InsNew */ +/* */ +/* Inserts a new profile in a linked list. */ +/* */ + static void + InsNew( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + Long x; + old = list; + current = *old; + x = profile->X; + while ( current ) + { + if ( x < current->X ) + break; + old = ¤t->link; + current = *old; + } + profile->link = current; + *old = profile; + } +/*************************************************************************/ +/* */ +/* DelOld */ +/* */ +/* Removes an old profile from a linked list. */ +/* */ + static void + DelOld( PProfileList list, + PProfile profile ) + { + PProfile *old, current; + old = list; + current = *old; + while ( current ) + { + if ( current == profile ) + { + *old = current->link; + return; + } + old = ¤t->link; + current = *old; + } +/* we should never get there, unless the profile was not part of */ +/* the list. */ + } +/*************************************************************************/ +/* */ +/* Sort */ +/* */ +/* Sorts a trace list. In 95%, the list is already sorted. We need */ +/* an algorithm which is fast in this case. Bubble sort is enough */ +/* and simple. */ +/* */ + static void + Sort( PProfileList list ) + { + PProfile *old, current, next; +/* First, set the new X coordinate of each profile */ + current = *list; + while ( current ) + { + current->X = *current->offset; + current->offset += current->flags & Flow_Up ? 1 : -1; + current->height--; + current = current->link; + } +/* Then sort them */ + old = list; + current = *old; + if ( !current ) + return; + next = current->link; + while ( next ) + { + if ( current->X <= next->X ) + { + old = ¤t->link; + current = *old; + if ( !current ) + return; + } + else + { + *old = next; + current->link = next->link; + next->link = current; + old = list; + current = *old; + } + next = current->link; + } + } +/*************************************************************************/ +/* */ +/* Vertical Sweep Procedure Set */ +/* */ +/* These four routines are used during the vertical black/white sweep */ +/* phase by the generic Draw_Sweep() function. */ +/* */ +/*************************************************************************/ + static void + Vertical_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + Long pitch = ras.target.pitch; + FT_UNUSED( max ); + ras.traceIncr = (Short)-pitch; + ras.traceOfs = -*min * pitch; + if ( pitch > 0 ) + ras.traceOfs += ( ras.target.rows - 1 ) * pitch; + ras.gray_min_x = 0; + ras.gray_max_x = 0; + } + static void + Vertical_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + int c1, c2; + Byte f1, f2; + Byte* target; + FT_UNUSED( y ); + FT_UNUSED( left ); + FT_UNUSED( right ); +/* Drop-out control */ + e1 = TRUNC( CEILING( x1 ) ); + if ( x2 - x1 - ras.precision <= ras.precision_jitter ) + e2 = e1; + else + e2 = TRUNC( FLOOR( x2 ) ); + if ( e2 >= 0 && e1 < ras.bWidth ) + { + if ( e1 < 0 ) + e1 = 0; + if ( e2 >= ras.bWidth ) + e2 = ras.bWidth - 1; + c1 = (Short)( e1 >> 3 ); + c2 = (Short)( e2 >> 3 ); + f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); + f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); + if ( ras.gray_min_x > c1 ) + ras.gray_min_x = (short)c1; + if ( ras.gray_max_x < c2 ) + ras.gray_max_x = (short)c2; + target = ras.bTarget + ras.traceOfs + c1; + c2 -= c1; + if ( c2 > 0 ) + { + target[0] |= f1; +/* memset() is slower than the following code on many platforms. */ +/* This is due to the fact that, in the vast majority of cases, */ +/* the span length in bytes is relatively small. */ + c2--; + while ( c2 > 0 ) + { + *(++target) = 0xFF; + c2--; + } + target[1] |= f2; + } + else + *target |= ( f1 & f2 ); + } + } + static void + Vertical_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2, pxl; + Short c1, f1; +/* Drop-out control */ +/* e2 x2 x1 e1 */ +/* */ +/* ^ | */ +/* | | */ +/* +-------------+---------------------+------------+ */ +/* | | */ +/* | v */ +/* */ +/* pixel contour contour pixel */ +/* center center */ +/* drop-out mode scan conversion rules (as defined in OpenType) */ +/* --------------------------------------------------------------- */ +/* 0 1, 2, 3 */ +/* 1 1, 2, 4 */ +/* 2 1, 2 */ +/* 3 same as mode 2 */ +/* 4 1, 2, 5 */ +/* 5 1, 2, 6 */ +/* 6, 7 same as mode 2 */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + pxl = e1; + if ( e1 > e2 ) + { + Int dropOutControl = left->flags & 7; + if ( e1 == e2 + ras.precision ) + { + switch ( dropOutControl ) + { +/* simple drop-outs including stubs */ + case 0: + pxl = e2; + break; +/* smart drop-outs including stubs */ + case 4: + pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); + break; +/* simple drop-outs excluding stubs */ + case 1: +/* smart drop-outs excluding stubs */ + case 5: +/* Drop-out Control Rules #4 and #6 */ +/* The specification neither provides an exact definition */ +/* of a `stub' nor gives exact rules to exclude them. */ +/* */ +/* Here the constraints we use to recognize a stub. */ +/* */ +/* upper stub: */ +/* */ +/* - P_Left and P_Right are in the same contour */ +/* - P_Right is the successor of P_Left in that contour */ +/* - y is the top of P_Left and P_Right */ +/* */ +/* lower stub: */ +/* */ +/* - P_Left and P_Right are in the same contour */ +/* - P_Left is the successor of P_Right in that contour */ +/* - y is the bottom of P_Left */ +/* */ +/* We draw a stub if the following constraints are met. */ +/* */ +/* - for an upper or lower stub, there is top or bottom */ +/* overshoot, respectively */ +/* - the covered interval is greater or equal to a half */ +/* pixel */ +/* upper stub test */ + if ( left->next == right && + left->height <= 0 && + !( left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + return; +/* lower stub test */ + if ( right->next == left && + left->start == y && + !( left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + return; + if ( dropOutControl == 1 ) + pxl = e2; + else + pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); + break; +/* modes 2, 3, 6, 7 */ + default: +/* no drop-out control */ + return; + } +/* undocumented but confirmed: If the drop-out would result in a */ +/* pixel outside of the bounding box, use the pixel inside of the */ +/* bounding box instead */ + if ( pxl < 0 ) + pxl = e1; + else if ( TRUNC( pxl ) >= ras.bWidth ) + pxl = e2; +/* check that the other pixel isn't set */ + e1 = pxl == e1 ? e2 : e1; + e1 = TRUNC( e1 ); + c1 = (Short)( e1 >> 3 ); + f1 = (Short)( e1 & 7 ); + if ( e1 >= 0 && e1 < ras.bWidth && + ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) + return; + } + else + return; + } + e1 = TRUNC( pxl ); + if ( e1 >= 0 && e1 < ras.bWidth ) + { + c1 = (Short)( e1 >> 3 ); + f1 = (Short)( e1 & 7 ); + if ( ras.gray_min_x > c1 ) + ras.gray_min_x = c1; + if ( ras.gray_max_x < c1 ) + ras.gray_max_x = c1; + ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); + } + } + static void + Vertical_Sweep_Step( RAS_ARG ) + { + ras.traceOfs += ras.traceIncr; + } +/***********************************************************************/ +/* */ +/* Horizontal Sweep Procedure Set */ +/* */ +/* These four routines are used during the horizontal black/white */ +/* sweep phase by the generic Draw_Sweep() function. */ +/* */ +/***********************************************************************/ + static void + Horizontal_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { +/* nothing, really */ + FT_UNUSED_RASTER; + FT_UNUSED( min ); + FT_UNUSED( max ); + } + static void + Horizontal_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte bits; + Byte f1; + FT_UNUSED( left ); + FT_UNUSED( right ); + if ( x2 - x1 < ras.precision ) + { + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + if ( e1 == e2 ) + { + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + e1 = TRUNC( e1 ); + if ( e1 >= 0 && e1 < ras.target.rows ) + { + PByte p; + p = bits - e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + p += ( ras.target.rows - 1 ) * ras.target.pitch; + p[0] |= f1; + } + } + } + } + static void + Horizontal_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2, pxl; + PByte bits; + Byte f1; +/* During the horizontal sweep, we only take care of drop-outs */ +/* e1 + <-- pixel center */ +/* | */ +/* x1 ---+--> <-- contour */ +/* | */ +/* | */ +/* x2 <--+--- <-- contour */ +/* | */ +/* | */ +/* e2 + <-- pixel center */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + pxl = e1; + if ( e1 > e2 ) + { + Int dropOutControl = left->flags & 7; + if ( e1 == e2 + ras.precision ) + { + switch ( dropOutControl ) + { +/* simple drop-outs including stubs */ + case 0: + pxl = e2; + break; +/* smart drop-outs including stubs */ + case 4: + pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); + break; +/* simple drop-outs excluding stubs */ + case 1: +/* smart drop-outs excluding stubs */ + case 5: +/* see Vertical_Sweep_Drop for details */ +/* rightmost stub test */ + if ( left->next == right && + left->height <= 0 && + !( left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + return; +/* leftmost stub test */ + if ( right->next == left && + left->start == y && + !( left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + return; + if ( dropOutControl == 1 ) + pxl = e2; + else + pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); + break; +/* modes 2, 3, 6, 7 */ + default: +/* no drop-out control */ + return; + } +/* undocumented but confirmed: If the drop-out would result in a */ +/* pixel outside of the bounding box, use the pixel inside of the */ +/* bounding box instead */ + if ( pxl < 0 ) + pxl = e1; + else if ( TRUNC( pxl ) >= ras.target.rows ) + pxl = e2; +/* check that the other pixel isn't set */ + e1 = pxl == e1 ? e2 : e1; + e1 = TRUNC( e1 ); + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + bits -= e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + bits += ( ras.target.rows - 1 ) * ras.target.pitch; + if ( e1 >= 0 && + e1 < ras.target.rows && + *bits & f1 ) + return; + } + else + return; + } + bits = ras.bTarget + ( y >> 3 ); + f1 = (Byte)( 0x80 >> ( y & 7 ) ); + e1 = TRUNC( pxl ); + if ( e1 >= 0 && e1 < ras.target.rows ) + { + bits -= e1 * ras.target.pitch; + if ( ras.target.pitch > 0 ) + bits += ( ras.target.rows - 1 ) * ras.target.pitch; + bits[0] |= f1; + } + } + static void + Horizontal_Sweep_Step( RAS_ARG ) + { +/* Nothing, really */ + FT_UNUSED_RASTER; + } +#ifdef FT_RASTER_OPTION_ANTI_ALIASING +/*************************************************************************/ +/* */ +/* Vertical Gray Sweep Procedure Set */ +/* */ +/* These two routines are used during the vertical gray-levels sweep */ +/* phase by the generic Draw_Sweep() function. */ +/* */ +/* NOTES */ +/* */ +/* - The target pixmap's width *must* be a multiple of 4. */ +/* */ +/* - You have to use the function Vertical_Sweep_Span() for the gray */ +/* span call. */ +/* */ +/*************************************************************************/ + static void + Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, + Short* max ) + { + Long pitch, byte_len; + *min = *min & -2; + *max = ( *max + 3 ) & -2; + ras.traceOfs = 0; + pitch = ras.target.pitch; + byte_len = -pitch; + ras.traceIncr = (Short)byte_len; + ras.traceG = ( *min / 2 ) * byte_len; + if ( pitch > 0 ) + { + ras.traceG += ( ras.target.rows - 1 ) * pitch; + byte_len = -byte_len; + } + ras.gray_min_x = (Short)byte_len; + ras.gray_max_x = -(Short)byte_len; + } + static void + Vertical_Gray_Sweep_Step( RAS_ARG ) + { + Int c1, c2; + PByte pix, bit, bit2; + short* count = (short*)count_table; + Byte* grays; + ras.traceOfs += ras.gray_width; + if ( ras.traceOfs > ras.gray_width ) + { + pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; + grays = ras.grays; + if ( ras.gray_max_x >= 0 ) + { + Long last_pixel = ras.target.width - 1; + Int last_cell = last_pixel >> 2; + Int last_bit = last_pixel & 3; + Bool over = 0; + if ( ras.gray_max_x >= last_cell && last_bit != 3 ) + { + ras.gray_max_x = last_cell - 1; + over = 1; + } + if ( ras.gray_min_x < 0 ) + ras.gray_min_x = 0; + bit = ras.bTarget + ras.gray_min_x; + bit2 = bit + ras.gray_width; + c1 = ras.gray_max_x - ras.gray_min_x; + while ( c1 >= 0 ) + { + c2 = count[*bit] + count[*bit2]; + if ( c2 ) + { + pix[0] = grays[(c2 >> 12) & 0x000F]; + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + pix[3] = grays[ c2 & 0x000F]; + *bit = 0; + *bit2 = 0; + } + bit++; + bit2++; + pix += 4; + c1--; + } + if ( over ) + { + c2 = count[*bit] + count[*bit2]; + if ( c2 ) + { + switch ( last_bit ) + { + case 2: + pix[2] = grays[(c2 >> 4 ) & 0x000F]; + case 1: + pix[1] = grays[(c2 >> 8 ) & 0x000F]; + default: + pix[0] = grays[(c2 >> 12) & 0x000F]; + } + *bit = 0; + *bit2 = 0; + } + } + } + ras.traceOfs = 0; + ras.traceG += ras.traceIncr; + ras.gray_min_x = 32000; + ras.gray_max_x = -32000; + } + } + static void + Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { +/* nothing, really */ + FT_UNUSED_RASTER; + FT_UNUSED( y ); + FT_UNUSED( x1 ); + FT_UNUSED( x2 ); + FT_UNUSED( left ); + FT_UNUSED( right ); + } + static void + Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, + FT_F26Dot6 x1, + FT_F26Dot6 x2, + PProfile left, + PProfile right ) + { + Long e1, e2; + PByte pixel; + Byte color; +/* During the horizontal sweep, we only take care of drop-outs */ + e1 = CEILING( x1 ); + e2 = FLOOR ( x2 ); + if ( e1 > e2 ) + { + Int dropOutControl = left->flags & 7; + if ( e1 == e2 + ras.precision ) + { + switch ( dropOutControl ) + { +/* simple drop-outs including stubs */ + case 0: + e1 = e2; + break; +/* smart drop-outs including stubs */ + case 4: + e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); + break; +/* simple drop-outs excluding stubs */ + case 1: +/* smart drop-outs excluding stubs */ + case 5: +/* see Vertical_Sweep_Drop for details */ +/* rightmost stub test */ + if ( left->next == right && left->height <= 0 ) + return; +/* leftmost stub test */ + if ( right->next == left && left->start == y ) + return; + if ( dropOutControl == 1 ) + e1 = e2; + else + e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); + break; +/* modes 2, 3, 6, 7 */ + default: +/* no drop-out control */ + return; + } + } + else + return; + } + if ( e1 >= 0 ) + { + if ( x2 - x1 >= ras.precision_half ) + color = ras.grays[2]; + else + color = ras.grays[1]; + e1 = TRUNC( e1 ) / 2; + if ( e1 < ras.target.rows ) + { + pixel = ras.gTarget - e1 * ras.target.pitch + y / 2; + if ( ras.target.pitch > 0 ) + pixel += ( ras.target.rows - 1 ) * ras.target.pitch; + if ( pixel[0] == ras.grays[0] ) + pixel[0] = color; + } + } + } +/* FT_RASTER_OPTION_ANTI_ALIASING */ +#endif +/*************************************************************************/ +/* */ +/* Generic Sweep Drawing routine */ +/* */ +/*************************************************************************/ + static Bool + Draw_Sweep( RAS_ARG ) + { + Short y, y_change, y_height; + PProfile P, Q, P_Left, P_Right; + Short min_Y, max_Y, top, bottom, dropouts; + Long x1, x2, xs, e1, e2; + TProfileList waiting; + TProfileList draw_left, draw_right; +/* initialize empty linked lists */ + Init_Linked( &waiting ); + Init_Linked( &draw_left ); + Init_Linked( &draw_right ); +/* first, compute min and max Y */ + P = ras.fProfile; + max_Y = (Short)TRUNC( ras.minY ); + min_Y = (Short)TRUNC( ras.maxY ); + while ( P ) + { + Q = P->link; + bottom = (Short)P->start; + top = (Short)( P->start + P->height - 1 ); + if ( min_Y > bottom ) + min_Y = bottom; + if ( max_Y < top ) + max_Y = top; + P->X = 0; + InsNew( &waiting, P ); + P = Q; + } +/* check the Y-turns */ + if ( ras.numTurns == 0 ) + { + ras.error = Raster_Err_Invalid; + return FAILURE; + } +/* now initialize the sweep */ + ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); +/* then compute the distance of each profile from min_Y */ + P = waiting; + while ( P ) + { + P->countL = (UShort)( P->start - min_Y ); + P = P->link; + } +/* let's go */ + y = min_Y; + y_height = 0; + if ( ras.numTurns > 0 && + ras.sizeBuff[-ras.numTurns] == min_Y ) + ras.numTurns--; + while ( ras.numTurns > 0 ) + { +/* check waiting list for new activations */ + P = waiting; + while ( P ) + { + Q = P->link; + P->countL -= y_height; + if ( P->countL == 0 ) + { + DelOld( &waiting, P ); + if ( P->flags & Flow_Up ) + InsNew( &draw_left, P ); + else + InsNew( &draw_right, P ); + } + P = Q; + } +/* sort the drawing lists */ + Sort( &draw_left ); + Sort( &draw_right ); + y_change = (Short)ras.sizeBuff[-ras.numTurns--]; + y_height = (Short)( y_change - y ); + while ( y < y_change ) + { +/* let's trace */ + dropouts = 0; + P_Left = draw_left; + P_Right = draw_right; + while ( P_Left ) + { + x1 = P_Left ->X; + x2 = P_Right->X; + if ( x1 > x2 ) + { + xs = x1; + x1 = x2; + x2 = xs; + } + e1 = FLOOR( x1 ); + e2 = CEILING( x2 ); + if ( x2 - x1 <= ras.precision && + e1 != x1 && e2 != x2 ) + { + if ( e1 > e2 || e2 == e1 + ras.precision ) + { + Int dropOutControl = P_Left->flags & 7; + if ( dropOutControl != 2 ) + { +/* a drop-out was detected */ + P_Left ->X = x1; + P_Right->X = x2; +/* mark profile for drop-out processing */ + P_Left->countL = 1; + dropouts++; + } + goto Skip_To_Next; + } + } + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); + Skip_To_Next: + P_Left = P_Left->link; + P_Right = P_Right->link; + } +/* handle drop-outs _after_ the span drawing -- */ +/* drop-out processing has been moved out of the loop */ +/* for performance tuning */ + if ( dropouts > 0 ) + goto Scan_DropOuts; + Next_Line: + ras.Proc_Sweep_Step( RAS_VAR ); + y++; + if ( y < y_change ) + { + Sort( &draw_left ); + Sort( &draw_right ); + } + } +/* now finalize the profiles that need it */ + P = draw_left; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_left, P ); + P = Q; + } + P = draw_right; + while ( P ) + { + Q = P->link; + if ( P->height == 0 ) + DelOld( &draw_right, P ); + P = Q; + } + } +/* for gray-scaling, flush the bitmap scanline cache */ + while ( y <= max_Y ) + { + ras.Proc_Sweep_Step( RAS_VAR ); + y++; + } + return SUCCESS; + Scan_DropOuts: + P_Left = draw_left; + P_Right = draw_right; + while ( P_Left ) + { + if ( P_Left->countL ) + { + P_Left->countL = 0; +#if 0 +/* -- this is useful when debugging only */ + dropouts--; +#endif + ras.Proc_Sweep_Drop( RAS_VARS y, + P_Left->X, + P_Right->X, + P_Left, + P_Right ); + } + P_Left = P_Left->link; + P_Right = P_Right->link; + } + goto Next_Line; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Render_Single_Pass */ +/* */ +/* <Description> */ +/* Perform one sweep with sub-banding. */ +/* */ +/* <Input> */ +/* flipped :: If set, flip the direction of the outline. */ +/* */ +/* <Return> */ +/* Renderer error code. */ +/* */ + static int + Render_Single_Pass( RAS_ARGS Bool flipped ) + { + Short i, j, k; + while ( ras.band_top >= 0 ) + { + ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; + ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; + ras.top = ras.buff; + ras.error = Raster_Err_None; + if ( Convert_Glyph( RAS_VARS flipped ) ) + { + if ( ras.error != Raster_Err_Overflow ) + return FAILURE; + ras.error = Raster_Err_None; +/* sub-banding */ +#ifdef DEBUG_RASTER + ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); +#endif + i = ras.band_stack[ras.band_top].y_min; + j = ras.band_stack[ras.band_top].y_max; + k = (Short)( ( i + j ) / 2 ); + if ( ras.band_top >= 7 || k < i ) + { + ras.band_top = 0; + ras.error = Raster_Err_Invalid; + return ras.error; + } + ras.band_stack[ras.band_top + 1].y_min = k; + ras.band_stack[ras.band_top + 1].y_max = j; + ras.band_stack[ras.band_top].y_max = (Short)( k - 1 ); + ras.band_top++; + } + else + { + if ( ras.fProfile ) + if ( Draw_Sweep( RAS_VAR ) ) + return ras.error; + ras.band_top--; + } + } + return SUCCESS; + } +/*************************************************************************/ +/* */ +/* <Function> */ +/* Render_Glyph */ +/* */ +/* <Description> */ +/* Render a glyph in a bitmap. Sub-banding if needed. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + Render_Glyph( RAS_ARG ) + { + FT_Error error; + Set_High_Precision( RAS_VARS ras.outline.flags & + FT_OUTLINE_HIGH_PRECISION ); + ras.scale_shift = ras.precision_shift; + if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) + ras.dropOutControl = 2; + else + { + if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) + ras.dropOutControl = 4; + else + ras.dropOutControl = 0; + if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) + ras.dropOutControl += 1; + } + ras.second_pass = (FT_Byte)( !( ras.outline.flags & + FT_OUTLINE_SINGLE_PASS ) ); +/* Vertical Sweep */ + ras.Proc_Sweep_Init = Vertical_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Sweep_Step; + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = (short)( ras.target.rows - 1 ); + ras.bWidth = (unsigned short)ras.target.width; + ras.bTarget = (Byte*)ras.target.buffer; + if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) + return error; +/* Horizontal Sweep */ + if ( ras.second_pass && ras.dropOutControl != 2 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = (short)( ras.target.width - 1 ); + if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) + return error; + } + return Raster_Err_None; + } +#ifdef FT_RASTER_OPTION_ANTI_ALIASING +/*************************************************************************/ +/* */ +/* <Function> */ +/* Render_Gray_Glyph */ +/* */ +/* <Description> */ +/* Render a glyph with grayscaling. Sub-banding if needed. */ +/* */ +/* <Return> */ +/* FreeType error code. 0 means success. */ +/* */ + FT_LOCAL_DEF( FT_Error ) + Render_Gray_Glyph( RAS_ARG ) + { + Long pixel_width; + FT_Error error; + Set_High_Precision( RAS_VARS ras.outline.flags & + FT_OUTLINE_HIGH_PRECISION ); + ras.scale_shift = ras.precision_shift + 1; + if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) + ras.dropOutControl = 2; + else + { + if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) + ras.dropOutControl = 4; + else + ras.dropOutControl = 0; + if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) + ras.dropOutControl += 1; + } + ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ); +/* Vertical Sweep */ + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = 2 * ras.target.rows - 1; + ras.bWidth = ras.gray_width; + pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); + if ( ras.bWidth > pixel_width ) + ras.bWidth = pixel_width; + ras.bWidth = ras.bWidth * 8; + ras.bTarget = (Byte*)ras.gray_lines; + ras.gTarget = (Byte*)ras.target.buffer; + ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; + ras.Proc_Sweep_Span = Vertical_Sweep_Span; + ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; + ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; + error = Render_Single_Pass( RAS_VARS 0 ); + if ( error ) + return error; +/* Horizontal Sweep */ + if ( ras.second_pass && ras.dropOutControl != 2 ) + { + ras.Proc_Sweep_Init = Horizontal_Sweep_Init; + ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; + ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; + ras.Proc_Sweep_Step = Horizontal_Sweep_Step; + ras.band_top = 0; + ras.band_stack[0].y_min = 0; + ras.band_stack[0].y_max = ras.target.width * 2 - 1; + error = Render_Single_Pass( RAS_VARS 1 ); + if ( error ) + return error; + } + return Raster_Err_None; + } +/* !FT_RASTER_OPTION_ANTI_ALIASING */ +#else + FT_LOCAL_DEF( FT_Error ) + Render_Gray_Glyph( RAS_ARG ) + { + FT_UNUSED_RASTER; + return Raster_Err_Unsupported; + } +/* !FT_RASTER_OPTION_ANTI_ALIASING */ +#endif + static void + ft_black_init( black_PRaster raster ) + { +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + FT_UInt n; +/* set default 5-levels gray palette */ + for ( n = 0; n < 5; n++ ) + raster->grays[n] = n * 255 / 4; + raster->gray_width = RASTER_GRAY_LINES / 2; +#else + FT_UNUSED( raster ); +#endif + } +/**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ +/**** a static object. *****/ +#ifdef _STANDALONE_ + static int + ft_black_new( void* memory, + FT_Raster *araster ) + { + static black_TRaster the_raster; + FT_UNUSED( memory ); + *araster = (FT_Raster)&the_raster; + FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); + ft_black_init( &the_raster ); + return 0; + } + static void + ft_black_done( FT_Raster raster ) + { +/* nothing */ + FT_UNUSED( raster ); + } +/* !_STANDALONE_ */ +#else + static int + ft_black_new( FT_Memory memory, + black_PRaster *araster ) + { + FT_Error error; + black_PRaster raster = NULL; + *araster = 0; + if ( !FT_NEW( raster ) ) + { + raster->memory = memory; + ft_black_init( raster ); + *araster = raster; + } + return error; + } + static void + ft_black_done( black_PRaster raster ) + { + FT_Memory memory = (FT_Memory)raster->memory; + FT_FREE( raster ); + } +/* !_STANDALONE_ */ +#endif + static void + ft_black_reset( black_PRaster raster, + char* pool_base, + long pool_size ) + { + if ( raster ) + { + if ( pool_base && pool_size >= (long)sizeof ( black_TWorker ) + 2048 ) + { + black_PWorker worker = (black_PWorker)pool_base; + raster->buffer = pool_base + ( ( sizeof ( *worker ) + 7 ) & ~7 ); + raster->buffer_size = pool_base + pool_size - (char*)raster->buffer; + raster->worker = worker; + } + else + { + raster->buffer = NULL; + raster->buffer_size = 0; + raster->worker = NULL; + } + } + } + static void + ft_black_set_mode( black_PRaster raster, + unsigned long mode, + const char* palette ) + { +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) + { +/* set 5-levels gray palette */ + raster->grays[0] = palette[0]; + raster->grays[1] = palette[1]; + raster->grays[2] = palette[2]; + raster->grays[3] = palette[3]; + raster->grays[4] = palette[4]; + } +#else + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( palette ); +#endif + } + static int + ft_black_render( black_PRaster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + black_PWorker worker; + if ( !raster || !raster->buffer || !raster->buffer_size ) + return Raster_Err_Not_Ini; + if ( !outline ) + return Raster_Err_Invalid; +/* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return Raster_Err_None; + if ( !outline->contours || !outline->points ) + return Raster_Err_Invalid; + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return Raster_Err_Invalid; + worker = raster->worker; +/* this version of the raster does not support direct rendering, sorry */ + if ( params->flags & FT_RASTER_FLAG_DIRECT ) + return Raster_Err_Unsupported; + if ( !target_map ) + return Raster_Err_Invalid; +/* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return Raster_Err_None; + if ( !target_map->buffer ) + return Raster_Err_Invalid; + ras.outline = *outline; + ras.target = *target_map; + worker->buff = (PLong) raster->buffer; + worker->sizeBuff = worker->buff + + raster->buffer_size / sizeof ( Long ); +#ifdef FT_RASTER_OPTION_ANTI_ALIASING + worker->grays = raster->grays; + worker->gray_width = raster->gray_width; + FT_MEM_ZERO( worker->gray_lines, worker->gray_width * 2 ); +#endif + return ( params->flags & FT_RASTER_FLAG_AA ) + ? Render_Gray_Glyph( RAS_VAR ) + : Render_Glyph( RAS_VAR ); + } + FT_DEFINE_RASTER_FUNCS( ft_standard_raster, + FT_GLYPH_FORMAT_OUTLINE, + (FT_Raster_New_Func) ft_black_new, + (FT_Raster_Reset_Func) ft_black_reset, + (FT_Raster_Set_Mode_Func)ft_black_set_mode, + (FT_Raster_Render_Func) ft_black_render, + (FT_Raster_Done_Func) ft_black_done + ) +/* END */ +/***************************************************************************/ +/* */ +/* ftrend1.c */ +/* */ +/* The FreeType glyph rasterizer interface (body). */ +/* */ +/* Copyright 1996-2003, 2005, 2006, 2011 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftrend1.h */ +/* */ +/* The FreeType glyph rasterizer interface (specification). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define __FTREND1_H__ +FT_BEGIN_HEADER + FT_DECLARE_RENDERER( ft_raster1_renderer_class ) +/* this renderer is _NOT_ part of the default modules, you'll need */ +/* to register it by hand in your application. It should only be */ +/* used for backwards-compatibility with FT 1.x anyway. */ +/* */ + FT_DECLARE_RENDERER( ft_raster5_renderer_class ) +FT_END_HEADER +/* END */ +/* initialize renderer -- init its raster */ + static FT_Error + ft_raster1_init( FT_Renderer render ) + { + FT_Library library = FT_MODULE_LIBRARY( render ); + render->clazz->raster_class->raster_reset( render->raster, + library->raster_pool, + library->raster_pool_size ); + return Raster_Err_Ok; + } +/* set render-specific mode */ + static FT_Error + ft_raster1_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { +/* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } +/* transform a given glyph image */ + static FT_Error + ft_raster1_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = Raster_Err_Ok; + if ( slot->format != render->glyph_format ) + { + error = Raster_Err_Invalid_Argument; + goto Exit; + } + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + Exit: + return error; + } +/* return the glyph's control box */ + static void + ft_raster1_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } +/* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_raster1_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error; + FT_Outline* outline; + FT_BBox cbox; + FT_UInt width, height, pitch; + FT_Bitmap* bitmap; + FT_Memory memory; + FT_Raster_Params params; +/* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = Raster_Err_Invalid_Argument; + goto Exit; + } +/* check rendering mode */ + if ( mode != FT_RENDER_MODE_MONO ) + { +/* raster1 is only capable of producing monochrome bitmaps */ + if ( render->clazz == &ft_raster1_renderer_class ) + return Raster_Err_Cannot_Render_Glyph; + } + else + { +/* raster5 is only capable of producing 5-gray-levels bitmaps */ + if ( render->clazz == &ft_raster5_renderer_class ) + return Raster_Err_Cannot_Render_Glyph; + } + outline = &slot->outline; +/* translate the outline to the new origin if needed */ + if ( origin ) + FT_Outline_Translate( outline, origin->x, origin->y ); +/* compute the control box, and grid fit it */ + FT_Outline_Get_CBox( outline, &cbox ); +/* undocumented but confirmed: bbox values get rounded */ +#if 1 + cbox.xMin = FT_PIX_ROUND( cbox.xMin ); + cbox.yMin = FT_PIX_ROUND( cbox.yMin ); + cbox.xMax = FT_PIX_ROUND( cbox.xMax ); + cbox.yMax = FT_PIX_ROUND( cbox.yMax ); +#else + cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); + cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); + cbox.xMax = FT_PIX_CEIL( cbox.xMax ); + cbox.yMax = FT_PIX_CEIL( cbox.yMax ); +#endif + width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); + height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); + if ( width > FT_USHORT_MAX || height > FT_USHORT_MAX ) + { + error = Raster_Err_Invalid_Argument; + goto Exit; + } + bitmap = &slot->bitmap; + memory = render->root.memory; +/* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } +/* allocate new one, depends on pixel format */ + if ( !( mode & FT_RENDER_MODE_MONO ) ) + { +/* we pad to 32 bits, only for backwards compatibility with FT 1.x */ + pitch = FT_PAD_CEIL( width, 4 ); + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + } + else + { + pitch = ( ( width + 15 ) >> 4 ) << 1; + bitmap->pixel_mode = FT_PIXEL_MODE_MONO; + } + bitmap->width = width; + bitmap->rows = height; + bitmap->pitch = pitch; + if ( FT_ALLOC_MULT( bitmap->buffer, pitch, height ) ) + goto Exit; + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; +/* translate outline to render it into the bitmap */ + FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin ); +/* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = 0; + if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY ) + params.flags |= FT_RASTER_FLAG_AA; +/* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + FT_Outline_Translate( outline, cbox.xMin, cbox.yMin ); + if ( error ) + goto Exit; + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 ); + slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 ); + Exit: + return error; + } + FT_DEFINE_RENDERER( ft_raster1_renderer_class, + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + "raster1", + 0x10000L, + 0x20000L, +/* module specific interface */ + 0, + (FT_Module_Constructor)ft_raster1_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + , + FT_GLYPH_FORMAT_OUTLINE, + (FT_Renderer_RenderFunc) ft_raster1_render, + (FT_Renderer_TransformFunc)ft_raster1_transform, + (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, + (FT_Renderer_SetModeFunc) ft_raster1_set_mode, + (FT_Raster_Funcs*) &FT_STANDARD_RASTER_GET + ) +/* This renderer is _NOT_ part of the default modules; you will need */ +/* to register it by hand in your application. It should only be */ +/* used for backwards-compatibility with FT 1.x anyway. */ +/* */ + FT_DEFINE_RENDERER( ft_raster5_renderer_class, + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + "raster5", + 0x10000L, + 0x20000L, +/* module specific interface */ + 0, + (FT_Module_Constructor)ft_raster1_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + , + FT_GLYPH_FORMAT_OUTLINE, + (FT_Renderer_RenderFunc) ft_raster1_render, + (FT_Renderer_TransformFunc)ft_raster1_transform, + (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, + (FT_Renderer_SetModeFunc) ft_raster1_set_mode, + (FT_Raster_Funcs*) &FT_STANDARD_RASTER_GET + ) +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* smooth.c */ +/* */ +/* FreeType anti-aliasing rasterer module component (body only). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* ftspic.c */ +/* */ +/* The FreeType position independent code services for smooth module. */ +/* */ +/* Copyright 2009, 2010, 2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftspic.h */ +/* */ +/* The FreeType position independent code services for smooth module. */ +/* */ +/* Copyright 2009 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __FTSPIC_H__ +FT_BEGIN_HEADER +#define FT_GRAYS_RASTER_GET ft_grays_raster +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* ftsmerrs.h */ +/* */ +/* smooth renderer error codes (specification only). */ +/* */ +/* Copyright 2001, 2012 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 smooth renderer error enumeration */ +/* constants. */ +/* */ +/*************************************************************************/ +#define __FTSMERRS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Smooth_Err_ +#define FT_ERR_BASE FT_Mod_Err_Smooth +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* ftgrays.c */ +/* */ +/* A new `perfect' anti-aliasing renderer (body). */ +/* */ +/* Copyright 2000-2003, 2005-2012 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 can be compiled without the rest of the FreeType engine, by */ +/* defining the _STANDALONE_ macro when compiling it. You also need to */ +/* put the files `ftgrays.h' and `ftimage.h' into the current */ +/* compilation directory. Typically, you could do something like */ +/* */ +/* - copy `src/smooth/ftgrays.c' (this file) to your current directory */ +/* */ +/* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */ +/* same directory */ +/* */ +/* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */ +/* */ +/* cc -c -D_STANDALONE_ ftgrays.c */ +/* */ +/* The renderer can be initialized with a call to */ +/* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */ +/* with a call to `ft_gray_raster.raster_render'. */ +/* */ +/* See the comments and documentation in the file `ftimage.h' for more */ +/* details on how the raster works. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* This is a new anti-aliasing scan-converter for FreeType 2. The */ +/* algorithm used here is _very_ different from the one in the standard */ +/* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ +/* coverage of the outline on each pixel cell. */ +/* */ +/* It is based on ideas that I initially found in Raph Levien's */ +/* excellent LibArt graphics library (see http://www.levien.com/libart */ +/* for more information, though the web pages do not tell anything */ +/* about the renderer; you'll have to dive into the source code to */ +/* understand how it works). */ +/* */ +/* Note, however, that this is a _very_ different implementation */ +/* compared to Raph's. Coverage information is stored in a very */ +/* different way, and I don't use sorted vector paths. Also, it doesn't */ +/* use floating point values. */ +/* */ +/* This renderer has the following advantages: */ +/* */ +/* - It doesn't need an intermediate bitmap. Instead, one can supply a */ +/* callback function that will be called by the renderer to draw gray */ +/* spans on any target surface. You can thus do direct composition on */ +/* any kind of bitmap, provided that you give the renderer the right */ +/* callback. */ +/* */ +/* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ +/* each pixel cell. */ +/* */ +/* - It performs a single pass on the outline (the `standard' FT2 */ +/* renderer makes two passes). */ +/* */ +/* - It can easily be modified to render to _any_ number of gray levels */ +/* cheaply. */ +/* */ +/* - For small (< 20) pixel sizes, it is faster than the standard */ +/* renderer. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* 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 trace_smooth +#ifdef _STANDALONE_ +/* define this to dump debugging information */ +/* #define FT_DEBUG_LEVEL_TRACE */ +#include <stddef.h> +#include <string.h> +#include <setjmp.h> +#include <limits.h> +#define FT_UINT_MAX UINT_MAX +#define FT_INT_MAX INT_MAX +#define ft_memset memset +#define ft_setjmp setjmp +#define ft_longjmp longjmp +#define ft_jmp_buf jmp_buf +typedef ptrdiff_t FT_PtrDist; +#define ErrRaster_Invalid_Mode -2 +#define ErrRaster_Invalid_Outline -1 +#define ErrRaster_Invalid_Argument -3 +#define ErrRaster_Memory_Overflow -4 +#define FT_BEGIN_HEADER +#define FT_END_HEADER +#include "ftimage.h" +/***************************************************************************/ +/* */ +/* ftgrays.h */ +/* */ +/* FreeType smooth renderer declaration */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define __FTGRAYS_H__ +#ifdef __cplusplus + extern "C" { +#endif +#ifdef _STANDALONE_ +#include "ftimage.h" +#else +/* for FT_CONFIG_OPTION_PIC */ +#endif +/*************************************************************************/ +/* */ +/* To make ftgrays.h independent from configuration files we check */ +/* whether FT_EXPORT_VAR has been defined already. */ +/* */ +/* On some systems and compilers (Win32 mostly), an extra keyword is */ +/* necessary to compile the library as a DLL. */ +/* */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) extern x +#endif + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster; +#ifdef __cplusplus + } +#endif +/* END */ +/* This macro is used to indicate that a function parameter is unused. */ +/* Its purpose is simply to reduce compiler warnings. Note also that */ +/* simply defining it as `(void)x' doesn't avoid warnings with certain */ +/* ANSI compilers (e.g. LCC). */ +#define FT_UNUSED( x ) (x) = (x) +/* we only use level 5 & 7 tracing messages; cf. ftdebug.h */ +/* nothing */ +#define FT_TRACE5( x ) do { } while ( 0 ) +/* nothing */ +#define FT_TRACE7( x ) do { } while ( 0 ) +/* nothing */ +#define FT_ERROR( x ) do { } while ( 0 ) +#define FT_DEFINE_OUTLINE_FUNCS( class_, \ + move_to_, line_to_, \ + conic_to_, cubic_to_, \ + shift_, delta_ ) \ + static const FT_Outline_Funcs class_ = \ + { \ + move_to_, \ + line_to_, \ + conic_to_, \ + cubic_to_, \ + shift_, \ + delta_ \ + }; +#define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, \ + raster_new_, raster_reset_, \ + raster_set_mode_, raster_render_, \ + raster_done_ ) \ + const FT_Raster_Funcs class_ = \ + { \ + glyph_format_, \ + raster_new_, \ + raster_reset_, \ + raster_set_mode_, \ + raster_render_, \ + raster_done_ \ + }; +/* !_STANDALONE_ */ +#else +#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph +#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline +#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory +#define ErrRaster_Invalid_Argument Smooth_Err_Invalid_Argument +/* !_STANDALONE_ */ +#endif +#ifndef FT_MEM_SET +#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) +#endif +#ifndef FT_MEM_ZERO +#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) +#endif +/* as usual, for the speed hungry :-) */ +#undef RAS_ARG +#undef RAS_ARG_ +#undef RAS_VAR +#undef RAS_VAR_ +#ifndef FT_STATIC_RASTER +#define RAS_ARG gray_PWorker worker +#define RAS_ARG_ gray_PWorker worker, +#define RAS_VAR worker +#define RAS_VAR_ worker, +/* FT_STATIC_RASTER */ +#else +/* empty */ +#define RAS_ARG +/* empty */ +#define RAS_ARG_ +/* empty */ +#define RAS_VAR +/* empty */ +#define RAS_VAR_ +/* FT_STATIC_RASTER */ +#endif +/* must be at least 6 bits! */ +#define PIXEL_BITS 8 +#undef FLOOR +#undef CEILING +#undef TRUNC +#undef SCALED +#define ONE_PIXEL ( 1L << PIXEL_BITS ) +#define PIXEL_MASK ( -1L << PIXEL_BITS ) +#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) +#define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) +#define FLOOR( x ) ( (x) & -ONE_PIXEL ) +#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) +#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) ) +#endif +/*************************************************************************/ +/* */ +/* TYPE DEFINITIONS */ +/* */ +/* don't change the following types to FT_Int or FT_Pos, since we might */ +/* need to define them to "float" or "double" when experimenting with */ +/* new algorithms */ +/* integer scanline/pixel coordinate */ + typedef long TCoord; +/* sub-pixel coordinate */ + typedef long TPos; +/* determine the type used to store cell areas. This normally takes at */ +/* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */ +/* `long' instead of `int', otherwise bad things happen */ +#if PIXEL_BITS <= 7 + typedef int TArea; +/* PIXEL_BITS >= 8 */ +#else +/* approximately determine the size of integers using an ANSI-C header */ +#if FT_UINT_MAX == 0xFFFFU + typedef long TArea; +#else + typedef int TArea; +#endif +/* PIXEL_BITS >= 8 */ +#endif +/* maximum number of gray spans in a call to the span callback */ +#define FT_MAX_GRAY_SPANS 32 + typedef struct TCell_* PCell; + typedef struct TCell_ + { +/* same with gray_TWorker.ex */ + TPos x; +/* same with gray_TWorker.cover */ + TCoord cover; + TArea area; + PCell next; + } TCell; + typedef struct gray_TWorker_ + { + TCoord ex, ey; + TPos min_ex, max_ex; + TPos min_ey, max_ey; + TPos count_ex, count_ey; + TArea area; + TCoord cover; + int invalid; + PCell cells; + FT_PtrDist max_cells; + FT_PtrDist num_cells; + TCoord cx, cy; + TPos x, y; + TPos last_ey; + FT_Vector bez_stack[32 * 3 + 1]; + int lev_stack[32]; + FT_Outline outline; + FT_Bitmap target; + FT_BBox clip_box; + FT_Span gray_spans[FT_MAX_GRAY_SPANS]; + int num_gray_spans; + FT_Raster_Span_Func render_span; + void* render_span_data; + int span_y; + int band_size; + int band_shoot; + ft_jmp_buf jump_buffer; + void* buffer; + long buffer_size; + PCell* ycells; + TPos ycount; + } gray_TWorker, *gray_PWorker; +#ifndef FT_STATIC_RASTER +#define ras (*worker) +#else + static gray_TWorker ras; +#endif + typedef struct gray_TRaster_ + { + void* buffer; + long buffer_size; + int band_size; + void* memory; + gray_PWorker worker; + } gray_TRaster, *gray_PRaster; +/*************************************************************************/ +/* */ +/* Initialize the cells table. */ +/* */ + static void + gray_init_cells( RAS_ARG_ void* buffer, + long byte_size ) + { + ras.buffer = buffer; + ras.buffer_size = byte_size; + ras.ycells = (PCell*) buffer; + ras.cells = NULL; + ras.max_cells = 0; + ras.num_cells = 0; + ras.area = 0; + ras.cover = 0; + ras.invalid = 1; + } +/*************************************************************************/ +/* */ +/* Compute the outline bounding box. */ +/* */ + static void + gray_compute_cbox( RAS_ARG ) + { + FT_Outline* outline = &ras.outline; + FT_Vector* vec = outline->points; + FT_Vector* limit = vec + outline->n_points; + if ( outline->n_points <= 0 ) + { + ras.min_ex = ras.max_ex = 0; + ras.min_ey = ras.max_ey = 0; + return; + } + ras.min_ex = ras.max_ex = vec->x; + ras.min_ey = ras.max_ey = vec->y; + vec++; + for ( ; vec < limit; vec++ ) + { + TPos x = vec->x; + TPos y = vec->y; + if ( x < ras.min_ex ) ras.min_ex = x; + if ( x > ras.max_ex ) ras.max_ex = x; + if ( y < ras.min_ey ) ras.min_ey = y; + if ( y > ras.max_ey ) ras.max_ey = y; + } +/* truncate the bounding box to integer pixels */ + ras.min_ex = ras.min_ex >> 6; + ras.min_ey = ras.min_ey >> 6; + ras.max_ex = ( ras.max_ex + 63 ) >> 6; + ras.max_ey = ( ras.max_ey + 63 ) >> 6; + } +/*************************************************************************/ +/* */ +/* Record the current cell in the table. */ +/* */ + static PCell + gray_find_cell( RAS_ARG ) + { + PCell *pcell, cell; + TPos x = ras.ex; + if ( x > ras.count_ex ) + x = ras.count_ex; + pcell = &ras.ycells[ras.ey]; + for (;;) + { + cell = *pcell; + if ( cell == NULL || cell->x > x ) + break; + if ( cell->x == x ) + goto Exit; + pcell = &cell->next; + } + if ( ras.num_cells >= ras.max_cells ) + ft_longjmp( ras.jump_buffer, 1 ); + cell = ras.cells + ras.num_cells++; + cell->x = x; + cell->area = 0; + cell->cover = 0; + cell->next = *pcell; + *pcell = cell; + Exit: + return cell; + } + static void + gray_record_cell( RAS_ARG ) + { + if ( !ras.invalid && ( ras.area | ras.cover ) ) + { + PCell cell = gray_find_cell( RAS_VAR ); + cell->area += ras.area; + cell->cover += ras.cover; + } + } +/*************************************************************************/ +/* */ +/* Set the current cell to a new position. */ +/* */ + static void + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { +/* Move the cell pointer to a new position. We set the `invalid' */ +/* flag to indicate that the cell isn't part of those we're interested */ +/* in during the render phase. This means that: */ +/* */ +/* . the new vertical position must be within min_ey..max_ey-1. */ +/* . the new horizontal position must be strictly less than max_ex */ +/* */ +/* Note that if a cell is to the left of the clipping region, it is */ +/* actually set to the (min_ex-1) horizontal position. */ +/* All cells that are on the left of the clipping region go to the */ +/* min_ex - 1 horizontal position. */ + ey -= ras.min_ey; + if ( ex > ras.max_ex ) + ex = ras.max_ex; + ex -= ras.min_ex; + if ( ex < 0 ) + ex = -1; +/* are we moving to a different cell ? */ + if ( ex != ras.ex || ey != ras.ey ) + { +/* record the current one if it is valid */ + if ( !ras.invalid ) + gray_record_cell( RAS_VAR ); + ras.area = 0; + ras.cover = 0; + } + ras.ex = ex; + ras.ey = ey; + ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey || + ex >= ras.count_ex ); + } +/*************************************************************************/ +/* */ +/* Start a new contour at a given cell. */ +/* */ + static void + gray_start_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + if ( ex > ras.max_ex ) + ex = (TCoord)( ras.max_ex ); + if ( ex < ras.min_ex ) + ex = (TCoord)( ras.min_ex - 1 ); + ras.area = 0; + ras.cover = 0; + ras.ex = ex - ras.min_ex; + ras.ey = ey - ras.min_ey; + ras.last_ey = SUBPIXELS( ey ); + ras.invalid = 0; + gray_set_cell( RAS_VAR_ ex, ey ); + } +/*************************************************************************/ +/* */ +/* Render a scanline as one or more cells. */ +/* */ + static void + gray_render_scanline( RAS_ARG_ TCoord ey, + TPos x1, + TCoord y1, + TPos x2, + TCoord y2 ) + { + TCoord ex1, ex2, fx1, fx2, delta, mod, lift, rem; + long p, first, dx; + int incr; + dx = x2 - x1; + ex1 = TRUNC( x1 ); + ex2 = TRUNC( x2 ); + fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); + fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); +/* trivial case. Happens often */ + if ( y1 == y2 ) + { + gray_set_cell( RAS_VAR_ ex2, ey ); + return; + } +/* everything is located in a single cell. That is easy! */ +/* */ + if ( ex1 == ex2 ) + { + delta = y2 - y1; + ras.area += (TArea)(( fx1 + fx2 ) * delta); + ras.cover += delta; + return; + } +/* ok, we'll have to render a run of adjacent cells on the same */ +/* scanline... */ +/* */ + p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); + first = ONE_PIXEL; + incr = 1; + if ( dx < 0 ) + { + p = fx1 * ( y2 - y1 ); + first = 0; + incr = -1; + dx = -dx; + } + delta = (TCoord)( p / dx ); + mod = (TCoord)( p % dx ); + if ( mod < 0 ) + { + delta--; + mod += (TCoord)dx; + } + ras.area += (TArea)(( fx1 + first ) * delta); + ras.cover += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + y1 += delta; + if ( ex1 != ex2 ) + { + p = ONE_PIXEL * ( y2 - y1 + delta ); + lift = (TCoord)( p / dx ); + rem = (TCoord)( p % dx ); + if ( rem < 0 ) + { + lift--; + rem += (TCoord)dx; + } + mod -= (int)dx; + while ( ex1 != ex2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= (TCoord)dx; + delta++; + } + ras.area += (TArea)(ONE_PIXEL * delta); + ras.cover += delta; + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + } + } + delta = y2 - y1; + ras.area += (TArea)(( fx2 + ONE_PIXEL - first ) * delta); + ras.cover += delta; + } +/*************************************************************************/ +/* */ +/* Render a given line as a series of scanlines. */ +/* */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TCoord ey1, ey2, fy1, fy2, mod; + TPos dx, dy, x, x2; + long p, first; + int delta, rem, lift, incr; + ey1 = TRUNC( ras.last_ey ); +/* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + ey2 = TRUNC( to_y ); + fy1 = (TCoord)( ras.y - ras.last_ey ); + fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); + dx = to_x - ras.x; + dy = to_y - ras.y; +/* XXX: we should do something about the trivial case where dx == 0, */ +/* as it happens very often! */ +/* perform vertical clipping */ + { + TCoord min, max; + min = ey1; + max = ey2; + if ( ey1 > ey2 ) + { + min = ey2; + max = ey1; + } + if ( min >= ras.max_ey || max < ras.min_ey ) + goto End; + } +/* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); + goto End; + } +/* vertical line - avoid calling gray_render_scanline */ + incr = 1; + if ( dx == 0 ) + { + TCoord ex = TRUNC( ras.x ); + TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); + TArea area; + first = ONE_PIXEL; + if ( dy < 0 ) + { + first = 0; + incr = -1; + } + delta = (int)( first - fy1 ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + ey1 += incr; + gray_set_cell( RAS_VAR_ ex, ey1 ); + delta = (int)( first + first - ONE_PIXEL ); + area = (TArea)two_fx * delta; + while ( ey1 != ey2 ) + { + ras.area += area; + ras.cover += delta; + ey1 += incr; + gray_set_cell( RAS_VAR_ ex, ey1 ); + } + delta = (int)( fy2 - ONE_PIXEL + first ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + goto End; + } +/* ok, we have to render several scanlines */ + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + if ( dy < 0 ) + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + delta = (int)( p / dy ); + mod = (int)( p % dy ); + if ( mod < 0 ) + { + delta--; + mod += (TCoord)dy; + } + x = ras.x + delta; + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + if ( ey1 != ey2 ) + { + p = ONE_PIXEL * dx; + lift = (int)( p / dy ); + rem = (int)( p % dy ); + if ( rem < 0 ) + { + lift--; + rem += (int)dy; + } + mod -= (int)dy; + while ( ey1 != ey2 ) + { + delta = lift; + mod += rem; + if ( mod >= 0 ) + { + mod -= (int)dy; + delta++; + } + x2 = x + delta; + gray_render_scanline( RAS_VAR_ ey1, x, + (TCoord)( ONE_PIXEL - first ), x2, + (TCoord)first ); + x = x2; + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + } + } + gray_render_scanline( RAS_VAR_ ey1, x, + (TCoord)( ONE_PIXEL - first ), to_x, + fy2 ); + End: + ras.x = to_x; + ras.y = to_y; + ras.last_ey = SUBPIXELS( ey2 ); + } + static void + gray_split_conic( FT_Vector* base ) + { + TPos a, b; + base[4].x = base[2].x; + b = base[1].x; + a = base[3].x = ( base[2].x + b ) / 2; + b = base[1].x = ( base[0].x + b ) / 2; + base[2].x = ( a + b ) / 2; + base[4].y = base[2].y; + b = base[1].y; + a = base[3].y = ( base[2].y + b ) / 2; + b = base[1].y = ( base[0].y + b ) / 2; + base[2].y = ( a + b ) / 2; + } + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + TPos dx, dy; + TPos min, max, y; + int top, level; + int* levels; + FT_Vector* arc; + levels = ras.lev_stack; + arc = ras.bez_stack; + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + top = 0; + dx = FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); + dy = FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); + if ( dx < dy ) + dx = dy; + if ( dx < ONE_PIXEL / 4 ) + goto Draw; +/* short-cut the arc that crosses the current band */ + min = max = arc[0].y; + y = arc[1].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + y = arc[2].y; + if ( y < min ) min = y; + if ( y > max ) max = y; + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) + goto Draw; + level = 0; + do + { + dx >>= 2; + level++; + } while ( dx > ONE_PIXEL / 4 ); + levels[0] = level; + do + { + level = levels[top]; + if ( level > 0 ) + { + gray_split_conic( arc ); + arc += 2; + top++; + levels[top] = levels[top - 1] = level - 1; + continue; + } + Draw: + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + top--; + arc -= 2; + } while ( top >= 0 ); + } + static void + gray_split_cubic( FT_Vector* base ) + { + TPos a, b, c, d; + base[6].x = base[3].x; + c = base[1].x; + d = base[2].x; + base[1].x = a = ( base[0].x + c ) / 2; + base[5].x = b = ( base[3].x + d ) / 2; + c = ( c + d ) / 2; + base[2].x = a = ( a + c ) / 2; + base[4].x = b = ( b + c ) / 2; + base[3].x = ( a + b ) / 2; + base[6].y = base[3].y; + c = base[1].y; + d = base[2].y; + base[1].y = a = ( base[0].y + c ) / 2; + base[5].y = b = ( base[3].y + d ) / 2; + c = ( c + d ) / 2; + base[2].y = a = ( a + c ) / 2; + base[4].y = b = ( b + c ) / 2; + base[3].y = ( a + b ) / 2; + } + static void + gray_render_cubic( RAS_ARG_ const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to ) + { + FT_Vector* arc; + TPos min, max, y; + arc = ras.bez_stack; + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + arc[2].y = UPSCALE( control1->y ); + arc[3].x = ras.x; + arc[3].y = ras.y; +/* Short-cut the arc that crosses the current band. */ + min = max = arc[0].y; + y = arc[1].y; + if ( y < min ) + min = y; + if ( y > max ) + max = y; + y = arc[2].y; + if ( y < min ) + min = y; + if ( y > max ) + max = y; + y = arc[3].y; + if ( y < min ) + min = y; + if ( y > max ) + max = y; + if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey ) + goto Draw; + for (;;) + { +/* Decide whether to split or draw. See `Rapid Termination */ +/* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */ +/* F. Hain, at */ +/* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */ + { + TPos dx, dy, dx_, dy_; + TPos dx1, dy1, dx2, dy2; + TPos L, s, s_limit; +/* dx and dy are x and y components of the P0-P3 chord vector. */ + dx = arc[3].x - arc[0].x; + dy = arc[3].y - arc[0].y; +/* L is an (under)estimate of the Euclidean distance P0-P3. */ +/* */ +/* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated */ +/* with least maximum error by */ +/* */ +/* r_upperbound = dx + (sqrt(2) - 1) * dy , */ +/* */ +/* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */ +/* error of no more than 8.4%. */ +/* */ +/* Similarly, some elementary calculus shows that r can be */ +/* underestimated with least maximum error by */ +/* */ +/* r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx */ +/* + sqrt(2 - sqrt(2)) / 2 * dy . */ +/* */ +/* 236/256 and 97/256 are (under)estimates of the two algebraic */ +/* numbers, giving an error of no more than 8.1%. */ + dx_ = FT_ABS( dx ); + dy_ = FT_ABS( dy ); +/* This is the same as */ +/* */ +/* L = ( 236 * FT_MAX( dx_, dy_ ) */ +/* + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */ + L = ( dx_ > dy_ ? 236 * dx_ + 97 * dy_ + : 97 * dx_ + 236 * dy_ ) >> 8; +/* Avoid possible arithmetic overflow below by splitting. */ + if ( L > 32767 ) + goto Split; +/* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */ + s_limit = L * (TPos)( ONE_PIXEL / 6 ); +/* s is L * the perpendicular distance from P1 to the line P0-P3. */ + dx1 = arc[1].x - arc[0].x; + dy1 = arc[1].y - arc[0].y; + s = FT_ABS( dy * dx1 - dx * dy1 ); + if ( s > s_limit ) + goto Split; +/* s is L * the perpendicular distance from P2 to the line P0-P3. */ + dx2 = arc[2].x - arc[0].x; + dy2 = arc[2].y - arc[0].y; + s = FT_ABS( dy * dx2 - dx * dy2 ); + if ( s > s_limit ) + goto Split; +/* Split super curvy segments where the off points are so far + from the chord that the angles P0-P1-P3 or P0-P2-P3 become + acute as detected by appropriate dot products. */ + if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 || + dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 ) + goto Split; +/* No reason to split. */ + goto Draw; + } + Split: + gray_split_cubic( arc ); + arc += 3; + continue; + Draw: + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + if ( arc == ras.bez_stack ) + return; + arc -= 3; + } + } + static int + gray_move_to( const FT_Vector* to, + gray_PWorker worker ) + { + TPos x, y; +/* record current cell, if any */ + gray_record_cell( RAS_VAR ); +/* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + gray_start_cell( RAS_VAR_ TRUNC( x ), TRUNC( y ) ); + worker->x = x; + worker->y = y; + return 0; + } + static int + gray_line_to( const FT_Vector* to, + gray_PWorker worker ) + { + gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); + return 0; + } + static int + gray_conic_to( const FT_Vector* control, + const FT_Vector* to, + gray_PWorker worker ) + { + gray_render_conic( RAS_VAR_ control, to ); + return 0; + } + static int + gray_cubic_to( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + gray_PWorker worker ) + { + gray_render_cubic( RAS_VAR_ control1, control2, to ); + return 0; + } + static void + gray_render_span( int y, + int count, + const FT_Span* spans, + gray_PWorker worker ) + { + unsigned char* p; + FT_Bitmap* map = &worker->target; +/* first of all, compute the scanline offset */ + p = (unsigned char*)map->buffer - y * map->pitch; + if ( map->pitch >= 0 ) + p += (unsigned)( ( map->rows - 1 ) * map->pitch ); + for ( ; count > 0; count--, spans++ ) + { + unsigned char coverage = spans->coverage; + if ( coverage ) + { +/* For small-spans it is faster to do it by ourselves than + * calling `memset'. This is mainly due to the cost of the + * function call. + */ + if ( spans->len >= 8 ) + FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len ); + else + { + unsigned char* q = p + spans->x; + switch ( spans->len ) + { + case 7: *q++ = (unsigned char)coverage; + case 6: *q++ = (unsigned char)coverage; + case 5: *q++ = (unsigned char)coverage; + case 4: *q++ = (unsigned char)coverage; + case 3: *q++ = (unsigned char)coverage; + case 2: *q++ = (unsigned char)coverage; + case 1: *q = (unsigned char)coverage; + default: + ; + } + } + } + } + } + static void + gray_hline( RAS_ARG_ TCoord x, + TCoord y, + TPos area, + TCoord acount ) + { + FT_Span* span; + int count; + int coverage; +/* compute the coverage line's coverage, depending on the */ +/* outline fill rule */ +/* */ +/* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ +/* */ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); +/* use range 0..256 */ + if ( coverage < 0 ) + coverage = -coverage; + if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) + { + coverage &= 511; + if ( coverage > 256 ) + coverage = 512 - coverage; + else if ( coverage == 256 ) + coverage = 255; + } + else + { +/* normal non-zero winding rule */ + if ( coverage >= 256 ) + coverage = 255; + } + y += (TCoord)ras.min_ey; + x += (TCoord)ras.min_ex; +/* FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ + if ( x >= 32767 ) + x = 32767; +/* FT_Span.y is an integer, so limit our coordinates appropriately */ + if ( y >= FT_INT_MAX ) + y = FT_INT_MAX; + if ( coverage ) + { +/* see whether we can add this span to the current list */ + count = ras.num_gray_spans; + span = ras.gray_spans + count - 1; + if ( count > 0 && + ras.span_y == y && + (int)span->x + span->len == (int)x && + span->coverage == coverage ) + { + span->len = (unsigned short)( span->len + acount ); + return; + } + if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS ) + { + if ( ras.render_span && count > 0 ) + ras.render_span( ras.span_y, count, ras.gray_spans, + ras.render_span_data ); + ras.num_gray_spans = 0; + ras.span_y = (int)y; + count = 0; + span = ras.gray_spans; + } + else + span++; +/* add a gray span to the current list */ + span->x = (short)x; + span->len = (unsigned short)acount; + span->coverage = (unsigned char)coverage; + ras.num_gray_spans++; + } + } + static void + gray_sweep( RAS_ARG_ const FT_Bitmap* target ) + { + int yindex; + FT_UNUSED( target ); + if ( ras.num_cells == 0 ) + return; + ras.num_gray_spans = 0; + FT_TRACE7(( "gray_sweep: start\n" )); + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + { + PCell cell = ras.ycells[yindex]; + TCoord cover = 0; + TCoord x = 0; + for ( ; cell != NULL; cell = cell->next ) + { + TPos area; + if ( cell->x > x && cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + cell->x - x ); + cover += cell->cover; + area = cover * ( ONE_PIXEL * 2 ) - cell->area; + if ( area != 0 && cell->x >= 0 ) + gray_hline( RAS_VAR_ cell->x, yindex, area, 1 ); + x = cell->x + 1; + } + if ( cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + ras.count_ex - x ); + } + if ( ras.render_span && ras.num_gray_spans > 0 ) + ras.render_span( ras.span_y, ras.num_gray_spans, + ras.gray_spans, ras.render_span_data ); + } +#ifdef _STANDALONE_ +/*************************************************************************/ +/* */ +/* The following function should only compile in stand-alone mode, */ +/* i.e., when building this component without the rest of FreeType. */ +/* */ +/*************************************************************************/ +/*************************************************************************/ +/* */ +/* <Function> */ +/* FT_Outline_Decompose */ +/* */ +/* <Description> */ +/* Walk over an outline's structure to decompose it into individual */ +/* segments and Bézier arcs. This function is also able to emit */ +/* `move to' and `close to' operations to indicate the start and end */ +/* of new contours in the outline. */ +/* */ +/* <Input> */ +/* outline :: A pointer to the source target. */ +/* */ +/* func_interface :: A table of `emitters', i.e., function pointers */ +/* called during decomposition to indicate path */ +/* operations. */ +/* */ +/* <InOut> */ +/* user :: A typeless pointer which is passed to each */ +/* emitter during the decomposition. It can be */ +/* used to store the state during the */ +/* decomposition. */ +/* */ +/* <Return> */ +/* Error code. 0 means success. */ +/* */ + static int + FT_Outline_Decompose( const FT_Outline* outline, + const FT_Outline_Funcs* func_interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ( (x) << shift ) - delta ) + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + FT_Vector* point; + FT_Vector* limit; + char* tags; + int error; +/* index of contour in outline */ + int n; +/* index of first point in contour */ + int first; +/* current point's state */ + char tag; + int shift; + TPos delta; + if ( !outline || !func_interface ) + return ErrRaster_Invalid_Argument; + shift = func_interface->shift; + delta = func_interface->delta; + first = 0; + for ( n = 0; n < outline->n_contours; n++ ) + { +/* index of last point in contour */ + int last; + FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); + last = outline->contours[n]; + if ( last < 0 ) + goto Invalid_Outline; + limit = outline->points + last; + v_start = outline->points[first]; + v_start.x = SCALED( v_start.x ); + v_start.y = SCALED( v_start.y ); + v_last = outline->points[last]; + v_last.x = SCALED( v_last.x ); + v_last.y = SCALED( v_last.y ); + v_control = v_start; + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); +/* A contour cannot start with a cubic control point! */ + if ( tag == FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; +/* check first point to determine origin */ + if ( tag == FT_CURVE_TAG_CONIC ) + { +/* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + { +/* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { +/* if both first and last points are conic, */ +/* start at their middle and record its position */ +/* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + v_last = v_start; + } + point--; + tags--; + } + FT_TRACE5(( " move to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->move_to( &v_start, user ); + if ( error ) + goto Exit; + while ( point < limit ) + { + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { +/* emit a single line_to */ + case FT_CURVE_TAG_ON: + { + FT_Vector vec; + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + FT_TRACE5(( " line to (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0 )); + error = func_interface->line_to( &vec, user ); + if ( error ) + goto Exit; + continue; + } +/* consume conic arcs */ + case FT_CURVE_TAG_CONIC: + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + Do_Conic: + if ( point < limit ) + { + FT_Vector vec; + FT_Vector v_middle; + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + if ( tag == FT_CURVE_TAG_ON ) + { + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &vec, user ); + if ( error ) + goto Exit; + continue; + } + if ( tag != FT_CURVE_TAG_CONIC ) + goto Invalid_Outline; + v_middle.x = ( v_control.x + vec.x ) / 2; + v_middle.y = ( v_control.y + vec.y ) / 2; + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_middle.x / 64.0, v_middle.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_middle, user ); + if ( error ) + goto Exit; + v_control = vec; + goto Do_Conic; + } + FT_TRACE5(( " conic to (%.2f, %.2f)" + " with control (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + v_control.x / 64.0, v_control.y / 64.0 )); + error = func_interface->conic_to( &v_control, &v_start, user ); + goto Close; +/* FT_CURVE_TAG_CUBIC */ + default: + { + FT_Vector vec1, vec2; + if ( point + 1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + point += 2; + tags += 2; + vec1.x = SCALED( point[-2].x ); + vec1.y = SCALED( point[-2].y ); + vec2.x = SCALED( point[-1].x ); + vec2.y = SCALED( point[-1].y ); + if ( point <= limit ) + { + FT_Vector vec; + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + vec.x / 64.0, vec.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); + if ( error ) + goto Exit; + continue; + } + FT_TRACE5(( " cubic to (%.2f, %.2f)" + " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0, + vec1.x / 64.0, vec1.y / 64.0, + vec2.x / 64.0, vec2.y / 64.0 )); + error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } +/* close the contour with a line segment */ + FT_TRACE5(( " line to (%.2f, %.2f)\n", + v_start.x / 64.0, v_start.y / 64.0 )); + error = func_interface->line_to( &v_start, user ); + Close: + if ( error ) + goto Exit; + first = last + 1; + } + FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); + return 0; + Exit: + FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error )); + return error; + Invalid_Outline: + return ErrRaster_Invalid_Outline; + } +/* _STANDALONE_ */ +#endif + typedef struct gray_TBand_ + { + TPos min, max; + } gray_TBand; + FT_DEFINE_OUTLINE_FUNCS(func_interface, + (FT_Outline_MoveTo_Func) gray_move_to, + (FT_Outline_LineTo_Func) gray_line_to, + (FT_Outline_ConicTo_Func)gray_conic_to, + (FT_Outline_CubicTo_Func)gray_cubic_to, + 0, + 0 + ) + static int + gray_convert_glyph_inner( RAS_ARG ) + { + volatile int error = 0; + if ( ft_setjmp( ras.jump_buffer ) == 0 ) + { + error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + gray_record_cell( RAS_VAR ); + } + else + error = ErrRaster_Memory_Overflow; + return error; + } + static int + gray_convert_glyph( RAS_ARG ) + { + gray_TBand bands[40]; + gray_TBand* volatile band; + int volatile n, num_bands; + TPos volatile min, max, max_y; + FT_BBox* clip; +/* Set up state in the raster object */ + gray_compute_cbox( RAS_VAR ); +/* clip to target bitmap, exit if nothing to do */ + clip = &ras.clip_box; + if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || + ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax ) + return 0; + if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin; + if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin; + if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax; + if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax; + ras.count_ex = ras.max_ex - ras.min_ex; + ras.count_ey = ras.max_ey - ras.min_ey; +/* set up vertical bands */ + num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size ); + if ( num_bands == 0 ) + num_bands = 1; + if ( num_bands >= 39 ) + num_bands = 39; + ras.band_shoot = 0; + min = ras.min_ey; + max_y = ras.max_ey; + for ( n = 0; n < num_bands; n++, min = max ) + { + max = min + ras.band_size; + if ( n == num_bands - 1 || max > max_y ) + max = max_y; + bands[0].min = min; + bands[0].max = max; + band = bands; + while ( band >= bands ) + { + TPos bottom, top, middle; + int error; + { + PCell cells_max; + int yindex; + long cell_start, cell_end, cell_mod; + ras.ycells = (PCell*)ras.buffer; + ras.ycount = band->max - band->min; + cell_start = sizeof ( PCell ) * ras.ycount; + cell_mod = cell_start % sizeof ( TCell ); + if ( cell_mod > 0 ) + cell_start += sizeof ( TCell ) - cell_mod; + cell_end = ras.buffer_size; + cell_end -= cell_end % sizeof ( TCell ); + cells_max = (PCell)( (char*)ras.buffer + cell_end ); + ras.cells = (PCell)( (char*)ras.buffer + cell_start ); + if ( ras.cells >= cells_max ) + goto ReduceBands; + ras.max_cells = cells_max - ras.cells; + if ( ras.max_cells < 2 ) + goto ReduceBands; + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + ras.ycells[yindex] = NULL; + } + ras.num_cells = 0; + ras.invalid = 1; + ras.min_ey = band->min; + ras.max_ey = band->max; + ras.count_ey = band->max - band->min; + error = gray_convert_glyph_inner( RAS_VAR ); + if ( !error ) + { + gray_sweep( RAS_VAR_ &ras.target ); + band--; + continue; + } + else if ( error != ErrRaster_Memory_Overflow ) + return 1; + ReduceBands: +/* render pool overflow; we will reduce the render band by half */ + bottom = band->min; + top = band->max; + middle = bottom + ( ( top - bottom ) >> 1 ); +/* This is too complex for a single scanline; there must */ +/* be some problems. */ + if ( middle == bottom ) + { + return 1; + } + if ( bottom-top >= ras.band_size ) + ras.band_shoot++; + band[1].min = bottom; + band[1].max = middle; + band[0].min = middle; + band[0].max = top; + band++; + } + } + if ( ras.band_shoot > 8 && ras.band_size > 16 ) + ras.band_size = ras.band_size / 2; + return 0; + } + static int + gray_raster_render( gray_PRaster raster, + const FT_Raster_Params* params ) + { + const FT_Outline* outline = (const FT_Outline*)params->source; + const FT_Bitmap* target_map = params->target; + gray_PWorker worker; + if ( !raster || !raster->buffer || !raster->buffer_size ) + return ErrRaster_Invalid_Argument; + if ( !outline ) + return ErrRaster_Invalid_Outline; +/* return immediately if the outline is empty */ + if ( outline->n_points == 0 || outline->n_contours <= 0 ) + return 0; + if ( !outline->contours || !outline->points ) + return ErrRaster_Invalid_Outline; + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return ErrRaster_Invalid_Outline; + worker = raster->worker; +/* if direct mode is not set, we must have a target bitmap */ + if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) ) + { + if ( !target_map ) + return ErrRaster_Invalid_Argument; +/* nothing to do */ + if ( !target_map->width || !target_map->rows ) + return 0; + if ( !target_map->buffer ) + return ErrRaster_Invalid_Argument; + } +/* this version does not support monochrome rendering */ + if ( !( params->flags & FT_RASTER_FLAG_AA ) ) + return ErrRaster_Invalid_Mode; +/* compute clipping box */ + if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) ) + { +/* compute clip box from target pixmap */ + ras.clip_box.xMin = 0; + ras.clip_box.yMin = 0; + ras.clip_box.xMax = target_map->width; + ras.clip_box.yMax = target_map->rows; + } + else if ( params->flags & FT_RASTER_FLAG_CLIP ) + ras.clip_box = params->clip_box; + else + { + ras.clip_box.xMin = -32768L; + ras.clip_box.yMin = -32768L; + ras.clip_box.xMax = 32767L; + ras.clip_box.yMax = 32767L; + } + gray_init_cells( RAS_VAR_ raster->buffer, raster->buffer_size ); + ras.outline = *outline; + ras.num_cells = 0; + ras.invalid = 1; + ras.band_size = raster->band_size; + ras.num_gray_spans = 0; + if ( params->flags & FT_RASTER_FLAG_DIRECT ) + { + ras.render_span = (FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + } + else + { + ras.target = *target_map; + ras.render_span = (FT_Raster_Span_Func)gray_render_span; + ras.render_span_data = &ras; + } + return gray_convert_glyph( RAS_VAR ); + } +/**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ +/**** a static object. *****/ +#ifdef _STANDALONE_ + static int + gray_raster_new( void* memory, + FT_Raster* araster ) + { + static gray_TRaster the_raster; + FT_UNUSED( memory ); + *araster = (FT_Raster)&the_raster; + FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); + return 0; + } + static void + gray_raster_done( FT_Raster raster ) + { +/* nothing */ + FT_UNUSED( raster ); + } +/* !_STANDALONE_ */ +#else + static int + gray_raster_new( FT_Memory memory, + FT_Raster* araster ) + { + FT_Error error; + gray_PRaster raster = NULL; + *araster = 0; + if ( !FT_ALLOC( raster, sizeof ( gray_TRaster ) ) ) + { + raster->memory = memory; + *araster = (FT_Raster)raster; + } + return error; + } + static void + gray_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; + FT_FREE( raster ); + } +/* !_STANDALONE_ */ +#endif + static void + gray_raster_reset( FT_Raster raster, + char* pool_base, + long pool_size ) + { + gray_PRaster rast = (gray_PRaster)raster; + if ( raster ) + { + if ( pool_base && pool_size >= (long)sizeof ( gray_TWorker ) + 2048 ) + { + gray_PWorker worker = (gray_PWorker)pool_base; + rast->worker = worker; + rast->buffer = pool_base + + ( ( sizeof ( gray_TWorker ) + + sizeof ( TCell ) - 1 ) & + ~( sizeof ( TCell ) - 1 ) ); + rast->buffer_size = (long)( ( pool_base + pool_size ) - + (char*)rast->buffer ) & + ~( sizeof ( TCell ) - 1 ); + rast->band_size = (int)( rast->buffer_size / + ( sizeof ( TCell ) * 8 ) ); + } + else + { + rast->buffer = NULL; + rast->buffer_size = 0; + rast->worker = NULL; + } + } + } + FT_DEFINE_RASTER_FUNCS(ft_grays_raster, + FT_GLYPH_FORMAT_OUTLINE, + (FT_Raster_New_Func) gray_raster_new, + (FT_Raster_Reset_Func) gray_raster_reset, + (FT_Raster_Set_Mode_Func)0, + (FT_Raster_Render_Func) gray_raster_render, + (FT_Raster_Done_Func) gray_raster_done + ) +/* END */ +/* Local Variables: */ +/* coding: utf-8 */ +/* End: */ +/***************************************************************************/ +/* */ +/* ftsmooth.c */ +/* */ +/* Anti-aliasing renderer interface (body). */ +/* */ +/* Copyright 2000-2006, 2009-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftsmooth.h */ +/* */ +/* Anti-aliasing renderer interface (specification). */ +/* */ +/* Copyright 1996-2001 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. */ +/* */ +/***************************************************************************/ +#define __FTSMOOTH_H__ +FT_BEGIN_HEADER +#ifndef FT_CONFIG_OPTION_NO_STD_RASTER + FT_DECLARE_RENDERER( ft_std_renderer_class ) +#endif +#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER + FT_DECLARE_RENDERER( ft_smooth_renderer_class ) + FT_DECLARE_RENDERER( ft_smooth_lcd_renderer_class ) + FT_DECLARE_RENDERER( ft_smooth_lcd_v_renderer_class ) +#endif +FT_END_HEADER +/* END */ +/* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Renderer render ) + { + FT_Library library = FT_MODULE_LIBRARY( render ); + render->clazz->raster_class->raster_reset( render->raster, + library->raster_pool, + library->raster_pool_size ); + return 0; + } +/* sets render-specific mode */ + static FT_Error + ft_smooth_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { +/* we simply pass it to the raster */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } +/* transform a given glyph image */ + static FT_Error + ft_smooth_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = Smooth_Err_Ok; + if ( slot->format != render->glyph_format ) + { + error = Smooth_Err_Invalid_Argument; + goto Exit; + } + if ( matrix ) + FT_Outline_Transform( &slot->outline, matrix ); + if ( delta ) + FT_Outline_Translate( &slot->outline, delta->x, delta->y ); + Exit: + return error; + } +/* return the glyph's control box */ + static void + ft_smooth_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_MEM_ZERO( cbox, sizeof ( *cbox ) ); + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } +/* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_smooth_render_generic( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin, + FT_Render_Mode required_mode ) + { + FT_Error error; + FT_Outline* outline = NULL; + FT_BBox cbox; + FT_Pos width, height, pitch; + FT_Bitmap* bitmap; + FT_Memory memory; + FT_Int hmul = mode == FT_RENDER_MODE_LCD; + FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; + FT_Pos x_shift, y_shift, x_left, y_top; + FT_Raster_Params params; + FT_Bool have_translated_origin = FALSE; + FT_Bool have_outline_shifted = FALSE; + FT_Bool have_buffer = FALSE; +/* check glyph image format */ + if ( slot->format != render->glyph_format ) + { + error = Smooth_Err_Invalid_Argument; + goto Exit; + } +/* check mode */ + if ( mode != required_mode ) + { + error = Smooth_Err_Cannot_Render_Glyph; + goto Exit; + } + outline = &slot->outline; +/* translate the outline to the new origin if needed */ + if ( origin ) + { + FT_Outline_Translate( outline, origin->x, origin->y ); + have_translated_origin = TRUE; + } +/* compute the control box, and grid fit it */ + FT_Outline_Get_CBox( outline, &cbox ); + cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); + cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); + cbox.xMax = FT_PIX_CEIL( cbox.xMax ); + cbox.yMax = FT_PIX_CEIL( cbox.yMax ); + if ( cbox.xMin < 0 && cbox.xMax > FT_INT_MAX + cbox.xMin ) + { + FT_ERROR(( "ft_smooth_render_generic: glyph too large:" + " xMin = %d, xMax = %d\n", + cbox.xMin >> 6, cbox.xMax >> 6 )); + error = Smooth_Err_Raster_Overflow; + goto Exit; + } + else + width = ( cbox.xMax - cbox.xMin ) >> 6; + if ( cbox.yMin < 0 && cbox.yMax > FT_INT_MAX + cbox.yMin ) + { + FT_ERROR(( "ft_smooth_render_generic: glyph too large:" + " yMin = %d, yMax = %d\n", + cbox.yMin >> 6, cbox.yMax >> 6 )); + error = Smooth_Err_Raster_Overflow; + goto Exit; + } + else + height = ( cbox.yMax - cbox.yMin ) >> 6; + bitmap = &slot->bitmap; + memory = render->root.memory; +/* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } +/* allocate new one */ + pitch = width; + if ( hmul ) + { + width = width * 3; + pitch = FT_PAD_CEIL( width, 4 ); + } + if ( vmul ) + height *= 3; + x_shift = (FT_Int) cbox.xMin; + y_shift = (FT_Int) cbox.yMin; + x_left = (FT_Int)( cbox.xMin >> 6 ); + y_top = (FT_Int)( cbox.yMax >> 6 ); + if ( slot->library->lcd_filter_func ) + { + FT_Int extra = slot->library->lcd_extra; + if ( hmul ) + { + x_shift -= 64 * ( extra >> 1 ); + width += 3 * extra; + pitch = FT_PAD_CEIL( width, 4 ); + x_left -= extra >> 1; + } + if ( vmul ) + { + y_shift -= 64 * ( extra >> 1 ); + height += 3 * extra; + y_top += extra >> 1; + } + } +#if FT_UINT_MAX > 0xFFFFU +/* Required check is (pitch * height < FT_ULONG_MAX), */ +/* but we care realistic cases only. Always pitch <= width. */ + if ( width > 0x7FFF || height > 0x7FFF ) + { + FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", + width, height )); + error = Smooth_Err_Raster_Overflow; + goto Exit; + } +#endif + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->num_grays = 256; + bitmap->width = width; + bitmap->rows = height; + bitmap->pitch = pitch; +/* translate outline to render it into the bitmap */ + FT_Outline_Translate( outline, -x_shift, -y_shift ); + have_outline_shifted = TRUE; + if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) ) + goto Exit; + else + have_buffer = TRUE; + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; +/* set up parameters */ + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; +/* implode outline if needed */ + { + FT_Vector* points = outline->points; + FT_Vector* points_end = points + outline->n_points; + FT_Vector* vec; + if ( hmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->x *= 3; + if ( vmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->y *= 3; + } +/* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); +/* deflate outline if needed */ + { + FT_Vector* points = outline->points; + FT_Vector* points_end = points + outline->n_points; + FT_Vector* vec; + if ( hmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->x /= 3; + if ( vmul ) + for ( vec = points; vec < points_end; vec++ ) + vec->y /= 3; + } + if ( error ) + goto Exit; + if ( slot->library->lcd_filter_func ) + slot->library->lcd_filter_func( bitmap, mode, slot->library ); +/* + * XXX: on 16bit system, we return an error for huge bitmap + * to prevent an overflow. + */ + if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) + { + error = Smooth_Err_Invalid_Pixel_Size; + goto Exit; + } + slot->format = FT_GLYPH_FORMAT_BITMAP; + slot->bitmap_left = (FT_Int)x_left; + slot->bitmap_top = (FT_Int)y_top; +/* everything is fine; don't deallocate buffer */ + have_buffer = FALSE; + error = Smooth_Err_Ok; + Exit: + if ( have_outline_shifted ) + FT_Outline_Translate( outline, x_shift, y_shift ); + if ( have_translated_origin ) + FT_Outline_Translate( outline, -origin->x, -origin->y ); + if ( have_buffer ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + return error; + } +/* convert a slot's glyph image into a bitmap */ + static FT_Error + ft_smooth_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + if ( mode == FT_RENDER_MODE_LIGHT ) + mode = FT_RENDER_MODE_NORMAL; + return ft_smooth_render_generic( render, slot, mode, origin, + FT_RENDER_MODE_NORMAL ); + } +/* convert a slot's glyph image into a horizontal LCD bitmap */ + static FT_Error + ft_smooth_render_lcd( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error; + error = ft_smooth_render_generic( render, slot, mode, origin, + FT_RENDER_MODE_LCD ); + if ( !error ) + slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; + return error; + } +/* convert a slot's glyph image into a vertical LCD bitmap */ + static FT_Error + ft_smooth_render_lcd_v( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error; + error = ft_smooth_render_generic( render, slot, mode, origin, + FT_RENDER_MODE_LCD_V ); + if ( !error ) + slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; + return error; + } + FT_DEFINE_RENDERER( ft_smooth_renderer_class, + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + "smooth", + 0x10000L, + 0x20000L, +/* module specific interface */ + 0, + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + , + FT_GLYPH_FORMAT_OUTLINE, + (FT_Renderer_RenderFunc) ft_smooth_render, + (FT_Renderer_TransformFunc)ft_smooth_transform, + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, + (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET + ) + FT_DEFINE_RENDERER( ft_smooth_lcd_renderer_class, + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + "smooth-lcd", + 0x10000L, + 0x20000L, +/* module specific interface */ + 0, + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + , + FT_GLYPH_FORMAT_OUTLINE, + (FT_Renderer_RenderFunc) ft_smooth_render_lcd, + (FT_Renderer_TransformFunc)ft_smooth_transform, + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, + (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET + ) + FT_DEFINE_RENDERER( ft_smooth_lcdv_renderer_class, + FT_MODULE_RENDERER, + sizeof ( FT_RendererRec ), + "smooth-lcdv", + 0x10000L, + 0x20000L, +/* module specific interface */ + 0, + (FT_Module_Constructor)ft_smooth_init, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + , + FT_GLYPH_FORMAT_OUTLINE, + (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v, + (FT_Renderer_TransformFunc)ft_smooth_transform, + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, + (FT_Raster_Funcs*) &FT_GRAYS_RASTER_GET + ) +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* autofit.c */ +/* */ +/* Auto-fitter module (body). */ +/* */ +/* Copyright 2003-2007, 2011 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. */ +/* */ +/***************************************************************************/ +#define FT_MAKE_OPTION_SINGLE_OBJECT +/***************************************************************************/ +/* */ +/* afpic.c */ +/* */ +/* The FreeType position independent code services for autofit module. */ +/* */ +/* Copyright 2009-2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* afpic.h */ +/* */ +/* The FreeType position independent code services for autofit module. */ +/* */ +/* Copyright 2009, 2011-2012 by */ +/* Oran Agra and Mickey Gabel. */ +/* */ +/* 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. */ +/* */ +/***************************************************************************/ +#define __AFPIC_H__ +FT_BEGIN_HEADER +#define AF_SERVICES_GET af_services +#define AF_SERVICE_PROPERTIES_GET af_service_properties +#define AF_SCRIPT_CLASSES_GET af_script_classes +#define AF_INTERFACE_GET af_autofitter_interface +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* aferrors.h */ +/* */ +/* Autofitter error codes (specification only). */ +/* */ +/* Copyright 2005, 2012 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. */ +/* */ +/*************************************************************************/ +#define __AFERRORS_H__ +#undef __FTERRORS_H__ +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX AF_Err_ +#define FT_ERR_BASE FT_Mod_Err_Autofit +/***************************************************************************/ +/* */ +/* fterrors.h */ +/* */ +/* FreeType error code handling (specification). */ +/* */ +/* Copyright 1996-2001, 2002, 2004, 2007 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 special header file is used to define the handling of FT2 */ +/* enumeration constants. It can also be used to generate error message */ +/* strings with a small macro trick explained below. */ +/* */ +/* I - Error Formats */ +/* ----------------- */ +/* */ +/* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */ +/* defined in ftoption.h in order to make the higher byte indicate */ +/* the module where the error has happened (this is not compatible */ +/* with standard builds of FreeType 2). You can then use the macro */ +/* FT_ERROR_BASE macro to extract the generic error code from an */ +/* FT_Error value. */ +/* */ +/* */ +/* II - Error Message strings */ +/* -------------------------- */ +/* */ +/* The error definitions below are made through special macros that */ +/* allow client applications to build a table of error message strings */ +/* if they need it. The strings are not included in a normal build of */ +/* FreeType 2 to save space (most client applications do not use */ +/* them). */ +/* */ +/* To do so, you have to define the following macros before including */ +/* this file: */ +/* */ +/* FT_ERROR_START_LIST :: */ +/* This macro is called before anything else to define the start of */ +/* the error list. It is followed by several FT_ERROR_DEF calls */ +/* (see below). */ +/* */ +/* FT_ERROR_DEF( e, v, s ) :: */ +/* This macro is called to define one single error. */ +/* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */ +/* `v' is the error numerical value. */ +/* `s' is the corresponding error string. */ +/* */ +/* FT_ERROR_END_LIST :: */ +/* This macro ends the list. */ +/* */ +/* Additionally, you have to undefine __FTERRORS_H__ before #including */ +/* this file. */ +/* */ +/* Here is a simple example: */ +/* */ +/* { */ +/* #undef __FTERRORS_H__ */ +/* #define FT_ERRORDEF( e, v, s ) { e, s }, */ +/* #define FT_ERROR_START_LIST { */ +/* #define FT_ERROR_END_LIST { 0, 0 } }; */ +/* */ +/* const struct */ +/* { */ +/* int err_code; */ +/* const char* err_msg; */ +/* } ft_errors[] = */ +/* */ +/* #include FT_ERRORS_H */ +/* } */ +/* */ +/*************************************************************************/ +#ifndef __FTERRORS_H__ +#define __FTERRORS_H__ +/* include module base error codes */ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SETUP MACROS *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_XCAT +#undef FT_ERR_CAT +#define FT_ERR_XCAT( x, y ) x ## y +#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y ) +/* FT_ERR_PREFIX is used as a prefix for error identifiers. */ +/* By default, we use `FT_Err_'. */ +/* */ +#ifndef FT_ERR_PREFIX +#define FT_ERR_PREFIX FT_Err_ +#endif +/* FT_ERR_BASE is used as the base for module-specific errors. */ +/* */ +#undef FT_ERR_BASE +#define FT_ERR_BASE 0 +/* If FT_ERRORDEF is not defined, we need to define a simple */ +/* enumeration type. */ +/* */ +#ifndef FT_ERRORDEF +#define FT_ERRORDEF( e, v, s ) e = v, +#define FT_ERROR_START_LIST enum { +#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) }; +#ifdef __cplusplus +#define FT_NEED_EXTERN_C + extern "C" { +#endif +/* !FT_ERRORDEF */ +#endif +/* this macro is used to define an error */ +#define FT_ERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s ) +/* this is only used for <module>_Err_Ok, which must be 0! */ +#define FT_NOERRORDEF_( e, v, s ) \ + FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s ) +#ifdef FT_ERROR_START_LIST + FT_ERROR_START_LIST +#endif +/* now include the error codes */ +/***************************************************************************/ +/* */ +/* fterrdef.h */ +/* */ +/* FreeType error codes (specification). */ +/* */ +/* Copyright 2002, 2004, 2006, 2007, 2010-2012 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. */ +/* */ +/***************************************************************************/ +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** LIST OF ERROR CODES/MESSAGES *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +/* You need to define both FT_ERRORDEF_ and FT_NOERRORDEF_ before */ +/* including this file. */ +/* generic errors */ + FT_NOERRORDEF_( Ok, 0x00, \ + "no error" ) + FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \ + "cannot open resource" ) + FT_ERRORDEF_( Unknown_File_Format, 0x02, \ + "unknown file format" ) + FT_ERRORDEF_( Invalid_File_Format, 0x03, \ + "broken file" ) + FT_ERRORDEF_( Invalid_Version, 0x04, \ + "invalid FreeType version" ) + FT_ERRORDEF_( Lower_Module_Version, 0x05, \ + "module version is too low" ) + FT_ERRORDEF_( Invalid_Argument, 0x06, \ + "invalid argument" ) + FT_ERRORDEF_( Unimplemented_Feature, 0x07, \ + "unimplemented feature" ) + FT_ERRORDEF_( Invalid_Table, 0x08, \ + "broken table" ) + FT_ERRORDEF_( Invalid_Offset, 0x09, \ + "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) + FT_ERRORDEF_( Missing_Module, 0x0B, \ + "missing module" ) + FT_ERRORDEF_( Missing_Property, 0x0C, \ + "missing property" ) +/* glyph/character errors */ + FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \ + "invalid glyph index" ) + FT_ERRORDEF_( Invalid_Character_Code, 0x11, \ + "invalid character code" ) + FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \ + "unsupported glyph image format" ) + FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \ + "cannot render this glyph format" ) + FT_ERRORDEF_( Invalid_Outline, 0x14, \ + "invalid outline" ) + FT_ERRORDEF_( Invalid_Composite, 0x15, \ + "invalid composite glyph" ) + FT_ERRORDEF_( Too_Many_Hints, 0x16, \ + "too many hints" ) + FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \ + "invalid pixel size" ) +/* handle errors */ + FT_ERRORDEF_( Invalid_Handle, 0x20, \ + "invalid object handle" ) + FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \ + "invalid library handle" ) + FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \ + "invalid module handle" ) + FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \ + "invalid face handle" ) + FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \ + "invalid size handle" ) + FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \ + "invalid glyph slot handle" ) + FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \ + "invalid charmap handle" ) + FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \ + "invalid cache manager handle" ) + FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \ + "invalid stream handle" ) +/* driver errors */ + FT_ERRORDEF_( Too_Many_Drivers, 0x30, \ + "too many modules" ) + FT_ERRORDEF_( Too_Many_Extensions, 0x31, \ + "too many extensions" ) +/* memory errors */ + FT_ERRORDEF_( Out_Of_Memory, 0x40, \ + "out of memory" ) + FT_ERRORDEF_( Unlisted_Object, 0x41, \ + "unlisted object" ) +/* stream errors */ + FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \ + "cannot open stream" ) + FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \ + "invalid stream seek" ) + FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \ + "invalid stream skip" ) + FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \ + "invalid stream read" ) + FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \ + "invalid stream operation" ) + FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \ + "invalid frame operation" ) + FT_ERRORDEF_( Nested_Frame_Access, 0x57, \ + "nested frame access" ) + FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \ + "invalid frame read" ) +/* raster errors */ + FT_ERRORDEF_( Raster_Uninitialized, 0x60, \ + "raster uninitialized" ) + FT_ERRORDEF_( Raster_Corrupted, 0x61, \ + "raster corrupted" ) + FT_ERRORDEF_( Raster_Overflow, 0x62, \ + "raster overflow" ) + FT_ERRORDEF_( Raster_Negative_Height, 0x63, \ + "negative height while rastering" ) +/* cache errors */ + FT_ERRORDEF_( Too_Many_Caches, 0x70, \ + "too many registered caches" ) +/* TrueType and SFNT errors */ + FT_ERRORDEF_( Invalid_Opcode, 0x80, \ + "invalid opcode" ) + FT_ERRORDEF_( Too_Few_Arguments, 0x81, \ + "too few arguments" ) + FT_ERRORDEF_( Stack_Overflow, 0x82, \ + "stack overflow" ) + FT_ERRORDEF_( Code_Overflow, 0x83, \ + "code overflow" ) + FT_ERRORDEF_( Bad_Argument, 0x84, \ + "bad argument" ) + FT_ERRORDEF_( Divide_By_Zero, 0x85, \ + "division by zero" ) + FT_ERRORDEF_( Invalid_Reference, 0x86, \ + "invalid reference" ) + FT_ERRORDEF_( Debug_OpCode, 0x87, \ + "found debug opcode" ) + FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \ + "found ENDF opcode in execution stream" ) + FT_ERRORDEF_( Nested_DEFS, 0x89, \ + "nested DEFS" ) + FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \ + "invalid code range" ) + FT_ERRORDEF_( Execution_Too_Long, 0x8B, \ + "execution context too long" ) + FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \ + "too many function definitions" ) + FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \ + "too many instruction definitions" ) + FT_ERRORDEF_( Table_Missing, 0x8E, \ + "SFNT font table missing" ) + FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \ + "horizontal header (hhea) table missing" ) + FT_ERRORDEF_( Locations_Missing, 0x90, \ + "locations (loca) table missing" ) + FT_ERRORDEF_( Name_Table_Missing, 0x91, \ + "name table missing" ) + FT_ERRORDEF_( CMap_Table_Missing, 0x92, \ + "character map (cmap) table missing" ) + FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \ + "horizontal metrics (hmtx) table missing" ) + FT_ERRORDEF_( Post_Table_Missing, 0x94, \ + "PostScript (post) table missing" ) + FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \ + "invalid horizontal metrics" ) + FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \ + "invalid character map (cmap) format" ) + FT_ERRORDEF_( Invalid_PPem, 0x97, \ + "invalid ppem value" ) + FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \ + "invalid vertical metrics" ) + FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \ + "could not find context" ) + FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \ + "invalid PostScript (post) table format" ) + FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \ + "invalid PostScript (post) table" ) +/* CFF, CID, and Type 1 errors */ + FT_ERRORDEF_( Syntax_Error, 0xA0, \ + "opcode syntax error" ) + FT_ERRORDEF_( Stack_Underflow, 0xA1, \ + "argument stack underflow" ) + FT_ERRORDEF_( Ignore, 0xA2, \ + "ignore" ) + FT_ERRORDEF_( No_Unicode_Glyph_Name, 0xA3, \ + "no Unicode glyph name found" ) +/* BDF errors */ + FT_ERRORDEF_( Missing_Startfont_Field, 0xB0, \ + "`STARTFONT' field missing" ) + FT_ERRORDEF_( Missing_Font_Field, 0xB1, \ + "`FONT' field missing" ) + FT_ERRORDEF_( Missing_Size_Field, 0xB2, \ + "`SIZE' field missing" ) + FT_ERRORDEF_( Missing_Fontboundingbox_Field, 0xB3, \ + "`FONTBOUNDINGBOX' field missing" ) + FT_ERRORDEF_( Missing_Chars_Field, 0xB4, \ + "`CHARS' field missing" ) + FT_ERRORDEF_( Missing_Startchar_Field, 0xB5, \ + "`STARTCHAR' field missing" ) + FT_ERRORDEF_( Missing_Encoding_Field, 0xB6, \ + "`ENCODING' field missing" ) + FT_ERRORDEF_( Missing_Bbx_Field, 0xB7, \ + "`BBX' field missing" ) + FT_ERRORDEF_( Bbx_Too_Big, 0xB8, \ + "`BBX' too big" ) + FT_ERRORDEF_( Corrupted_Font_Header, 0xB9, \ + "Font header corrupted or missing fields" ) + FT_ERRORDEF_( Corrupted_Font_Glyphs, 0xBA, \ + "Font glyphs corrupted or missing fields" ) +/* END */ +#ifdef FT_ERROR_END_LIST + FT_ERROR_END_LIST +#endif +/*******************************************************************/ +/*******************************************************************/ +/***** *****/ +/***** SIMPLE CLEANUP *****/ +/***** *****/ +/*******************************************************************/ +/*******************************************************************/ +#ifdef FT_NEED_EXTERN_C + } +#endif +#undef FT_ERROR_START_LIST +#undef FT_ERROR_END_LIST +#undef FT_ERRORDEF +#undef FT_ERRORDEF_ +#undef FT_NOERRORDEF_ +#undef FT_NEED_EXTERN_C +#undef FT_ERR_BASE +/* FT_KEEP_ERR_PREFIX is needed for ftvalid.h */ +#ifndef FT_KEEP_ERR_PREFIX +#undef FT_ERR_PREFIX +#else +#undef FT_KEEP_ERR_PREFIX +#endif +/* __FTERRORS_H__ */ +#endif +/* END */ +/* END */ +/* END */ +/***************************************************************************/ +/* */ +/* afangles.c */ +/* */ +/* Routines used to compute vector angles with limited accuracy */ +/* and very high speed. It also contains sorting routines (body). */ +/* */ +/* Copyright 2003-2006, 2011-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* aftypes.h */ +/* */ +/* Auto-fitter types (specification only). */ +/* */ +/* Copyright 2003-2009, 2011-2012 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 + * scripts in order to apply language-specific rules. + * + * The code has also been compartmentized into several entities that + * should make algorithmic experimentation easier than with the old + * code. + * + * Finally, we get rid of the Catharon license, since this code is + * released under the FreeType one. + * + *************************************************************************/ +#define __AFTYPES_H__ +FT_BEGIN_HEADER +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** D E B U G G I N G *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** U T I L I T Y S T U F F *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + typedef struct AF_WidthRec_ + { +/* original position/width in font units */ + FT_Pos org; +/* current/scaled position/width in device sub-pixels */ + FT_Pos cur; +/* current/fitted position/width in device sub-pixels */ + FT_Pos fit; + } 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 ); +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** A N G L E T Y P E S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* + * The auto-fitter doesn't need a very high angular accuracy; + * this allows us to speed up some computations considerably with a + * light Cordic algorithm (see afangles.c). + */ + typedef FT_Int AF_Angle; +#define AF_ANGLE_PI 256 +#define AF_ANGLE_2PI ( AF_ANGLE_PI * 2 ) +#define AF_ANGLE_PI2 ( AF_ANGLE_PI / 2 ) +#define AF_ANGLE_PI4 ( AF_ANGLE_PI / 4 ) +#if 0 +/* + * compute the angle of a given 2-D vector + */ + FT_LOCAL( AF_Angle ) + af_angle_atan( FT_Pos dx, + FT_Pos dy ); +/* + * compute `angle2 - angle1'; the result is always within + * the range [-AF_ANGLE_PI .. AF_ANGLE_PI - 1] + */ + FT_LOCAL( AF_Angle ) + af_angle_diff( AF_Angle angle1, + AF_Angle angle2 ); +/* 0 */ +#endif +#define AF_ANGLE_DIFF( result, angle1, angle2 ) \ + FT_BEGIN_STMNT \ + AF_Angle _delta = (angle2) - (angle1); \ + \ + \ + _delta %= AF_ANGLE_2PI; \ + if ( _delta < 0 ) \ + _delta += AF_ANGLE_2PI; \ + \ + if ( _delta > AF_ANGLE_PI ) \ + _delta -= AF_ANGLE_2PI; \ + \ + result = _delta; \ + FT_END_STMNT +/* 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. + */ + typedef enum AF_ScalerFlags_ + { +/* disable horizontal hinting */ + AF_SCALER_FLAG_NO_HORIZONTAL = 1, +/* disable vertical hinting */ + AF_SCALER_FLAG_NO_VERTICAL = 2, +/* disable advance hinting */ + AF_SCALER_FLAG_NO_ADVANCE = 4 + } AF_ScalerFlags; + typedef struct AF_ScalerRec_ + { +/* source font face */ + FT_Face face; +/* from font units to 1/64th device pixels */ + FT_Fixed x_scale; +/* from font units to 1/64th device pixels */ + FT_Fixed y_scale; +/* in 1/64th device pixels */ + FT_Pos x_delta; +/* in 1/64th device pixels */ + FT_Pos y_delta; +/* monochrome, anti-aliased, LCD, etc. */ + FT_Render_Mode render_mode; +/* additional control flags, see above */ + FT_UInt32 flags; + } 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 ) +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** S C R I P T S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* + * The list of known scripts. Each different script corresponds to the + * following information: + * + * - A set of Unicode ranges to test whether the face supports the + * script. + * + * - A specific global analyzer that will compute global metrics + * specific to the script. + * + * - A specific glyph analyzer that will compute segments and + * edges for each glyph covered by the script. + * + * - A specific grid-fitting algorithm that will distort the + * scaled glyph outline according to the results of the glyph + * analyzer. + * + * Note that a given analyzer and/or grid-fitting algorithm can be + * used by more than one script. + */ + typedef enum AF_Script_ + { + AF_SCRIPT_DUMMY = 0, + AF_SCRIPT_LATIN = 1, + AF_SCRIPT_CJK = 2, + AF_SCRIPT_INDIC = 3, +#ifdef FT_OPTION_AUTOFIT2 + AF_SCRIPT_LATIN2 = 4, +#endif +/* add new scripts here. Don't forget to update the list in */ +/* `afglobal.c'. */ +/* do not remove */ + AF_SCRIPT_MAX + } AF_Script; + typedef struct AF_ScriptClassRec_ const* AF_ScriptClass; + typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + typedef struct AF_ScriptMetricsRec_ + { + AF_ScriptClass clazz; + AF_ScalerRec scaler; + FT_Bool digits_have_same_width; +/* to access properties */ + AF_FaceGlobals globals; + } AF_ScriptMetricsRec, *AF_ScriptMetrics; +/* This function parses an FT_Face to compute global metrics for + * a specific script. + */ + typedef FT_Error + (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics metrics, + FT_Face face ); + typedef void + (*AF_Script_ScaleMetricsFunc)( AF_ScriptMetrics metrics, + AF_Scaler scaler ); + typedef void + (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics metrics ); + typedef FT_Error + (*AF_Script_InitHintsFunc)( AF_GlyphHints hints, + AF_ScriptMetrics metrics ); + typedef void + (*AF_Script_ApplyHintsFunc)( AF_GlyphHints hints, + FT_Outline* outline, + AF_ScriptMetrics metrics ); + 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 must be { 0, 0 } */ + AF_Script_UniRange script_uni_ranges; +/* for default width and height */ + FT_UInt32 standard_char; + FT_Offset script_metrics_size; + AF_Script_InitMetricsFunc script_metrics_init; + AF_Script_ScaleMetricsFunc script_metrics_scale; + AF_Script_DoneMetricsFunc script_metrics_done; + AF_Script_InitHintsFunc script_hints_init; + AF_Script_ApplyHintsFunc script_hints_apply; + } AF_ScriptClassRec; +/* Declare and define vtables for classes */ +#define AF_DECLARE_SCRIPT_CLASS( script_class ) \ + FT_CALLBACK_TABLE const AF_ScriptClassRec \ + script_class; +#define AF_DEFINE_SCRIPT_CLASS( script_class, script_, ranges, def_char, \ + m_size, \ + m_init, m_scale, m_done, h_init, h_apply ) \ + FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec script_class = \ + { \ + script_, \ + ranges, \ + def_char, \ + \ + m_size, \ + \ + m_init, \ + m_scale, \ + m_done, \ + \ + h_init, \ + h_apply \ + }; +/* */ +FT_END_HEADER +/* END */ +#if 0 + FT_LOCAL_DEF( FT_Int ) + af_corner_is_flat( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ) + { + FT_Pos ax = x_in; + FT_Pos ay = y_in; + FT_Pos d_in, d_out, d_corner; + if ( ax < 0 ) + ax = -ax; + if ( ay < 0 ) + ay = -ay; + d_in = ax + ay; + ax = x_out; + if ( ax < 0 ) + ax = -ax; + ay = y_out; + if ( ay < 0 ) + ay = -ay; + d_out = ax + ay; + ax = x_out + x_in; + if ( ax < 0 ) + ax = -ax; + ay = y_out + y_in; + if ( ay < 0 ) + ay = -ay; + d_corner = ax + ay; + return ( d_in + d_out - d_corner ) < ( d_corner >> 4 ); + } + FT_LOCAL_DEF( FT_Int ) + af_corner_orientation( FT_Pos x_in, + FT_Pos y_in, + FT_Pos x_out, + FT_Pos y_out ) + { + FT_Pos delta; + delta = x_in * y_out - y_in * x_out; + if ( delta == 0 ) + return 0; + else + return 1 - 2 * ( delta < 0 ); + } +/* 0 */ +#endif +/* + * We are not using `af_angle_atan' anymore, but we keep the source + * code below just in case... + */ +#if 0 +/* + * The trick here is to realize that we don't need a very accurate angle + * approximation. We are going to use the result of `af_angle_atan' to + * only compare the sign of angle differences, or check whether its + * magnitude is very small. + * + * The approximation + * + * dy * PI / (|dx|+|dy|) + * + * should be enough, and much faster to compute. + */ + FT_LOCAL_DEF( AF_Angle ) + af_angle_atan( FT_Fixed dx, + FT_Fixed dy ) + { + AF_Angle angle; + FT_Fixed ax = dx; + FT_Fixed ay = dy; + if ( ax < 0 ) + ax = -ax; + if ( ay < 0 ) + ay = -ay; + ax += ay; + if ( ax == 0 ) + angle = 0; + else + { + angle = ( AF_ANGLE_PI2 * dy ) / ( ax + ay ); + if ( dx < 0 ) + { + if ( angle >= 0 ) + angle = AF_ANGLE_PI - angle; + else + angle = -AF_ANGLE_PI - angle; + } + } + return angle; + } +#elif 0 +/* the following table has been automatically generated with */ +/* the `mather.py' Python script */ +#define AF_ATAN_BITS 8 + static const FT_Byte af_arctan[1L << AF_ATAN_BITS] = + { + 0, 0, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 12, 12, 12, + 13, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 16, 16, 16, 17, 17, 17, + 18, 18, 18, 18, 19, 19, 19, 20, + 20, 20, 21, 21, 21, 21, 22, 22, + 22, 23, 23, 23, 24, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 26, 27, + 27, 27, 28, 28, 28, 28, 29, 29, + 29, 30, 30, 30, 30, 31, 31, 31, + 31, 32, 32, 32, 33, 33, 33, 33, + 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 38, + 38, 38, 38, 39, 39, 39, 39, 40, + 40, 40, 40, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, + 46, 46, 46, 46, 46, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 49, + 49, 49, 50, 50, 50, 50, 50, 51, + 51, 51, 51, 51, 52, 52, 52, 52, + 52, 53, 53, 53, 53, 53, 54, 54, + 54, 54, 54, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 58, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 59, 60, 60, + 60, 60, 60, 61, 61, 61, 61, 61, + 61, 62, 62, 62, 62, 62, 62, 63, + 63, 63, 63, 63, 63, 64, 64, 64 + }; + FT_LOCAL_DEF( AF_Angle ) + af_angle_atan( FT_Fixed dx, + FT_Fixed dy ) + { + AF_Angle angle; +/* check trivial cases */ + if ( dy == 0 ) + { + angle = 0; + if ( dx < 0 ) + angle = AF_ANGLE_PI; + return angle; + } + else if ( dx == 0 ) + { + angle = AF_ANGLE_PI2; + if ( dy < 0 ) + angle = -AF_ANGLE_PI2; + return angle; + } + angle = 0; + if ( dx < 0 ) + { + dx = -dx; + dy = -dy; + angle = AF_ANGLE_PI; + } + if ( dy < 0 ) + { + FT_Pos tmp; + tmp = dx; + dx = -dy; + dy = tmp; + angle -= AF_ANGLE_PI2; + } + if ( dx == 0 && dy == 0 ) + return 0; + if ( dx == dy ) + angle += AF_ANGLE_PI4; + else if ( dx > dy ) + angle += af_arctan[FT_DivFix( dy, dx ) >> ( 16 - AF_ATAN_BITS )]; + else + angle += AF_ANGLE_PI2 - + af_arctan[FT_DivFix( dx, dy ) >> ( 16 - AF_ATAN_BITS )]; + if ( angle > AF_ANGLE_PI ) + angle -= AF_ANGLE_2PI; + return angle; + } +/* 0 */ +#endif + FT_LOCAL_DEF( void ) + af_sort_pos( FT_UInt count, + FT_Pos* table ) + { + FT_UInt i, j; + FT_Pos swap; + for ( i = 1; i < count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j] >= table[j - 1] ) + break; + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + } + FT_LOCAL_DEF( void ) + af_sort_and_quantize_widths( FT_UInt* count, + AF_Width table, + FT_Pos threshold ) + { + FT_UInt i, j; + FT_UInt cur_idx; + FT_Pos cur_val; + FT_Pos sum; + AF_WidthRec swap; + if ( *count == 1 ) + return; +/* sort */ + for ( i = 1; i < *count; i++ ) + { + for ( j = i; j > 0; j-- ) + { + if ( table[j].org >= table[j - 1].org ) + break; + swap = table[j]; + table[j] = table[j - 1]; + table[j - 1] = swap; + } + } + cur_idx = 0; + cur_val = table[cur_idx].org; +/* compute and use mean values for clusters not larger than */ +/* `threshold'; this is very primitive and might not yield */ +/* the best result, but normally, using reference character */ +/* `o', `*count' is 2, so the code below is fully sufficient */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org - cur_val > threshold || + i == *count - 1 ) + { + sum = 0; +/* fix loop for end of array */ + if ( table[i].org - cur_val <= threshold && + i == *count - 1 ) + i++; + for ( j = cur_idx; j < i; j++ ) + { + sum += table[j].org; + table[j].org = 0; + } + table[cur_idx].org = sum / j; + if ( i < *count - 1 ) + { + cur_idx = i + 1; + cur_val = table[cur_idx].org; + } + } + } + cur_idx = 1; +/* compress array to remove zero values */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org ) + table[cur_idx++] = table[i]; + } + *count = cur_idx; + } +/* END */ +/***************************************************************************/ +/* */ +/* afglobal.c */ +/* */ +/* Auto-fitter routines to compute global hinting values (body). */ +/* */ +/* Copyright 2003-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* afglobal.h */ +/* */ +/* Auto-fitter routines to compute global hinting values */ +/* (specification). */ +/* */ +/* Copyright 2003-2005, 2007, 2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +#define __AFGLOBAL_H__ +/***************************************************************************/ +/* */ +/* afmodule.h */ +/* */ +/* Auto-fitter module implementation (specification). */ +/* */ +/* Copyright 2003, 2004, 2005 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. */ +/* */ +/***************************************************************************/ +#define __AFMODULE_H__ +/***************************************************************************/ +/* */ +/* afloader.h */ +/* */ +/* Auto-fitter glyph loading routines (specification). */ +/* */ +/* Copyright 2003-2005, 2011-2012 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. */ +/* */ +/***************************************************************************/ +#define __AFLOADER_H__ +/***************************************************************************/ +/* */ +/* afhints.h */ +/* */ +/* Auto-fitter hinting routines (specification). */ +/* */ +/* Copyright 2003-2008, 2010-2012 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. */ +/* */ +/***************************************************************************/ +#define __AFHINTS_H__ +#define xxAF_SORT_SEGMENTS +FT_BEGIN_HEADER +/* + * The definition of outline glyph hints. These are shared by all + * script analysis routines (until now). + */ + typedef enum AF_Dimension_ + { +/* x coordinates, */ + AF_DIMENSION_HORZ = 0, +/* i.e., vertical segments & edges */ +/* y coordinates, */ + AF_DIMENSION_VERT = 1, +/* i.e., horizontal segments & edges */ +/* do not remove */ + AF_DIMENSION_MAX + } 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 + * + * http://www.tug.org/TUGboat/Articles/tb24-3/lemberg.pdf + * + * + * Segments + * + * `af_{cjk,latin,...}_hints_compute_segments' are the functions to + * find segments in an outline. A segment is a series of consecutive + * points that are approximately aligned along a coordinate axis. The + * analysis to do so is specific to a script. + * + * A segment must have at least two points, except in the case of + * `fake' segments that are generated to hint metrics appropriately, + * and which consist of a single point. + * + * + * 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). + * + * The auto-hinter first tries to grid fit edges, then to align + * segments on the edges unless it detects that they form a serif. + * + * `af_{cjk,latin,...}_hints_compute_edges' are the functions to find + * edges; they are specific to a script. + * + * + * A H + * | | + * | | + * | | + * | | + * C | | F + * +------<-----+ +-----<------+ + * | B G | + * | | + * | | + * +--------------->------------------+ + * D E + * + * + * Stems + * + * 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'. + * + * Stems are detected by `af_{cjk,latin,...}_hint_edges'. + * + * 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. + * + * + * Serifs + * + * On the opposite, a serif 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). + * + * Serifs are detected by `af_{cjk,latin,...}_hint_edges'. + * + * + * 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 which are 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) + * + * `af_glyph_hints_align_strong_points' is the function which 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 */ + typedef enum AF_Flags_ + { + AF_FLAG_NONE = 0, +/* point type flags */ + AF_FLAG_CONIC = 1 << 0, + AF_FLAG_CUBIC = 1 << 1, + AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC, +/* point extremum flags */ + AF_FLAG_EXTREMA_X = 1 << 2, + AF_FLAG_EXTREMA_Y = 1 << 3, +/* point roundness flags */ + AF_FLAG_ROUND_X = 1 << 4, + AF_FLAG_ROUND_Y = 1 << 5, +/* point touch flags */ + AF_FLAG_TOUCH_X = 1 << 6, + AF_FLAG_TOUCH_Y = 1 << 7, +/* candidates for weak interpolation have this flag set */ + AF_FLAG_WEAK_INTERPOLATION = 1 << 8, +/* all inflection points in the outline have this flag set */ + AF_FLAG_INFLECTION = 1 << 9 + } AF_Flags; +/* edge hint flags */ + typedef enum AF_Edge_Flags_ + { + AF_EDGE_NORMAL = 0, + AF_EDGE_ROUND = 1 << 0, + AF_EDGE_SERIF = 1 << 1, + AF_EDGE_DONE = 1 << 2 + } AF_Edge_Flags; + typedef struct AF_PointRec_* AF_Point; + typedef struct AF_SegmentRec_* AF_Segment; + typedef struct AF_EdgeRec_* AF_Edge; + typedef struct AF_PointRec_ + { +/* point flags used by hinter */ + FT_UShort flags; +/* direction of inwards vector */ + FT_Char in_dir; +/* direction of outwards vector */ + FT_Char out_dir; +/* original, scaled position */ + FT_Pos ox, oy; +/* original, unscaled position (in font units) */ + FT_Short fx, fy; +/* current position */ + FT_Pos x, y; +/* current (x,y) or (y,x) depending on context */ + FT_Pos u, v; +/* next point in contour */ + AF_Point next; +/* previous point in contour */ + AF_Point prev; + } AF_PointRec; + typedef struct AF_SegmentRec_ + { +/* edge/segment flags for this segment */ + FT_Byte flags; +/* segment direction */ + FT_Char dir; +/* position of segment */ + FT_Short pos; +/* minimum coordinate of segment */ + FT_Short min_coord; +/* maximum coordinate of segment */ + FT_Short max_coord; +/* the hinted segment height */ + FT_Short height; +/* the segment's parent edge */ + AF_Edge edge; +/* link to next segment in parent edge */ + AF_Segment edge_next; +/* (stem) link segment */ + AF_Segment link; +/* primary segment for serifs */ + AF_Segment serif; +/* number of linked segments */ + FT_Pos num_linked; +/* used during stem matching */ + FT_Pos score; +/* used during stem matching */ + FT_Pos len; +/* first point in edge segment */ + AF_Point first; +/* last point in edge segment */ + AF_Point last; + } AF_SegmentRec; + typedef struct AF_EdgeRec_ + { +/* original, unscaled position (in font units) */ + FT_Short fpos; +/* original, scaled position */ + FT_Pos opos; +/* current position */ + FT_Pos pos; +/* edge flags */ + FT_Byte flags; +/* edge direction */ + FT_Char dir; +/* used to speed up interpolation between edges */ + FT_Fixed scale; +/* non-NULL if this is a blue edge */ + AF_Width blue_edge; +/* link edge */ + AF_Edge link; +/* primary edge for serifs */ + AF_Edge serif; +/* number of linked edges */ + FT_Short num_linked; +/* used during stem matching */ + FT_Int score; +/* first segment in edge */ + AF_Segment first; +/* last segment in edge */ + AF_Segment last; + } AF_EdgeRec; + typedef struct AF_AxisHintsRec_ + { +/* number of used segments */ + FT_Int num_segments; +/* number of allocated segments */ + FT_Int max_segments; +/* segments array */ + AF_Segment segments; +#ifdef AF_SORT_SEGMENTS + FT_Int mid_segments; +#endif +/* number of used edges */ + FT_Int num_edges; +/* number of allocated edges */ + FT_Int max_edges; +/* edges array */ + AF_Edge edges; +/* either vertical or horizontal */ + AF_Direction major_dir; + } AF_AxisHintsRec, *AF_AxisHints; + typedef struct AF_GlyphHintsRec_ + { + FT_Memory memory; + FT_Fixed x_scale; + FT_Pos x_delta; + FT_Fixed y_scale; + FT_Pos y_delta; +/* number of allocated points */ + FT_Int max_points; +/* number of used points */ + FT_Int num_points; +/* points array */ + AF_Point points; +/* number of allocated contours */ + FT_Int max_contours; +/* number of used contours */ + FT_Int num_contours; +/* contours array */ + AF_Point* contours; + AF_AxisHintsRec axis[AF_DIMENSION_MAX]; +/* copy of scaler flags */ + FT_UInt32 scaler_flags; +/* free for script-specific */ + FT_UInt32 other_flags; +/* implementations */ + AF_ScriptMetrics metrics; +/* used for warping */ + FT_Pos xmin_delta; + FT_Pos xmax_delta; + } AF_GlyphHintsRec; +#define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) ) +#define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) ) +#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_ADVANCE( h ) \ + !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE ) +#define AF_HINTS_DO_BLUES( h ) 1 + 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_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_ScriptMetrics 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 +/* END */ +FT_BEGIN_HEADER + typedef struct AF_ModuleRec_* AF_Module; +/* + * 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 */ + FT_GlyphLoader gloader; + AF_GlyphHintsRec hints; + AF_ScriptMetrics 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( FT_Error ) + af_loader_init( AF_Module module ); + FT_LOCAL( FT_Error ) + af_loader_reset( AF_Module module, + FT_Face face ); + FT_LOCAL( void ) + af_loader_done( AF_Module module ); + FT_LOCAL( FT_Error ) + af_loader_load_glyph( AF_Module module, + FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags ); +/* */ +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/* + * This is the `extended' FT_Module structure which holds the + * autofitter's global data. Right before hinting a glyph, the data + * specific to the glyph's face (blue zones, stem widths, etc.) are + * loaded into `loader' (see function `af_loader_reset'). + */ + typedef struct AF_ModuleRec_ + { + FT_ModuleRec root; + FT_UInt fallback_script; + AF_LoaderRec loader[1]; + } AF_ModuleRec; +FT_DECLARE_MODULE(autofit_module_class) +FT_END_HEADER +/* END */ +FT_BEGIN_HEADER +/* + * Default values and flags for both autofitter globals (found in + * AF_ModuleRec) and face globals (in AF_FaceGlobalsRec). + */ +/* index of fallback script in `af_script_classes' */ +#define AF_SCRIPT_FALLBACK 2 +/* a bit mask indicating an uncovered glyph */ +#define AF_SCRIPT_NONE 0x7F +/* if this flag is set, we have an ASCII digit */ +#define AF_DIGIT 0x80 +/* `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_scripts[] is used to map each glyph into + * an index into the `af_script_classes' array. + * + */ + typedef struct AF_FaceGlobalsRec_ + { + FT_Face face; +/* same as face->num_glyphs */ + FT_Long glyph_count; + FT_Byte* glyph_scripts; +/* per-face auto-hinter properties */ + FT_UInt increase_x_height; + AF_ScriptMetrics metrics[AF_SCRIPT_MAX]; +/* to access global properties */ + AF_Module module; + } AF_FaceGlobalsRec; +/* + * model the global hints data for a given face, decomposed into + * script-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_ScriptMetrics *ametrics ); + FT_LOCAL( void ) + af_face_globals_free( AF_FaceGlobals globals ); + FT_LOCAL_DEF( FT_Bool ) + af_face_globals_is_digit( AF_FaceGlobals globals, + FT_UInt gindex ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* afdummy.h */ +/* */ +/* Auto-fitter dummy routines to be used if no hinting should be */ +/* performed (specification). */ +/* */ +/* Copyright 2003-2005, 2011 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. */ +/* */ +/***************************************************************************/ +#define __AFDUMMY_H__ +FT_BEGIN_HEADER +/* A dummy script metrics class used when no hinting should + * be performed. This is the default for non-latin glyphs! + */ + AF_DECLARE_SCRIPT_CLASS( af_dummy_script_class ) +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* aflatin.h */ +/* */ +/* Auto-fitter hinting routines for latin script (specification). */ +/* */ +/* Copyright 2003-2007, 2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +#define __AFLATIN_H__ +FT_BEGIN_HEADER +/* the latin-specific script class */ + AF_DECLARE_SCRIPT_CLASS( af_latin_script_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 script hinters to + * re-use some of them. + */ +/* Latin (global) metrics management */ + enum + { + AF_LATIN_BLUE_CAPITAL_TOP, + AF_LATIN_BLUE_CAPITAL_BOTTOM, + AF_LATIN_BLUE_SMALL_F_TOP, + AF_LATIN_BLUE_SMALL_TOP, + AF_LATIN_BLUE_SMALL_BOTTOM, + AF_LATIN_BLUE_SMALL_MINOR, + AF_LATIN_BLUE_MAX + }; +#define AF_LATIN_IS_TOP_BLUE( b ) ( (b) == AF_LATIN_BLUE_CAPITAL_TOP || \ + (b) == AF_LATIN_BLUE_SMALL_F_TOP || \ + (b) == AF_LATIN_BLUE_SMALL_TOP ) +#define AF_LATIN_MAX_WIDTHS 16 +#define AF_LATIN_MAX_BLUES AF_LATIN_BLUE_MAX + enum + { +/* set if zone height is <= 3/4px */ + AF_LATIN_BLUE_ACTIVE = 1 << 0, +/* result of AF_LATIN_IS_TOP_BLUE */ + AF_LATIN_BLUE_TOP = 1 << 1, +/* used for scale adjustment */ + AF_LATIN_BLUE_ADJUSTMENT = 1 << 2, +/* optimization */ + AF_LATIN_BLUE_FLAG_MAX + }; + typedef struct AF_LatinBlueRec_ + { + AF_WidthRec ref; + AF_WidthRec shoot; + FT_UInt flags; + } AF_LatinBlueRec, *AF_LatinBlue; + typedef struct AF_LatinAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; +/* number of used widths */ + FT_UInt width_count; +/* widths array */ + AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]; +/* used for creating edges */ + FT_Pos edge_distance_threshold; +/* the default stem thickness */ + FT_Pos standard_width; +/* is standard width very light? */ + FT_Bool extra_light; +/* ignored for horizontal metrics */ + FT_UInt blue_count; + AF_LatinBlueRec blues[AF_LATIN_BLUE_MAX]; + FT_Fixed org_scale; + FT_Pos org_delta; + } AF_LatinAxisRec, *AF_LatinAxis; + typedef struct AF_LatinMetricsRec_ + { + AF_ScriptMetricsRec 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_LatinMetrics metrics, + FT_Face face ); + FT_LOCAL( void ) + af_latin_metrics_scale( AF_LatinMetrics 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 *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + enum + { +/* enable stem width snapping */ + AF_LATIN_HINTS_HORZ_SNAP = 1 << 0, +/* enable stem height snapping */ + AF_LATIN_HINTS_VERT_SNAP = 1 << 1, +/* enable stem width/height */ + AF_LATIN_HINTS_STEM_ADJUST = 1 << 2, +/* adjustment */ +/* indicate monochrome */ + AF_LATIN_HINTS_MONO = 1 << 3 +/* 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 + * scripts 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, + 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, + AF_Dimension dim ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* afcjk.h */ +/* */ +/* Auto-fitter hinting routines for CJK script (specification). */ +/* */ +/* Copyright 2006, 2007, 2011, 2012 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. */ +/* */ +/***************************************************************************/ +#define __AFCJK_H__ +FT_BEGIN_HEADER +/* the CJK-specific script class */ + AF_DECLARE_SCRIPT_CLASS( af_cjk_script_class ) +/* CJK (global) metrics management */ +/* + * 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. + */ + enum + { + AF_CJK_BLUE_TOP, + AF_CJK_BLUE_BOTTOM, + AF_CJK_BLUE_LEFT, + AF_CJK_BLUE_RIGHT, + AF_CJK_BLUE_MAX + }; +#define AF_CJK_MAX_WIDTHS 16 +#define AF_CJK_MAX_BLUES AF_CJK_BLUE_MAX + enum + { + AF_CJK_BLUE_ACTIVE = 1 << 0, + AF_CJK_BLUE_IS_TOP = 1 << 1, + AF_CJK_BLUE_IS_RIGHT = 1 << 2, +/* used for scale adjustment */ + AF_CJK_BLUE_ADJUSTMENT = 1 << 3, +/* optimization */ + AF_CJK_BLUE_FLAG_MAX + }; + typedef struct AF_CJKBlueRec_ + { + AF_WidthRec ref; +/* undershoot */ + AF_WidthRec shoot; + FT_UInt flags; + } AF_CJKBlueRec, *AF_CJKBlue; + typedef struct AF_CJKAxisRec_ + { + FT_Fixed scale; + FT_Pos delta; + FT_UInt width_count; + AF_WidthRec widths[AF_CJK_MAX_WIDTHS]; + FT_Pos edge_distance_threshold; + FT_Pos standard_width; + FT_Bool extra_light; +/* used for horizontal metrics too for CJK */ + FT_Bool control_overshoot; + FT_UInt blue_count; + AF_CJKBlueRec blues[AF_CJK_BLUE_MAX]; + FT_Fixed org_scale; + FT_Pos org_delta; + } AF_CJKAxisRec, *AF_CJKAxis; + typedef struct AF_CJKMetricsRec_ + { + AF_ScriptMetricsRec root; + FT_UInt units_per_em; + AF_CJKAxisRec axis[AF_DIMENSION_MAX]; + } AF_CJKMetricsRec, *AF_CJKMetrics; + FT_LOCAL( FT_Error ) + af_cjk_metrics_init( AF_CJKMetrics metrics, + FT_Face face ); + FT_LOCAL( void ) + af_cjk_metrics_scale( AF_CJKMetrics metrics, + AF_Scaler scaler ); + FT_LOCAL( FT_Error ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_CJKMetrics metrics ); + FT_LOCAL( FT_Error ) + af_cjk_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_CJKMetrics 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 ); +/* */ +FT_END_HEADER +/* END */ +/***************************************************************************/ +/* */ +/* afindic.h */ +/* */ +/* Auto-fitter hinting routines for Indic scripts (specification). */ +/* */ +/* Copyright 2007, 2012 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. */ +/* */ +/***************************************************************************/ +#define __AFINDIC_H__ +FT_BEGIN_HEADER +/* the Indic-specific script class */ + AF_DECLARE_SCRIPT_CLASS( af_indic_script_class ) +/* */ +FT_END_HEADER +/* END */ +#ifdef FT_OPTION_AUTOFIT2 +/***************************************************************************/ +/* */ +/* aflatin2.h */ +/* */ +/* Auto-fitter hinting routines for latin script (specification). */ +/* */ +/* Copyright 2003-2007, 2012 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. */ +/* */ +/***************************************************************************/ +#define __AFLATIN2_H__ +FT_BEGIN_HEADER +/* the latin-specific script class */ + AF_DECLARE_SCRIPT_CLASS( af_latin2_script_class ) +/* */ +FT_END_HEADER +/* END */ +#endif +/* when updating this table, don't forget to update */ +/* AF_SCRIPT_CLASSES_COUNT and autofit_module_class_pic_init */ +/* populate this list when you add new scripts */ + static AF_ScriptClass const af_script_classes[] = + { + &af_dummy_script_class, +#ifdef FT_OPTION_AUTOFIT2 + &af_latin2_script_class, +#endif + &af_latin_script_class, + &af_cjk_script_class, + &af_indic_script_class, +/* do not remove */ + NULL + }; +/* Compute the script index of each glyph within a given face. */ + static FT_Error + af_face_globals_compute_script_coverage( AF_FaceGlobals globals ) + { + FT_Error error = AF_Err_Ok; + FT_Face face = globals->face; + FT_CharMap old_charmap = face->charmap; + FT_Byte* gscripts = globals->glyph_scripts; + FT_UInt ss; + FT_UInt i; +/* the value AF_SCRIPT_NONE means `uncovered glyph' */ + FT_MEM_SET( globals->glyph_scripts, + AF_SCRIPT_NONE, + globals->glyph_count ); + error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); + if ( error ) + { +/* + * Ignore this error; we simply use the fallback script. + * XXX: Shouldn't we rather disable hinting? + */ + error = AF_Err_Ok; + goto Exit; + } +/* scan each script in a Unicode charmap */ + for ( ss = 0; AF_SCRIPT_CLASSES_GET[ss]; ss++ ) + { + AF_ScriptClass clazz = AF_SCRIPT_CLASSES_GET[ss]; + AF_Script_UniRange range; + if ( clazz->script_uni_ranges == NULL ) + continue; +/* + * Scan all Unicode points in the range and set the corresponding + * glyph script index. + */ + for ( range = clazz->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 < (FT_ULong)globals->glyph_count && + gscripts[gindex] == AF_SCRIPT_NONE ) + gscripts[gindex] = (FT_Byte)ss; + for (;;) + { + charcode = FT_Get_Next_Char( face, charcode, &gindex ); + if ( gindex == 0 || charcode > range->last ) + break; + if ( gindex < (FT_ULong)globals->glyph_count && + gscripts[gindex] == AF_SCRIPT_NONE ) + gscripts[gindex] = (FT_Byte)ss; + } + } + } +/* mark ASCII digits */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt gindex = FT_Get_Char_Index( face, i ); + if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) + gscripts[gindex] |= AF_DIGIT; + } + Exit: +/* + * By default, all uncovered glyphs are set to the fallback script. + * XXX: Shouldn't we disable hinting or do something similar? + */ + if ( globals->module->fallback_script != AF_SCRIPT_NONE ) + { + FT_Long nn; + for ( nn = 0; nn < globals->glyph_count; nn++ ) + { + if ( ( gscripts[nn] & ~AF_DIGIT ) == AF_SCRIPT_NONE ) + { + gscripts[nn] &= ~AF_SCRIPT_NONE; + gscripts[nn] |= globals->module->fallback_script; + } + } + } + FT_Set_Charmap( face, 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; + if ( FT_ALLOC( globals, sizeof ( *globals ) + + face->num_glyphs * sizeof ( FT_Byte ) ) ) + goto Exit; + globals->face = face; + globals->glyph_count = face->num_glyphs; + globals->glyph_scripts = (FT_Byte*)( globals + 1 ); + globals->module = module; + error = af_face_globals_compute_script_coverage( globals ); + if ( error ) + { + af_face_globals_free( globals ); + globals = NULL; + } + globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX; + Exit: + *aglobals = globals; + return error; + } + FT_LOCAL_DEF( void ) + af_face_globals_free( AF_FaceGlobals globals ) + { + if ( globals ) + { + FT_Memory memory = globals->face->memory; + FT_UInt nn; + for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ ) + { + if ( globals->metrics[nn] ) + { + AF_ScriptClass clazz = AF_SCRIPT_CLASSES_GET[nn]; + FT_ASSERT( globals->metrics[nn]->clazz == clazz ); + if ( clazz->script_metrics_done ) + clazz->script_metrics_done( globals->metrics[nn] ); + FT_FREE( globals->metrics[nn] ); + } + } + globals->glyph_count = 0; +/* no need to free this one! */ + globals->glyph_scripts = NULL; + globals->face = NULL; + FT_FREE( globals ); + } + } + FT_LOCAL_DEF( FT_Error ) + af_face_globals_get_metrics( AF_FaceGlobals globals, + FT_UInt gindex, + FT_UInt options, + AF_ScriptMetrics *ametrics ) + { + AF_ScriptMetrics metrics = NULL; + FT_UInt gidx; + AF_ScriptClass clazz; + FT_UInt script = options & 15; + const FT_Offset script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) / + sizeof ( AF_SCRIPT_CLASSES_GET[0] ); + FT_Error error = AF_Err_Ok; + if ( gindex >= (FT_ULong)globals->glyph_count ) + { + error = AF_Err_Invalid_Argument; + goto Exit; + } + gidx = script; + if ( gidx == 0 || gidx + 1 >= script_max ) + gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_NONE; + clazz = AF_SCRIPT_CLASSES_GET[gidx]; + if ( script == 0 ) + script = clazz->script; + metrics = globals->metrics[clazz->script]; + if ( metrics == NULL ) + { +/* create the global metrics object if necessary */ + FT_Memory memory = globals->face->memory; + if ( FT_ALLOC( metrics, clazz->script_metrics_size ) ) + goto Exit; + metrics->clazz = clazz; + metrics->globals = globals; + if ( clazz->script_metrics_init ) + { + error = clazz->script_metrics_init( metrics, globals->face ); + if ( error ) + { + if ( clazz->script_metrics_done ) + clazz->script_metrics_done( metrics ); + FT_FREE( metrics ); + goto Exit; + } + } + globals->metrics[clazz->script] = metrics; + } + Exit: + *ametrics = metrics; + return error; + } + FT_LOCAL_DEF( FT_Bool ) + af_face_globals_is_digit( AF_FaceGlobals globals, + FT_UInt gindex ) + { + if ( gindex < (FT_ULong)globals->glyph_count ) + return (FT_Bool)( globals->glyph_scripts[gindex] & AF_DIGIT ); + return (FT_Bool)0; + } +/* END */ +/***************************************************************************/ +/* */ +/* afhints.c */ +/* */ +/* Auto-fitter hinting routines (body). */ +/* */ +/* Copyright 2003-2007, 2009-2012 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 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 trace_afhints +/* Get new segment for given axis. */ + FT_LOCAL_DEF( FT_Error ) + af_axis_hints_new_segment( AF_AxisHints axis, + FT_Memory memory, + AF_Segment *asegment ) + { + FT_Error error = AF_Err_Ok; + AF_Segment segment = NULL; + if ( axis->num_segments >= axis->max_segments ) + { + FT_Int old_max = axis->max_segments; + FT_Int new_max = old_max; + FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) ); + if ( old_max >= big_max ) + { + error = AF_Err_Out_Of_Memory; + goto Exit; + } + new_max += ( new_max >> 2 ) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) ) + goto Exit; + axis->max_segments = new_max; + } + segment = axis->segments + axis->num_segments++; + Exit: + *asegment = segment; + return error; + } +/* Get new edge for given axis, direction, and position. */ + FT_LOCAL( FT_Error ) + af_axis_hints_new_edge( AF_AxisHints axis, + FT_Int fpos, + AF_Direction dir, + FT_Memory memory, + AF_Edge *anedge ) + { + FT_Error error = AF_Err_Ok; + AF_Edge edge = NULL; + AF_Edge edges; + if ( axis->num_edges >= axis->max_edges ) + { + FT_Int old_max = axis->max_edges; + FT_Int new_max = old_max; + FT_Int big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) ); + if ( old_max >= big_max ) + { + error = AF_Err_Out_Of_Memory; + goto Exit; + } + new_max += ( new_max >> 2 ) + 4; + if ( new_max < old_max || new_max > big_max ) + new_max = big_max; + if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) ) + goto Exit; + axis->max_edges = new_max; + } + edges = axis->edges; + edge = edges + axis->num_edges; + while ( edge > edges ) + { + if ( edge[-1].fpos < fpos ) + break; +/* we want the edge with same position and minor direction */ +/* to appear before those in the major one in the list */ + if ( edge[-1].fpos == fpos && dir == axis->major_dir ) + break; + edge[0] = edge[-1]; + edge--; + } + axis->num_edges++; + FT_ZERO( edge ); + edge->fpos = (FT_Short)fpos; + edge->dir = (FT_Char)dir; + Exit: + *anedge = edge; + return error; + } +/* these empty stubs are only used to link the `ftgrid' test program */ +/* if debugging is disabled */ +#ifdef __cplusplus + extern "C" { +#endif + void + af_glyph_hints_dump_points( AF_GlyphHints hints ) + { + FT_UNUSED( hints ); + } + void + af_glyph_hints_dump_segments( AF_GlyphHints hints ) + { + FT_UNUSED( hints ); + } + FT_Error + af_glyph_hints_get_num_segments( AF_GlyphHints hints, + FT_Int dimension, + FT_Int* num_segments ) + { + FT_UNUSED( hints ); + FT_UNUSED( dimension ); + FT_UNUSED( num_segments ); + return 0; + } + FT_Error + af_glyph_hints_get_segment_offset( AF_GlyphHints hints, + FT_Int dimension, + FT_Int idx, + FT_Pos* offset ) + { + FT_UNUSED( hints ); + FT_UNUSED( dimension ); + FT_UNUSED( idx ); + FT_UNUSED( offset ); + return 0; + } + void + af_glyph_hints_dump_edges( AF_GlyphHints hints ) + { + FT_UNUSED( hints ); + } +#ifdef __cplusplus + } +#endif +/* Compute the direction value of a given vector. */ + FT_LOCAL_DEF( AF_Direction ) + af_direction_compute( FT_Pos dx, + FT_Pos dy ) + { +/* long and short arm lengths */ + FT_Pos ll, ss; +/* candidate direction */ + AF_Direction dir; + if ( dy >= dx ) + { + if ( dy >= -dx ) + { + dir = AF_DIR_UP; + ll = dy; + ss = dx; + } + else + { + dir = AF_DIR_LEFT; + ll = -dx; + ss = dy; + } + } +/* dy < dx */ + else + { + if ( dy >= -dx ) + { + dir = AF_DIR_RIGHT; + ll = dx; + ss = dy; + } + else + { + dir = AF_DIR_DOWN; + ll = dy; + ss = dx; + } + } +/* return no direction if arm lengths differ too much */ +/* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */ + ss *= 14; + if ( FT_ABS( ll ) <= FT_ABS( ss ) ) + dir = AF_DIR_NONE; + return dir; + } + FT_LOCAL_DEF( void ) + af_glyph_hints_init( AF_GlyphHints hints, + FT_Memory memory ) + { + FT_ZERO( hints ); + hints->memory = memory; + } + FT_LOCAL_DEF( void ) + af_glyph_hints_done( AF_GlyphHints hints ) + { + FT_Memory memory = hints->memory; + int dim; + if ( !( hints && hints->memory ) ) + return; +/* + * note that we don't need to free the segment and edge + * buffers since they are really within the hints->points array + */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_AxisHints axis = &hints->axis[dim]; + axis->num_segments = 0; + axis->max_segments = 0; + FT_FREE( axis->segments ); + axis->num_edges = 0; + axis->max_edges = 0; + FT_FREE( axis->edges ); + } + FT_FREE( hints->contours ); + hints->max_contours = 0; + hints->num_contours = 0; + FT_FREE( hints->points ); + hints->num_points = 0; + hints->max_points = 0; + hints->memory = NULL; + } +/* Reset metrics. */ + FT_LOCAL_DEF( void ) + af_glyph_hints_rescale( AF_GlyphHints hints, + AF_ScriptMetrics metrics ) + { + hints->metrics = metrics; + hints->scaler_flags = metrics->scaler.flags; + } +/* Recompute all AF_Point in AF_GlyphHints from the definitions */ +/* in a source outline. */ + FT_LOCAL_DEF( FT_Error ) + af_glyph_hints_reload( AF_GlyphHints hints, + FT_Outline* outline ) + { + FT_Error error = AF_Err_Ok; + AF_Point points; + FT_UInt old_max, new_max; + FT_Fixed x_scale = hints->x_scale; + FT_Fixed y_scale = hints->y_scale; + FT_Pos x_delta = hints->x_delta; + FT_Pos y_delta = hints->y_delta; + FT_Memory memory = hints->memory; + hints->num_points = 0; + hints->num_contours = 0; + hints->axis[0].num_segments = 0; + hints->axis[0].num_edges = 0; + hints->axis[1].num_segments = 0; + hints->axis[1].num_edges = 0; +/* first of all, reallocate the contours array if necessary */ + new_max = (FT_UInt)outline->n_contours; + old_max = hints->max_contours; + if ( new_max > old_max ) + { +/* round up to a multiple of 4 */ + new_max = ( new_max + 3 ) & ~3; + if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) + goto Exit; + hints->max_contours = new_max; + } +/* + * then reallocate the points arrays if necessary -- + * note that we reserve two additional point positions, used to + * hint metrics appropriately + */ + new_max = (FT_UInt)( outline->n_points + 2 ); + old_max = hints->max_points; + if ( new_max > old_max ) + { +/* round up to a multiple of 8 */ + new_max = ( new_max + 2 + 7 ) & ~7; + if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) + goto Exit; + hints->max_points = new_max; + } + hints->num_points = outline->n_points; + hints->num_contours = outline->n_contours; +/* We can't rely on the value of `FT_Outline.flags' to know the fill */ +/* direction used for a glyph, given that some fonts are broken (e.g., */ +/* the Arphic ones). We thus recompute it each time we need to. */ +/* */ + hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP; + hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT; + if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) + { + hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN; + hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT; + } + hints->x_scale = x_scale; + hints->y_scale = y_scale; + hints->x_delta = x_delta; + hints->y_delta = y_delta; + hints->xmin_delta = 0; + hints->xmax_delta = 0; + points = hints->points; + if ( hints->num_points == 0 ) + goto Exit; + { + AF_Point point; + AF_Point point_limit = points + hints->num_points; +/* compute coordinates & Bezier flags, next and prev */ + { + FT_Vector* vec = outline->points; + char* tag = outline->tags; + AF_Point end = points + outline->contours[0]; + AF_Point prev = end; + FT_Int contour_index = 0; + for ( point = points; point < point_limit; point++, vec++, tag++ ) + { + point->fx = (FT_Short)vec->x; + point->fy = (FT_Short)vec->y; + point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; + point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; + switch ( FT_CURVE_TAG( *tag ) ) + { + case FT_CURVE_TAG_CONIC: + point->flags = AF_FLAG_CONIC; + break; + case FT_CURVE_TAG_CUBIC: + point->flags = AF_FLAG_CUBIC; + break; + default: + point->flags = AF_FLAG_NONE; + } + point->prev = prev; + prev->next = point; + prev = point; + if ( point == end ) + { + if ( ++contour_index < outline->n_contours ) + { + end = points + outline->contours[contour_index]; + prev = end; + } + } + } + } +/* set up the contours array */ + { + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + short* end = outline->contours; + short idx = 0; + for ( ; contour < contour_limit; contour++, end++ ) + { + contour[0] = points + idx; + idx = (short)( end[0] + 1 ); + } + } +/* compute directions of in & out vectors */ + { + AF_Point first = points; + AF_Point prev = NULL; + FT_Pos in_x = 0; + FT_Pos in_y = 0; + AF_Direction in_dir = AF_DIR_NONE; + for ( point = points; point < point_limit; point++ ) + { + AF_Point next; + FT_Pos out_x, out_y; + if ( point == first ) + { + prev = first->prev; + in_x = first->fx - prev->fx; + in_y = first->fy - prev->fy; + in_dir = af_direction_compute( in_x, in_y ); + first = prev + 1; + } + point->in_dir = (FT_Char)in_dir; + next = point->next; + out_x = next->fx - point->fx; + out_y = next->fy - point->fy; + in_dir = af_direction_compute( out_x, out_y ); + point->out_dir = (FT_Char)in_dir; +/* check for weak points */ + if ( point->flags & AF_FLAG_CONTROL ) + { + Is_Weak_Point: + point->flags |= AF_FLAG_WEAK_INTERPOLATION; + } + else if ( point->out_dir == point->in_dir ) + { + if ( point->out_dir != AF_DIR_NONE ) + goto Is_Weak_Point; + if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) ) + goto Is_Weak_Point; + } + else if ( point->in_dir == -point->out_dir ) + goto Is_Weak_Point; + in_x = out_x; + in_y = out_y; + prev = point; + } + } + } + Exit: + return error; + } +/* Store the hinted outline in an FT_Outline structure. */ + FT_LOCAL_DEF( void ) + af_glyph_hints_save( AF_GlyphHints hints, + FT_Outline* outline ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + FT_Vector* vec = outline->points; + char* tag = outline->tags; + for ( ; point < limit; point++, vec++, tag++ ) + { + vec->x = point->x; + vec->y = point->y; + if ( point->flags & AF_FLAG_CONIC ) + tag[0] = FT_CURVE_TAG_CONIC; + else if ( point->flags & AF_FLAG_CUBIC ) + tag[0] = FT_CURVE_TAG_CUBIC; + else + tag[0] = FT_CURVE_TAG_ON; + } + } +/**************************************************************** + * + * EDGE POINT GRID-FITTING + * + ****************************************************************/ +/* Align all points of an edge to the same coordinate value, */ +/* either horizontally or vertically. */ + FT_LOCAL_DEF( void ) + af_glyph_hints_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment seg; + if ( dim == AF_DIMENSION_HORZ ) + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge edge = seg->edge; + AF_Point point, first, last; + if ( edge == NULL ) + continue; + first = seg->first; + last = seg->last; + point = first; + for (;;) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + if ( point == last ) + break; + point = point->next; + } + } + } + else + { + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge edge = seg->edge; + AF_Point point, first, last; + if ( edge == NULL ) + continue; + first = seg->first; + last = seg->last; + point = first; + for (;;) + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + if ( point == last ) + break; + point = point->next; + } + } + } + } +/**************************************************************** + * + * STRONG POINT INTERPOLATION + * + ****************************************************************/ +/* Hint the strong points -- this is equivalent to the TrueType `IP' */ +/* hinting instruction. */ + FT_LOCAL_DEF( void ) + af_glyph_hints_align_strong_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Flags touch_flag; + if ( dim == AF_DIMENSION_HORZ ) + touch_flag = AF_FLAG_TOUCH_X; + else + touch_flag = AF_FLAG_TOUCH_Y; + if ( edges < edge_limit ) + { + AF_Point point; + AF_Edge edge; + for ( point = points; point < point_limit; point++ ) + { +/* point position */ + FT_Pos u, ou, fu; + FT_Pos delta; + if ( point->flags & touch_flag ) + continue; +/* if this point is candidate to weak interpolation, we */ +/* interpolate it after all strong points have been processed */ + if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) && + !( point->flags & AF_FLAG_INFLECTION ) ) + continue; + if ( dim == AF_DIMENSION_VERT ) + { + u = point->fy; + ou = point->oy; + } + else + { + u = point->fx; + ou = point->ox; + } + fu = u; +/* is the point before the first edge? */ + edge = edges; + delta = edge->fpos - u; + if ( delta >= 0 ) + { + u = edge->pos - ( edge->opos - ou ); + goto Store_Point; + } +/* is the point after the last edge? */ + edge = edge_limit - 1; + delta = u - edge->fpos; + if ( delta >= 0 ) + { + u = edge->pos + ( ou - edge->opos ); + goto Store_Point; + } + { + FT_PtrDist min, max, mid; + FT_Pos fpos; +/* find enclosing edges */ + min = 0; + max = edge_limit - edges; +#if 1 +/* for a small number of edges, a linear search is better */ + if ( max <= 8 ) + { + FT_PtrDist nn; + for ( nn = 0; nn < max; nn++ ) + if ( edges[nn].fpos >= u ) + break; + if ( edges[nn].fpos == u ) + { + u = edges[nn].pos; + goto Store_Point; + } + min = nn; + } + else +#endif + while ( min < max ) + { + mid = ( max + min ) >> 1; + edge = edges + mid; + fpos = edge->fpos; + if ( u < fpos ) + max = mid; + else if ( u > fpos ) + min = mid + 1; + else + { +/* we are on the edge */ + u = edge->pos; + goto Store_Point; + } + } +/* point is not on an edge */ + { + AF_Edge before = edges + min - 1; + AF_Edge after = edges + min + 0; +/* assert( before && after && before != after ) */ + if ( before->scale == 0 ) + before->scale = FT_DivFix( after->pos - before->pos, + after->fpos - before->fpos ); + u = before->pos + FT_MulFix( fu - before->fpos, + before->scale ); + } + } + Store_Point: +/* save the point position */ + if ( dim == AF_DIMENSION_HORZ ) + point->x = u; + else + point->y = u; + point->flags |= touch_flag; + } + } + } +/**************************************************************** + * + * WEAK POINT INTERPOLATION + * + ****************************************************************/ +/* Shift the original coordinates of all points between `p1' and */ +/* `p2' to get hinted coordinates, using the same difference as */ +/* given by `ref'. */ + static void + af_iup_shift( AF_Point p1, + AF_Point p2, + AF_Point ref ) + { + AF_Point p; + FT_Pos delta = ref->u - ref->v; + if ( delta == 0 ) + return; + for ( p = p1; p < ref; p++ ) + p->u = p->v + delta; + for ( p = ref + 1; p <= p2; p++ ) + p->u = p->v + delta; + } +/* Interpolate the original coordinates of all points between `p1' and */ +/* `p2' to get hinted coordinates, using `ref1' and `ref2' as the */ +/* reference points. The `u' and `v' members are the current and */ +/* original coordinate values, respectively. */ +/* */ +/* Details can be found in the TrueType bytecode specification. */ + static void + af_iup_interp( AF_Point p1, + AF_Point p2, + AF_Point ref1, + AF_Point ref2 ) + { + AF_Point p; + FT_Pos u; + FT_Pos v1 = ref1->v; + FT_Pos v2 = ref2->v; + FT_Pos d1 = ref1->u - v1; + FT_Pos d2 = ref2->u - v2; + if ( p1 > p2 ) + return; + if ( v1 == v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + if ( u <= v1 ) + u += d1; + else + u += d2; + p->u = u; + } + return; + } + if ( v1 < v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + p->u = u; + } + } + else + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + if ( u <= v2 ) + u += d2; + else if ( u >= v1 ) + u += d1; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + p->u = u; + } + } + } +/* Hint the weak points -- this is equivalent to the TrueType `IUP' */ +/* hinting instruction. */ + FT_LOCAL_DEF( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Flags touch_flag; + AF_Point point; + AF_Point end_point; + AF_Point first_point; +/* PASS 1: Move segment points to edge positions */ + if ( dim == AF_DIMENSION_HORZ ) + { + touch_flag = AF_FLAG_TOUCH_X; + for ( point = points; point < point_limit; point++ ) + { + point->u = point->x; + point->v = point->ox; + } + } + else + { + touch_flag = AF_FLAG_TOUCH_Y; + for ( point = points; point < point_limit; point++ ) + { + point->u = point->y; + point->v = point->oy; + } + } + point = points; + for ( ; contour < contour_limit; contour++ ) + { + AF_Point first_touched, last_touched; + point = *contour; + end_point = point->prev; + first_point = point; +/* find first touched point */ + for (;;) + { +/* no touched point in contour */ + if ( point > end_point ) + goto NextContour; + if ( point->flags & touch_flag ) + break; + point++; + } + first_touched = point; + last_touched = point; + for (;;) + { + FT_ASSERT( point <= end_point && + ( point->flags & touch_flag ) != 0 ); +/* skip any touched neighbours */ + while ( point < end_point && + ( point[1].flags & touch_flag ) != 0 ) + point++; + last_touched = point; +/* find the next touched point, if any */ + point++; + for (;;) + { + if ( point > end_point ) + goto EndContour; + if ( ( point->flags & touch_flag ) != 0 ) + break; + point++; + } +/* interpolate between last_touched and point */ + af_iup_interp( last_touched + 1, point - 1, + last_touched, point ); + } + EndContour: +/* special case: only one point was touched */ + if ( last_touched == first_touched ) + af_iup_shift( first_point, end_point, first_touched ); +/* interpolate the last part */ + else + { + if ( last_touched < end_point ) + af_iup_interp( last_touched + 1, end_point, + last_touched, first_touched ); + if ( first_touched > points ) + af_iup_interp( first_point, first_touched - 1, + last_touched, first_touched ); + } + NextContour: + ; + } +/* now save the interpolated values back to x/y */ + if ( dim == AF_DIMENSION_HORZ ) + { + for ( point = points; point < point_limit; point++ ) + point->x = point->u; + } + else + { + for ( point = points; point < point_limit; point++ ) + point->y = point->u; + } + } +/* END */ +/***************************************************************************/ +/* */ +/* afdummy.c */ +/* */ +/* Auto-fitter dummy routines to be used if no hinting should be */ +/* performed (body). */ +/* */ +/* Copyright 2003-2005, 2011 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. */ +/* */ +/***************************************************************************/ + static FT_Error + af_dummy_hints_init( AF_GlyphHints hints, + AF_ScriptMetrics metrics ) + { + af_glyph_hints_rescale( hints, + metrics ); + return AF_Err_Ok; + } + static FT_Error + af_dummy_hints_apply( AF_GlyphHints hints, + FT_Outline* outline ) + { + FT_UNUSED( hints ); + FT_UNUSED( outline ); + return AF_Err_Ok; + } + AF_DEFINE_SCRIPT_CLASS( af_dummy_script_class, + AF_SCRIPT_DUMMY, + NULL, + 0, + sizeof ( AF_ScriptMetricsRec ), + (AF_Script_InitMetricsFunc) NULL, + (AF_Script_ScaleMetricsFunc)NULL, + (AF_Script_DoneMetricsFunc) NULL, + (AF_Script_InitHintsFunc) af_dummy_hints_init, + (AF_Script_ApplyHintsFunc) af_dummy_hints_apply + ) +/* END */ +/***************************************************************************/ +/* */ +/* aflatin.c */ +/* */ +/* Auto-fitter hinting routines for latin script (body). */ +/* */ +/* Copyright 2003-2012 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 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 trace_aflatin +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N G L O B A L M E T R I C S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* Find segments and links, compute all stem widths, and initialize */ +/* standard width and height for the glyph with given charcode. */ + FT_LOCAL_DEF( void ) + af_latin_metrics_init_widths( AF_LatinMetrics metrics, + FT_Face face ) + { +/* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + FT_TRACE5(( "standard widths computation\n" + "===========================\n\n" )); + af_glyph_hints_init( hints, face->memory ); + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + { + FT_Error error; + FT_UInt glyph_index; + int dim; + AF_LatinMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + glyph_index = FT_Get_Char_Index( face, + metrics->root.clazz->standard_char ); + if ( glyph_index == 0 ) + goto Exit; + FT_TRACE5(( "standard character: 0x%X (glyph index %d)\n", + metrics->root.clazz->standard_char, glyph_index )); + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + FT_ZERO( dummy ); + dummy->units_per_em = metrics->units_per_em; + scaler->x_scale = 0x10000L; + scaler->y_scale = 0x10000L; + scaler->x_delta = 0; + scaler->y_delta = 0; + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + error = af_latin_hints_compute_segments( hints, + (AF_Dimension)dim ); + if ( error ) + goto Exit; + af_latin_hints_link_segments( hints, + (AF_Dimension)dim ); + seg = axhints->segments; + limit = seg + axhints->num_segments; + for ( ; seg < limit; seg++ ) + { + link = seg->link; +/* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + if ( num_widths < AF_LATIN_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } +/* this also replaces multiple almost identical stem widths */ +/* with a single one (the value 100 is heuristic) */ + af_sort_and_quantize_widths( &num_widths, axis->widths, + dummy->units_per_em / 100 ); + axis->width_count = num_widths; + } + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + stdw = ( axis->width_count > 0 ) + ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); +/* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + } + } + FT_TRACE5(( "\n" )); + af_glyph_hints_done( hints ); + } +#define AF_LATIN_MAX_TEST_CHARACTERS 12 + static const char af_latin_blue_chars[AF_LATIN_MAX_BLUES] + [AF_LATIN_MAX_TEST_CHARACTERS + 1] = + { + "THEZOCQS", + "HEZLOCUS", + "fijkdbh", + "xzroesc", + "xzroesc", + "pqgjy" + }; +/* Find all blue zones. Flat segments give the reference points, */ +/* round segments the overshoot positions. */ + static void + af_latin_metrics_init_blues( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS]; + FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS]; + FT_Int num_flats; + FT_Int num_rounds; + FT_Int bb; + AF_LatinBlue blue; + FT_Error error; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + FT_Outline outline; +/* we compute the blues simply by loading each character from the */ +/* `af_latin_blue_chars[blues]' string, then finding its top-most or */ +/* bottom-most points (depending on `AF_IS_TOP_BLUE') */ + FT_TRACE5(( "blue zones computation\n" + "======================\n\n" )); + for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) + { + const char* p = af_latin_blue_chars[bb]; + const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + FT_TRACE5(( "blue zone %d:\n", bb )); + num_flats = 0; + num_rounds = 0; + for ( ; p < limit && *p; p++ ) + { + FT_UInt glyph_index; +/* same as points.y */ + FT_Pos best_y; + FT_Int best_point, best_contour_first, best_contour_last; + FT_Vector* points; + FT_Bool round = 0; +/* load the character in the face -- skip unknown or empty ones */ + glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); + if ( glyph_index == 0 ) + continue; + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + outline = face->glyph->outline; + if ( error || outline.n_points <= 0 ) + continue; +/* now compute min or max point indices and coordinates */ + points = outline.points; + best_point = -1; +/* make compiler happy */ + best_y = 0; +/* ditto */ + best_contour_first = 0; +/* ditto */ + best_contour_last = 0; + { + FT_Int nn; + FT_Int first = 0; + FT_Int last = -1; + for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) + { + FT_Int old_best_point = best_point; + FT_Int pp; + last = outline.contours[nn]; +/* Avoid single-point contours since they are never rasterized. */ +/* In some fonts, they correspond to mark attachment points */ +/* which are way outside of the glyph's real outline. */ + if ( last <= first ) + continue; + if ( AF_LATIN_IS_TOP_BLUE( bb ) ) + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y > best_y ) + { + best_point = pp; + best_y = points[pp].y; + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y < best_y ) + { + best_point = pp; + best_y = points[pp].y; + } + } + if ( best_point != old_best_point ) + { + best_contour_first = first; + best_contour_last = last; + } + } + FT_TRACE5(( " %c %ld", *p, best_y )); + } +/* now check whether the point belongs to a straight or round */ +/* segment; we first need to find in which contour the extremum */ +/* lies, then inspect its previous and next points */ + if ( best_point >= 0 ) + { + FT_Pos best_x = points[best_point].x; + FT_Int prev, next; + FT_Int best_on_point_first, best_on_point_last; + FT_Pos dist; + if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON ) + { + best_on_point_first = best_point; + best_on_point_last = best_point; + } + else + { + best_on_point_first = -1; + best_on_point_last = -1; + } +/* look for the previous and next points that are not on the */ +/* same Y coordinate, then threshold the `closeness'... */ + prev = best_point; + next = prev; + do + { + if ( prev > best_contour_first ) + prev--; + else + prev = best_contour_last; + dist = FT_ABS( points[prev].y - best_y ); +/* accept a small distance or a small angle (both values are */ +/* heuristic; value 20 corresponds to approx. 2.9 degrees) */ + if ( dist > 5 ) + if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist ) + break; + if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON ) + { + best_on_point_first = prev; + if ( best_on_point_last < 0 ) + best_on_point_last = prev; + } + } while ( prev != best_point ); + do + { + if ( next < best_contour_last ) + next++; + else + next = best_contour_first; + dist = FT_ABS( points[next].y - best_y ); + if ( dist > 5 ) + if ( FT_ABS( points[next].x - best_x ) <= 20 * dist ) + break; + if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON ) + { + best_on_point_last = next; + if ( best_on_point_first < 0 ) + best_on_point_first = next; + } + } while ( next != best_point ); +/* now set the `round' flag depending on the segment's kind */ +/* (value 8 is heuristic) */ + if ( best_on_point_first >= 0 && + best_on_point_last >= 0 && + (FT_UInt)( FT_ABS( points[best_on_point_last].x - + points[best_on_point_first].x ) ) > + metrics->units_per_em / 8 ) + round = 0; + else + round = FT_BOOL( + FT_CURVE_TAG( outline.tags[prev] ) != FT_CURVE_TAG_ON || + FT_CURVE_TAG( outline.tags[next] ) != FT_CURVE_TAG_ON ); + FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); + } + if ( round ) + rounds[num_rounds++] = best_y; + else + flats[num_flats++] = best_y; + } + if ( num_flats == 0 && num_rounds == 0 ) + { +/* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( " empty\n" )); + continue; + } +/* we have computed the contents of the `rounds' and `flats' tables, */ +/* now determine the reference and overshoot position of the blue -- */ +/* we simply take the median value after a simple sort */ + af_sort_pos( num_rounds, rounds ); + af_sort_pos( num_flats, flats ); + blue = &axis->blues[axis->blue_count]; + blue_ref = &blue->ref.org; + blue_shoot = &blue->shoot.org; + axis->blue_count++; + if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = rounds[num_rounds / 2]; + } + else if ( num_rounds == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = flats[num_flats / 2]; + *blue_shoot = rounds[num_rounds / 2]; + } +/* there are sometimes problems: if the overshoot position of top */ +/* zones is under its reference position, or the opposite for bottom */ +/* zones. We must thus check everything there and correct the errors */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool over_ref = FT_BOOL( shoot > ref ); + if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + FT_TRACE5(( " [overshoot smaller than reference," + " taking mean value]\n" )); + } + } + blue->flags = 0; + if ( AF_LATIN_IS_TOP_BLUE( bb ) ) + blue->flags |= AF_LATIN_BLUE_TOP; +/* + * The following flag is used later to adjust the y and x scales + * in order to optimize the pixel grid alignment of the top of small + * letters. + */ + if ( bb == AF_LATIN_BLUE_SMALL_TOP ) + blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; + FT_TRACE5(( " -> reference = %ld\n" + " overshoot = %ld\n", + *blue_ref, *blue_shoot )); + } + FT_TRACE5(( "\n" )); + return; + } +/* Check whether all ASCII digits have the same advance width. */ + FT_LOCAL_DEF( void ) + af_latin_metrics_check_digits( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_UInt i; + FT_Bool started = 0, same_width = 1; + FT_Fixed advance, old_advance = 0; +/* digit `0' is 0x30 in all supported charmaps */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt glyph_index; + glyph_index = FT_Get_Char_Index( face, i ); + if ( glyph_index == 0 ) + continue; + if ( FT_Get_Advance( face, glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + &advance ) ) + continue; + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + metrics->root.digits_have_same_width = same_width; + } +/* Initialize global metrics. */ + FT_LOCAL_DEF( FT_Error ) + af_latin_metrics_init( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_CharMap oldmap = face->charmap; + metrics->units_per_em = face->units_per_EM; + if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) ) + { + af_latin_metrics_init_widths( metrics, face ); + af_latin_metrics_init_blues( metrics, face ); + af_latin_metrics_check_digits( metrics, face ); + } + FT_Set_Charmap( face, oldmap ); + return AF_Err_Ok; + } +/* Adjust scaling value, then scale and shift widths */ +/* and blue zones (if applicable) for given dimension. */ + static void + af_latin_metrics_scale_dim( AF_LatinMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_LatinAxis axis; + FT_UInt nn; + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + axis = &metrics->axis[dim]; + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + axis->org_scale = scale; + axis->org_delta = delta; +/* + * correct X and Y scale to optimize the alignment of the top of small + * letters to the pixel grid + */ + { + AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; + AF_LatinBlue blue = NULL; + for ( nn = 0; nn < Axis->blue_count; nn++ ) + { + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) + { + blue = &Axis->blues[nn]; + break; + } + } + if ( blue ) + { + FT_Pos scaled; + FT_Pos threshold; + FT_Pos fitted; + FT_UInt limit; + FT_UInt ppem; + scaled = FT_MulFix( blue->shoot.org, scaler->y_scale ); + ppem = metrics->root.scaler.face->size->metrics.x_ppem; + limit = metrics->root.globals->increase_x_height; + threshold = 40; +/* if the `increase-x-height' property is active, */ +/* we round up much more often */ + if ( limit && + ppem <= limit && + ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN ) + threshold = 52; + fitted = ( scaled + threshold ) & ~63; + if ( scaled != fitted ) + { +#if 0 + if ( dim == AF_DIMENSION_HORZ ) + { + if ( fitted < scaled ) +/* scale *= 0.98 */ + scale -= scale / 50; + } + else +#endif + if ( dim == AF_DIMENSION_VERT ) + scale = FT_MulDiv( scale, fitted, scaled ); + } + } + } + axis->scale = scale; + axis->delta = delta; + if ( dim == AF_DIMENSION_HORZ ) + { + metrics->root.scaler.x_scale = scale; + metrics->root.scaler.x_delta = delta; + } + else + { + metrics->root.scaler.y_scale = scale; + metrics->root.scaler.y_delta = delta; + } +/* scale the widths */ + for ( nn = 0; nn < axis->width_count; nn++ ) + { + AF_Width width = axis->widths + nn; + width->cur = FT_MulFix( width->org, scale ); + width->fit = width->cur; + } +/* an extra-light axis corresponds to a standard width that is */ +/* smaller than 5/8 pixels */ + axis->extra_light = + (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); + if ( dim == AF_DIMENSION_VERT ) + { +/* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + FT_Pos dist; + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_LATIN_BLUE_ACTIVE; +/* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { +#if 0 + FT_Pos delta1; +#endif + FT_Pos delta2; +/* use discrete values for blue zone widths */ +#if 0 +/* generic, original code */ + delta1 = blue->shoot.org - blue->ref.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + delta2 = FT_MulFix( delta2, scale ); + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); + else + delta2 = FT_PIX_ROUND( delta2 ); + if ( delta1 < 0 ) + delta2 = -delta2; + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit + delta2; +#else +/* simplified version due to abs(dist) <= 48 */ + delta2 = dist; + if ( dist < 0 ) + delta2 = -delta2; + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta < 48 ) + delta2 = 32; + else + delta2 = 64; + if ( dist < 0 ) + delta2 = -delta2; + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit - delta2; +#endif + blue->flags |= AF_LATIN_BLUE_ACTIVE; + } + } + } + } +/* Scale global values in both directions. */ + FT_LOCAL_DEF( void ) + af_latin_metrics_scale( AF_LatinMetrics metrics, + AF_Scaler scaler ) + { + metrics->root.scaler.render_mode = scaler->render_mode; + metrics->root.scaler.face = scaler->face; + metrics->root.scaler.flags = scaler->flags; + af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N G L Y P H A N A L Y S I S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* Walk over all contours and compute its segments. */ + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Memory memory = hints->memory; + FT_Error error = AF_Err_Ok; + AF_Segment segment = NULL; + AF_SegmentRec seg0; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Direction major_dir, segment_dir; + FT_ZERO( &seg0 ); + seg0.score = 32000; + seg0.flags = AF_EDGE_NORMAL; + major_dir = (AF_Direction)FT_ABS( axis->major_dir ); + segment_dir = major_dir; + axis->num_segments = 0; +/* set up (u,v) in each point */ + if ( dim == AF_DIMENSION_HORZ ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + for ( ; point < limit; point++ ) + { + point->u = point->fx; + point->v = point->fy; + } + } + else + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + for ( ; point < limit; point++ ) + { + point->u = point->fy; + point->v = point->fx; + } + } +/* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AF_Point point = contour[0]; + AF_Point last = point->prev; + int on_edge = 0; +/* minimum segment pos != min_coord */ + FT_Pos min_pos = 32000; +/* maximum segment pos != max_coord */ + FT_Pos max_pos = -32000; + FT_Bool passed; +/* skip singletons -- just in case */ + if ( point == last ) + continue; + if ( FT_ABS( last->out_dir ) == major_dir && + FT_ABS( point->out_dir ) == major_dir ) + { +/* we are already on an edge, try to locate its start */ + last = point; + for (;;) + { + point = point->prev; + if ( FT_ABS( point->out_dir ) != major_dir ) + { + point = point->next; + break; + } + if ( point == last ) + break; + } + } + last = point; + passed = 0; + for (;;) + { + FT_Pos u, v; + if ( on_edge ) + { + u = point->u; + if ( u < min_pos ) + min_pos = u; + if ( u > max_pos ) + max_pos = u; + if ( point->out_dir != segment_dir || point == last ) + { +/* we are just leaving an edge; record a new segment! */ + segment->last = point; + segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); +/* a segment is round if either its first or last point */ +/* is a control point */ + if ( ( segment->first->flags | point->flags ) & + AF_FLAG_CONTROL ) + segment->flags |= AF_EDGE_ROUND; +/* compute segment size */ + min_pos = max_pos = point->v; + v = segment->first->v; + if ( v < min_pos ) + min_pos = v; + if ( v > max_pos ) + max_pos = v; + segment->min_coord = (FT_Short)min_pos; + segment->max_coord = (FT_Short)max_pos; + segment->height = (FT_Short)( segment->max_coord - + segment->min_coord ); + on_edge = 0; + segment = NULL; +/* fall through */ + } + } +/* now exit if we are at the start/end point */ + if ( point == last ) + { + if ( passed ) + break; + passed = 1; + } + if ( !on_edge && FT_ABS( point->out_dir ) == major_dir ) + { +/* this is the start of a new segment! */ + segment_dir = (AF_Direction)point->out_dir; +/* clear all segment fields */ + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error ) + goto Exit; + segment[0] = seg0; + segment->dir = (FT_Char)segment_dir; + min_pos = max_pos = point->u; + segment->first = point; + segment->last = point; + on_edge = 1; + } + point = point->next; + } +/* contours */ + } +/* now slightly increase the height of segments if this makes */ +/* sense -- this is used to better detect and ignore serifs */ + { + AF_Segment segments = axis->segments; + AF_Segment segments_end = segments + axis->num_segments; + for ( segment = segments; segment < segments_end; segment++ ) + { + AF_Point first = segment->first; + AF_Point last = segment->last; + FT_Pos first_v = first->v; + FT_Pos last_v = last->v; + if ( first == last ) + continue; + if ( first_v < last_v ) + { + AF_Point p; + p = first->prev; + if ( p->v < first_v ) + segment->height = (FT_Short)( segment->height + + ( ( first_v - p->v ) >> 1 ) ); + p = last->next; + if ( p->v > last_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - last_v ) >> 1 ) ); + } + else + { + AF_Point p; + p = first->prev; + if ( p->v > first_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - first_v ) >> 1 ) ); + p = last->next; + if ( p->v < last_v ) + segment->height = (FT_Short)( segment->height + + ( ( last_v - p->v ) >> 1 ) ); + } + } + } + Exit: + return error; + } +/* Link segments to form stems and serifs. */ + FT_LOCAL_DEF( void ) + af_latin_hints_link_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + FT_Pos len_threshold, len_score; + AF_Segment seg1, seg2; + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + if ( len_threshold == 0 ) + len_threshold = 1; + len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 ); +/* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { +/* the fake segments are introduced to hint the metrics -- */ +/* we must never link them to anything */ + if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) + continue; +/* search for stems having opposite directions, */ +/* with seg1 to the `left' of seg2 */ + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + FT_Pos pos1 = seg1->pos; + FT_Pos pos2 = seg2->pos; + if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 ) + { +/* compute distance between the two segments */ + FT_Pos dist = pos2 - pos1; + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len, score; + if ( min < seg2->min_coord ) + min = seg2->min_coord; + if ( max > seg2->max_coord ) + max = seg2->max_coord; +/* compute maximum coordinate difference of the two segments */ + len = max - min; + if ( len >= len_threshold ) + { +/* small coordinate differences cause a higher score, and */ +/* segments with a greater distance cause a higher score also */ + score = dist + len_score / len; +/* and we search for the smallest score */ +/* of the sum of the two values */ + if ( score < seg1->score ) + { + seg1->score = score; + seg1->link = seg2; + } + if ( score < seg2->score ) + { + seg2->score = score; + seg2->link = seg1; + } + } + } + } + } +/* now compute the `serif' segments, cf. explanations in `afhints.h' */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + if ( seg2 ) + { + if ( seg2->link != seg1 ) + { + seg1->link = 0; + seg1->serif = seg2->link; + } + } + } + } +/* Link segments to edges, using feature analysis for selection. */ + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = AF_Err_Ok; + FT_Memory memory = hints->memory; + AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment seg; +#if 0 + AF_Direction up_dir; +#endif + FT_Fixed scale; + FT_Pos edge_distance_threshold; + FT_Pos segment_length_threshold; + axis->num_edges = 0; + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; +#if 0 + up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP + : AF_DIR_RIGHT; +#endif +/* + * We ignore all segments that are less than 1 pixel in length + * to avoid many problems with serif fonts. We compute the + * corresponding threshold in font units. + */ + if ( dim == AF_DIMENSION_HORZ ) + segment_length_threshold = FT_DivFix( 64, hints->y_scale ); + else + segment_length_threshold = 0; +/*********************************************************************/ +/* */ +/* We begin by generating a sorted table of edges for the current */ +/* direction. To do so, we simply scan each segment and try to find */ +/* an edge in our table that corresponds to its position. */ +/* */ +/* If no edge is found, we create and insert a new edge in the */ +/* sorted table. Otherwise, we simply add the segment to the edge's */ +/* list which gets processed in the second step to compute the */ +/* edge's properties. */ +/* */ +/* Note that the table of edges is sorted along the segment/edge */ +/* position. */ +/* */ +/*********************************************************************/ +/* assure that edge distance threshold is at most 0.25px */ + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = 64 / 4; + edge_distance_threshold = FT_DivFix( edge_distance_threshold, + scale ); + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = NULL; + FT_Int ee; + if ( seg->height < segment_length_threshold ) + continue; +/* A special case for serif edges: If they are smaller than */ +/* 1.5 pixels we ignore them. */ + if ( seg->serif && + 2 * seg->height < 3 * segment_length_threshold ) + continue; +/* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + if ( dist < edge_distance_threshold && edge->dir == seg->dir ) + { + found = edge; + break; + } + } + if ( !found ) + { + AF_Edge edge; +/* insert a new edge in the list and */ +/* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, + (AF_Direction)seg->dir, + memory, &edge ); + if ( error ) + goto Exit; +/* add the segment to the new edge's list */ + FT_ZERO( edge ); + edge->first = seg; + edge->last = seg; + edge->dir = seg->dir; + edge->fpos = seg->pos; + edge->opos = FT_MulFix( seg->pos, scale ); + edge->pos = edge->opos; + seg->edge_next = seg; + } + else + { +/* if an edge was found, simply add the segment to the edge's */ +/* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } +/******************************************************************/ +/* */ +/* Good, we now compute each edge's properties according to the */ +/* segments found on its position. Basically, these are */ +/* */ +/* - the edge's main direction */ +/* - stem edge, serif edge or both (which defaults to stem then) */ +/* - rounded edge, straight or both (which defaults to straight) */ +/* - link for edge */ +/* */ +/******************************************************************/ +/* first of all, set the `edge' field in each segment -- this is */ +/* required in order to compute edge links */ +/* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + } while ( seg != edge->first ); + } +/* now compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { +/* does it contain round segments? */ + FT_Int is_round = 0; +/* does it contain straight segments? */ + FT_Int is_straight = 0; +#if 0 +/* number of upwards segments */ + FT_Pos ups = 0; +/* number of downwards segments */ + FT_Pos downs = 0; +#endif + seg = edge->first; + do + { + FT_Bool is_serif; +/* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; +#if 0 +/* check for segment direction */ + if ( seg->dir == up_dir ) + ups += seg->max_coord - seg->min_coord; + else + downs += seg->max_coord - seg->min_coord; +#endif +/* check for links -- if seg->serif is set, then seg->link must */ +/* be ignored */ + is_serif = (FT_Bool)( seg->serif && + seg->serif->edge && + seg->serif->edge != edge ); + if ( ( seg->link && seg->link->edge != NULL ) || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + edge2 = edge->link; + seg2 = seg->link; + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + seg_delta = seg->pos - seg2->pos; + if ( seg_delta < 0 ) + seg_delta = -seg_delta; + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + seg = seg->edge_next; + } while ( seg != edge->first ); +/* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; +#if 0 +/* set the edge's main direction */ + edge->dir = AF_DIR_NONE; + if ( ups > downs ) + edge->dir = (FT_Char)up_dir; + else if ( ups < downs ) + edge->dir = (FT_Char)-up_dir; + else if ( ups == downs ) +/* both up and down! */ + edge->dir = 0; +#endif +/* get rid of serifs if link is set */ +/* XXX: This gets rid of many unpleasant artefacts! */ +/* Example: the `c' in cour.pfa at size 13 */ + if ( edge->serif && edge->link ) + edge->serif = 0; + } + } + Exit: + return error; + } +/* Detect segments and edges for given dimension. */ + FT_LOCAL_DEF( FT_Error ) + af_latin_hints_detect_features( AF_GlyphHints hints, + AF_Dimension dim ) + { + FT_Error error; + error = af_latin_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_latin_hints_link_segments( hints, dim ); + error = af_latin_hints_compute_edges( hints, dim ); + } + return error; + } +/* Compute all edges which lie within blue zones. */ + FT_LOCAL_DEF( void ) + af_latin_hints_compute_blue_edges( AF_GlyphHints hints, + AF_LatinMetrics metrics ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = edge + axis->num_edges; + AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; + FT_Fixed scale = latin->scale; +/* compute which blue zones are active, i.e. have their scaled */ +/* size < 3/4 pixels */ +/* for each horizontal edge search the blue zone which is closest */ + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; +/* initial threshold */ + FT_Pos best_dist; +/* compute the initial threshold as a fraction of the EM size */ +/* (the value 40 is heuristic) */ + best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); +/* assure a minimum distance of 0.5px */ + if ( best_dist > 64 / 2 ) + best_dist = 64 / 2; + for ( bb = 0; bb < latin->blue_count; bb++ ) + { + AF_LatinBlue blue = latin->blues + bb; + FT_Bool is_top_blue, is_major_dir; +/* skip inactive blue zones (i.e., those that are too large) */ + if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; +/* if it is a top zone, check for right edges -- if it is a bottom */ +/* zone, check for left edges */ +/* */ +/* of course, that's for TrueType */ + is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 ); + is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); +/* if it is a top zone, the edge must be against the major */ +/* direction; if it is a bottom zone, it must be in the major */ +/* direction */ + if ( is_top_blue ^ is_major_dir ) + { + FT_Pos dist; +/* first of all, compare it to the reference position */ + dist = edge->fpos - blue->ref.org; + if ( dist < 0 ) + dist = -dist; + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = &blue->ref; + } +/* now compare it to the overshoot position and check whether */ +/* the edge is rounded, and whether the edge is over the */ +/* reference position of a top zone, or under the reference */ +/* position of a bottom zone */ + if ( edge->flags & AF_EDGE_ROUND && dist != 0 ) + { + FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); + if ( is_top_blue ^ is_under_ref ) + { + dist = edge->fpos - blue->shoot.org; + if ( dist < 0 ) + dist = -dist; + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = &blue->shoot; + } + } + } + } + } + if ( best_blue ) + edge->blue_edge = best_blue; + } + } +/* Initalize hinting engine. */ + static FT_Error + af_latin_hints_init( AF_GlyphHints hints, + AF_LatinMetrics metrics ) + { + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + FT_Face face = metrics->root.scaler.face; + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics ); +/* + * correct x_scale and y_scale if needed, since they may have + * been modified by `af_latin_metrics_scale_dim' above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; +/* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; +/* #ifdef AF_CONFIG_OPTION_USE_WARPER */ +#if 0 + if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) + metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; +#endif + scaler_flags = hints->scaler_flags; + other_flags = 0; +/* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; +/* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; +/* + * We adjust stems to full pixels only if we don't use the `light' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; +/* + * In `light' hinting mode we disable horizontal hinting completely. + * We also do it if the face is italic. + */ + if ( mode == FT_RENDER_MODE_LIGHT || + ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) + scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + return AF_Err_Ok; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N G L Y P H G R I D - F I T T I N G *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* Snap a given width in scaled coordinates to one of the */ +/* current standard widths. */ + static FT_Pos + af_latin_snap_width( AF_Width widths, + FT_Int count, + FT_Pos width ) + { + int n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + scaled = FT_PIX_ROUND( reference ); + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + return width; + } +/* Compute the snapped width of a given stem, ignoring very thin ones. */ +/* There is a lot of voodoo in this function; changing the hard-coded */ +/* parameters influence the whole hinting process. */ + static FT_Pos + af_latin_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + AF_Edge_Flags base_flags, + AF_Edge_Flags stem_flags ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics; + AF_LatinAxis axis = & metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Int vertical = ( dim == AF_DIMENSION_VERT ); + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { +/* smooth hinting process: very lightly quantize the stem width */ +/* leave the widths of serifs alone */ + if ( ( stem_flags & AF_EDGE_SERIF ) && + vertical && + ( dist < 3 * 64 ) ) + goto Done_Width; + else if ( base_flags & AF_EDGE_ROUND ) + { + if ( dist < 80 ) + dist = 64; + } + else if ( dist < 56 ) + dist = 56; + if ( axis->width_count > 0 ) + { + FT_Pos delta; +/* compare to standard width */ + delta = dist - axis->widths[0].cur; + if ( delta < 0 ) + delta = -delta; + if ( delta < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + goto Done_Width; + } + if ( dist < 3 * 64 ) + { + delta = dist & 63; + dist &= -64; + if ( delta < 10 ) + dist += delta; + else if ( delta < 32 ) + dist += 10; + else if ( delta < 54 ) + dist += 54; + else + dist += delta; + } + else + dist = ( dist + 32 ) & ~63; + } + } + else + { +/* strong hinting process: snap the stem width to integer pixels */ + FT_Pos org_dist = dist; + dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); + if ( vertical ) + { +/* in the case of vertical hinting, always round */ +/* the stem heights to integer pixels */ + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { +/* monochrome horizontal hinting: snap widths to integer pixels */ +/* with a different threshold */ + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { +/* for horizontal anti-aliased hinting, we adopt a more subtle */ +/* approach: we strengthen small stems, round stems whose size */ +/* is between 1 and 2 pixels to an integer, otherwise nothing */ + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + else if ( dist < 128 ) + { +/* We only round to an integer width if the corresponding */ +/* distortion is less than 1/4 pixel. Otherwise this */ +/* makes everything worse since the diagonals, which are */ +/* not hinted, appear a lot bolder or thinner than the */ +/* vertical stems. */ + FT_Pos delta; + dist = ( dist + 22 ) & ~63; + delta = dist - org_dist; + if ( delta < 0 ) + delta = -delta; + if (delta >= 16) + { + dist = org_dist; + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + } + } + else +/* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + Done_Width: + if ( sign ) + dist = -dist; + return dist; + } +/* Align one stem edge relative to the previous stem edge. */ + static void + af_latin_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist = stem_edge->opos - base_edge->opos; + FT_Pos fitted_width = af_latin_compute_stem_width( + hints, dim, dist, + (AF_Edge_Flags)base_edge->flags, + (AF_Edge_Flags)stem_edge->flags ); + stem_edge->pos = base_edge->pos + fitted_width; + FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f," + " dist was %.2f, now %.2f\n", + stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0, + stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 )); + } +/* Shift the coordinates of the `serif' edge by the same amount */ +/* as the corresponding `base' edge has been moved already. */ + static void + af_latin_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + serif->pos = base->pos + ( serif->opos - base->opos ); + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** E D G E H I N T I N G ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/* The main grid-fitting routine. */ + FT_LOCAL_DEF( void ) + af_latin_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + FT_PtrDist n_edges; + AF_Edge edge; + AF_Edge anchor = NULL; + FT_Int has_serifs = 0; + FT_TRACE5(( "%s edge hinting\n", + dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" )); +/* we begin by aligning all stems relative to the blue zone */ +/* if needed -- that's only for horizontal edges */ + if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; +/* these edges form the stem to check */ + AF_Edge edge1, edge2; + if ( edge->flags & AF_EDGE_DONE ) + continue; + blue = edge->blue_edge; + edge1 = NULL; + edge2 = edge->link; + if ( blue ) + edge1 = edge; +/* flip edges if the other stem is aligned to a blue zone */ + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + if ( !edge1 ) + continue; + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + if ( edge2 && !edge2->blue_edge ) + { + af_latin_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + } + if ( !anchor ) + anchor = edge; + } + } +/* now we align all other stem edges, trying to maintain the */ +/* relative order of stems in the glyph */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + if ( edge->flags & AF_EDGE_DONE ) + continue; +/* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + has_serifs++; + continue; + } +/* now align the stem */ +/* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2-edges )); + af_latin_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + continue; + } + if ( !anchor ) + { +/* if we reach this if clause, no stem has been aligned yet */ + FT_Pos org_len, org_center, cur_len; + FT_Pos cur_pos1, error1, error2, u_off, d_off; + org_len = edge2->opos - edge->opos; + cur_len = af_latin_compute_stem_width( + hints, dim, org_len, + (AF_Edge_Flags)edge->flags, + (AF_Edge_Flags)edge2->flags ); +/* some voodoo to specially round edges for small stem widths; */ +/* the idea is to align the center of a stem, then shifting */ +/* the stem edges to suitable positions */ + if ( cur_len <= 64 ) + { +/* width <= 1px */ + u_off = 32; + d_off = 32; + } + else + { +/* 1px < width < 1.5px */ + u_off = 38; + d_off = 26; + } + if ( cur_len < 96 ) + { + org_center = edge->opos + ( org_len >> 1 ); + cur_pos1 = FT_PIX_ROUND( org_center ); + error1 = org_center - ( cur_pos1 - u_off ); + if ( error1 < 0 ) + error1 = -error1; + error2 = org_center - ( cur_pos1 + d_off ); + if ( error2 < 0 ) + error2 = -error2; + if ( error1 < error2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = edge->pos + cur_len; + } + else + edge->pos = FT_PIX_ROUND( edge->opos ); + anchor = edge; + edge->flags |= AF_EDGE_DONE; + FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, edge->opos / 64.0, + edge2 - edges, edge2->opos / 64.0, + edge->pos / 64.0, edge2->pos / 64.0 )); + af_latin_align_linked_edge( hints, dim, edge, edge2 ); + } + else + { + FT_Pos org_pos, org_len, org_center, cur_len; + FT_Pos cur_pos1, cur_pos2, delta1, delta2; + org_pos = anchor->pos + ( edge->opos - anchor->opos ); + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + cur_len = af_latin_compute_stem_width( + hints, dim, org_len, + (AF_Edge_Flags)edge->flags, + (AF_Edge_Flags)edge2->flags ); + if ( edge2->flags & AF_EDGE_DONE ) + { + FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n", + edge - edges, edge->pos / 64.0, + ( edge2->pos - cur_len ) / 64.0 )); + edge->pos = edge2->pos - cur_len; + } + else if ( cur_len < 96 ) + { + FT_Pos u_off, d_off; + cur_pos1 = FT_PIX_ROUND( org_center ); + if (cur_len <= 64 ) + { + u_off = 32; + d_off = 32; + } + else + { + u_off = 38; + d_off = 26; + } + delta1 = org_center - ( cur_pos1 - u_off ); + if ( delta1 < 0 ) + delta1 = -delta1; + delta2 = org_center - ( cur_pos1 + d_off ); + if ( delta2 < 0 ) + delta2 = -delta2; + if ( delta1 < delta2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = cur_pos1 + cur_len / 2; + FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, edge->opos / 64.0, + edge2 - edges, edge2->opos / 64.0, + edge->pos / 64.0, edge2->pos / 64.0 )); + } + else + { + org_pos = anchor->pos + ( edge->opos - anchor->opos ); + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + cur_len = af_latin_compute_stem_width( + hints, dim, org_len, + (AF_Edge_Flags)edge->flags, + (AF_Edge_Flags)edge2->flags ); + cur_pos1 = FT_PIX_ROUND( org_pos ); + delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center; + if ( delta1 < 0 ) + delta1 = -delta1; + cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len; + delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center; + if ( delta2 < 0 ) + delta2 = -delta2; + edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2; + edge2->pos = edge->pos + cur_len; + FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)" + " snapped to %.2f and %.2f\n", + edge - edges, edge->opos / 64.0, + edge2 - edges, edge2->opos / 64.0, + edge->pos / 64.0, edge2->pos / 64.0 )); + } + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + if ( edge > edges && edge->pos < edge[-1].pos ) + { + edge->pos = edge[-1].pos; + } + } + } +/* make sure that lowercase m's maintain their symmetry */ +/* In general, lowercase m's have six vertical edges if they are sans */ +/* serif, or twelve if they are with serifs. This implementation is */ +/* based on that assumption, and seems to work very well with most */ +/* faces. However, if for a certain face this assumption is not */ +/* true, the m is just rendered like before. In addition, any stem */ +/* correction will only be applied to symmetrical glyphs (even if the */ +/* glyph is not an m), so the potential for unwanted distortion is */ +/* relatively low. */ +/* We don't handle horizontal edges since we can't easily assure that */ +/* the third (lowest) stem aligns with the base line; it might end up */ +/* one pixel higher or lower. */ + n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span, delta; + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + if ( span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; +/* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + if ( has_serifs || !anchor ) + { +/* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Pos delta; + if ( edge->flags & AF_EDGE_DONE ) + continue; + delta = 1000; + if ( edge->serif ) + { + delta = edge->serif->opos - edge->opos; + if ( delta < 0 ) + delta = -delta; + } + if ( delta < 64 + 16 ) + { + af_latin_align_serif_edge( hints, edge->serif, edge ); + FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)" + " aligned to %.2f\n", + edge - edges, edge->opos / 64.0, + edge->serif - edges, edge->serif->opos / 64.0, + edge->pos / 64.0 )); + } + else if ( !anchor ) + { + edge->pos = FT_PIX_ROUND( edge->opos ); + anchor = edge; + FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)" + " snapped to %.2f\n", + edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); + } + else + { + AF_Edge before, after; + for ( before = edge - 1; before >= edges; before-- ) + if ( before->flags & AF_EDGE_DONE ) + break; + for ( after = edge + 1; after < edge_limit; after++ ) + if ( after->flags & AF_EDGE_DONE ) + break; + if ( before >= edges && before < edge && + after < edge_limit && after > edge ) + { + if ( after->opos == before->opos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->opos - before->opos, + after->pos - before->pos, + after->opos - before->opos ); + FT_TRACE5(( " SERIF_LINK1: edge %d (opos=%.2f) snapped to %.2f" + " from %d (opos=%.2f)\n", + edge - edges, edge->opos / 64.0, + edge->pos / 64.0, + before - edges, before->opos / 64.0 )); + } + else + { + edge->pos = anchor->pos + + ( ( edge->opos - anchor->opos + 16 ) & ~31 ); + FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)" + " snapped to %.2f\n", + edge - edges, edge->opos / 64.0, edge->pos / 64.0 )); + } + } + edge->flags |= AF_EDGE_DONE; + if ( edge > edges && edge->pos < edge[-1].pos ) + { + edge->pos = edge[-1].pos; + } + if ( edge + 1 < edge_limit && + edge[1].flags & AF_EDGE_DONE && + edge->pos > edge[1].pos ) + { + edge->pos = edge[1].pos; + } + } + } + } +/* Apply the complete hinting algorithm to a latin glyph. */ + static FT_Error + af_latin_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_LatinMetrics metrics ) + { + FT_Error error; + int dim; + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; +/* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + } + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + error = af_latin_hints_detect_features( hints, AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + af_latin_hints_compute_blue_edges( hints, metrics ); + } +/* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_latin_hint_edges( hints, (AF_Dimension)dim ); + af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } + af_glyph_hints_save( hints, outline ); + Exit: + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N S C R I P T C L A S S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* XXX: this should probably fine tuned to differentiate better between */ +/* scripts... */ + static const AF_Script_UniRangeRec af_latin_uniranges[] = + { +/* Basic Latin (no control chars) */ + AF_UNIRANGE_REC( 0x0020UL, 0x007FUL ), +/* Latin-1 Supplement (no control chars) */ + AF_UNIRANGE_REC( 0x00A0UL, 0x00FFUL ), +/* Latin Extended-A */ + AF_UNIRANGE_REC( 0x0100UL, 0x017FUL ), +/* Latin Extended-B */ + AF_UNIRANGE_REC( 0x0180UL, 0x024FUL ), +/* IPA Extensions */ + AF_UNIRANGE_REC( 0x0250UL, 0x02AFUL ), +/* Spacing Modifier Letters */ + AF_UNIRANGE_REC( 0x02B0UL, 0x02FFUL ), +/* Combining Diacritical Marks */ + AF_UNIRANGE_REC( 0x0300UL, 0x036FUL ), +/* Greek and Coptic */ + AF_UNIRANGE_REC( 0x0370UL, 0x03FFUL ), +/* Cyrillic */ + AF_UNIRANGE_REC( 0x0400UL, 0x04FFUL ), +/* Cyrillic Supplement */ + AF_UNIRANGE_REC( 0x0500UL, 0x052FUL ), +/* Phonetic Extensions */ + AF_UNIRANGE_REC( 0x1D00UL, 0x1D7FUL ), +/* Phonetic Extensions Supplement */ + AF_UNIRANGE_REC( 0x1D80UL, 0x1DBFUL ), +/* Combining Diacritical Marks Supplement */ + AF_UNIRANGE_REC( 0x1DC0UL, 0x1DFFUL ), +/* Latin Extended Additional */ + AF_UNIRANGE_REC( 0x1E00UL, 0x1EFFUL ), +/* Greek Extended */ + AF_UNIRANGE_REC( 0x1F00UL, 0x1FFFUL ), +/* General Punctuation */ + AF_UNIRANGE_REC( 0x2000UL, 0x206FUL ), +/* Superscripts and Subscripts */ + AF_UNIRANGE_REC( 0x2070UL, 0x209FUL ), +/* Currency Symbols */ + AF_UNIRANGE_REC( 0x20A0UL, 0x20CFUL ), +/* Number Forms */ + AF_UNIRANGE_REC( 0x2150UL, 0x218FUL ), +/* Enclosed Alphanumerics */ + AF_UNIRANGE_REC( 0x2460UL, 0x24FFUL ), +/* Latin Extended-C */ + AF_UNIRANGE_REC( 0x2C60UL, 0x2C7FUL ), +/* Cyrillic Extended-A */ + AF_UNIRANGE_REC( 0x2DE0UL, 0x2DFFUL ), +/* Supplemental Punctuation */ + AF_UNIRANGE_REC( 0x2E00UL, 0x2E7FUL ), +/* Cyrillic Extended-B */ + AF_UNIRANGE_REC( 0xA640UL, 0xA69FUL ), +/* Latin Extended-D */ + AF_UNIRANGE_REC( 0xA720UL, 0xA7FFUL ), +/* Alphab. Present. Forms (Latin Ligs) */ + AF_UNIRANGE_REC( 0xFB00UL, 0xFB06UL ), +/* Mathematical Alphanumeric Symbols */ + AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ), +/* Enclosed Alphanumeric Supplement */ + AF_UNIRANGE_REC( 0x1F100UL, 0x1F1FFUL ), + AF_UNIRANGE_REC( 0UL, 0UL ) + }; + AF_DEFINE_SCRIPT_CLASS( af_latin_script_class, + AF_SCRIPT_LATIN, + af_latin_uniranges, + 'o', + sizeof ( AF_LatinMetricsRec ), + (AF_Script_InitMetricsFunc) af_latin_metrics_init, + (AF_Script_ScaleMetricsFunc)af_latin_metrics_scale, + (AF_Script_DoneMetricsFunc) NULL, + (AF_Script_InitHintsFunc) af_latin_hints_init, + (AF_Script_ApplyHintsFunc) af_latin_hints_apply + ) +/* END */ +#ifdef FT_OPTION_AUTOFIT2 +/***************************************************************************/ +/* */ +/* aflatin2.c */ +/* */ +/* Auto-fitter hinting routines for latin script (body). */ +/* */ +/* Copyright 2003-2012 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 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 trace_aflatin2 + FT_LOCAL_DEF( FT_Error ) + af_latin2_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ); + FT_LOCAL_DEF( void ) + af_latin2_hints_link_segments( AF_GlyphHints hints, + AF_Dimension dim ); +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N G L O B A L M E T R I C S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + af_latin2_metrics_init_widths( AF_LatinMetrics metrics, + FT_Face face ) + { +/* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + af_glyph_hints_init( hints, face->memory ); + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + { + FT_Error error; + FT_UInt glyph_index; + int dim; + AF_LatinMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + glyph_index = FT_Get_Char_Index( face, + metrics->root.clazz->standard_char ); + if ( glyph_index == 0 ) + goto Exit; + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + FT_ZERO( dummy ); + dummy->units_per_em = metrics->units_per_em; + scaler->x_scale = scaler->y_scale = 0x10000L; + scaler->x_delta = scaler->y_delta = 0; + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + error = af_latin2_hints_compute_segments( hints, + (AF_Dimension)dim ); + if ( error ) + goto Exit; + af_latin2_hints_link_segments( hints, + (AF_Dimension)dim ); + seg = axhints->segments; + limit = seg + axhints->num_segments; + for ( ; seg < limit; seg++ ) + { + link = seg->link; +/* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + if ( num_widths < AF_LATIN_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } + af_sort_widths( num_widths, axis->widths ); + axis->width_count = num_widths; + } + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_LatinAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + stdw = ( axis->width_count > 0 ) + ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); +/* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + } + } + af_glyph_hints_done( hints ); + } +#define AF_LATIN_MAX_TEST_CHARACTERS 12 + static const char af_latin2_blue_chars[AF_LATIN_MAX_BLUES] + [AF_LATIN_MAX_TEST_CHARACTERS+1] = + { + "THEZOCQS", + "HEZLOCUS", + "fijkdbh", + "xzroesc", + "xzroesc", + "pqgjy" + }; + static void + af_latin2_metrics_init_blues( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS]; + FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS]; + FT_Int num_flats; + FT_Int num_rounds; + FT_Int bb; + AF_LatinBlue blue; + FT_Error error; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + FT_GlyphSlot glyph = face->glyph; +/* we compute the blues simply by loading each character from the */ +/* 'af_latin2_blue_chars[blues]' string, then compute its top-most or */ +/* bottom-most points (depending on `AF_IS_TOP_BLUE') */ + FT_TRACE5(( "blue zones computation\n" + "======================\n\n" )); + for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) + { + const char* p = af_latin2_blue_chars[bb]; + const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + FT_TRACE5(( "blue zone %d:\n", bb )); + num_flats = 0; + num_rounds = 0; + for ( ; p < limit && *p; p++ ) + { + FT_UInt glyph_index; + FT_Int best_point, best_y, best_first, best_last; + FT_Vector* points; + FT_Bool round; +/* load the character in the face -- skip unknown or empty ones */ + glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); + if ( glyph_index == 0 ) + continue; + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || glyph->outline.n_points <= 0 ) + continue; +/* now compute min or max point indices and coordinates */ + points = glyph->outline.points; + best_point = -1; +/* make compiler happy */ + best_y = 0; +/* ditto */ + best_first = 0; +/* ditto */ + best_last = 0; + { + FT_Int nn; + FT_Int first = 0; + FT_Int last = -1; + for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ ) + { + FT_Int old_best_point = best_point; + FT_Int pp; + last = glyph->outline.contours[nn]; +/* Avoid single-point contours since they are never rasterized. */ +/* In some fonts, they correspond to mark attachment points */ +/* which are way outside of the glyph's real outline. */ + if ( last == first ) + continue; + if ( AF_LATIN_IS_TOP_BLUE( bb ) ) + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y > best_y ) + { + best_point = pp; + best_y = points[pp].y; + } + } + else + { + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y < best_y ) + { + best_point = pp; + best_y = points[pp].y; + } + } + if ( best_point != old_best_point ) + { + best_first = first; + best_last = last; + } + } + FT_TRACE5(( " %c %d", *p, best_y )); + } +/* now check whether the point belongs to a straight or round */ +/* segment; we first need to find in which contour the extremum */ +/* lies, then inspect its previous and next points */ + { + FT_Pos best_x = points[best_point].x; + FT_Int start, end, prev, next; + FT_Pos dist; +/* now look for the previous and next points that are not on the */ +/* same Y coordinate. Threshold the `closeness'... */ + start = end = best_point; + do + { + prev = start - 1; + if ( prev < best_first ) + prev = best_last; + dist = FT_ABS( points[prev].y - best_y ); +/* accept a small distance or a small angle (both values are */ +/* heuristic; value 20 corresponds to approx. 2.9 degrees) */ + if ( dist > 5 ) + if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist ) + break; + start = prev; + } while ( start != best_point ); + do + { + next = end + 1; + if ( next > best_last ) + next = best_first; + dist = FT_ABS( points[next].y - best_y ); + if ( dist > 5 ) + if ( FT_ABS( points[next].x - best_x ) <= 20 * dist ) + break; + end = next; + } while ( end != best_point ); +/* now, set the `round' flag depending on the segment's kind */ + round = FT_BOOL( + FT_CURVE_TAG( glyph->outline.tags[start] ) != FT_CURVE_TAG_ON || + FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON ); + FT_TRACE5(( " (%s)\n", round ? "round" : "flat" )); + } + if ( round ) + rounds[num_rounds++] = best_y; + else + flats[num_flats++] = best_y; + } + if ( num_flats == 0 && num_rounds == 0 ) + { +/* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( " empty\n" )); + continue; + } +/* we have computed the contents of the `rounds' and `flats' tables, */ +/* now determine the reference and overshoot position of the blue -- */ +/* we simply take the median value after a simple sort */ + af_sort_pos( num_rounds, rounds ); + af_sort_pos( num_flats, flats ); + blue = & axis->blues[axis->blue_count]; + blue_ref = & blue->ref.org; + blue_shoot = & blue->shoot.org; + axis->blue_count++; + if ( num_flats == 0 ) + { + *blue_ref = + *blue_shoot = rounds[num_rounds / 2]; + } + else if ( num_rounds == 0 ) + { + *blue_ref = + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = flats[num_flats / 2]; + *blue_shoot = rounds[num_rounds / 2]; + } +/* there are sometimes problems: if the overshoot position of top */ +/* zones is under its reference position, or the opposite for bottom */ +/* zones. We must thus check everything there and correct the errors */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool over_ref = FT_BOOL( shoot > ref ); + if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref ) + { + *blue_ref = + *blue_shoot = ( shoot + ref ) / 2; + FT_TRACE5(( " [overshoot smaller than reference," + " taking mean value]\n" )); + } + } + blue->flags = 0; + if ( AF_LATIN_IS_TOP_BLUE( bb ) ) + blue->flags |= AF_LATIN_BLUE_TOP; +/* + * The following flags is used later to adjust the y and x scales + * in order to optimize the pixel grid alignment of the top of small + * letters. + */ + if ( bb == AF_LATIN_BLUE_SMALL_TOP ) + blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; + FT_TRACE5(( " -> reference = %ld\n" + " overshoot = %ld\n", + *blue_ref, *blue_shoot )); + } + return; + } + FT_LOCAL_DEF( void ) + af_latin2_metrics_check_digits( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_UInt i; + FT_Bool started = 0, same_width = 1; + FT_Fixed advance, old_advance = 0; +/* check whether all ASCII digits have the same advance width; */ +/* digit `0' is 0x30 in all supported charmaps */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt glyph_index; + glyph_index = FT_Get_Char_Index( face, i ); + if ( glyph_index == 0 ) + continue; + if ( FT_Get_Advance( face, glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + &advance ) ) + continue; + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + metrics->root.digits_have_same_width = same_width; + } + FT_LOCAL_DEF( FT_Error ) + af_latin2_metrics_init( AF_LatinMetrics metrics, + FT_Face face ) + { + FT_Error error = AF_Err_Ok; + FT_CharMap oldmap = face->charmap; + FT_UInt ee; + static const FT_Encoding latin_encodings[] = + { + FT_ENCODING_UNICODE, + FT_ENCODING_APPLE_ROMAN, + FT_ENCODING_ADOBE_STANDARD, + FT_ENCODING_ADOBE_LATIN_1, +/* end of list */ + FT_ENCODING_NONE + }; + metrics->units_per_em = face->units_per_EM; +/* do we have a latin charmap in there? */ + for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ ) + { + error = FT_Select_Charmap( face, latin_encodings[ee] ); + if ( !error ) + break; + } + if ( !error ) + { + af_latin2_metrics_init_widths( metrics, face ); + af_latin2_metrics_init_blues( metrics, face ); + af_latin2_metrics_check_digits( metrics, face ); + } + FT_Set_Charmap( face, oldmap ); + return AF_Err_Ok; + } + static void + af_latin2_metrics_scale_dim( AF_LatinMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_LatinAxis axis; + FT_UInt nn; + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + axis = &metrics->axis[dim]; + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + axis->org_scale = scale; + axis->org_delta = delta; +/* + * correct Y scale to optimize the alignment of the top of small + * letters to the pixel grid + */ + if ( dim == AF_DIMENSION_VERT ) + { + AF_LatinAxis vaxis = &metrics->axis[AF_DIMENSION_VERT]; + AF_LatinBlue blue = NULL; + for ( nn = 0; nn < vaxis->blue_count; nn++ ) + { + if ( vaxis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) + { + blue = &vaxis->blues[nn]; + break; + } + } + if ( blue ) + { + FT_Pos scaled; + FT_Pos threshold; + FT_Pos fitted; + FT_UInt limit; + FT_UInt ppem; + scaled = FT_MulFix( blue->shoot.org, scaler->y_scale ); + ppem = metrics->root.scaler.face->size->metrics.x_ppem; + limit = metrics->root.globals->increase_x_height; + threshold = 40; +/* if the `increase-x-height' property is active, */ +/* we round up much more often */ + if ( limit && + ppem <= limit && + ppem >= AF_PROP_INCREASE_X_HEIGHT_MIN ) + threshold = 52; + fitted = ( scaled + threshold ) & ~63; +#if 1 + if ( scaled != fitted ) + { + scale = FT_MulDiv( scale, fitted, scaled ); + FT_TRACE5(( "== scaled x-top = %.2g" + " fitted = %.2g, scaling = %.4g\n", + scaled / 64.0, fitted / 64.0, + ( fitted * 1.0 ) / scaled )); + } +#endif + } + } + axis->scale = scale; + axis->delta = delta; + if ( dim == AF_DIMENSION_HORZ ) + { + metrics->root.scaler.x_scale = scale; + metrics->root.scaler.x_delta = delta; + } + else + { + metrics->root.scaler.y_scale = scale; + metrics->root.scaler.y_delta = delta; + } +/* scale the standard widths */ + for ( nn = 0; nn < axis->width_count; nn++ ) + { + AF_Width width = axis->widths + nn; + width->cur = FT_MulFix( width->org, scale ); + width->fit = width->cur; + } +/* an extra-light axis corresponds to a standard width that is */ +/* smaller than 5/8 pixels */ + axis->extra_light = + (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); + if ( dim == AF_DIMENSION_VERT ) + { +/* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_LatinBlue blue = &axis->blues[nn]; + FT_Pos dist; + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_LATIN_BLUE_ACTIVE; +/* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { + FT_Pos delta1, delta2; + delta1 = blue->shoot.org - blue->ref.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + delta2 = FT_MulFix( delta2, scale ); + if ( delta2 < 32 ) + delta2 = 0; + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); + else + delta2 = FT_PIX_ROUND( delta2 ); + if ( delta1 < 0 ) + delta2 = -delta2; + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->shoot.fit = blue->ref.fit + delta2; + FT_TRACE5(( ">> activating blue zone %d:" + " ref.cur=%.2g ref.fit=%.2g" + " shoot.cur=%.2g shoot.fit=%.2g\n", + nn, blue->ref.cur / 64.0, blue->ref.fit / 64.0, + blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); + blue->flags |= AF_LATIN_BLUE_ACTIVE; + } + } + } + } + FT_LOCAL_DEF( void ) + af_latin2_metrics_scale( AF_LatinMetrics metrics, + AF_Scaler scaler ) + { + metrics->root.scaler.render_mode = scaler->render_mode; + metrics->root.scaler.face = scaler->face; + metrics->root.scaler.flags = scaler->flags; + af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N G L Y P H A N A L Y S I S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +#define SORT_SEGMENTS + FT_LOCAL_DEF( FT_Error ) + af_latin2_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Memory memory = hints->memory; + FT_Error error = AF_Err_Ok; + AF_Segment segment = NULL; + AF_SegmentRec seg0; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Direction major_dir, segment_dir; + FT_ZERO( &seg0 ); + seg0.score = 32000; + seg0.flags = AF_EDGE_NORMAL; + major_dir = (AF_Direction)FT_ABS( axis->major_dir ); + segment_dir = major_dir; + axis->num_segments = 0; +/* set up (u,v) in each point */ + if ( dim == AF_DIMENSION_HORZ ) + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + for ( ; point < limit; point++ ) + { + point->u = point->fx; + point->v = point->fy; + } + } + else + { + AF_Point point = hints->points; + AF_Point limit = point + hints->num_points; + for ( ; point < limit; point++ ) + { + point->u = point->fy; + point->v = point->fx; + } + } +/* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AF_Point point = contour[0]; + AF_Point start = point; + AF_Point last = point->prev; +/* skip singletons -- just in case */ + if ( point == last ) + continue; +/* already on an edge ?, backtrack to find its start */ + if ( FT_ABS( point->in_dir ) == major_dir ) + { + point = point->prev; + while ( point->in_dir == start->in_dir ) + point = point->prev; + } +/* otherwise, find first segment start, if any */ + else + { + while ( FT_ABS( point->out_dir ) != major_dir ) + { + point = point->next; + if ( point == start ) + goto NextContour; + } + } + start = point; + for (;;) + { + AF_Point first; + FT_Pos min_u, min_v, max_u, max_v; +/* we're at the start of a new segment */ + FT_ASSERT( FT_ABS( point->out_dir ) == major_dir && + point->in_dir != point->out_dir ); + first = point; + min_u = max_u = point->u; + min_v = max_v = point->v; + point = point->next; + while ( point->out_dir == first->out_dir ) + { + point = point->next; + if ( point->u < min_u ) + min_u = point->u; + if ( point->u > max_u ) + max_u = point->u; + } + if ( point->v < min_v ) + min_v = point->v; + if ( point->v > max_v ) + max_v = point->v; +/* record new segment */ + error = af_axis_hints_new_segment( axis, memory, &segment ); + if ( error ) + goto Exit; + segment[0] = seg0; + segment->dir = first->out_dir; + segment->first = first; + segment->last = point; + segment->pos = (FT_Short)(( min_u + max_u ) >> 1); + segment->min_coord = (FT_Short) min_v; + segment->max_coord = (FT_Short) max_v; + segment->height = (FT_Short)(max_v - min_v); +/* a segment is round if it doesn't have successive */ +/* on-curve points. */ + { + AF_Point pt = first; + AF_Point last = point; + AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL); + AF_Flags f1; + segment->flags &= ~AF_EDGE_ROUND; + for ( ; pt != last; f0 = f1 ) + { + pt = pt->next; + f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL); + if ( !f0 && !f1 ) + break; + if ( pt == last ) + segment->flags |= AF_EDGE_ROUND; + } + } +/* this can happen in the case of a degenerate contour + * e.g. a 2-point vertical contour + */ + if ( point == start ) + break; +/* jump to the start of the next segment, if any */ + while ( FT_ABS(point->out_dir) != major_dir ) + { + point = point->next; + if ( point == start ) + goto NextContour; + } + } + NextContour: + ; +/* contours */ + } +/* now slightly increase the height of segments when this makes */ +/* sense -- this is used to better detect and ignore serifs */ + { + AF_Segment segments = axis->segments; + AF_Segment segments_end = segments + axis->num_segments; + for ( segment = segments; segment < segments_end; segment++ ) + { + AF_Point first = segment->first; + AF_Point last = segment->last; + AF_Point p; + FT_Pos first_v = first->v; + FT_Pos last_v = last->v; + if ( first == last ) + continue; + if ( first_v < last_v ) + { + p = first->prev; + if ( p->v < first_v ) + segment->height = (FT_Short)( segment->height + + ( ( first_v - p->v ) >> 1 ) ); + p = last->next; + if ( p->v > last_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - last_v ) >> 1 ) ); + } + else + { + p = first->prev; + if ( p->v > first_v ) + segment->height = (FT_Short)( segment->height + + ( ( p->v - first_v ) >> 1 ) ); + p = last->next; + if ( p->v < last_v ) + segment->height = (FT_Short)( segment->height + + ( ( last_v - p->v ) >> 1 ) ); + } + } + } +#ifdef AF_SORT_SEGMENTS +/* place all segments with a negative direction to the start + * of the array, used to speed up segment linking later... + */ + { + AF_Segment segments = axis->segments; + FT_UInt count = axis->num_segments; + FT_UInt ii, jj; + for (ii = 0; ii < count; ii++) + { + if ( segments[ii].dir > 0 ) + { + for (jj = ii+1; jj < count; jj++) + { + if ( segments[jj].dir < 0 ) + { + AF_SegmentRec tmp; + tmp = segments[ii]; + segments[ii] = segments[jj]; + segments[jj] = tmp; + break; + } + } + if ( jj == count ) + break; + } + } + axis->mid_segments = ii; + } +#endif + Exit: + return error; + } + FT_LOCAL_DEF( void ) + af_latin2_hints_link_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; +#ifdef AF_SORT_SEGMENTS + AF_Segment segment_mid = segments + axis->mid_segments; +#endif + FT_Pos len_threshold, len_score; + AF_Segment seg1, seg2; + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + if ( len_threshold == 0 ) + len_threshold = 1; + len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 ); +#ifdef AF_SORT_SEGMENTS + for ( seg1 = segments; seg1 < segment_mid; seg1++ ) + { + if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) + continue; + for ( seg2 = segment_mid; seg2 < segment_limit; seg2++ ) +#else +/* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { +/* the fake segments are introduced to hint the metrics -- */ +/* we must never link them to anything */ + if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) + continue; + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos ) +#endif + { + FT_Pos pos1 = seg1->pos; + FT_Pos pos2 = seg2->pos; + FT_Pos dist = pos2 - pos1; + if ( dist < 0 ) + continue; + { + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len, score; + if ( min < seg2->min_coord ) + min = seg2->min_coord; + if ( max > seg2->max_coord ) + max = seg2->max_coord; + len = max - min; + if ( len >= len_threshold ) + { + score = dist + len_score / len; + if ( score < seg1->score ) + { + seg1->score = score; + seg1->link = seg2; + } + if ( score < seg2->score ) + { + seg2->score = score; + seg2->link = seg1; + } + } + } + } + } +#if 0 + } +#endif +/* now, compute the `serif' segments */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + if ( seg2 ) + { + if ( seg2->link != seg1 ) + { + seg1->link = 0; + seg1->serif = seg2->link; + } + } + } + } + FT_LOCAL_DEF( FT_Error ) + af_latin2_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = AF_Err_Ok; + FT_Memory memory = hints->memory; + AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment seg; + AF_Direction up_dir; + FT_Fixed scale; + FT_Pos edge_distance_threshold; + FT_Pos segment_length_threshold; + axis->num_edges = 0; + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP + : AF_DIR_RIGHT; +/* + * We want to ignore very small (mostly serif) segments, we do that + * by ignoring those that whose length is less than a given fraction + * of the standard width. If there is no standard width, we ignore + * those that are less than a given size in pixels + * + * also, unlink serif segments that are linked to segments farther + * than 50% of the standard width + */ + if ( dim == AF_DIMENSION_HORZ ) + { + if ( laxis->width_count > 0 ) + segment_length_threshold = (laxis->standard_width * 10 ) >> 4; + else + segment_length_threshold = FT_DivFix( 64, hints->y_scale ); + } + else + segment_length_threshold = 0; +/*********************************************************************/ +/* */ +/* We will begin by generating a sorted table of edges for the */ +/* current direction. To do so, we simply scan each segment and try */ +/* to find an edge in our table that corresponds to its position. */ +/* */ +/* If no edge is found, we create and insert a new edge in the */ +/* sorted table. Otherwise, we simply add the segment to the edge's */ +/* list which will be processed in the second step to compute the */ +/* edge's properties. */ +/* */ +/* Note that the edges table is sorted along the segment/edge */ +/* position. */ +/* */ +/*********************************************************************/ + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = 64 / 4; + edge_distance_threshold = FT_DivFix( edge_distance_threshold, + scale ); + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = 0; + FT_Int ee; + if ( seg->height < segment_length_threshold ) + continue; +/* A special case for serif edges: If they are smaller than */ +/* 1.5 pixels we ignore them. */ + if ( seg->serif ) + { + FT_Pos dist = seg->serif->pos - seg->pos; + if (dist < 0) + dist = -dist; + if (dist >= laxis->standard_width >> 1) + { +/* unlink this serif, it is too distant from its reference stem */ + seg->serif = NULL; + } + else if ( 2*seg->height < 3 * segment_length_threshold ) + continue; + } +/* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + if ( dist < edge_distance_threshold && edge->dir == seg->dir ) + { + found = edge; + break; + } + } + if ( !found ) + { + AF_Edge edge; +/* insert a new edge in the list and */ +/* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, + memory, &edge ); + if ( error ) + goto Exit; +/* add the segment to the new edge's list */ + FT_ZERO( edge ); + edge->first = seg; + edge->last = seg; + edge->fpos = seg->pos; + edge->dir = seg->dir; + edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); + seg->edge_next = seg; + } + else + { +/* if an edge was found, simply add the segment to the edge's */ +/* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } +/*********************************************************************/ +/* */ +/* Good, we will now compute each edge's properties according to */ +/* segments found on its position. Basically, these are: */ +/* */ +/* - edge's main direction */ +/* - stem edge, serif edge or both (which defaults to stem then) */ +/* - rounded edge, straight or both (which defaults to straight) */ +/* - link for edge */ +/* */ +/*********************************************************************/ +/* first of all, set the `edge' field in each segment -- this is */ +/* required in order to compute edge links */ +/* + * Note that removing this loop and setting the `edge' field of each + * segment directly in the code above slows down execution speed for + * some reasons on platforms like the Sun. + */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + } while ( seg != edge->first ); + } +/* now, compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { +/* does it contain round segments? */ + FT_Int is_round = 0; +/* does it contain straight segments? */ + FT_Int is_straight = 0; +#if 0 +/* number of upwards segments */ + FT_Pos ups = 0; +/* number of downwards segments */ + FT_Pos downs = 0; +#endif + seg = edge->first; + do + { + FT_Bool is_serif; +/* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; +#if 0 +/* check for segment direction */ + if ( seg->dir == up_dir ) + ups += seg->max_coord-seg->min_coord; + else + downs += seg->max_coord-seg->min_coord; +#endif +/* check for links -- if seg->serif is set, then seg->link must */ +/* be ignored */ + is_serif = (FT_Bool)( seg->serif && + seg->serif->edge && + seg->serif->edge != edge ); + if ( ( seg->link && seg->link->edge != NULL ) || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + edge2 = edge->link; + seg2 = seg->link; + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + seg_delta = seg->pos - seg2->pos; + if ( seg_delta < 0 ) + seg_delta = -seg_delta; + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + seg = seg->edge_next; + } while ( seg != edge->first ); +/* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; +#if 0 +/* set the edge's main direction */ + edge->dir = AF_DIR_NONE; + if ( ups > downs ) + edge->dir = (FT_Char)up_dir; + else if ( ups < downs ) + edge->dir = (FT_Char)-up_dir; + else if ( ups == downs ) +/* both up and down! */ + edge->dir = 0; +#endif +/* gets rid of serifs if link is set */ +/* XXX: This gets rid of many unpleasant artefacts! */ +/* Example: the `c' in cour.pfa at size 13 */ + if ( edge->serif && edge->link ) + edge->serif = 0; + } + } + Exit: + return error; + } + FT_LOCAL_DEF( FT_Error ) + af_latin2_hints_detect_features( AF_GlyphHints hints, + AF_Dimension dim ) + { + FT_Error error; + error = af_latin2_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_latin2_hints_link_segments( hints, dim ); + error = af_latin2_hints_compute_edges( hints, dim ); + } + return error; + } + FT_LOCAL_DEF( void ) + af_latin2_hints_compute_blue_edges( AF_GlyphHints hints, + AF_LatinMetrics metrics ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = edge + axis->num_edges; + AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; + FT_Fixed scale = latin->scale; +/* initial threshold */ + FT_Pos best_dist0; +/* compute the initial threshold as a fraction of the EM size */ + best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); + if ( best_dist0 > 64 / 2 ) + best_dist0 = 64 / 2; +/* compute which blue zones are active, i.e. have their scaled */ +/* size < 3/4 pixels */ +/* for each horizontal edge search the blue zone which is closest */ + for ( ; edge < edge_limit; edge++ ) + { + FT_Int bb; + AF_Width best_blue = NULL; + FT_Pos best_dist = best_dist0; + for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) + { + AF_LatinBlue blue = latin->blues + bb; + FT_Bool is_top_blue, is_major_dir; +/* skip inactive blue zones (i.e., those that are too small) */ + if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) + continue; +/* if it is a top zone, check for right edges -- if it is a bottom */ +/* zone, check for left edges */ +/* */ +/* of course, that's for TrueType */ + is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 ); + is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); +/* if it is a top zone, the edge must be against the major */ +/* direction; if it is a bottom zone, it must be in the major */ +/* direction */ + if ( is_top_blue ^ is_major_dir ) + { + FT_Pos dist; + AF_Width compare; +/* if it's a rounded edge, compare it to the overshoot position */ +/* if it's a flat edge, compare it to the reference position */ + if ( edge->flags & AF_EDGE_ROUND ) + compare = &blue->shoot; + else + compare = &blue->ref; + dist = edge->fpos - compare->org; + if (dist < 0) + dist = -dist; + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = compare; + } +#if 0 +/* now, compare it to the overshoot position if the edge is */ +/* rounded, and if the edge is over the reference position of a */ +/* top zone, or under the reference position of a bottom zone */ + if ( edge->flags & AF_EDGE_ROUND && dist != 0 ) + { + FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); + if ( is_top_blue ^ is_under_ref ) + { + blue = latin->blues + bb; + dist = edge->fpos - blue->shoot.org; + if ( dist < 0 ) + dist = -dist; + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = & blue->shoot; + } + } + } +#endif + } + } + if ( best_blue ) + edge->blue_edge = best_blue; + } + } + static FT_Error + af_latin2_hints_init( AF_GlyphHints hints, + AF_LatinMetrics metrics ) + { + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + FT_Face face = metrics->root.scaler.face; + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics ); +/* + * correct x_scale and y_scale if needed, since they may have + * been modified `af_latin2_metrics_scale_dim' above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; +/* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; +/* #ifdef AF_CONFIG_OPTION_USE_WARPER */ +#if 0 + if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ) + { + metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL; + } +#endif + scaler_flags = hints->scaler_flags; + other_flags = 0; +/* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; +/* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; +/* + * We adjust stems to full pixels only if we don't use the `light' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; +/* + * In `light' hinting mode we disable horizontal hinting completely. + * We also do it if the face is italic. + */ + if ( mode == FT_RENDER_MODE_LIGHT || + (face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 ) + scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + return 0; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N G L Y P H G R I D - F I T T I N G *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* snap a given width in scaled coordinates to one of the */ +/* current standard widths */ + static FT_Pos + af_latin2_snap_width( AF_Width widths, + FT_Int count, + FT_Pos width ) + { + int n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + scaled = FT_PIX_ROUND( reference ); + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + return width; + } +/* compute the snapped width of a given stem */ + static FT_Pos + af_latin2_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + AF_Edge_Flags base_flags, + AF_Edge_Flags stem_flags ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics; + AF_LatinAxis axis = & metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Int vertical = ( dim == AF_DIMENSION_VERT ); + FT_UNUSED(base_flags); + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { +/* smooth hinting process: very lightly quantize the stem width */ +/* leave the widths of serifs alone */ + if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) + goto Done_Width; +#if 0 + else if ( ( base_flags & AF_EDGE_ROUND ) ) + { + if ( dist < 80 ) + dist = 64; + } + else if ( dist < 56 ) + dist = 56; +#endif + if ( axis->width_count > 0 ) + { + FT_Pos delta; +/* compare to standard width */ + if ( axis->width_count > 0 ) + { + delta = dist - axis->widths[0].cur; + if ( delta < 0 ) + delta = -delta; + if ( delta < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + goto Done_Width; + } + } + if ( dist < 3 * 64 ) + { + delta = dist & 63; + dist &= -64; + if ( delta < 10 ) + dist += delta; + else if ( delta < 32 ) + dist += 10; + else if ( delta < 54 ) + dist += 54; + else + dist += delta; + } + else + dist = ( dist + 32 ) & ~63; + } + } + else + { +/* strong hinting process: snap the stem width to integer pixels */ + FT_Pos org_dist = dist; + dist = af_latin2_snap_width( axis->widths, axis->width_count, dist ); + if ( vertical ) + { +/* in the case of vertical hinting, always round */ +/* the stem heights to integer pixels */ + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { +/* monochrome horizontal hinting: snap widths to integer pixels */ +/* with a different threshold */ + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { +/* for horizontal anti-aliased hinting, we adopt a more subtle */ +/* approach: we strengthen small stems, round stems whose size */ +/* is between 1 and 2 pixels to an integer, otherwise nothing */ + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + else if ( dist < 128 ) + { +/* We only round to an integer width if the corresponding */ +/* distortion is less than 1/4 pixel. Otherwise this */ +/* makes everything worse since the diagonals, which are */ +/* not hinted, appear a lot bolder or thinner than the */ +/* vertical stems. */ + FT_Int delta; + dist = ( dist + 22 ) & ~63; + delta = dist - org_dist; + if ( delta < 0 ) + delta = -delta; + if (delta >= 16) + { + dist = org_dist; + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + } + } + else +/* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + Done_Width: + if ( sign ) + dist = -dist; + return dist; + } +/* align one stem edge relative to the previous stem edge */ + static void + af_latin2_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist = stem_edge->opos - base_edge->opos; + FT_Pos fitted_width = af_latin2_compute_stem_width( + hints, dim, dist, + (AF_Edge_Flags)base_edge->flags, + (AF_Edge_Flags)stem_edge->flags ); + stem_edge->pos = base_edge->pos + fitted_width; + FT_TRACE5(( "LINK: edge %d (opos=%.2f) linked to (%.2f), " + "dist was %.2f, now %.2f\n", + stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0, + stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 )); + } + static void + af_latin2_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + serif->pos = base->pos + (serif->opos - base->opos); + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** E D G E H I N T I N G ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + FT_LOCAL_DEF( void ) + af_latin2_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + AF_Edge anchor = 0; + FT_Int has_serifs = 0; + FT_Pos anchor_drift = 0; + FT_TRACE5(( "==== hinting %s edges =====\n", + dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); +/* we begin by aligning all stems relative to the blue zone */ +/* if needed -- that's only for horizontal edges */ + if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; + if ( edge->flags & AF_EDGE_DONE ) + continue; + blue = edge->blue_edge; + edge1 = NULL; + edge2 = edge->link; + if ( blue ) + { + edge1 = edge; + } + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + if ( !edge1 ) + continue; + FT_TRACE5(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), " + "was (%.2f)\n", + edge1-edges, edge1->opos / 64.0, blue->fit / 64.0, + edge1->pos / 64.0 )); + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + if ( edge2 && !edge2->blue_edge ) + { + af_latin2_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + } + if ( !anchor ) + { + anchor = edge; + anchor_drift = (anchor->pos - anchor->opos); + if (edge2) + anchor_drift = (anchor_drift + (edge2->pos - edge2->opos)) >> 1; + } + } + } +/* now we will align all stem edges, trying to maintain the */ +/* relative order of stems in the glyph */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + if ( edge->flags & AF_EDGE_DONE ) + continue; +/* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + has_serifs++; + continue; + } +/* now align the stem */ +/* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges )); + af_latin2_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + continue; + } + if ( !anchor ) + { + FT_Pos org_len, org_center, cur_len; + FT_Pos cur_pos1, error1, error2, u_off, d_off; + org_len = edge2->opos - edge->opos; + cur_len = af_latin2_compute_stem_width( + hints, dim, org_len, + (AF_Edge_Flags)edge->flags, + (AF_Edge_Flags)edge2->flags ); + if ( cur_len <= 64 ) + u_off = d_off = 32; + else + { + u_off = 38; + d_off = 26; + } + if ( cur_len < 96 ) + { + org_center = edge->opos + ( org_len >> 1 ); + cur_pos1 = FT_PIX_ROUND( org_center ); + error1 = org_center - ( cur_pos1 - u_off ); + if ( error1 < 0 ) + error1 = -error1; + error2 = org_center - ( cur_pos1 + d_off ); + if ( error2 < 0 ) + error2 = -error2; + if ( error1 < error2 ) + cur_pos1 -= u_off; + else + cur_pos1 += d_off; + edge->pos = cur_pos1 - cur_len / 2; + edge2->pos = edge->pos + cur_len; + } + else + edge->pos = FT_PIX_ROUND( edge->opos ); + FT_TRACE5(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)" + " snapped to (%.2f) (%.2f)\n", + edge-edges, edge->opos / 64.0, + edge2-edges, edge2->opos / 64.0, + edge->pos / 64.0, edge2->pos / 64.0 )); + anchor = edge; + edge->flags |= AF_EDGE_DONE; + af_latin2_align_linked_edge( hints, dim, edge, edge2 ); + edge2->flags |= AF_EDGE_DONE; + anchor_drift = ( (anchor->pos - anchor->opos) + + (edge2->pos - edge2->opos)) >> 1; + FT_TRACE5(( "DRIFT: %.2f\n", anchor_drift/64.0 )); + } + else + { + FT_Pos org_pos, org_len, org_center, cur_center, cur_len; + FT_Pos org_left, org_right; + org_pos = edge->opos + anchor_drift; + org_len = edge2->opos - edge->opos; + org_center = org_pos + ( org_len >> 1 ); + cur_len = af_latin2_compute_stem_width( + hints, dim, org_len, + (AF_Edge_Flags)edge->flags, + (AF_Edge_Flags)edge2->flags ); + org_left = org_pos + ((org_len - cur_len) >> 1); + org_right = org_pos + ((org_len + cur_len) >> 1); + FT_TRACE5(( "ALIGN: left=%.2f right=%.2f ", + org_left / 64.0, org_right / 64.0 )); + cur_center = org_center; + if ( edge2->flags & AF_EDGE_DONE ) + { + FT_TRACE5(( "\n" )); + edge->pos = edge2->pos - cur_len; + } + else + { +/* we want to compare several displacement, and choose + * the one that increases fitness while minimizing + * distortion as well + */ + FT_Pos displacements[6], scores[6], org, fit, delta; + FT_UInt count = 0; +/* note: don't even try to fit tiny stems */ + if ( cur_len < 32 ) + { + FT_TRACE5(( "tiny stem\n" )); + goto AlignStem; + } +/* if the span is within a single pixel, don't touch it */ + if ( FT_PIX_FLOOR(org_left) == FT_PIX_CEIL(org_right) ) + { + FT_TRACE5(( "single pixel stem\n" )); + goto AlignStem; + } + if (cur_len <= 96) + { +/* we want to avoid the absolute worst case which is + * when the left and right edges of the span each represent + * about 50% of the gray. we'd better want to change this + * to 25/75%, since this is much more pleasant to the eye with + * very acceptable distortion + */ + FT_Pos frac_left = (org_left) & 63; + FT_Pos frac_right = (org_right) & 63; + if ( frac_left >= 22 && frac_left <= 42 && + frac_right >= 22 && frac_right <= 42 ) + { + org = frac_left; + fit = (org <= 32) ? 16 : 48; + delta = FT_ABS(fit - org); + displacements[count] = fit - org; + scores[count++] = delta; + FT_TRACE5(( "dispA=%.2f (%d) ", (fit - org) / 64.0, delta )); + org = frac_right; + fit = (org <= 32) ? 16 : 48; + delta = FT_ABS(fit - org); + displacements[count] = fit - org; + scores[count++] = delta; + FT_TRACE5(( "dispB=%.2f (%d) ", (fit - org) / 64.0, delta )); + } + } +/* snapping the left edge to the grid */ + org = org_left; + fit = FT_PIX_ROUND(org); + delta = FT_ABS(fit - org); + displacements[count] = fit - org; + scores[count++] = delta; + FT_TRACE5(( "dispC=%.2f (%d) ", (fit - org) / 64.0, delta )); +/* snapping the right edge to the grid */ + org = org_right; + fit = FT_PIX_ROUND(org); + delta = FT_ABS(fit - org); + displacements[count] = fit - org; + scores[count++] = delta; + FT_TRACE5(( "dispD=%.2f (%d) ", (fit - org) / 64.0, delta )); +/* now find the best displacement */ + { + FT_Pos best_score = scores[0]; + FT_Pos best_disp = displacements[0]; + FT_UInt nn; + for (nn = 1; nn < count; nn++) + { + if (scores[nn] < best_score) + { + best_score = scores[nn]; + best_disp = displacements[nn]; + } + } + cur_center = org_center + best_disp; + } + FT_TRACE5(( "\n" )); + } + AlignStem: + edge->pos = cur_center - (cur_len >> 1); + edge2->pos = edge->pos + cur_len; + FT_TRACE5(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f)" + " snapped to (%.2f) and (%.2f)," + " org_len=%.2f cur_len=%.2f\n", + edge-edges, edge->opos / 64.0, + edge2-edges, edge2->opos / 64.0, + edge->pos / 64.0, edge2->pos / 64.0, + org_len / 64.0, cur_len / 64.0 )); + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + if ( edge > edges && edge->pos < edge[-1].pos ) + { + FT_TRACE5(( "BOUND: %d (pos=%.2f) to (%.2f)\n", + edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 )); + edge->pos = edge[-1].pos; + } + } + } +/* make sure that lowercase m's maintain their symmetry */ +/* In general, lowercase m's have six vertical edges if they are sans */ +/* serif, or twelve if they are with serifs. This implementation is */ +/* based on that assumption, and seems to work very well with most */ +/* faces. However, if for a certain face this assumption is not */ +/* true, the m is just rendered like before. In addition, any stem */ +/* correction will only be applied to symmetrical glyphs (even if the */ +/* glyph is not an m), so the potential for unwanted distortion is */ +/* relatively low. */ +/* We don't handle horizontal edges since we can't easily assure that */ +/* the third (lowest) stem aligns with the base line; it might end up */ +/* one pixel higher or lower. */ +#if 0 + { + FT_Int n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span, delta; + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + if ( span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; +/* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + } +#endif + if ( has_serifs || !anchor ) + { +/* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + FT_Pos delta; + if ( edge->flags & AF_EDGE_DONE ) + continue; + delta = 1000; + if ( edge->serif ) + { + delta = edge->serif->opos - edge->opos; + if ( delta < 0 ) + delta = -delta; + } + if ( delta < 64 + 16 ) + { + af_latin2_align_serif_edge( hints, edge->serif, edge ); + FT_TRACE5(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)" + " aligned to (%.2f)\n", + edge-edges, edge->opos / 64.0, + edge->serif - edges, edge->serif->opos / 64.0, + edge->pos / 64.0 )); + } + else if ( !anchor ) + { + FT_TRACE5(( "SERIF_ANCHOR: edge %d (opos=%.2f)" + " snapped to (%.2f)\n", + edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); + edge->pos = FT_PIX_ROUND( edge->opos ); + anchor = edge; + } + else + { + AF_Edge before, after; + for ( before = edge - 1; before >= edges; before-- ) + if ( before->flags & AF_EDGE_DONE ) + break; + for ( after = edge + 1; after < edge_limit; after++ ) + if ( after->flags & AF_EDGE_DONE ) + break; + if ( before >= edges && before < edge && + after < edge_limit && after > edge ) + { + if ( after->opos == before->opos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->opos - before->opos, + after->pos - before->pos, + after->opos - before->opos ); + FT_TRACE5(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f)" + " from %d (opos=%.2f)\n", + edge-edges, edge->opos / 64.0, edge->pos / 64.0, + before - edges, before->opos / 64.0 )); + } + else + { + edge->pos = anchor->pos + + ( ( edge->opos - anchor->opos + 16 ) & ~31 ); + FT_TRACE5(( "SERIF_LINK2: edge %d (opos=%.2f)" + " snapped to (%.2f)\n", + edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); + } + } + edge->flags |= AF_EDGE_DONE; + if ( edge > edges && edge->pos < edge[-1].pos ) + edge->pos = edge[-1].pos; + if ( edge + 1 < edge_limit && + edge[1].flags & AF_EDGE_DONE && + edge->pos > edge[1].pos ) + edge->pos = edge[1].pos; + } + } + } + static FT_Error + af_latin2_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_LatinMetrics metrics ) + { + FT_Error error; + int dim; + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; +/* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + error = af_latin2_hints_detect_features( hints, AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + } + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + error = af_latin2_hints_detect_features( hints, AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + af_latin2_hints_compute_blue_edges( hints, metrics ); + } +/* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_latin2_hint_edges( hints, (AF_Dimension)dim ); + af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } + af_glyph_hints_save( hints, outline ); + Exit: + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** L A T I N S C R I P T C L A S S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static const AF_Script_UniRangeRec af_latin2_uniranges[] = + { +/* TODO: Add new Unicode ranges here! */ + AF_UNIRANGE_REC( 32UL, 127UL ), + AF_UNIRANGE_REC( 160UL, 255UL ), + AF_UNIRANGE_REC( 0UL, 0UL ) + }; + AF_DEFINE_SCRIPT_CLASS( af_latin2_script_class, + AF_SCRIPT_LATIN2, + af_latin2_uniranges, + 'o', + sizeof ( AF_LatinMetricsRec ), + (AF_Script_InitMetricsFunc) af_latin2_metrics_init, + (AF_Script_ScaleMetricsFunc)af_latin2_metrics_scale, + (AF_Script_DoneMetricsFunc) NULL, + (AF_Script_InitHintsFunc) af_latin2_hints_init, + (AF_Script_ApplyHintsFunc) af_latin2_hints_apply + ) +/* END */ +#endif +/***************************************************************************/ +/* */ +/* afcjk.c */ +/* */ +/* Auto-fitter hinting routines for CJK script (body). */ +/* */ +/* Copyright 2006-2012 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 algorithm is based on akito's autohint patch, available here: + * + * http://www.kde.gr.jp/~akito/patch/freetype2/ + * + */ +#undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT +/*************************************************************************/ +/* */ +/* 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 trace_afcjk +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** C J K G L O B A L M E T R I C S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* Basically the Latin version with AF_CJKMetrics */ +/* to replace AF_LatinMetrics. */ + FT_LOCAL_DEF( void ) + af_cjk_metrics_init_widths( AF_CJKMetrics metrics, + FT_Face face ) + { +/* scan the array of segments in each direction */ + AF_GlyphHintsRec hints[1]; + af_glyph_hints_init( hints, face->memory ); + metrics->axis[AF_DIMENSION_HORZ].width_count = 0; + metrics->axis[AF_DIMENSION_VERT].width_count = 0; + { + FT_Error error; + FT_UInt glyph_index; + int dim; + AF_CJKMetricsRec dummy[1]; + AF_Scaler scaler = &dummy->root.scaler; + glyph_index = FT_Get_Char_Index( face, + metrics->root.clazz->standard_char ); + if ( glyph_index == 0 ) + goto Exit; + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || face->glyph->outline.n_points <= 0 ) + goto Exit; + FT_ZERO( dummy ); + dummy->units_per_em = metrics->units_per_em; + scaler->x_scale = 0x10000L; + scaler->y_scale = 0x10000L; + scaler->x_delta = 0; + scaler->y_delta = 0; + scaler->face = face; + scaler->render_mode = FT_RENDER_MODE_NORMAL; + scaler->flags = 0; + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); + error = af_glyph_hints_reload( hints, &face->glyph->outline ); + if ( error ) + goto Exit; + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + AF_AxisHints axhints = &hints->axis[dim]; + AF_Segment seg, limit, link; + FT_UInt num_widths = 0; + error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim ); + if ( error ) + goto Exit; + af_latin_hints_link_segments( hints, (AF_Dimension)dim ); + seg = axhints->segments; + limit = seg + axhints->num_segments; + for ( ; seg < limit; seg++ ) + { + link = seg->link; +/* we only consider stem segments there! */ + if ( link && link->link == seg && link > seg ) + { + FT_Pos dist; + dist = seg->pos - link->pos; + if ( dist < 0 ) + dist = -dist; + if ( num_widths < AF_CJK_MAX_WIDTHS ) + axis->widths[num_widths++].org = dist; + } + } +/* this also replaces multiple almost identical stem widths */ +/* with a single one (the value 100 is heuristic) */ + af_sort_and_quantize_widths( &num_widths, axis->widths, + dummy->units_per_em / 100 ); + axis->width_count = num_widths; + } + Exit: + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + AF_CJKAxis axis = &metrics->axis[dim]; + FT_Pos stdw; + stdw = ( axis->width_count > 0 ) ? axis->widths[0].org + : AF_LATIN_CONSTANT( metrics, 50 ); +/* let's try 20% of the smallest width */ + axis->edge_distance_threshold = stdw / 5; + axis->standard_width = stdw; + axis->extra_light = 0; + } + } + af_glyph_hints_done( hints ); + } +#define AF_CJK_MAX_TEST_CHARACTERS 32 +/* Each blue zone has two types of fill and unfill, this is, */ +/* filling the entire glyph square or not. */ + enum + { + AF_CJK_BLUE_TYPE_FILL, + AF_CJK_BLUE_TYPE_UNFILL, + AF_CJK_BLUE_TYPE_MAX + }; +/* Put some common and representative Han Ideographs characters here. */ + static const FT_ULong af_cjk_hani_blue_chars[AF_CJK_BLUE_MAX] + [AF_CJK_BLUE_TYPE_MAX] + [AF_CJK_MAX_TEST_CHARACTERS] = + { + { + { + 0x4ED6, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730, + 0x5BF9, 0x5C0D, 0x5C31, 0x5E2D, 0x6211, 0x65F6, 0x6642, 0x6703, + 0x6765, 0x70BA, 0x80FD, 0x8230, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019, +/* top fill */ + 0x9F4A + }, + { + 0x519B, 0x540C, 0x5DF2, 0x613F, 0x65E2, 0x661F, 0x662F, 0x666F, + 0x6C11, 0x7167, 0x73B0, 0x73FE, 0x7406, 0x7528, 0x7F6E, 0x8981, + 0x8ECD, 0x90A3, 0x914D, 0x91CC, 0x958B, 0x96F7, 0x9732, 0x9762, +/* top unfill */ + 0x987E + } + }, + { + { + 0x4E2A, 0x4E3A, 0x4EBA, 0x4ED6, 0x4EE5, 0x4EEC, 0x4F60, 0x4F86, + 0x500B, 0x5011, 0x5230, 0x548C, 0x5927, 0x5BF9, 0x5C0D, 0x5C31, + 0x6211, 0x65F6, 0x6642, 0x6709, 0x6765, 0x70BA, 0x8981, 0x8AAA, +/* bottom fill */ + 0x8BF4 + }, + { + 0x4E3B, 0x4E9B, 0x56E0, 0x5B83, 0x60F3, 0x610F, 0x7406, 0x751F, + 0x7576, 0x770B, 0x7740, 0x7F6E, 0x8005, 0x81EA, 0x8457, 0x88E1, + 0x8FC7, 0x8FD8, 0x8FDB, 0x9032, 0x904E, 0x9053, 0x9084, 0x91CC, +/* bottom unfill */ + 0x9762 + } + }, +#ifndef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT + { {0x0000}, {0x0000} }, + { {0x0000}, {0x0000} } +#else + { + { + 0x4E9B, 0x4EEC, 0x4F60, 0x4F86, 0x5011, 0x5230, 0x548C, 0x5730, + 0x5979, 0x5C06, 0x5C07, 0x5C31, 0x5E74, 0x5F97, 0x60C5, 0x6700, + 0x6837, 0x6A23, 0x7406, 0x80FD, 0x8AAA, 0x8BF4, 0x8FD9, 0x9019, +/* left fill */ + 0x901A + }, + { + 0x5373, 0x5417, 0x5427, 0x542C, 0x5462, 0x54C1, 0x54CD, 0x55CE, + 0x5E08, 0x5E2B, 0x6536, 0x65AD, 0x65B7, 0x660E, 0x773C, 0x9593, + 0x95F4, 0x9645, 0x9648, 0x9650, 0x9664, 0x9673, 0x968F, 0x969B, +/* left unfill */ + 0x96A8 + } + }, + { + { + 0x4E8B, 0x524D, 0x5B78, 0x5C06, 0x5C07, 0x60C5, 0x60F3, 0x6216, + 0x653F, 0x65AF, 0x65B0, 0x6837, 0x6A23, 0x6C11, 0x6C92, 0x6CA1, + 0x7136, 0x7279, 0x73B0, 0x73FE, 0x7403, 0x7B2C, 0x7D93, 0x8C01, +/* right fill */ + 0x8D77 + }, + { + 0x4F8B, 0x5225, 0x522B, 0x5236, 0x52A8, 0x52D5, 0x5417, 0x55CE, + 0x589E, 0x6307, 0x660E, 0x671D, 0x671F, 0x6784, 0x7269, 0x786E, + 0x79CD, 0x8ABF, 0x8C03, 0x8CBB, 0x8D39, 0x90A3, 0x90FD, 0x9593, +/* right unfill */ + 0x95F4 + } + } +/* AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT */ +#endif + }; +/* Calculate blue zones for all the CJK_BLUE_XXX's. */ + static void + af_cjk_metrics_init_blues( AF_CJKMetrics metrics, + FT_Face face, + const FT_ULong blue_chars + [AF_CJK_BLUE_MAX] + [AF_CJK_BLUE_TYPE_MAX] + [AF_CJK_MAX_TEST_CHARACTERS] ) + { + FT_Pos fills[AF_CJK_MAX_TEST_CHARACTERS]; + FT_Pos flats[AF_CJK_MAX_TEST_CHARACTERS]; + FT_Int num_fills; + FT_Int num_flats; + FT_Int bb; + AF_CJKBlue blue; + FT_Error error; + AF_CJKAxis axis; + FT_GlyphSlot glyph = face->glyph; +/* We compute the blues simply by loading each character from the */ +/* `blue_chars[blues]' string, then computing its extreme points */ +/* (depending blue zone type etc.). */ + FT_TRACE5(( "cjk blue zones computation\n" )); + FT_TRACE5(( "------------------------------------------------\n" )); + for ( bb = 0; bb < AF_CJK_BLUE_MAX; bb++ ) + { + FT_Int fill_type; + FT_Pos* blue_ref; + FT_Pos* blue_shoot; + num_fills = 0; + num_flats = 0; + for ( fill_type = 0; fill_type < AF_CJK_BLUE_TYPE_MAX; fill_type++ ) + { + const FT_ULong* p = blue_chars[bb][fill_type]; + const FT_ULong* limit = p + AF_CJK_MAX_TEST_CHARACTERS; + FT_Bool fill = FT_BOOL( + fill_type == AF_CJK_BLUE_TYPE_FILL ); + FT_TRACE5(( "cjk blue %s/%s\n", cjk_blue_name[bb], + cjk_blue_type_name[fill_type] )); + for ( ; p < limit && *p; p++ ) + { + FT_UInt glyph_index; +/* same as points.y */ + FT_Pos best_pos; + FT_Int best_point; + FT_Vector* points; + FT_TRACE5(( " U+%lX...", *p )); +/* load the character in the face -- skip unknown or empty ones */ + glyph_index = FT_Get_Char_Index( face, *p ); + if ( glyph_index == 0 ) + { + FT_TRACE5(( "unavailable\n" )); + continue; + } + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); + if ( error || glyph->outline.n_points <= 0 ) + { + FT_TRACE5(( "no outline\n" )); + continue; + } +/* now compute min or max point indices and coordinates */ + points = glyph->outline.points; + best_point = -1; +/* make compiler happy */ + best_pos = 0; + { + FT_Int nn; + FT_Int first = 0; + FT_Int last = -1; + for ( nn = 0; + nn < glyph->outline.n_contours; + first = last + 1, nn++ ) + { + FT_Int pp; + last = glyph->outline.contours[nn]; +/* Avoid single-point contours since they are never */ +/* rasterized. In some fonts, they correspond to mark */ +/* attachment points which are way outside of the glyph's */ +/* real outline. */ + if ( last <= first ) + continue; + switch ( bb ) + { + case AF_CJK_BLUE_TOP: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y > best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + break; + case AF_CJK_BLUE_BOTTOM: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].y < best_pos ) + { + best_point = pp; + best_pos = points[pp].y; + } + break; + case AF_CJK_BLUE_LEFT: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x < best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + break; + case AF_CJK_BLUE_RIGHT: + for ( pp = first; pp <= last; pp++ ) + if ( best_point < 0 || points[pp].x > best_pos ) + { + best_point = pp; + best_pos = points[pp].x; + } + break; + default: + ; + } + } + FT_TRACE5(( "best_pos=%5ld\n", best_pos )); + } + if ( fill ) + fills[num_fills++] = best_pos; + else + flats[num_flats++] = best_pos; + } + } + if ( num_flats == 0 && num_fills == 0 ) + { +/* + * we couldn't find a single glyph to compute this blue zone, + * we will simply ignore it then + */ + FT_TRACE5(( "empty\n" )); + continue; + } +/* we have computed the contents of the `fill' and `flats' tables, */ +/* now determine the reference position of the blue -- */ +/* we simply take the median value after a simple sort */ + af_sort_pos( num_flats, flats ); + af_sort_pos( num_fills, fills ); + if ( AF_CJK_BLUE_TOP == bb || AF_CJK_BLUE_BOTTOM == bb ) + axis = &metrics->axis[AF_DIMENSION_VERT]; + else + axis = &metrics->axis[AF_DIMENSION_HORZ]; + blue = & axis->blues[axis->blue_count]; + blue_ref = & blue->ref.org; + blue_shoot = & blue->shoot.org; + axis->blue_count++; + if ( num_flats == 0 ) + { + *blue_ref = fills[num_fills / 2]; + *blue_shoot = fills[num_fills / 2]; + } + else if ( num_fills == 0 ) + { + *blue_ref = flats[num_flats / 2]; + *blue_shoot = flats[num_flats / 2]; + } + else + { + *blue_ref = fills[num_fills / 2]; + *blue_shoot = flats[num_flats / 2]; + } +/* make sure blue_ref >= blue_shoot for top/right or */ +/* vice versa for bottom/left */ + if ( *blue_shoot != *blue_ref ) + { + FT_Pos ref = *blue_ref; + FT_Pos shoot = *blue_shoot; + FT_Bool under_ref = FT_BOOL( shoot < ref ); + if ( (AF_CJK_BLUE_TOP == bb || AF_CJK_BLUE_RIGHT == bb) ^ under_ref ) + *blue_shoot = *blue_ref = ( shoot + ref ) / 2; + } + blue->flags = 0; + if ( AF_CJK_BLUE_TOP == bb ) + blue->flags |= AF_CJK_BLUE_IS_TOP; + else if ( AF_CJK_BLUE_RIGHT == bb ) + blue->flags |= AF_CJK_BLUE_IS_RIGHT; + FT_TRACE5(( "-- cjk %s bluezone ref = %ld shoot = %ld\n", + cjk_blue_name[bb], *blue_ref, *blue_shoot )); + } + return; + } +/* Basically the Latin version with type AF_CJKMetrics for metrics. */ + FT_LOCAL_DEF( void ) + af_cjk_metrics_check_digits( AF_CJKMetrics metrics, + FT_Face face ) + { + FT_UInt i; + FT_Bool started = 0, same_width = 1; + FT_Fixed advance, old_advance = 0; +/* check whether all ASCII digits have the same advance width; */ +/* digit `0' is 0x30 in all supported charmaps */ + for ( i = 0x30; i <= 0x39; i++ ) + { + FT_UInt glyph_index; + glyph_index = FT_Get_Char_Index( face, i ); + if ( glyph_index == 0 ) + continue; + if ( FT_Get_Advance( face, glyph_index, + FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_IGNORE_TRANSFORM, + &advance ) ) + continue; + if ( started ) + { + if ( advance != old_advance ) + { + same_width = 0; + break; + } + } + else + { + old_advance = advance; + started = 1; + } + } + metrics->root.digits_have_same_width = same_width; + } + FT_LOCAL_DEF( FT_Error ) + af_cjk_metrics_init( AF_CJKMetrics metrics, + FT_Face face ) + { + 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 ); + af_cjk_metrics_init_blues( metrics, face, af_cjk_hani_blue_chars ); + af_cjk_metrics_check_digits( metrics, face ); + } + FT_Set_Charmap( face, oldmap ); + return AF_Err_Ok; + } + static void + af_cjk_metrics_scale_dim( AF_CJKMetrics metrics, + AF_Scaler scaler, + AF_Dimension dim ) + { + FT_Fixed scale; + FT_Pos delta; + AF_CJKAxis axis; + FT_UInt nn; + axis = &metrics->axis[dim]; + if ( dim == AF_DIMENSION_HORZ ) + { + scale = scaler->x_scale; + delta = scaler->x_delta; + } + else + { + scale = scaler->y_scale; + delta = scaler->y_delta; + } + if ( axis->org_scale == scale && axis->org_delta == delta ) + return; + axis->org_scale = scale; + axis->org_delta = delta; + axis->scale = scale; + axis->delta = delta; +/* scale the blue zones */ + for ( nn = 0; nn < axis->blue_count; nn++ ) + { + AF_CJKBlue blue = &axis->blues[nn]; + FT_Pos dist; + blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta; + blue->ref.fit = blue->ref.cur; + blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta; + blue->shoot.fit = blue->shoot.cur; + blue->flags &= ~AF_CJK_BLUE_ACTIVE; +/* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); + if ( dist <= 48 && dist >= -48 ) + { + FT_Pos delta1, delta2; + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); +/* shoot is under shoot for cjk */ + delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; + delta2 = delta1; + if ( delta1 < 0 ) + delta2 = -delta2; + delta2 = FT_MulFix( delta2, scale ); + FT_TRACE5(( "delta: %d", delta1 )); + if ( delta2 < 32 ) + delta2 = 0; +#if 0 + else if ( delta2 < 64 ) + delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 ); +#endif + else + delta2 = FT_PIX_ROUND( delta2 ); + FT_TRACE5(( "/%d\n", delta2 )); + if ( delta1 < 0 ) + delta2 = -delta2; + blue->shoot.fit = blue->ref.fit - delta2; + FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]: " + "ref: cur=%.2f fit=%.2f shoot: cur=%.2f fit=%.2f\n", + ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', + nn, blue->ref.org, blue->shoot.org, + blue->ref.cur / 64.0, blue->ref.fit / 64.0, + blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); + blue->flags |= AF_CJK_BLUE_ACTIVE; + } + } + } + FT_LOCAL_DEF( void ) + af_cjk_metrics_scale( AF_CJKMetrics metrics, + AF_Scaler scaler ) + { + metrics->root.scaler = *scaler; + af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ ); + af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** C J K G L Y P H A N A L Y S I S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static FT_Error + af_cjk_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + FT_Error error; + AF_Segment seg; + error = af_latin_hints_compute_segments( hints, dim ); + if ( error ) + return error; +/* a segment is round if it doesn't have successive */ +/* on-curve points. */ + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Point pt = seg->first; + AF_Point last = seg->last; + AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL); + AF_Flags f1; + seg->flags &= ~AF_EDGE_ROUND; + for ( ; pt != last; f0 = f1 ) + { + pt = pt->next; + f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL); + if ( !f0 && !f1 ) + break; + if ( pt == last ) + seg->flags |= AF_EDGE_ROUND; + } + } + return AF_Err_Ok; + } + static void + af_cjk_hints_link_segments( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + AF_Direction major_dir = axis->major_dir; + AF_Segment seg1, seg2; + FT_Pos len_threshold; + FT_Pos dist_threshold; + len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 ); + dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; + dist_threshold = FT_DivFix( 64 * 3, dist_threshold ); +/* now compare each segment to the others */ + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { +/* the fake segments are for metrics hinting only */ + if ( seg1->first == seg1->last ) + continue; + if ( seg1->dir != major_dir ) + continue; + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 ) + { + FT_Pos dist = seg2->pos - seg1->pos; + if ( dist < 0 ) + continue; + { + FT_Pos min = seg1->min_coord; + FT_Pos max = seg1->max_coord; + FT_Pos len; + if ( min < seg2->min_coord ) + min = seg2->min_coord; + if ( max > seg2->max_coord ) + max = seg2->max_coord; + len = max - min; + if ( len >= len_threshold ) + { + if ( dist * 8 < seg1->score * 9 && + ( dist * 8 < seg1->score * 7 || seg1->len < len ) ) + { + seg1->score = dist; + seg1->len = len; + seg1->link = seg2; + } + if ( dist * 8 < seg2->score * 9 && + ( dist * 8 < seg2->score * 7 || seg2->len < len ) ) + { + seg2->score = dist; + seg2->len = len; + seg2->link = seg1; + } + } + } + } + } +/* + * now compute the `serif' segments + * + * In Hanzi, some strokes are wider on one or both of the ends. + * We either identify the stems on the ends as serifs or remove + * the linkage, depending on the length of the stems. + * + */ + { + AF_Segment link1, link2; + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + link1 = seg1->link; + if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos ) + continue; + if ( seg1->score >= dist_threshold ) + continue; + for ( seg2 = segments; seg2 < segment_limit; seg2++ ) + { + if ( seg2->pos > seg1->pos || seg1 == seg2 ) + continue; + link2 = seg2->link; + if ( !link2 || link2->link != seg2 || link2->pos < link1->pos ) + continue; + if ( seg1->pos == seg2->pos && link1->pos == link2->pos ) + continue; + if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score ) + continue; +/* seg2 < seg1 < link1 < link2 */ + if ( seg1->len >= seg2->len * 3 ) + { + AF_Segment seg; + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Segment link = seg->link; + if ( link == seg2 ) + { + seg->link = 0; + seg->serif = link1; + } + else if ( link == link2 ) + { + seg->link = 0; + seg->serif = seg1; + } + } + } + else + { + seg1->link = link1->link = 0; + break; + } + } + } + } + for ( seg1 = segments; seg1 < segment_limit; seg1++ ) + { + seg2 = seg1->link; + if ( seg2 ) + { + seg2->num_linked++; + if ( seg2->link != seg1 ) + { + seg1->link = 0; + if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 ) + seg1->serif = seg2->link; + else + seg2->num_linked--; + } + } + } + } + static FT_Error + af_cjk_hints_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + FT_Error error = AF_Err_Ok; + FT_Memory memory = hints->memory; + AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; + AF_Segment segments = axis->segments; + AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment seg; + FT_Fixed scale; + FT_Pos edge_distance_threshold; + axis->num_edges = 0; + scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale + : hints->y_scale; +/*********************************************************************/ +/* */ +/* We begin by generating a sorted table of edges for the current */ +/* direction. To do so, we simply scan each segment and try to find */ +/* an edge in our table that corresponds to its position. */ +/* */ +/* If no edge is found, we create and insert a new edge in the */ +/* sorted table. Otherwise, we simply add the segment to the edge's */ +/* list which is then processed in the second step to compute the */ +/* edge's properties. */ +/* */ +/* Note that the edges table is sorted along the segment/edge */ +/* position. */ +/* */ +/*********************************************************************/ + edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, + scale ); + if ( edge_distance_threshold > 64 / 4 ) + edge_distance_threshold = FT_DivFix( 64 / 4, scale ); + else + edge_distance_threshold = laxis->edge_distance_threshold; + for ( seg = segments; seg < segment_limit; seg++ ) + { + AF_Edge found = 0; + FT_Pos best = 0xFFFFU; + FT_Int ee; +/* look for an edge corresponding to the segment */ + for ( ee = 0; ee < axis->num_edges; ee++ ) + { + AF_Edge edge = axis->edges + ee; + FT_Pos dist; + if ( edge->dir != seg->dir ) + continue; + dist = seg->pos - edge->fpos; + if ( dist < 0 ) + dist = -dist; + if ( dist < edge_distance_threshold && dist < best ) + { + AF_Segment link = seg->link; +/* check whether all linked segments of the candidate edge */ +/* can make a single edge. */ + if ( link ) + { + AF_Segment seg1 = edge->first; + AF_Segment link1; + FT_Pos dist2 = 0; + do + { + link1 = seg1->link; + if ( link1 ) + { + dist2 = AF_SEGMENT_DIST( link, link1 ); + if ( dist2 >= edge_distance_threshold ) + break; + } + } while ( ( seg1 = seg1->edge_next ) != edge->first ); + if ( dist2 >= edge_distance_threshold ) + continue; + } + best = dist; + found = edge; + } + } + if ( !found ) + { + AF_Edge edge; +/* insert a new edge in the list and */ +/* sort according to the position */ + error = af_axis_hints_new_edge( axis, seg->pos, + (AF_Direction)seg->dir, + memory, &edge ); + if ( error ) + goto Exit; +/* add the segment to the new edge's list */ + FT_ZERO( edge ); + edge->first = seg; + edge->last = seg; + edge->fpos = seg->pos; + edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); + seg->edge_next = seg; + edge->dir = seg->dir; + } + else + { +/* if an edge was found, simply add the segment to the edge's */ +/* list */ + seg->edge_next = found->first; + found->last->edge_next = seg; + found->last = seg; + } + } +/*********************************************************************/ +/* */ +/* Good, we now compute each edge's properties according to segments */ +/* found on its position. Basically, these are as follows. */ +/* */ +/* - edge's main direction */ +/* - stem edge, serif edge or both (which defaults to stem then) */ +/* - rounded edge, straight or both (which defaults to straight) */ +/* - link for edge */ +/* */ +/*********************************************************************/ +/* first of all, set the `edge' field in each segment -- this is */ +/* required in order to compute edge links */ +/* */ +/* Note that removing this loop and setting the `edge' field of each */ +/* segment directly in the code above slows down execution speed for */ +/* some reasons on platforms like the Sun. */ + { + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + for ( edge = edges; edge < edge_limit; edge++ ) + { + seg = edge->first; + if ( seg ) + do + { + seg->edge = edge; + seg = seg->edge_next; + } while ( seg != edge->first ); + } +/* now compute each edge properties */ + for ( edge = edges; edge < edge_limit; edge++ ) + { +/* does it contain round segments? */ + FT_Int is_round = 0; +/* does it contain straight segments? */ + FT_Int is_straight = 0; + seg = edge->first; + do + { + FT_Bool is_serif; +/* check for roundness of segment */ + if ( seg->flags & AF_EDGE_ROUND ) + is_round++; + else + is_straight++; +/* check for links -- if seg->serif is set, then seg->link must */ +/* be ignored */ + is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge ); + if ( seg->link || is_serif ) + { + AF_Edge edge2; + AF_Segment seg2; + edge2 = edge->link; + seg2 = seg->link; + if ( is_serif ) + { + seg2 = seg->serif; + edge2 = edge->serif; + } + if ( edge2 ) + { + FT_Pos edge_delta; + FT_Pos seg_delta; + edge_delta = edge->fpos - edge2->fpos; + if ( edge_delta < 0 ) + edge_delta = -edge_delta; + seg_delta = AF_SEGMENT_DIST( seg, seg2 ); + if ( seg_delta < edge_delta ) + edge2 = seg2->edge; + } + else + edge2 = seg2->edge; + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AF_EDGE_SERIF; + } + else + edge->link = edge2; + } + seg = seg->edge_next; + } while ( seg != edge->first ); +/* set the round/straight flags */ + edge->flags = AF_EDGE_NORMAL; + if ( is_round > 0 && is_round >= is_straight ) + edge->flags |= AF_EDGE_ROUND; +/* get rid of serifs if link is set */ +/* XXX: This gets rid of many unpleasant artefacts! */ +/* Example: the `c' in cour.pfa at size 13 */ + if ( edge->serif && edge->link ) + edge->serif = 0; + } + } + Exit: + return error; + } + static FT_Error + af_cjk_hints_detect_features( AF_GlyphHints hints, + AF_Dimension dim ) + { + FT_Error error; + error = af_cjk_hints_compute_segments( hints, dim ); + if ( !error ) + { + af_cjk_hints_link_segments( hints, dim ); + error = af_cjk_hints_compute_edges( hints, dim ); + } + return error; + } + FT_LOCAL_DEF( void ) + af_cjk_hints_compute_blue_edges( AF_GlyphHints hints, + AF_CJKMetrics metrics, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edge = axis->edges; + AF_Edge edge_limit = edge + axis->num_edges; + AF_CJKAxis cjk = &metrics->axis[dim]; + FT_Fixed scale = cjk->scale; +/* initial threshold */ + FT_Pos best_dist0; +/* compute the initial threshold as a fraction of the EM size */ + best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale ); +/* maximum 1/2 pixel */ + if ( best_dist0 > 64 / 2 ) + best_dist0 = 64 / 2; +/* compute which blue zones are active, i.e. have their scaled */ +/* size < 3/4 pixels */ +/* If the distant between an edge and a blue zone is shorter than */ +/* best_dist0, set the blue zone for the edge. Then search for */ +/* the blue zone with the smallest best_dist to the edge. */ + for ( ; edge < edge_limit; edge++ ) + { + FT_UInt bb; + AF_Width best_blue = NULL; + FT_Pos best_dist = best_dist0; + for ( bb = 0; bb < cjk->blue_count; bb++ ) + { + AF_CJKBlue blue = cjk->blues + bb; + FT_Bool is_top_right_blue, is_major_dir; +/* skip inactive blue zones (i.e., those that are too small) */ + if ( !( blue->flags & AF_CJK_BLUE_ACTIVE ) ) + continue; +/* if it is a top zone, check for right edges -- if it is a bottom */ +/* zone, check for left edges */ +/* */ +/* of course, that's for TrueType */ + is_top_right_blue = + FT_BOOL( ( ( blue->flags & AF_CJK_BLUE_IS_TOP ) != 0 ) || + ( ( blue->flags & AF_CJK_BLUE_IS_RIGHT ) != 0 ) ); + is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); +/* if it is a top zone, the edge must be against the major */ +/* direction; if it is a bottom zone, it must be in the major */ +/* direction */ + if ( is_top_right_blue ^ is_major_dir ) + { + FT_Pos dist; + AF_Width compare; +/* Compare the edge to the closest blue zone type */ + if ( FT_ABS( edge->fpos - blue->ref.org ) > + FT_ABS( edge->fpos - blue->shoot.org ) ) + compare = &blue->shoot; + else + compare = &blue->ref; + dist = edge->fpos - compare->org; + if ( dist < 0 ) + dist = -dist; + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { + best_dist = dist; + best_blue = compare; + } + } + } + if ( best_blue ) + edge->blue_edge = best_blue; + } + } + FT_LOCAL_DEF( FT_Error ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_CJKMetrics metrics ) + { + FT_Render_Mode mode; + FT_UInt32 scaler_flags, other_flags; + af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics ); +/* + * correct x_scale and y_scale when needed, since they may have + * been modified af_cjk_scale_dim above + */ + hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; + hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; + hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; + hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; +/* compute flags depending on render mode, etc. */ + mode = metrics->root.scaler.render_mode; + scaler_flags = hints->scaler_flags; + other_flags = 0; +/* + * We snap the width of vertical stems for the monochrome and + * horizontal LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) + other_flags |= AF_LATIN_HINTS_HORZ_SNAP; +/* + * We snap the width of horizontal stems for the monochrome and + * vertical LCD rendering targets only. + */ + if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) + other_flags |= AF_LATIN_HINTS_VERT_SNAP; +/* + * We adjust stems to full pixels only if we don't use the `light' mode. + */ + if ( mode != FT_RENDER_MODE_LIGHT ) + other_flags |= AF_LATIN_HINTS_STEM_ADJUST; + if ( mode == FT_RENDER_MODE_MONO ) + other_flags |= AF_LATIN_HINTS_MONO; + scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE; + hints->scaler_flags = scaler_flags; + hints->other_flags = other_flags; + return 0; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** C J K G L Y P H G R I D - F I T T I N G *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* snap a given width in scaled coordinates to one of the */ +/* current standard widths */ + static FT_Pos + af_cjk_snap_width( AF_Width widths, + FT_Int count, + FT_Pos width ) + { + int n; + FT_Pos best = 64 + 32 + 2; + FT_Pos reference = width; + FT_Pos scaled; + for ( n = 0; n < count; n++ ) + { + FT_Pos w; + FT_Pos dist; + w = widths[n].cur; + dist = width - w; + if ( dist < 0 ) + dist = -dist; + if ( dist < best ) + { + best = dist; + reference = w; + } + } + scaled = FT_PIX_ROUND( reference ); + if ( width >= reference ) + { + if ( width < scaled + 48 ) + width = reference; + } + else + { + if ( width > scaled - 48 ) + width = reference; + } + return width; + } +/* compute the snapped width of a given stem */ + static FT_Pos + af_cjk_compute_stem_width( AF_GlyphHints hints, + AF_Dimension dim, + FT_Pos width, + AF_Edge_Flags base_flags, + AF_Edge_Flags stem_flags ) + { + AF_CJKMetrics metrics = (AF_CJKMetrics) hints->metrics; + AF_CJKAxis axis = & metrics->axis[dim]; + FT_Pos dist = width; + FT_Int sign = 0; + FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT ); + FT_UNUSED( base_flags ); + FT_UNUSED( stem_flags ); + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + return width; + if ( dist < 0 ) + { + dist = -width; + sign = 1; + } + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + { +/* smooth hinting process: very lightly quantize the stem width */ + if ( axis->width_count > 0 ) + { + if ( FT_ABS( dist - axis->widths[0].cur ) < 40 ) + { + dist = axis->widths[0].cur; + if ( dist < 48 ) + dist = 48; + goto Done_Width; + } + } + if ( dist < 54 ) + dist += ( 54 - dist ) / 2 ; + else if ( dist < 3 * 64 ) + { + FT_Pos delta; + delta = dist & 63; + dist &= -64; + if ( delta < 10 ) + dist += delta; + else if ( delta < 22 ) + dist += 10; + else if ( delta < 42 ) + dist += delta; + else if ( delta < 54 ) + dist += 54; + else + dist += delta; + } + } + else + { +/* strong hinting process: snap the stem width to integer pixels */ + dist = af_cjk_snap_width( axis->widths, axis->width_count, dist ); + if ( vertical ) + { +/* in the case of vertical hinting, always round */ +/* the stem heights to integer pixels */ + if ( dist >= 64 ) + dist = ( dist + 16 ) & ~63; + else + dist = 64; + } + else + { + if ( AF_LATIN_HINTS_DO_MONO( hints ) ) + { +/* monochrome horizontal hinting: snap widths to integer pixels */ +/* with a different threshold */ + if ( dist < 64 ) + dist = 64; + else + dist = ( dist + 32 ) & ~63; + } + else + { +/* for horizontal anti-aliased hinting, we adopt a more subtle */ +/* approach: we strengthen small stems, round stems whose size */ +/* is between 1 and 2 pixels to an integer, otherwise nothing */ + if ( dist < 48 ) + dist = ( dist + 64 ) >> 1; + else if ( dist < 128 ) + dist = ( dist + 22 ) & ~63; + else +/* round otherwise to prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & ~63; + } + } + } + Done_Width: + if ( sign ) + dist = -dist; + return dist; + } +/* align one stem edge relative to the previous stem edge */ + static void + af_cjk_align_linked_edge( AF_GlyphHints hints, + AF_Dimension dim, + AF_Edge base_edge, + AF_Edge stem_edge ) + { + FT_Pos dist = stem_edge->opos - base_edge->opos; + FT_Pos fitted_width = af_cjk_compute_stem_width( + hints, dim, dist, + (AF_Edge_Flags)base_edge->flags, + (AF_Edge_Flags)stem_edge->flags ); + stem_edge->pos = base_edge->pos + fitted_width; + } + static void + af_cjk_align_serif_edge( AF_GlyphHints hints, + AF_Edge base, + AF_Edge serif ) + { + FT_UNUSED( hints ); + serif->pos = base->pos + ( serif->opos - base->opos ); + } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** E D G E H I N T I N G ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +#define AF_LIGHT_MODE_MAX_HORZ_GAP 9 +#define AF_LIGHT_MODE_MAX_VERT_GAP 15 +#define AF_LIGHT_MODE_MAX_DELTA_ABS 14 + static FT_Pos + af_hint_normal_stem( AF_GlyphHints hints, + AF_Edge edge, + AF_Edge edge2, + FT_Pos anchor, + AF_Dimension dim ) + { + FT_Pos org_len, cur_len, org_center; + FT_Pos cur_pos1, cur_pos2; + FT_Pos d_off1, u_off1, d_off2, u_off2, delta; + FT_Pos offset; + FT_Pos threshold = 64; + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + { + if ( ( edge->flags & AF_EDGE_ROUND ) && + ( edge2->flags & AF_EDGE_ROUND ) ) + { + if ( dim == AF_DIMENSION_VERT ) + threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP; + else + threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP; + } + else + { + if ( dim == AF_DIMENSION_VERT ) + threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3; + else + threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3; + } + } + org_len = edge2->opos - edge->opos; + cur_len = af_cjk_compute_stem_width( hints, dim, org_len, + (AF_Edge_Flags)edge->flags, + (AF_Edge_Flags)edge2->flags ); + org_center = ( edge->opos + edge2->opos ) / 2 + anchor; + cur_pos1 = org_center - cur_len / 2; + cur_pos2 = cur_pos1 + cur_len; + d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 ); + d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 ); + u_off1 = 64 - d_off1; + u_off2 = 64 - d_off2; + delta = 0; + if ( d_off1 == 0 || d_off2 == 0 ) + goto Exit; + if ( cur_len <= threshold ) + { + if ( d_off2 < cur_len ) + { + if ( u_off1 <= d_off2 ) + delta = u_off1; + else + delta = -d_off2; + } + goto Exit; + } + if ( threshold < 64 ) + { + if ( d_off1 >= threshold || u_off1 >= threshold || + d_off2 >= threshold || u_off2 >= threshold ) + goto Exit; + } + offset = cur_len & 63; + if ( offset < 32 ) + { + if ( u_off1 <= offset || d_off2 <= offset ) + goto Exit; + } + else + offset = 64 - threshold; + d_off1 = threshold - u_off1; + u_off1 = u_off1 - offset; + u_off2 = threshold - d_off2; + d_off2 = d_off2 - offset; + if ( d_off1 <= u_off1 ) + u_off1 = -d_off1; + if ( d_off2 <= u_off2 ) + u_off2 = -d_off2; + if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) ) + delta = u_off1; + else + delta = u_off2; + Exit: +#if 1 + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ) + { + if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS ) + delta = AF_LIGHT_MODE_MAX_DELTA_ABS; + else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS ) + delta = -AF_LIGHT_MODE_MAX_DELTA_ABS; + } +#endif + cur_pos1 += delta; + if ( edge->opos < edge2->opos ) + { + edge->pos = cur_pos1; + edge2->pos = cur_pos1 + cur_len; + } + else + { + edge->pos = cur_pos1 + cur_len; + edge2->pos = cur_pos1; + } + return delta; + } + static void + af_cjk_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + FT_PtrDist n_edges; + AF_Edge edge; + AF_Edge anchor = 0; + FT_Pos delta = 0; + FT_Int skipped = 0; + FT_Bool has_last_stem = FALSE; + FT_Pos last_stem_pos = 0; +/* we begin by aligning all stems relative to the blue zone */ + FT_TRACE5(( "==== cjk hinting %s edges =====\n", + dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" )); + if ( AF_HINTS_DO_BLUES( hints ) ) + { + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Width blue; + AF_Edge edge1, edge2; + if ( edge->flags & AF_EDGE_DONE ) + continue; + blue = edge->blue_edge; + edge1 = NULL; + edge2 = edge->link; + if ( blue ) + { + edge1 = edge; + } + else if ( edge2 && edge2->blue_edge ) + { + blue = edge2->blue_edge; + edge1 = edge2; + edge2 = edge; + } + if ( !edge1 ) + continue; + FT_TRACE5(( "CJKBLUE: edge %d @%d (opos=%.2f) snapped to (%.2f), " + "was (%.2f)\n", + edge1-edges, edge1->fpos, edge1->opos / 64.0, blue->fit / 64.0, + edge1->pos / 64.0 )); + edge1->pos = blue->fit; + edge1->flags |= AF_EDGE_DONE; + if ( edge2 && !edge2->blue_edge ) + { + af_cjk_align_linked_edge( hints, dim, edge1, edge2 ); + edge2->flags |= AF_EDGE_DONE; + } + if ( !anchor ) + anchor = edge; + } + } +/* now we align all stem edges. */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge edge2; + if ( edge->flags & AF_EDGE_DONE ) + continue; +/* skip all non-stem edges */ + edge2 = edge->link; + if ( !edge2 ) + { + skipped++; + continue; + } +/* Some CJK characters have so many stems that + * the hinter is likely to merge two adjacent ones. + * To solve this problem, if either edge of a stem + * is too close to the previous one, we avoid + * aligning the two edges, but rather interpolate + * their locations at the end of this function in + * order to preserve the space between the stems. + */ + if ( has_last_stem && + ( edge->pos < last_stem_pos + 64 || + edge2->pos < last_stem_pos + 64 ) ) + { + skipped++; + continue; + } +/* now align the stem */ +/* this should not happen, but it's better to be safe */ + if ( edge2->blue_edge ) + { + FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges )); + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; + continue; + } + if ( edge2 < edge ) + { + af_cjk_align_linked_edge( hints, dim, edge2, edge ); + edge->flags |= AF_EDGE_DONE; +/* We rarely reaches here it seems; + * usually the two edges belonging + * to one stem are marked as DONE together + */ + has_last_stem = TRUE; + last_stem_pos = edge->pos; + continue; + } + if ( dim != AF_DIMENSION_VERT && !anchor ) + { +#if 0 + if ( fixedpitch ) + { + AF_Edge left = edge; + AF_Edge right = edge_limit - 1; + AF_EdgeRec left1, left2, right1, right2; + FT_Pos target, center1, center2; + FT_Pos delta1, delta2, d1, d2; + while ( right > left && !right->link ) + right--; + left1 = *left; + left2 = *left->link; + right1 = *right->link; + right2 = *right; + delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2; + target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16; + delta1 = delta; + delta1 += af_hint_normal_stem( hints, left, left->link, + delta1, 0 ); + if ( left->link != right ) + af_hint_normal_stem( hints, right->link, right, delta1, 0 ); + center1 = left->pos + ( right->pos - left->pos ) / 2; + if ( center1 >= target ) + delta2 = delta - 32; + else + delta2 = delta + 32; + delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 ); + if ( delta1 != delta2 ) + { + if ( left->link != right ) + af_hint_normal_stem( hints, &right1, &right2, delta2, 0 ); + center2 = left1.pos + ( right2.pos - left1.pos ) / 2; + d1 = center1 - target; + d2 = center2 - target; + if ( FT_ABS( d2 ) < FT_ABS( d1 ) ) + { + left->pos = left1.pos; + left->link->pos = left2.pos; + if ( left->link != right ) + { + right->link->pos = right1.pos; + right->pos = right2.pos; + } + delta1 = delta2; + } + } + delta = delta1; + right->link->flags |= AF_EDGE_DONE; + right->flags |= AF_EDGE_DONE; + } + else +/* 0 */ +#endif + delta = af_hint_normal_stem( hints, edge, edge2, 0, + AF_DIMENSION_HORZ ); + } + else + af_hint_normal_stem( hints, edge, edge2, delta, dim ); +#if 0 + printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n", + edge - edges, edge2 - edges, + ( edge->pos - edge->opos ) / 64.0, + ( edge2->pos - edge2->opos ) / 64.0 ); +#endif + anchor = edge; + edge->flags |= AF_EDGE_DONE; + edge2->flags |= AF_EDGE_DONE; + has_last_stem = TRUE; + last_stem_pos = edge2->pos; + } +/* make sure that lowercase m's maintain their symmetry */ +/* In general, lowercase m's have six vertical edges if they are sans */ +/* serif, or twelve if they are with serifs. This implementation is */ +/* based on that assumption, and seems to work very well with most */ +/* faces. However, if for a certain face this assumption is not */ +/* true, the m is just rendered like before. In addition, any stem */ +/* correction will only be applied to symmetrical glyphs (even if the */ +/* glyph is not an m), so the potential for unwanted distortion is */ +/* relatively low. */ +/* We don't handle horizontal edges since we can't easily assure that */ +/* the third (lowest) stem aligns with the base line; it might end up */ +/* one pixel higher or lower. */ + n_edges = edge_limit - edges; + if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) ) + { + AF_Edge edge1, edge2, edge3; + FT_Pos dist1, dist2, span; + if ( n_edges == 6 ) + { + edge1 = edges; + edge2 = edges + 2; + edge3 = edges + 4; + } + else + { + edge1 = edges + 1; + edge2 = edges + 5; + edge3 = edges + 9; + } + dist1 = edge2->opos - edge1->opos; + dist2 = edge3->opos - edge2->opos; + span = dist1 - dist2; + if ( span < 0 ) + span = -span; + if ( edge1->link == edge1 + 1 && + edge2->link == edge2 + 1 && + edge3->link == edge3 + 1 && span < 8 ) + { + delta = edge3->pos - ( 2 * edge2->pos - edge1->pos ); + edge3->pos -= delta; + if ( edge3->link ) + edge3->link->pos -= delta; +/* move the serifs along with the stem */ + if ( n_edges == 12 ) + { + ( edges + 8 )->pos -= delta; + ( edges + 11 )->pos -= delta; + } + edge3->flags |= AF_EDGE_DONE; + if ( edge3->link ) + edge3->link->flags |= AF_EDGE_DONE; + } + } + if ( !skipped ) + return; +/* + * now hint the remaining edges (serifs and single) in order + * to complete our processing + */ + for ( edge = edges; edge < edge_limit; edge++ ) + { + if ( edge->flags & AF_EDGE_DONE ) + continue; + if ( edge->serif ) + { + af_cjk_align_serif_edge( hints, edge->serif, edge ); + edge->flags |= AF_EDGE_DONE; + skipped--; + } + } + if ( !skipped ) + return; + for ( edge = edges; edge < edge_limit; edge++ ) + { + AF_Edge before, after; + if ( edge->flags & AF_EDGE_DONE ) + continue; + before = after = edge; + while ( --before >= edges ) + if ( before->flags & AF_EDGE_DONE ) + break; + while ( ++after < edge_limit ) + if ( after->flags & AF_EDGE_DONE ) + break; + if ( before >= edges || after < edge_limit ) + { + if ( before < edges ) + af_cjk_align_serif_edge( hints, after, edge ); + else if ( after >= edge_limit ) + af_cjk_align_serif_edge( hints, before, edge ); + else + { + if ( after->fpos == before->fpos ) + edge->pos = before->pos; + else + edge->pos = before->pos + + FT_MulDiv( edge->fpos - before->fpos, + after->pos - before->pos, + after->fpos - before->fpos ); + } + } + } + } + static void + af_cjk_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + FT_Bool snapping; + snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ && + AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) || + ( dim == AF_DIMENSION_VERT && + AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ); + for ( edge = edges; edge < edge_limit; edge++ ) + { +/* move the points of each segment */ +/* in each edge to the edge's position */ + AF_Segment seg = edge->first; + if ( snapping ) + { + do + { + AF_Point point = seg->first; + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + } + if ( point == seg->last ) + break; + point = point->next; + } + seg = seg->edge_next; + } while ( seg != edge->first ); + } + else + { + FT_Pos delta = edge->pos - edge->opos; + do + { + AF_Point point = seg->first; + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x += delta; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y += delta; + point->flags |= AF_FLAG_TOUCH_Y; + } + if ( point == seg->last ) + break; + point = point->next; + } + seg = seg->edge_next; + } while ( seg != edge->first ); + } + } + } + FT_LOCAL_DEF( FT_Error ) + af_cjk_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_CJKMetrics metrics ) + { + FT_Error error; + int dim; + FT_UNUSED( metrics ); + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; +/* analyze glyph outline */ + if ( AF_HINTS_DO_HORIZONTAL( hints ) ) + { + error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ ); + if ( error ) + goto Exit; + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_HORZ ); + } + if ( AF_HINTS_DO_VERTICAL( hints ) ) + { + error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT ); + if ( error ) + goto Exit; + af_cjk_hints_compute_blue_edges( hints, metrics, AF_DIMENSION_VERT ); + } +/* grid-fit the outline */ + for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) + { + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || + ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + { + af_cjk_hint_edges( hints, (AF_Dimension)dim ); + af_cjk_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + } +#if 0 + af_glyph_hints_dump_points( hints ); + af_glyph_hints_dump_segments( hints ); + af_glyph_hints_dump_edges( hints ); +#endif + af_glyph_hints_save( hints, outline ); + Exit: + return error; + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** C J K S C R I P T C L A S S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/* this corresponds to Unicode 6.0 */ + static const AF_Script_UniRangeRec af_cjk_uniranges[] = + { +/* Hangul Jamo */ + AF_UNIRANGE_REC( 0x1100UL, 0x11FFUL ), +/* CJK Radicals Supplement */ + AF_UNIRANGE_REC( 0x2E80UL, 0x2EFFUL ), +/* Kangxi Radicals */ + AF_UNIRANGE_REC( 0x2F00UL, 0x2FDFUL ), +/* Ideographic Description Characters */ + AF_UNIRANGE_REC( 0x2FF0UL, 0x2FFFUL ), +/* CJK Symbols and Punctuation */ + AF_UNIRANGE_REC( 0x3000UL, 0x303FUL ), +/* Hiragana */ + AF_UNIRANGE_REC( 0x3040UL, 0x309FUL ), +/* Katakana */ + AF_UNIRANGE_REC( 0x30A0UL, 0x30FFUL ), +/* Bopomofo */ + AF_UNIRANGE_REC( 0x3100UL, 0x312FUL ), +/* Hangul Compatibility Jamo */ + AF_UNIRANGE_REC( 0x3130UL, 0x318FUL ), +/* Kanbun */ + AF_UNIRANGE_REC( 0x3190UL, 0x319FUL ), +/* Bopomofo Extended */ + AF_UNIRANGE_REC( 0x31A0UL, 0x31BFUL ), +/* CJK Strokes */ + AF_UNIRANGE_REC( 0x31C0UL, 0x31EFUL ), +/* Katakana Phonetic Extensions */ + AF_UNIRANGE_REC( 0x31F0UL, 0x31FFUL ), +/* Enclosed CJK Letters and Months */ + AF_UNIRANGE_REC( 0x3200UL, 0x32FFUL ), +/* CJK Compatibility */ + AF_UNIRANGE_REC( 0x3300UL, 0x33FFUL ), +/* CJK Unified Ideographs Extension A */ + AF_UNIRANGE_REC( 0x3400UL, 0x4DBFUL ), +/* Yijing Hexagram Symbols */ + AF_UNIRANGE_REC( 0x4DC0UL, 0x4DFFUL ), +/* CJK Unified Ideographs */ + AF_UNIRANGE_REC( 0x4E00UL, 0x9FFFUL ), +/* Hangul Jamo Extended-A */ + AF_UNIRANGE_REC( 0xA960UL, 0xA97FUL ), +/* Hangul Syllables */ + AF_UNIRANGE_REC( 0xAC00UL, 0xD7AFUL ), +/* Hangul Jamo Extended-B */ + AF_UNIRANGE_REC( 0xD7B0UL, 0xD7FFUL ), +/* CJK Compatibility Ideographs */ + AF_UNIRANGE_REC( 0xF900UL, 0xFAFFUL ), +/* Vertical forms */ + AF_UNIRANGE_REC( 0xFE10UL, 0xFE1FUL ), +/* CJK Compatibility Forms */ + AF_UNIRANGE_REC( 0xFE30UL, 0xFE4FUL ), +/* Halfwidth and Fullwidth Forms */ + AF_UNIRANGE_REC( 0xFF00UL, 0xFFEFUL ), +/* Kana Supplement */ + AF_UNIRANGE_REC( 0x1B000UL, 0x1B0FFUL ), +/* Tai Xuan Hing Symbols */ + AF_UNIRANGE_REC( 0x1D300UL, 0x1D35FUL ), +/* Enclosed Ideographic Supplement */ + AF_UNIRANGE_REC( 0x1F200UL, 0x1F2FFUL ), +/* CJK Unified Ideographs Extension B */ + AF_UNIRANGE_REC( 0x20000UL, 0x2A6DFUL ), +/* CJK Unified Ideographs Extension C */ + AF_UNIRANGE_REC( 0x2A700UL, 0x2B73FUL ), +/* CJK Unified Ideographs Extension D */ + AF_UNIRANGE_REC( 0x2B740UL, 0x2B81FUL ), +/* CJK Compatibility Ideographs Supplement */ + AF_UNIRANGE_REC( 0x2F800UL, 0x2FA1FUL ), + AF_UNIRANGE_REC( 0UL, 0UL ) + }; + AF_DEFINE_SCRIPT_CLASS( af_cjk_script_class, + AF_SCRIPT_CJK, + af_cjk_uniranges, +/* ç”° */ + 0x7530, + sizeof ( AF_CJKMetricsRec ), + (AF_Script_InitMetricsFunc) af_cjk_metrics_init, + (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale, + (AF_Script_DoneMetricsFunc) NULL, + (AF_Script_InitHintsFunc) af_cjk_hints_init, + (AF_Script_ApplyHintsFunc) af_cjk_hints_apply + ) +/* END */ +/***************************************************************************/ +/* */ +/* afindic.c */ +/* */ +/* Auto-fitter hinting routines for Indic scripts (body). */ +/* */ +/* Copyright 2007, 2011, 2012 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. */ +/* */ +/***************************************************************************/ + static FT_Error + af_indic_metrics_init( AF_CJKMetrics metrics, + FT_Face face ) + { +/* 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 ); + } + FT_Set_Charmap( face, oldmap ); + return AF_Err_Ok; + } + static void + af_indic_metrics_scale( AF_CJKMetrics metrics, + AF_Scaler scaler ) + { +/* use CJK routines */ + af_cjk_metrics_scale( metrics, scaler ); + } + static FT_Error + af_indic_hints_init( AF_GlyphHints hints, + AF_CJKMetrics metrics ) + { +/* use CJK routines */ + return af_cjk_hints_init( hints, metrics ); + } + static FT_Error + af_indic_hints_apply( AF_GlyphHints hints, + FT_Outline* outline, + AF_CJKMetrics metrics ) + { +/* use CJK routines */ + return af_cjk_hints_apply( hints, outline, metrics ); + } +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** I N D I C S C R I P T C L A S S *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ + static const AF_Script_UniRangeRec af_indic_uniranges[] = + { +#if 0 +/* why this? */ + AF_UNIRANGE_REC( 0x0100UL, 0xFFFFUL ), +#endif +/* Indic Range */ + AF_UNIRANGE_REC( 0x0900UL, 0x0DFFUL), +/* Tibetan */ + AF_UNIRANGE_REC( 0x0F00UL, 0x0FFFUL), +/* Limbu */ + AF_UNIRANGE_REC( 0x1900UL, 0x194FUL), +/* Sundanese */ + AF_UNIRANGE_REC( 0x1B80UL, 0x1BBFUL), +/* Meetei Mayak */ + AF_UNIRANGE_REC( 0x1C80UL, 0x1CDFUL), +/* Syloti Nagri */ + AF_UNIRANGE_REC( 0xA800UL, 0xA82FUL), +/* Sharada */ + AF_UNIRANGE_REC( 0x11800UL, 0x118DFUL), + AF_UNIRANGE_REC( 0UL, 0UL) + }; + AF_DEFINE_SCRIPT_CLASS( af_indic_script_class, + AF_SCRIPT_INDIC, + af_indic_uniranges, +/* XXX */ + 'o', + sizeof ( AF_CJKMetricsRec ), + (AF_Script_InitMetricsFunc) af_indic_metrics_init, + (AF_Script_ScaleMetricsFunc)af_indic_metrics_scale, + (AF_Script_DoneMetricsFunc) NULL, + (AF_Script_InitHintsFunc) af_indic_hints_init, + (AF_Script_ApplyHintsFunc) af_indic_hints_apply + ) +/* END */ +/***************************************************************************/ +/* */ +/* afloader.c */ +/* */ +/* Auto-fitter glyph loading routines (body). */ +/* */ +/* Copyright 2003-2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +/* Initialize glyph loader. */ + FT_LOCAL_DEF( FT_Error ) + af_loader_init( AF_Module module ) + { + AF_Loader loader = module->loader; + FT_Memory memory = module->root.library->memory; + FT_ZERO( loader ); + af_glyph_hints_init( &loader->hints, memory ); + return FT_GlyphLoader_New( memory, &loader->gloader ); + } +/* Reset glyph loader and compute globals if necessary. */ + FT_LOCAL_DEF( FT_Error ) + af_loader_reset( AF_Module module, + FT_Face face ) + { + FT_Error error = AF_Err_Ok; + AF_Loader loader = module->loader; + loader->face = face; + loader->globals = (AF_FaceGlobals)face->autohint.data; + FT_GlyphLoader_Rewind( loader->gloader ); + if ( loader->globals == NULL ) + { + error = af_face_globals_new( face, &loader->globals, module ); + if ( !error ) + { + face->autohint.data = + (FT_Pointer)loader->globals; + face->autohint.finalizer = + (FT_Generic_Finalizer)af_face_globals_free; + } + } + return error; + } +/* Finalize glyph loader. */ + FT_LOCAL_DEF( void ) + af_loader_done( AF_Module module ) + { + AF_Loader loader = module->loader; + af_glyph_hints_done( &loader->hints ); + loader->face = NULL; + loader->globals = NULL; + FT_GlyphLoader_Done( loader->gloader ); + loader->gloader = NULL; + } +/* Load a single glyph component. This routine calls itself */ +/* recursively, if necessary, and does the main work of */ +/* `af_loader_load_glyph.' */ + static FT_Error + af_loader_load_g( AF_Loader loader, + AF_Scaler scaler, + FT_UInt glyph_index, + FT_Int32 load_flags, + FT_UInt depth ) + { + FT_Error error; + FT_Face face = loader->face; + FT_GlyphLoader gloader = loader->gloader; + AF_ScriptMetrics metrics = loader->metrics; + AF_GlyphHints hints = &loader->hints; + FT_GlyphSlot slot = face->glyph; + FT_Slot_Internal internal = slot->internal; + FT_Int32 flags; + flags = load_flags | FT_LOAD_LINEAR_DESIGN; + error = FT_Load_Glyph( face, glyph_index, flags ); + if ( error ) + goto Exit; + loader->transformed = internal->glyph_transformed; + if ( loader->transformed ) + { + FT_Matrix inverse; + loader->trans_matrix = internal->glyph_matrix; + loader->trans_delta = internal->glyph_delta; + inverse = loader->trans_matrix; + 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 ); +/* copy the outline points in the loader's current */ +/* extra points which are used to keep original glyph coordinates */ + error = FT_GLYPHLOADER_CHECK_POINTS( gloader, + slot->outline.n_points + 4, + slot->outline.n_contours ); + if ( error ) + goto Exit; + FT_ARRAY_COPY( gloader->current.outline.points, + slot->outline.points, + slot->outline.n_points ); + FT_ARRAY_COPY( gloader->current.outline.contours, + slot->outline.contours, + slot->outline.n_contours ); + FT_ARRAY_COPY( gloader->current.outline.tags, + slot->outline.tags, + slot->outline.n_points ); + gloader->current.outline.n_points = slot->outline.n_points; + gloader->current.outline.n_contours = slot->outline.n_contours; +/* 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 ( metrics->clazz->script_hints_apply ) + metrics->clazz->script_hints_apply( hints, + &gloader->current.outline, + metrics ); +/* 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 ) + { + FT_Pos old_rsb, old_lsb, new_lsb; + FT_Pos pp1x_uh, pp2x_uh; + AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; +/* leftmost edge */ + AF_Edge edge1 = axis->edges; + AF_Edge edge2 = edge1 + +/* rightmost edge */ + axis->num_edges - 1; + if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) + { + old_rsb = loader->pp2.x - edge2->opos; + old_lsb = edge1->opos; + new_lsb = edge1->pos; +/* remember unhinted values to later account */ +/* for rounding errors */ + pp1x_uh = new_lsb - old_lsb; + 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; + } + } + else + { + FT_Pos pp1x = loader->pp1.x; + FT_Pos pp2x = loader->pp2.x; + loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); + loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); + slot->lsb_delta = loader->pp1.x - pp1x; + slot->rsb_delta = loader->pp2.x - pp2x; + } +/* good, we simply add the glyph to our loader's base */ + FT_GlyphLoader_Add( gloader ); + break; + case FT_GLYPH_FORMAT_COMPOSITE: + { + FT_UInt nn, num_subglyphs = slot->num_subglyphs; + FT_UInt num_base_subgs, start_point; + FT_SubGlyph subglyph; + start_point = gloader->base.outline.n_points; +/* first of all, copy the subglyph descriptors in the glyph loader */ + error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); + if ( error ) + goto Exit; + FT_ARRAY_COPY( gloader->current.subglyphs, + slot->subglyphs, + num_subglyphs ); + gloader->current.num_subglyphs = num_subglyphs; + num_base_subgs = gloader->base.num_subglyphs; +/* now read each subglyph independently */ + for ( nn = 0; nn < num_subglyphs; nn++ ) + { + FT_Vector pp1, pp2; + FT_Pos x, y; + FT_UInt num_points, num_new_points, num_base_points; +/* gloader.current.subglyphs can change during glyph loading due */ +/* to re-allocation -- we must recompute the current subglyph on */ +/* each iteration */ + subglyph = gloader->base.subglyphs + num_base_subgs + nn; + pp1 = loader->pp1; + pp2 = loader->pp2; + num_base_points = gloader->base.outline.n_points; + error = af_loader_load_g( loader, scaler, subglyph->index, + load_flags, depth + 1 ); + if ( error ) + goto Exit; +/* recompute subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + nn; + if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) + { + pp1 = loader->pp1; + pp2 = loader->pp2; + } + else + { + loader->pp1 = pp1; + loader->pp2 = pp2; + } + num_points = gloader->base.outline.n_points; + num_new_points = num_points - num_base_points; +/* now perform the transformation required for this subglyph */ + if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | + FT_SUBGLYPH_FLAG_XY_SCALE | + FT_SUBGLYPH_FLAG_2X2 ) ) + { + FT_Vector* cur = gloader->base.outline.points + + num_base_points; + FT_Vector* limit = cur + num_new_points; + for ( ; cur < limit; cur++ ) + FT_Vector_Transform( cur, &subglyph->transform ); + } +/* apply offset */ + if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) + { + FT_Int k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + if ( start_point + k >= num_base_points || + l >= (FT_UInt)num_new_points ) + { + error = AF_Err_Invalid_Composite; + goto Exit; + } + l += num_base_points; +/* for now, only use the current point coordinates; */ +/* we eventually may consider another approach */ + p1 = gloader->base.outline.points + start_point + k; + p2 = gloader->base.outline.points + start_point + l; + x = p1->x - p2->x; + y = p1->y - p2->y; + } + else + { + x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; + y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; + x = FT_PIX_ROUND( x ); + y = FT_PIX_ROUND( y ); + } + { + FT_Outline dummy = gloader->base.outline; + dummy.points += num_base_points; + dummy.n_points = (short)num_new_points; + FT_Outline_Translate( &dummy, x, y ); + } + } + } + break; + default: +/* we don't support other formats (yet?) */ + error = AF_Err_Unimplemented_Feature; + } + Hint_Metrics: + if ( depth == 0 ) + { + 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, metrics->scaler.x_scale ); + vvector.y = FT_MulFix( vvector.y, 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 ); + } +#if 1 +/* 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 ); +#endif + 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 0 + if ( !FT_IS_FIXED_WIDTH( slot->face ) ) + slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + else + slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, + x_scale ); +#else + if ( scaler->render_mode != FT_RENDER_MODE_LIGHT && + ( FT_IS_FIXED_WIDTH( slot->face ) || + ( af_face_globals_is_digit( loader->globals, glyph_index ) && + metrics->digits_have_same_width ) ) ) + { + slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, + 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; + } +#endif + slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, + metrics->scaler.y_scale ); + slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); + slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); +/* now copy outline into glyph slot */ + FT_GlyphLoader_Rewind( internal->loader ); + error = FT_GlyphLoader_CopyPoints( internal->loader, gloader ); + if ( error ) + goto Exit; +/* reassign all outline fields except flags to protect them */ + slot->outline.n_contours = internal->loader->base.outline.n_contours; + slot->outline.n_points = internal->loader->base.outline.n_points; + slot->outline.points = internal->loader->base.outline.points; + slot->outline.tags = internal->loader->base.outline.tags; + slot->outline.contours = internal->loader->base.outline.contours; + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + Exit: + return error; + } +/* Load a glyph. */ + FT_LOCAL_DEF( FT_Error ) + af_loader_load_glyph( AF_Module module, + FT_Face face, + FT_UInt gindex, + FT_Int32 load_flags ) + { + FT_Error error; + FT_Size size = face->size; + AF_Loader loader = module->loader; + AF_ScalerRec scaler; + if ( !size ) + return AF_Err_Invalid_Argument; + FT_ZERO( &scaler ); + scaler.face = face; + scaler.x_scale = size->metrics.x_scale; +/* XXX: TODO: add support for sub-pixel hinting */ + scaler.x_delta = 0; + scaler.y_scale = size->metrics.y_scale; +/* XXX: TODO: add support for sub-pixel hinting */ + scaler.y_delta = 0; + scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); +/* XXX: fix this */ + scaler.flags = 0; + error = af_loader_reset( module, face ); + if ( !error ) + { + AF_ScriptMetrics metrics; + FT_UInt options = 0; +#ifdef FT_OPTION_AUTOFIT2 +/* XXX: undocumented hook to activate the latin2 hinter */ + if ( load_flags & ( 1UL << 20 ) ) + options = 2; +#endif + error = af_face_globals_get_metrics( loader->globals, gindex, + options, &metrics ); + if ( !error ) + { + loader->metrics = metrics; + if ( metrics->clazz->script_metrics_scale ) + metrics->clazz->script_metrics_scale( metrics, &scaler ); + else + metrics->scaler = scaler; + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; + load_flags &= ~FT_LOAD_RENDER; + if ( metrics->clazz->script_hints_init ) + { + error = metrics->clazz->script_hints_init( &loader->hints, + metrics ); + if ( error ) + goto Exit; + } + error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); + } + } + Exit: + return error; + } +/* END */ +/***************************************************************************/ +/* */ +/* afmodule.c */ +/* */ +/* Auto-fitter module implementation (body). */ +/* */ +/* Copyright 2003-2006, 2009, 2011-2012 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. */ +/* */ +/***************************************************************************/ +/***************************************************************************/ +/* */ +/* ftautoh.h */ +/* */ +/* FreeType API for controlling the auto-hinter (specification only). */ +/* */ +/* Copyright 2012 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. */ +/* */ +/***************************************************************************/ +#define __FTAUTOH_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 +FT_BEGIN_HEADER +/************************************************************************** + * + * @section: + * auto_hinter + * + * @title: + * The auto-hinter + * + * @abstract: + * Controlling the auto-hinting module. + * + * @description: + * While FreeType's auto-hinter doesn't expose API functions by itself, + * it is possible to control its behaviour with @FT_Property_Set and + * @FT_Property_Get. The following lists the available properties + * together with the necessary macros and structures. + * + * Note that the auto-hinter's module name is `autofitter' for + * historical reasons. + * + */ +/************************************************************************** + * + * @property: + * glyph-to-script-map + * + * @description: + * The auto-hinter provides various script modules to hint glyphs. + * Examples of supported scripts are Latin or CJK. Before a glyph is + * auto-hinted, the Unicode character map of the font gets examined, and + * the script is then determined based on Unicode character ranges, see + * below. + * + * OpenType fonts, however, often provide much more glyphs than + * character codes (small caps, superscripts, ligatures, swashes, etc.), + * to be controlled by so-called `features'. Handling OpenType features + * can be quite complicated and thus needs a separate library on top of + * FreeType. + * + * The mapping between glyph indices and scripts (in the auto-hinter + * sense, see the @FT_AUTOHINTER_SCRIPT_XXX values) is stored as an + * array with `num_glyphs' elements, as found in the font's @FT_Face + * structure. The `glyph-to-script-map' property returns a pointer to + * this array which can be modified as needed. Note that the + * modification should happen before the first glyph gets processed by + * the auto-hinter so that the global analysis of the font shapes + * actually uses the modified mapping. + * + * The following example code demonstrates how to access it (omitting + * the error handling). + * + * { + * FT_Library library; + * FT_Face face; + * FT_Prop_GlyphToScriptMap prop; + * + * + * FT_Init_FreeType( &library ); + * FT_New_Face( library, "foo.ttf", 0, &face ); + * + * prop.face = face; + * + * FT_Property_Get( library, "autofitter", + * "glyph-to-script-map", &prop ); + * + * // adjust `prop.map' as needed right here + * + * FT_Load_Glyph( face, ..., FT_LOAD_FORCE_AUTOHINT ); + * } + * + */ +/************************************************************************** + * + * @enum: + * FT_AUTOHINTER_SCRIPT_XXX + * + * @description: + * A list of constants used for the @glyph-to-script-map property to + * specify the script submodule the auto-hinter should use for hinting a + * particular glyph. + * + * @values: + * FT_AUTOHINTER_SCRIPT_NONE :: + * Don't auto-hint this glyph. + * + * FT_AUTOHINTER_SCRIPT_LATIN :: + * Apply the latin auto-hinter. For the auto-hinter, `latin' is a + * very broad term, including Cyrillic and Greek also since characters + * from those scripts share the same design constraints. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * { + * U+0020 - U+007F // Basic Latin (no control characters) + * U+00A0 - U+00FF // Latin-1 Supplement (no control characters) + * U+0100 - U+017F // Latin Extended-A + * U+0180 - U+024F // Latin Extended-B + * U+0250 - U+02AF // IPA Extensions + * U+02B0 - U+02FF // Spacing Modifier Letters + * U+0300 - U+036F // Combining Diacritical Marks + * U+0370 - U+03FF // Greek and Coptic + * U+0400 - U+04FF // Cyrillic + * U+0500 - U+052F // Cyrillic Supplement + * U+1D00 - U+1D7F // Phonetic Extensions + * U+1D80 - U+1DBF // Phonetic Extensions Supplement + * U+1DC0 - U+1DFF // Combining Diacritical Marks Supplement + * U+1E00 - U+1EFF // Latin Extended Additional + * U+1F00 - U+1FFF // Greek Extended + * U+2000 - U+206F // General Punctuation + * U+2070 - U+209F // Superscripts and Subscripts + * U+20A0 - U+20CF // Currency Symbols + * U+2150 - U+218F // Number Forms + * U+2460 - U+24FF // Enclosed Alphanumerics + * U+2C60 - U+2C7F // Latin Extended-C + * U+2DE0 - U+2DFF // Cyrillic Extended-A + * U+2E00 - U+2E7F // Supplemental Punctuation + * U+A640 - U+A69F // Cyrillic Extended-B + * U+A720 - U+A7FF // Latin Extended-D + * U+FB00 - U+FB06 // Alphab. Present. Forms (Latin Ligatures) + * U+1D400 - U+1D7FF // Mathematical Alphanumeric Symbols + * U+1F100 - U+1F1FF // Enclosed Alphanumeric Supplement + * } + * + * FT_AUTOHINTER_SCRIPT_CJK :: + * Apply the CJK auto-hinter, covering Chinese, Japanese, Korean, old + * Vietnamese, and some other scripts. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * { + * U+1100 - U+11FF // Hangul Jamo + * U+2E80 - U+2EFF // CJK Radicals Supplement + * U+2F00 - U+2FDF // Kangxi Radicals + * U+2FF0 - U+2FFF // Ideographic Description Characters + * U+3000 - U+303F // CJK Symbols and Punctuation + * U+3040 - U+309F // Hiragana + * U+30A0 - U+30FF // Katakana + * U+3100 - U+312F // Bopomofo + * U+3130 - U+318F // Hangul Compatibility Jamo + * U+3190 - U+319F // Kanbun + * U+31A0 - U+31BF // Bopomofo Extended + * U+31C0 - U+31EF // CJK Strokes + * U+31F0 - U+31FF // Katakana Phonetic Extensions + * U+3200 - U+32FF // Enclosed CJK Letters and Months + * U+3300 - U+33FF // CJK Compatibility + * U+3400 - U+4DBF // CJK Unified Ideographs Extension A + * U+4DC0 - U+4DFF // Yijing Hexagram Symbols + * U+4E00 - U+9FFF // CJK Unified Ideographs + * U+A960 - U+A97F // Hangul Jamo Extended-A + * U+AC00 - U+D7AF // Hangul Syllables + * U+D7B0 - U+D7FF // Hangul Jamo Extended-B + * U+F900 - U+FAFF // CJK Compatibility Ideographs + * U+FE10 - U+FE1F // Vertical forms + * U+FE30 - U+FE4F // CJK Compatibility Forms + * U+FF00 - U+FFEF // Halfwidth and Fullwidth Forms + * U+1B000 - U+1B0FF // Kana Supplement + * U+1D300 - U+1D35F // Tai Xuan Hing Symbols + * U+1F200 - U+1F2FF // Enclosed Ideographic Supplement + * U+20000 - U+2A6DF // CJK Unified Ideographs Extension B + * U+2A700 - U+2B73F // CJK Unified Ideographs Extension C + * U+2B740 - U+2B81F // CJK Unified Ideographs Extension D + * U+2F800 - U+2FA1F // CJK Compatibility Ideographs Supplement + * } + * + * FT_AUTOHINTER_SCRIPT_INDIC :: + * Apply the indic auto-hinter, covering all major scripts from the + * Indian sub-continent and some other related scripts like Thai, Lao, + * or Tibetan. + * + * By default, characters from the following Unicode ranges are + * assigned to this submodule. + * + * { + * U+0900 - U+0DFF // Indic Range + * U+0F00 - U+0FFF // Tibetan + * U+1900 - U+194F // Limbu + * U+1B80 - U+1BBF // Sundanese + * U+1C80 - U+1CDF // Meetei Mayak + * U+A800 - U+A82F // Syloti Nagri + * U+11800 - U+118DF // Sharada + * } + * + * Note that currently Indic support is rudimentary only, missing blue + * zone support. + * + */ +#define FT_AUTOHINTER_SCRIPT_NONE 0 +#define FT_AUTOHINTER_SCRIPT_LATIN 1 +#define FT_AUTOHINTER_SCRIPT_CJK 2 +#define FT_AUTOHINTER_SCRIPT_INDIC 3 +/************************************************************************** + * + * @struct: + * FT_Prop_GlyphToScriptMap + * + * @description: + * The data exchange structure for the @glyph-to-script-map property. + * + */ + typedef struct FT_Prop_GlyphToScriptMap_ + { + FT_Face face; + FT_Byte* map; + } FT_Prop_GlyphToScriptMap; +/************************************************************************** + * + * @property: + * fallback-script + * + * @description: + * If no auto-hinter script module can be assigned to a glyph, a + * fallback script gets assigned to it (see also the + * @glyph-to-script-map property). By default, this is + * @FT_AUTOHINTER_SCRIPT_CJK. Using the `fallback-script' property, + * this fallback value can be changed. + * + * { + * FT_Library library; + * FT_UInt fallback_script = FT_AUTOHINTER_SCRIPT_NONE; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "autofitter", + * "fallback-script", &fallback_script ); + * } + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * It's important to use the right timing for changing this value: The + * creation of the glyph-to-script map which eventually uses the + * fallback script value gets triggered either by setting or reading a + * face-specific property like @glyph-to-script-map, or by auto-hinting + * any glyph from that face. In particular, if you have already created + * an @FT_Face structure but not loaded any glyph (using the + * auto-hinter), a change of the fallback glyph will affect this face. + * + */ +/************************************************************************** + * + * @property: + * increase-x-height + * + * @description: + * For ppem values in the range 6~<= ppem <= `increase-x-height', round + * up the font's x~height much more often than normally. If the value + * is set to~0, which is the default, this feature is switched off. Use + * this property to improve the legibility of small font sizes if + * necessary. + * + * { + * FT_Library library; + * FT_Face face; + * FT_Prop_IncreaseXHeight prop; + * + * + * FT_Init_FreeType( &library ); + * FT_New_Face( library, "foo.ttf", 0, &face ); + * FT_Set_Char_Size( face, 10 * 64, 0, 72, 0 ); + * + * prop.face = face; + * prop.limit = 14; + * + * FT_Property_Set( library, "autofitter", + * "increase-x-height", &prop ); + * } + * + * @note: + * This property can be used with @FT_Property_Get also. + * + * Set this value right after calling @FT_Set_Char_Size, but before + * loading any glyph (using the auto-hinter). + * + */ +/************************************************************************** + * + * @struct: + * FT_Prop_IncreaseXHeight + * + * @description: + * The data exchange structure for the @increase-x-height property. + * + */ + typedef struct FT_Prop_IncreaseXHeight_ + { + FT_Face face; + FT_UInt limit; + } FT_Prop_IncreaseXHeight; +/* */ +FT_END_HEADER +/* END */ +/*************************************************************************/ +/* */ +/* 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 trace_afmodule + FT_Error + af_property_get_face_globals( FT_Face face, + AF_FaceGlobals* aglobals, + AF_Module module ) + { + FT_Error error = AF_Err_Ok; + AF_FaceGlobals globals; + if ( !face ) + return AF_Err_Invalid_Argument; + globals = (AF_FaceGlobals)face->autohint.data; + if ( !globals ) + { +/* trigger computation of the global script 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 = + (FT_Generic_Finalizer)af_face_globals_free; + } + } + if ( !error ) + *aglobals = globals; + return error; + } + FT_Error + af_property_set( FT_Module ft_module, + const char* property_name, + const void* value ) + { + FT_Error error = AF_Err_Ok; + AF_Module module = (AF_Module)ft_module; + if ( !ft_strcmp( property_name, "fallback-script" ) ) + { + FT_UInt* fallback_script = (FT_UInt*)value; + module->fallback_script = *fallback_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 ) + globals->increase_x_height = prop->limit; + return error; + } + FT_TRACE0(( "af_property_get: missing property `%s'\n", + property_name )); + return AF_Err_Missing_Property; + } + FT_Error + af_property_get( FT_Module ft_module, + const char* property_name, + void* value ) + { + FT_Error error = AF_Err_Ok; + AF_Module module = (AF_Module)ft_module; + FT_UInt fallback_script = module->fallback_script; + 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_scripts; + return error; + } + else if ( !ft_strcmp( property_name, "fallback-script" ) ) + { + FT_UInt* val = (FT_UInt*)value; + *val = fallback_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; + } + FT_TRACE0(( "af_property_get: missing property `%s'\n", + property_name )); + return AF_Err_Missing_Property; + } + FT_DEFINE_SERVICE_PROPERTIESREC( + af_service_properties, + (FT_Properties_SetFunc)af_property_set, + (FT_Properties_GetFunc)af_property_get ) + FT_DEFINE_SERVICEDESCREC1( + af_services, + FT_SERVICE_ID_PROPERTIES, &AF_SERVICE_PROPERTIES_GET ) + FT_CALLBACK_DEF( FT_Module_Interface ) + af_get_interface( FT_Module module, + const char* module_interface ) + { +/* AF_SERVICES_GET derefers `library' in PIC mode */ + FT_UNUSED( module ); + return ft_service_list_lookup( AF_SERVICES_GET, module_interface ); + } + FT_CALLBACK_DEF( FT_Error ) + af_autofitter_init( AF_Module module ) + { + module->fallback_script = AF_SCRIPT_FALLBACK; + return af_loader_init( module ); + } + FT_CALLBACK_DEF( void ) + af_autofitter_done( AF_Module module ) + { + af_loader_done( module ); + } + FT_CALLBACK_DEF( FT_Error ) + af_autofitter_load_glyph( AF_Module module, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + FT_UNUSED( size ); + return af_loader_load_glyph( module, slot->face, + glyph_index, load_flags ); + } + FT_DEFINE_AUTOHINTER_INTERFACE( + af_autofitter_interface, +/* reset_face */ + NULL, +/* get_global_hints */ + NULL, +/* done_global_hints */ + NULL, +/* load_glyph */ + (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph ) + FT_DEFINE_MODULE( + autofit_module_class, + FT_MODULE_HINTER, + sizeof ( AF_ModuleRec ), + "autofitter", +/* version 1.0 of the autofitter */ + 0x10000L, +/* requires FreeType 2.0 or above */ + 0x20000L, + (const void*)&AF_INTERFACE_GET, + (FT_Module_Constructor)af_autofitter_init, + (FT_Module_Destructor) af_autofitter_done, + (FT_Module_Requester) af_get_interface ) +/* END */ +/* END */ diff --git a/examples/10-font_alpha/basics.cpp b/examples/10-font_alpha/basics.cpp new file mode 100644 index 00000000..6e594fdb --- /dev/null +++ b/examples/10-font_alpha/basics.cpp @@ -0,0 +1,207 @@ +#include <bgfx.h> +#include <bx/bx.h> +#include <bx/timer.h> +#include "../common/entry.h" +#include "../common/dbg.h" +#include "../common/math.h" +#include "../common/processevents.h" + +#include "../common/font/font_manager.h" +#include "../common/font/text_buffer_manager.h" + +#include <stdio.h> +#include <string.h> + +static const char* s_shaderPath = NULL; + +int _main_(int /*_argc*/, char** /*_argv*/) +{ + uint32_t width = 1280; + uint32_t height = 720; + uint32_t debug = BGFX_DEBUG_TEXT; + uint32_t reset = 0; + + bgfx::init(); + + + bgfx::reset(width, height); + + // Enable debug text. + bgfx::setDebug(debug); + + // Set view 0 clear state. + bgfx::setViewClear(0 + , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT + , 0x303030ff + , 1.0f + , 0 + ); + + // Setup root path for binary shaders. Shader binaries are different + // for each renderer. + switch (bgfx::getRendererType() ) + { + default: + case bgfx::RendererType::Direct3D9: + s_shaderPath = "shaders/dx9/"; + break; + + case bgfx::RendererType::Direct3D11: + s_shaderPath = "shaders/dx11/"; + break; + + case bgfx::RendererType::OpenGL: + s_shaderPath = "shaders/glsl/"; + break; + + case bgfx::RendererType::OpenGLES2: + case bgfx::RendererType::OpenGLES3: + s_shaderPath = "shaders/gles/"; + break; + } + + //init the text rendering system + bgfx_font::FontManager* fontManager = new bgfx_font::FontManager(512); + bgfx_font::TextBufferManager* textBufferManager = new bgfx_font::TextBufferManager(fontManager); + textBufferManager->init(s_shaderPath); + + + //load some truetype files + bgfx_font::TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); + bgfx_font::TrueTypeHandle consola_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/consola.ttf"); + + //create some usable font with of a specific size + bgfx_font::FontHandle times_24 = fontManager->createFontByPixelSize(times_tt, 0, 24); + + //preload glyphs and blit them to atlas + fontManager->preloadGlyph(times_24, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); + + //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph + fontManager->unloadTrueType(times_tt); + + //this font doesn't have any preloaded glyph's but the truetype file is loaded + //so glyph will be generated as needed + bgfx_font::FontHandle consola_16 = fontManager->createFontByPixelSize(consola_tt, 0, 16); + + //create a static text buffer compatible with alpha font + //a static text buffer content cannot be modified after its first submit. + bgfx_font::TextBufferHandle staticText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_ALPHA, bgfx_font::STATIC); + + //the pen position represent the top left of the box of the first line of text + textBufferManager->setPenPosition(staticText, 20.0f, 100.0f); + + //add some text to the buffer + textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); + //the position of the pen is adjusted when there is an endline + + //setup style colors + textBufferManager->setBackgroundColor(staticText, 0x551111FF); + textBufferManager->setUnderlineColor(staticText, 0xFF2222FF); + textBufferManager->setOverlineColor(staticText, 0x2222FFFF); + textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); + + + //text + bkg + textBufferManager->setStyle(staticText, bgfx_font::STYLE_BACKGROUND); + textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); + + //text + strike-through + textBufferManager->setStyle(staticText, bgfx_font::STYLE_STRIKE_THROUGH); + textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); + + //text + overline + textBufferManager->setStyle(staticText, bgfx_font::STYLE_OVERLINE); + textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); + + //text + underline + textBufferManager->setStyle(staticText, bgfx_font::STYLE_UNDERLINE); + textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); + + + //text + bkg + strike-through + textBufferManager->setStyle(staticText, bgfx_font::STYLE_BACKGROUND|bgfx_font::STYLE_STRIKE_THROUGH); + textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); + + //create a transient buffer for realtime data + bgfx_font::TextBufferHandle transientText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_ALPHA, bgfx_font::TRANSIENT); + + + uint32_t w = 0,h = 0; + while (!processEvents(width, height, debug, reset) ) + { + + if(w!=width|| h!=height) + { + w=width; + h= height; + printf("ri: %d,%d\n",width,height); + } + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, width, height); + + // This dummy draw call is here to make sure that view 0 is cleared + // if no other draw calls are submitted to view 0. + bgfx::submit(0); + + int64_t now = bx::getHPCounter(); + static int64_t last = now; + const int64_t frameTime = now - last; + last = now; + + const double freq = double(bx::getHPFrequency() ); + const double toMs = 1000.0/freq; + //float time = (float)(bx::getHPCounter()/double(bx::getHPFrequency() ) ); + + float at[3] = { 0, 0, 0.0f }; + float eye[3] = {0, 0, -1.0f }; + + float view[16]; + float proj[16]; + mtxLookAt(view, eye, at); + //setup a top-left ortho matrix for screen space drawing + float centering = 0.5f; + mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + + // Set view and projection matrix for view 0. + bgfx::setViewTransform(0, view, proj); + + //submit the static text + textBufferManager->submitTextBuffer(staticText, 0); + + + //submit some realtime text + wchar_t fpsText[64]; + swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); + + textBufferManager->clearTextBuffer(transientText); + textBufferManager->setPenPosition(transientText, 20.0, 4.0f); + + textBufferManager->appendText(transientText, consola_16, L"bgfx_font\\sample\\01_basics\n"); + textBufferManager->appendText(transientText, consola_16, L"Description: truetype, font, text and style\n"); + textBufferManager->appendText(transientText, consola_16, fpsText); + + textBufferManager->submitTextBuffer(transientText, 0); + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + //just to prevent my CG Fan to howl + Sleep(2); + } + + + fontManager->unloadTrueType(consola_tt); + fontManager->destroyFont(consola_16); + fontManager->destroyFont(times_24); + + textBufferManager->destroyTextBuffer(staticText); + textBufferManager->destroyTextBuffer(transientText); + + delete textBufferManager; + delete fontManager; + + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; +} diff --git a/examples/11-font_distance_field/distance_field_text.cpp b/examples/11-font_distance_field/distance_field_text.cpp new file mode 100644 index 00000000..ba00dcad --- /dev/null +++ b/examples/11-font_distance_field/distance_field_text.cpp @@ -0,0 +1,160 @@ +#include <bgfx.h> +#include <bx/bx.h> +#include <bx/timer.h> +#include "../common/entry.h" +#include "../common/dbg.h" +#include "../common/math.h" +#include "../common/processevents.h" + +#include "../common/font/font_manager.h" +#include "../common/font/text_buffer_manager.h" + +#include <stdio.h> +#include <string.h> + +static const char* s_shaderPath = NULL; + +int _main_(int /*_argc*/, char** /*_argv*/) +{ + uint32_t width = 1280; + uint32_t height = 720; + uint32_t debug = BGFX_DEBUG_TEXT; + uint32_t reset = 0; + + bgfx::init(); + + bgfx::reset(width, height); + + // Enable debug text. + bgfx::setDebug(debug); + + // Set view 0 clear state. + bgfx::setViewClear(0 + , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT + //, 0x303030ff + //, 0xffffffff + , 0x000000FF + , 1.0f + , 0 + ); + + // Setup root path for binary shaders. Shader binaries are different + // for each renderer. + switch (bgfx::getRendererType() ) + { + default: + case bgfx::RendererType::Direct3D9: + s_shaderPath = "shaders/dx9/"; + break; + + case bgfx::RendererType::Direct3D11: + s_shaderPath = "shaders/dx11/"; + break; + + case bgfx::RendererType::OpenGL: + s_shaderPath = "shaders/glsl/"; + break; + + case bgfx::RendererType::OpenGLES2: + case bgfx::RendererType::OpenGLES3: + s_shaderPath = "shaders/gles/"; + break; + } + + //init the text rendering system + bgfx_font::FontManager* fontManager = new bgfx_font::FontManager(512); + bgfx_font::TextBufferManager* textBufferManager = new bgfx_font::TextBufferManager(fontManager); + textBufferManager->init(s_shaderPath); + + //load a truetype files + bgfx_font::TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); + bgfx_font::FontHandle distance_font = fontManager->createFontByPixelSize(times_tt, 0, 48, bgfx_font::FONT_TYPE_DISTANCE); + //preload glyph and generate (generate bitmap's) + fontManager->preloadGlyph(distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); + + uint32_t fontsCount = 0; + bgfx_font::FontHandle fonts[64]; + fonts[fontsCount++] = distance_font; + //generate various sub distance field fonts at various size + int step=4; + for(int i = 64; i>1 ; i-=step) + { + if(i<32) step = 2; + //instantiate a usable font + bgfx_font::FontHandle font = fontManager->createScaledFontToPixelSize(distance_font, i); + fonts[fontsCount++] = font; + } + //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph + fontManager->unloadTrueType(times_tt); + + bgfx_font::TextBufferHandle staticText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_DISTANCE, bgfx_font::STATIC); + + textBufferManager->setPenPosition(staticText, 10.0f, 10.0f); + textBufferManager->setTextColor(staticText, 0xFFFFFFFF); + //textBufferManager->setTextColor(staticText, 0x000000FF); + for(size_t i = 0; i< fontsCount; ++i) + { + textBufferManager->appendText(staticText, fonts[i], L"The quick brown fox jumps over the lazy dog\n"); + //textBufferManager->appendText(staticText, fonts[i], L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); + } + + while (!processEvents(width, height, debug, reset) ) + { + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, width, height); + + // This dummy draw call is here to make sure that view 0 is cleared + // if no other draw calls are submitted to view 0. + bgfx::submit(0); + + //int64_t now = bx::getHPCounter(); + //static int64_t last = now; + //const int64_t frameTime = now - last; + //last = now; + //const double freq = double(bx::getHPFrequency() ); + //const double toMs = 1000.0/freq; + //float time = (float)(bx::getHPCounter()/double(bx::getHPFrequency() ) ); + + // Use debug font to print information about this example. + bgfx::dbgTextClear(); + //bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/00-helloworld"); + //bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Initialization and debug text."); + //bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + + float at[3] = { 0, 0, 0.0f }; + float eye[3] = {0, 0, -1.0f }; + + float view[16]; + float proj[16]; + mtxLookAt(view, eye, at); + float centering = 0.5f; + //setup a top-left ortho matrix for screen space drawing + mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + + // Set view and projection matrix for view 0. + bgfx::setViewTransform(0, view, proj); + + //draw your text + textBufferManager->submitTextBuffer(staticText, 0); + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + //just to prevent my CG Fan to howl + Sleep(2); + } + + //destroy the fonts + for(size_t i=0; i<fontsCount;++i) + { + fontManager->destroyFont(fonts[i]); + } + + textBufferManager->destroyTextBuffer(staticText); + delete textBufferManager; + delete fontManager; + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; +} diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp new file mode 100644 index 00000000..3f705807 --- /dev/null +++ b/examples/common/cube_atlas.cpp @@ -0,0 +1,483 @@ +/* Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause +*/ +#pragma once +#include <bgfx.h> +#include <assert.h> +#include <vector> +#include "cube_atlas.h" + +namespace bgfx +{ + +//********** Rectangle packer implementation ************ +class RectanglePacker +{ +public: + RectanglePacker(); + RectanglePacker(uint32_t width, uint32_t height); + + /// non constructor initialization + void init(uint32_t width, uint32_t height); + /// find a suitable position for the given rectangle + /// @return true if the rectangle can be added, false otherwise + bool addRectangle(uint16_t width, uint16_t height, uint16_t& outX, uint16_t& outY ); + /// return the used surface in squared unit + uint32_t getUsedSurface() { return m_usedSpace; } + /// return the total available surface in squared unit + uint32_t getTotalSurface() { return m_width*m_height; } + /// return the usage ratio of the available surface [0:1] + float getUsageRatio(); + /// reset to initial state + void clear(); + +private: + int32_t fit(uint32_t skylineNodeIndex, uint16_t width, uint16_t height); + /// Merges all skyline nodes that are at the same level. + void merge(); + + struct Node + { + Node(int16_t _x, int16_t _y, int16_t _width):x(_x), y(_y), width(_width) {} + + /// The starting x-coordinate (leftmost). + int16_t x; + /// The y-coordinate of the skyline level line. + int16_t y; + /// The line width. The ending coordinate (inclusive) will be x+width-1. + int32_t width; //32bit to avoid padding + }; + + /// Width (in pixels) of the underlying texture + uint32_t m_width; + /// Height (in pixels) of the underlying texture + uint32_t m_height; + /// Surface used in squared pixel + uint32_t m_usedSpace; + /// node of the skyline algorithm + std::vector<Node> m_skyline; +}; + +RectanglePacker::RectanglePacker(): m_width(0), m_height(0), m_usedSpace(0) +{ +} + +RectanglePacker::RectanglePacker(uint32_t width, uint32_t height):m_width(width), m_height(height), m_usedSpace(0) +{ + // We want a one pixel border around the whole atlas to avoid any artefact when + // sampling texture + m_skyline.push_back(Node(1,1, width-2)); +} + +void RectanglePacker::init(uint32_t width, uint32_t height) +{ + assert(width > 2); + assert(height > 2); + m_width = width; + m_height = height; + m_usedSpace = 0; + + m_skyline.clear(); + // We want a one pixel border around the whole atlas to avoid any artifact when + // sampling texture + m_skyline.push_back(Node(1,1, width-2)); +} + +bool RectanglePacker::addRectangle(uint16_t width, uint16_t height, uint16_t& outX, uint16_t& outY) +{ + int y, best_height, best_index; + int32_t best_width; + Node* node; + Node* prev; + outX = 0; + outY = 0; + + size_t i; + + best_height = INT_MAX; + best_index = -1; + best_width = INT_MAX; + for( i = 0; i < m_skyline.size(); ++i ) + { + y = fit( i, width, height ); + if( y >= 0 ) + { + node = &m_skyline[i]; + if( ( (y + height) < best_height ) || + ( ((y + height) == best_height) && (node->width < best_width)) ) + { + best_height = y + height; + best_index = i; + best_width = node->width; + outX = node->x; + outY = y; + } + } + } + + if( best_index == -1 ) + { + return false; + } + + Node newNode(outX,outY + height, width); + m_skyline.insert(m_skyline.begin() + best_index, newNode); + + for(i = best_index+1; i < m_skyline.size(); ++i) + { + node = &m_skyline[i]; + prev = &m_skyline[i-1]; + if (node->x < (prev->x + prev->width) ) + { + int shrink = prev->x + prev->width - node->x; + node->x += shrink; + node->width -= shrink; + if (node->width <= 0) + { + m_skyline.erase(m_skyline.begin() + i); + --i; + } + else + { + break; + } + } + else + { + break; + } + } + + merge(); + m_usedSpace += width * height; + return true; +} + +float RectanglePacker::getUsageRatio() +{ + uint32_t total = m_width*m_height; + if(total > 0) + return (float) m_usedSpace / (float) total; + else + return 0.0f; +} + +void RectanglePacker::clear() +{ + m_skyline.clear(); + m_usedSpace = 0; + + // We want a one pixel border around the whole atlas to avoid any artefact when + // sampling texture + m_skyline.push_back(Node(1,1, m_width-2)); +} + +int32_t RectanglePacker::fit(uint32_t skylineNodeIndex, uint16_t _width, uint16_t _height) +{ + int32_t width = _width; + int32_t height = _height; + + const Node& baseNode = m_skyline[skylineNodeIndex]; + + int32_t x = baseNode.x, y; + int32_t width_left = width; + int32_t i = skylineNodeIndex; + + if ( (x + width) > (int32_t)(m_width-1) ) + { + return -1; + } + y = baseNode.y; + while( width_left > 0 ) + { + const Node& node = m_skyline[i]; + if( node.y > y ) + { + y = node.y; + } + if( (y + height) > (int32_t)(m_height-1) ) + { + return -1; + } + width_left -= node.width; + ++i; + } + return y; +} + +void RectanglePacker::merge() +{ + Node* node; + Node* next; + uint32_t i; + + for( i=0; i < m_skyline.size()-1; ++i ) + { + node = (Node *) &m_skyline[i]; + next = (Node *) &m_skyline[i+1]; + if( node->y == next->y ) + { + node->width += next->width; + m_skyline.erase(m_skyline.begin() + i + 1); + --i; + } + } +} + +//********** Cube Atlas implementation ************ + +struct Atlas::PackedLayer +{ + RectanglePacker packer; + AtlasRegion faceRegion; +}; + +Atlas::Atlas(uint16_t textureSize, uint16_t maxRegionsCount ) +{ + assert(textureSize >= 64 && textureSize <= 4096 && "suspicious texture size" ); + assert(maxRegionsCount >= 64 && maxRegionsCount <= 32000 && "suspicious regions count" ); + m_layers = new PackedLayer[24]; + for(int i=0; i<24;++i) + { + m_layers[i].packer.init(textureSize, textureSize); + } + m_usedLayers = 0; + m_usedFaces = 0; + + m_textureSize = textureSize; + m_regionCount = 0; + m_maxRegionCount = maxRegionsCount; + m_regions = new AtlasRegion[maxRegionsCount]; + m_textureBuffer = new uint8_t[ textureSize * textureSize * 6 * 4 ]; + memset(m_textureBuffer, 0, textureSize * textureSize * 6 * 4); + //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; + //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT + //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP + uint32_t flags = 0;// BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; + + //Uncomment this to debug atlas + //const bgfx::Memory* mem = bgfx::alloc(textureSize*textureSize * 6 * 4); + //memset(mem->data, 255, mem->size); + const bgfx::Memory* mem = NULL; + m_textureHandle = bgfx::createTextureCube(6 + , textureSize + , 1 + , bgfx::TextureFormat::BGRA8 + , flags + ,mem + ); +} + +Atlas::Atlas(uint16_t textureSize, const uint8_t* textureBuffer , uint16_t regionCount, const uint8_t* regionBuffer, uint16_t maxRegionsCount) +{ + assert(regionCount <= 64 && maxRegionsCount <= 4096); + //layers are frozen + m_usedLayers = 24; + m_usedFaces = 6; + + m_textureSize = textureSize; + m_regionCount = regionCount; + //regions are frozen + m_maxRegionCount = regionCount; + m_regions = new AtlasRegion[regionCount]; + m_textureBuffer = new uint8_t[getTextureBufferSize()]; + + //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; + //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT + //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP + uint32_t flags = 0;//BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; + memcpy(m_regions, regionBuffer, regionCount * sizeof(AtlasRegion)); + memcpy(m_textureBuffer, textureBuffer, getTextureBufferSize()); + + m_textureHandle = bgfx::createTextureCube(6 + , textureSize + , 1 + , bgfx::TextureFormat::BGRA8 + , flags + , bgfx::makeRef(m_textureBuffer, getTextureBufferSize()) + ); +} + +Atlas::~Atlas() +{ + delete[] m_layers; + delete[] m_regions; + delete[] m_textureBuffer; +} + +uint16_t Atlas::addRegion(uint16_t width, uint16_t height, const uint8_t* bitmapBuffer, AtlasRegion::Type type) +{ + if (m_regionCount >= m_maxRegionCount) + { + return UINT16_MAX; + } + + uint16_t x,y; + // We want each bitmap to be separated by at least one black pixel + // TODO manage mipmaps + uint32_t idx = 0; + while(idx<m_usedLayers) + { + if(m_layers[idx].faceRegion.getType() == type) + { + if(m_layers[idx].packer.addRectangle(width+1,height+1,x,y)) break; + } + idx++; + } + + if(idx >= m_usedLayers) + { + //do we have still room to add layers ? + if( (idx + type) > 24 || m_usedFaces>=6) + { + return UINT16_MAX; + } + //create new layers + for(int i=0; i < type;++i) + { + m_layers[idx+i].faceRegion.setMask(type, m_usedFaces, i); + } + m_usedLayers += type; + m_usedFaces++; + + + //add it to the created layer + if(!m_layers[idx].packer.addRectangle(width+1,height+1,x,y)) + { + return UINT16_MAX; + } + } + + AtlasRegion& region = m_regions[m_regionCount]; + region.x = x; + region.y = y; + region.width = width; + region.height = height; + region.mask = m_layers[idx].faceRegion.mask; + + updateRegion(region, bitmapBuffer); + return m_regionCount++; +} + +void Atlas::updateRegion(const AtlasRegion& region, const uint8_t* bitmapBuffer) +{ + const bgfx::Memory* mem = bgfx::alloc(region.width * region.height * 4); + //BAD! + memset(mem->data,0, mem->size); + if(region.getType() == AtlasRegion::TYPE_BGRA8) + { + const uint8_t* inLineBuffer = bitmapBuffer; + uint8_t* outLineBuffer = m_textureBuffer + region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((region.y *m_textureSize)+region.x)*4); + + //update the cpu buffer + for(int y = 0; y < region.height; ++y) + { + memcpy(outLineBuffer, inLineBuffer, region.width * 4); + inLineBuffer += region.width*4; + outLineBuffer += m_textureSize*4; + } + //update the GPU buffer + memcpy(mem->data, bitmapBuffer, mem->size); + }else + { + uint32_t layer = region.getComponentIndex(); + uint32_t face = region.getFaceIndex(); + const uint8_t* inLineBuffer = bitmapBuffer; + uint8_t* outLineBuffer = (m_textureBuffer + region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((region.y *m_textureSize)+region.x)*4)); + + //update the cpu buffer + for(int y = 0; y<region.height; ++y) + { + for(int x = 0; x<region.width; ++x) + { + outLineBuffer[(x*4) + layer] = inLineBuffer[x]; + } + //update the GPU buffer + memcpy(mem->data + y*region.width*4, outLineBuffer, region.width*4); + inLineBuffer += region.width; + outLineBuffer += m_textureSize*4; + } + } + bgfx::updateTextureCube(m_textureHandle, (uint8_t)region.getFaceIndex(), 0, region.x, region.y, region.width, region.height, mem); +} + +void Atlas::packFaceLayerUV(uint32_t idx, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ) +{ + packUV(m_layers[idx].faceRegion, vertexBuffer, offset, stride); +} + +void Atlas::packUV( uint16_t handle, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ) +{ + const AtlasRegion& region = m_regions[handle]; + packUV(region, vertexBuffer, offset, stride); +} + +void Atlas::packUV( const AtlasRegion& region, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ) +{ + float texMult = 65535.0f / ((float)(m_textureSize)); + static const int16_t minVal = -32768; + static const int16_t maxVal = 32767; + + int16_t x0 = (int16_t)(region.x * texMult)-32768; + int16_t y0 = (int16_t)(region.y * texMult)-32768; + int16_t x1 = (int16_t)((region.x + region.width)* texMult)-32768; + int16_t y1 = (int16_t)((region.y + region.height)* texMult)-32768; + int16_t w = (int16_t) ((32767.0f/4.0f) * region.getComponentIndex()); + + vertexBuffer+=offset; + switch(region.getFaceIndex()) + { + case 0: // +X + x0= -x0; + x1= -x1; + y0= -y0; + y1= -y1; + writeUV(vertexBuffer, maxVal, y0, x0, w); vertexBuffer+=stride; + writeUV(vertexBuffer, maxVal, y1, x0, w); vertexBuffer+=stride; + writeUV(vertexBuffer, maxVal, y1, x1, w); vertexBuffer+=stride; + writeUV(vertexBuffer, maxVal, y0, x1, w); vertexBuffer+=stride; + break; + case 1: // -X + y0= -y0; + y1= -y1; + writeUV(vertexBuffer, minVal, y0, x0, w); vertexBuffer+=stride; + writeUV(vertexBuffer, minVal, y1, x0, w); vertexBuffer+=stride; + writeUV(vertexBuffer, minVal, y1, x1, w); vertexBuffer+=stride; + writeUV(vertexBuffer, minVal, y0, x1, w); vertexBuffer+=stride; + break; + case 2: // +Y + writeUV(vertexBuffer, x0, maxVal, y0, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x0, maxVal, y1, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, maxVal, y1, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, maxVal, y0, w); vertexBuffer+=stride; + break; + case 3: // -Y + y0= -y0; + y1= -y1; + writeUV(vertexBuffer, x0, minVal, y0, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x0, minVal, y1, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, minVal, y1, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, minVal, y0, w); vertexBuffer+=stride; + break; + case 4: // +Z + y0= -y0; + y1= -y1; + writeUV(vertexBuffer, x0, y0, maxVal, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x0, y1, maxVal, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, y1, maxVal, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, y0, maxVal, w); vertexBuffer+=stride; + break; + case 5: // -Z + x0= -x0; + x1= -x1; + y0= -y0; + y1= -y1; + writeUV(vertexBuffer, x0, y0, minVal, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x0, y1, minVal, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, y1, minVal, w); vertexBuffer+=stride; + writeUV(vertexBuffer, x1, y0, minVal, w); vertexBuffer+=stride; + break; + } +} + +} \ No newline at end of file diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h new file mode 100644 index 00000000..70b10eaf --- /dev/null +++ b/examples/common/cube_atlas.h @@ -0,0 +1,136 @@ +/* Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause +*/ +#pragma once + +/// Inspired from texture-atlas from freetype-gl (http://code.google.com/p/freetype-gl/) +/// by Nicolas Rougier (Nicolas.Rougier@inria.fr) +/// The actual implementation is based on the article by Jukka Jylänki : "A +/// Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional +/// Rectangle Bin Packing", February 27, 2010. +/// More precisely, this is an implementation of the Skyline Bottom-Left +/// algorithm based on C++ sources provided by Jukka Jylänki at: +/// http://clb.demon.fi/files/RectangleBinPack/ + +#include <bgfx.h> + +namespace bgfx +{ + +struct AtlasRegion +{ + enum Type + { + TYPE_GRAY = 1, // 1 component + TYPE_BGRA8 = 4 // 4 components + }; + + uint16_t x, y; + uint16_t width, height; + uint32_t mask; //encode the region type, the face index and the component index in case of a gray region + + Type getType()const { return (Type) ((mask >> 0) & 0x0000000F); } + uint32_t getFaceIndex()const { return (mask >> 4) & 0x0000000F; } + uint32_t getComponentIndex()const { return (mask >> 8) & 0x0000000F; } + void setMask(Type type, uint32_t faceIndex, uint32_t componentIndex) { mask = (componentIndex << 8) + (faceIndex << 4) + (uint32_t)type; } +}; + +class Atlas +{ +public: + /// create an empty dynamic atlas (region can be updated and added) + /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) + /// @param maxRegionCount maximum number of region allowed in the atlas + Atlas(uint16_t textureSize, uint16_t _maxRegionsCount = 4096); + + /// initialize a static atlas with serialized data (region can be updated but not added) + /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) + /// @param textureBuffer buffer of size 6*textureSize*textureSize*sizeof(uint32_t) (will be copied) + /// @param regionCount number of region in the Atlas + /// @param regionBuffer buffer containing the region (will be copied) + /// @param maxRegionCount maximum number of region allowed in the atlas + Atlas(uint16_t textureSize, const uint8_t * textureBuffer, uint16_t regionCount, const uint8_t* regionBuffer, uint16_t maxRegionsCount = 4096); + ~Atlas(); + + /// add a region to the atlas, and copy the content of mem to the underlying texture + uint16_t addRegion(uint16_t width, uint16_t height, const uint8_t* bitmapBuffer, AtlasRegion::Type type = AtlasRegion::TYPE_BGRA8); + + /// update a preallocated region + void updateRegion(const AtlasRegion& region, const uint8_t* bitmapBuffer); + + /// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format. + /// v0 -- v3 + /// | | encoded in that order: v0,v1,v2,v3 + /// v1 -- v2 + /// @remark the UV are four signed short normalized components. + /// @remark the x,y,z components encode cube uv coordinates. The w component encode the color channel if any. + /// @param handle handle to the region we are interested in + /// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first. + /// @param offset byte offset to the first uv coordinate of the vertex in the buffer + /// @param stride stride between tho UV coordinates, usually size of a Vertex. + void packUV( uint16_t regionHandle, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ); + void packUV( const AtlasRegion& region, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ); + + /// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas + void packFaceLayerUV(uint32_t idx, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ); + + /// Pack the vertex index of the region as 2 quad into an index buffer + void packIndex(uint16_t* indexBuffer, uint32_t startIndex, uint32_t startVertex ) + { + indexBuffer[startIndex+0] = startVertex+0; + indexBuffer[startIndex+1] = startVertex+1; + indexBuffer[startIndex+2] = startVertex+2; + indexBuffer[startIndex+3] = startVertex+0; + indexBuffer[startIndex+4] = startVertex+2; + indexBuffer[startIndex+5] = startVertex+3; + } + + /// return the TextureHandle (cube) of the atlas + bgfx::TextureHandle getTextureHandle() const { return m_textureHandle; } + + //retrieve a region info + const AtlasRegion& getRegion(uint16_t handle) const { return m_regions[handle]; } + + /// retrieve the size of side of a texture in pixels + uint16_t getTextureSize(){ return m_textureSize; } + + /// retrieve the usage ratio of the atlas + //float getUsageRatio() const { return 0.0f; } + + /// retrieve the numbers of region in the atlas + uint16_t getRegionCount() const { return m_regionCount; } + + /// retrieve a pointer to the region buffer (in order to serialize it) + const AtlasRegion* getRegionBuffer() const { return m_regions; } + + /// retrieve the byte size of the texture + uint32_t getTextureBufferSize() const { return 6*m_textureSize*m_textureSize*4; } + + /// retrieve the mirrored texture buffer (to serialize it) + const uint8_t* getTextureBuffer() const { return m_textureBuffer; } + +private: + + void writeUV( uint8_t* vertexBuffer, int16_t x, int16_t y, int16_t z, int16_t w) + { + ((uint16_t*) vertexBuffer)[0] = x; + ((uint16_t*) vertexBuffer)[1] = y; + ((uint16_t*) vertexBuffer)[2] = z; + ((uint16_t*) vertexBuffer)[3] = w; + } + struct PackedLayer; + PackedLayer* m_layers; + + uint32_t m_usedLayers; + uint32_t m_usedFaces; + + bgfx::TextureHandle m_textureHandle; + uint16_t m_textureSize; + + uint16_t m_regionCount; + uint16_t m_maxRegionCount; + + AtlasRegion* m_regions; + uint8_t* m_textureBuffer; + +};} \ No newline at end of file diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp new file mode 100644 index 00000000..d12d96e2 --- /dev/null +++ b/examples/common/font/font_manager.cpp @@ -0,0 +1,792 @@ +/* Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause +*/ +#include "font_manager.h" +#include "../cube_atlas.h" + +#pragma warning( push ) +#pragma warning( disable: 4146 ) +#pragma warning( disable: 4700 ) +#pragma warning( disable: 4100 ) +#pragma warning( disable: 4701 ) +#include "../../../3rdparty/freetype/freetype.h" +#pragma warning( pop ) + +#include "../../../3rdparty/edtaa3/edtaa3func.h" +#include "../../../3rdparty/edtaa3/edtaa3func.cpp" +#include <math.h> +#include <assert.h> + + +#if BGFX_CONFIG_USE_TINYSTL +namespace tinystl +{ + //struct bgfx_allocator + //{ + //static void* static_allocate(size_t _bytes); + //static void static_deallocate(void* _ptr, size_t /*_bytes*/); + //}; +} // namespace tinystl +//# define TINYSTL_ALLOCATOR tinystl::bgfx_allocator +# include <TINYSTL/unordered_map.h> +//# include <TINYSTL/unordered_set.h> +namespace stl = tinystl; +#else +# include <unordered_map> +namespace std { namespace tr1 {} } +namespace stl { + using namespace std; + using namespace std::tr1; +} +#endif // BGFX_CONFIG_USE_TINYSTL + + +#define BGFX_FONT_ASSERT(cond, message) assert((cond) && (message)); + +namespace bgfx_font +{ + +class FontManager::TrueTypeFont +{ +public: + TrueTypeFont(); + ~TrueTypeFont(); + + /// Initialize from an external buffer + /// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime + /// @return true if the initialization succeed + bool init(const uint8_t* buffer, uint32_t bufferSize, int32_t fontIndex, uint32_t pixelHeight ); + + /// return the font descriptor of the current font + FontInfo getFontInfo(); + + /// raster a glyph as 8bit alpha to a memory buffer + /// update the GlyphInfo according to the raster strategy + /// @ remark buffer min size: glyphInfo.width * glyphInfo * height * sizeof(char) + bool bakeGlyphAlpha(CodePoint_t codePoint, GlyphInfo& outGlyphInfo, uint8_t* outBuffer); + + /// raster a glyph as 32bit subpixel rgba to a memory buffer + /// update the GlyphInfo according to the raster strategy + /// @ remark buffer min size: glyphInfo.width * glyphInfo * height * sizeof(uint32_t) + bool bakeGlyphSubpixel(CodePoint_t codePoint, GlyphInfo& outGlyphInfo, uint8_t* outBuffer); + + /// raster a glyph as 8bit signed distance to a memory buffer + /// update the GlyphInfo according to the raster strategy + /// @ remark buffer min size: glyphInfo.width * glyphInfo * height * sizeof(char) + bool bakeGlyphDistance(CodePoint_t codePoint, GlyphInfo& outGlyphInfo, uint8_t* outBuffer); +private: + void* m_font; +}; + + +struct FTHolder +{ + FT_Library library; + FT_Face face; +}; +FontManager::TrueTypeFont::TrueTypeFont(): m_font(NULL) +{ +} + +FontManager::TrueTypeFont::~TrueTypeFont() +{ + if(m_font!=NULL) + { + FTHolder* holder = (FTHolder*) m_font; + FT_Done_Face( holder->face ); + FT_Done_FreeType( holder->library ); + delete m_font; + m_font = NULL; + } +} + +bool FontManager::TrueTypeFont::init(const uint8_t* buffer, uint32_t bufferSize, int32_t fontIndex, uint32_t pixelHeight) +{ + assert((bufferSize > 256 && bufferSize < 100000000) && "TrueType buffer size is suspicious"); + assert((pixelHeight > 4 && pixelHeight < 128) && "TrueType buffer size is suspicious"); + + assert(m_font == NULL && "TrueTypeFont already initialized" ); + + FTHolder* holder = new FTHolder(); + + // Initialize Freetype library + FT_Error error = FT_Init_FreeType( &holder->library ); + if( error) + { + delete holder; + return false; + } + + error = FT_New_Memory_Face( holder->library, buffer, bufferSize, fontIndex, &holder->face ); + if ( error == FT_Err_Unknown_File_Format ) + { + // the font file could be opened and read, but it appears + //that its font format is unsupported + FT_Done_FreeType( holder->library ); + delete holder; + return false; + } + else if ( error ) + { + // another error code means that the font file could not + // be opened or read, or simply that it is broken... + FT_Done_FreeType( holder->library ); + delete holder; + return false; + } + + // Select unicode charmap + error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE ); + if( error ) + { + FT_Done_Face( holder->face ); + FT_Done_FreeType( holder->library ); + return false; + } + //set size in pixels + error = FT_Set_Pixel_Sizes( holder->face, 0, pixelHeight ); + if( error ) + { + FT_Done_Face( holder->face ); + FT_Done_FreeType( holder->library ); + return false; + } + + m_font = holder; + return true; +} + +FontInfo FontManager::TrueTypeFont::getFontInfo() +{ + assert(m_font != NULL && "TrueTypeFont not initialized" ); + FTHolder* holder = (FTHolder*) m_font; + + assert(FT_IS_SCALABLE (holder->face)); + + FT_Size_Metrics metrics = holder->face->size->metrics; + + //todo manage unscalable font + FontInfo outFontInfo; + outFontInfo.scale = 1.0f; + outFontInfo.ascender = metrics.ascender /64.0f; + outFontInfo.descender = metrics.descender /64.0f; + outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; + + outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f; + outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f; + return outFontInfo; +} + +bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer) +{ + assert(m_font != NULL && "TrueTypeFont not initialized" ); + FTHolder* holder = (FTHolder*) m_font; + + glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint ); + + FT_GlyphSlot slot = holder->face->glyph; + FT_Error error = FT_Load_Glyph( holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); + if(error) { return false; } + + FT_Glyph glyph; + error = FT_Get_Glyph( slot, &glyph ); + if ( error ) { return false; } + + error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 ); + if(error){ return false; } + + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + + int x = bitmap->left; + int y = -bitmap->top; + int w = bitmap->bitmap.width; + int h = bitmap->bitmap.rows; + + glyphInfo.offset_x = (float) x; + glyphInfo.offset_y = (float) y; + glyphInfo.width = (float) w; + glyphInfo.height = (float) h; + glyphInfo.advance_x = (float)slot->advance.x /64.0f; + glyphInfo.advance_y = (float)slot->advance.y /64.0f; + + int charsize = 1; + int depth=1; + int stride = bitmap->bitmap.pitch; + for( int i=0; i<h; ++i ) + { + memcpy(outBuffer+(i*w) * charsize * depth, + bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); + } + FT_Done_Glyph(glyph); + return true; +} + +bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer) +{ + assert(m_font != NULL && "TrueTypeFont not initialized" ); + FTHolder* holder = (FTHolder*) m_font; + + glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint ); + + FT_GlyphSlot slot = holder->face->glyph; + FT_Error error = FT_Load_Glyph( holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); + if(error) { return false; } + + FT_Glyph glyph; + error = FT_Get_Glyph( slot, &glyph ); + if ( error ) { return false; } + + error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_LCD, 0, 1 ); + if(error){ return false; } + + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + int x = bitmap->left; + int y = -bitmap->top; + int w = bitmap->bitmap.width; + int h = bitmap->bitmap.rows; + + glyphInfo.offset_x = (float) x; + glyphInfo.offset_y = (float) y; + glyphInfo.width = (float) w; + glyphInfo.height = (float) h; + glyphInfo.advance_x = (float)slot->advance.x /64.0f; + glyphInfo.advance_y = (float)slot->advance.y /64.0f; + int charsize = 1; + int depth=3; + int stride = bitmap->bitmap.pitch; + for( int i=0; i<h; ++i ) + { + memcpy(outBuffer+(i*w) * charsize * depth, + bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); + } + FT_Done_Glyph(glyph); + return true; +} + +//TODO optimize: remove dynamic allocation and convert double to float +void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int width, unsigned int height ) +{ + short * xdist = (short *) malloc( width * height * sizeof(short) ); + short * ydist = (short *) malloc( width * height * sizeof(short) ); + double * gx = (double *) calloc( width * height, sizeof(double) ); + double * gy = (double *) calloc( width * height, sizeof(double) ); + double * data = (double *) calloc( width * height, sizeof(double) ); + double * outside = (double *) calloc( width * height, sizeof(double) ); + double * inside = (double *) calloc( width * height, sizeof(double) ); + uint32_t i; + + // Convert img into double (data) + double img_min = 255, img_max = -255; + for( i=0; i<width*height; ++i) + { + double v = img[i]; + data[i] = v; + if (v > img_max) img_max = v; + if (v < img_min) img_min = v; + } + // Rescale image levels between 0 and 1 + for( i=0; i<width*height; ++i) + { + data[i] = (img[i]-img_min)/(img_max-img_min); + } + + // Compute outside = edtaa3(bitmap); % Transform background (0's) + computegradient( data, width, height, gx, gy); + edtaa3(data, gx, gy, width, height, xdist, ydist, outside); + for( i=0; i<width*height; ++i) + if( outside[i] < 0 ) + outside[i] = 0.0; + + // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) + memset(gx, 0, sizeof(double)*width*height ); + memset(gy, 0, sizeof(double)*width*height ); + for( i=0; i<width*height; ++i) + data[i] = 1.0 - data[i]; + computegradient( data, width, height, gx, gy); + edtaa3(data, gx, gy, width, height, xdist, ydist, inside); + for( i=0; i<width*height; ++i) + if( inside[i] < 0 ) + inside[i] = 0.0; + + // distmap = outside - inside; % Bipolar distance field + unsigned char *out = outImg;//(unsigned char *) malloc( width * height * sizeof(unsigned char) ); + for( i=0; i<width*height; ++i) + { + //out[i] = 127 - outside[i]*8; + //if(out[i]<0) out[i] = 0; + //out[i] += inside[i]*16; + //if(out[i]>255) out[i] = 255; + + outside[i] -= inside[i]; + outside[i] = 128 + outside[i]*16; + + //if(outside[i] > 8) outside[i] = 8; + //if(inside[i] > 8) outside[i] = 8; + + //outside[i] = 128 - inside[i]*8 + outside[i]*8; + + if( outside[i] < 0 ) outside[i] = 0; + if( outside[i] > 255 ) outside[i] = 255; + out[i] = 255 - (unsigned char) outside[i]; + //out[i] = (unsigned char) outside[i]; + } + + free( xdist ); + free( ydist ); + free( gx ); + free( gy ); + free( data ); + free( outside ); + free( inside ); +} + + +bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer) +{ + assert(m_font != NULL && "TrueTypeFont not initialized" ); + FTHolder* holder = (FTHolder*) m_font; + + glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint ); + + FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING; + FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL; + + FT_GlyphSlot slot = holder->face->glyph; + FT_Error error = FT_Load_Glyph( holder->face, glyphInfo.glyphIndex, loadMode ); + if(error) { return false; } + + FT_Glyph glyph; + error = FT_Get_Glyph( slot, &glyph ); + if ( error ) { return false; } + + error = FT_Glyph_To_Bitmap( &glyph, renderMode, 0, 1 ); + if(error){ return false; } + + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + + int x = bitmap->left; + int y = -bitmap->top; + int w = bitmap->bitmap.width; + int h = bitmap->bitmap.rows; + + glyphInfo.offset_x = (float) x; + glyphInfo.offset_y = (float) y; + glyphInfo.width = (float) w; + glyphInfo.height = (float) h; + glyphInfo.advance_x = (float)slot->advance.x /64.0f; + glyphInfo.advance_y = (float)slot->advance.y /64.0f; + + int charsize = 1; + int depth=1; + int stride = bitmap->bitmap.pitch; + + for( int i=0; i<h; ++i ) + { + + memcpy(outBuffer+(i*w) * charsize * depth, + bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); + } + FT_Done_Glyph(glyph); + + if(w*h >0) + { + uint32_t dw = 6; + uint32_t dh = 6; + if(dw<2) dw = 2; + if(dh<2) dh = 2; + + uint32_t nw = w + dw*2; + uint32_t nh = h + dh*2; + assert(nw*nh < 128*128); + uint32_t buffSize = nw*nh*sizeof(uint8_t); + + uint8_t * alphaImg = (uint8_t *) malloc( buffSize ); + memset(alphaImg, 0, nw*nh*sizeof(uint8_t)); + + //copy the original buffer to the temp one + for(uint32_t i= dh; i< nh-dh; ++i) + { + memcpy(alphaImg+i*nw+dw, outBuffer+(i-dh)*w, w); + } + + make_distance_map(alphaImg, outBuffer, nw, nh); + free(alphaImg); + + glyphInfo.offset_x -= (float) dw; + glyphInfo.offset_y -= (float) dh; + glyphInfo.width = (float) nw ; + glyphInfo.height = (float) nh; + } + + return true; +} + + + +//************************************************************* + +typedef stl::unordered_map<CodePoint_t, GlyphInfo> GlyphHash_t; +// cache font data +struct FontManager::CachedFont +{ + CachedFont(){ trueTypeFont = NULL; masterFontHandle.idx = -1; } + FontInfo fontInfo; + GlyphHash_t cachedGlyphs; + FontManager::TrueTypeFont* trueTypeFont; + // an handle to a master font in case of sub distance field font + FontHandle masterFontHandle; + int16_t __padding__; +}; + + + + +const uint16_t MAX_OPENED_FILES = 64; +const uint16_t MAX_OPENED_FONT = 64; +const uint32_t MAX_FONT_BUFFER_SIZE = 512*512*4; + +FontManager::FontManager(bgfx::Atlas* atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +{ + m_atlas = atlas; + m_ownAtlas = false; + init(); +} + +FontManager::FontManager(uint32_t textureSideWidth):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +{ + m_atlas = new bgfx::Atlas(textureSideWidth); + m_ownAtlas = true; + init(); +} + +void FontManager::init() +{ + m_cachedFiles = new CachedFile[MAX_OPENED_FILES]; + m_cachedFonts = new CachedFont[MAX_OPENED_FONT]; + m_buffer = new uint8_t[MAX_FONT_BUFFER_SIZE]; + + // Create filler rectangle + uint8_t buffer[4*4*4]; + memset( buffer, 255, 4 * 4 * 4); + + m_blackGlyph.width=3; + m_blackGlyph.height=3; + assert( addBitmap(m_blackGlyph, buffer) ); + //make sure the black glyph doesn't bleed + + /*int16_t texUnit = 65535 / m_textureWidth; + m_blackGlyph.texture_x0 += texUnit; + m_blackGlyph.texture_y0 += texUnit; + m_blackGlyph.texture_x1 -= texUnit; + m_blackGlyph.texture_y1 -= texUnit;*/ + +} + +FontManager::~FontManager() +{ + assert(m_fontHandles.getNumHandles() == 0 && "All the fonts must be destroyed before destroying the manager"); + delete [] m_cachedFonts; + + assert(m_filesHandles.getNumHandles() == 0 && "All the font files must be destroyed before destroying the manager"); + delete [] m_cachedFiles; + + delete [] m_buffer; + + if(m_ownAtlas) + { + delete m_atlas; + } +} + + + +TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* fontPath) +{ + FILE * pFile; + pFile = fopen (fontPath, "rb"); + if (pFile==NULL) + { + TrueTypeHandle invalid = BGFX_INVALID_HANDLE; + return invalid; + } + + // Go to the end of the file. + if (fseek(pFile, 0L, SEEK_END) == 0) + { + // Get the size of the file. + long bufsize = ftell(pFile); + if (bufsize == -1) + { + fclose(pFile); + TrueTypeHandle invalid = BGFX_INVALID_HANDLE; + return invalid; + } + + uint8_t* buffer = new uint8_t[bufsize]; + + // Go back to the start of the file. + fseek(pFile, 0L, SEEK_SET); + + // Read the entire file into memory. + size_t newLen = fread((void*)buffer, sizeof(char), bufsize, pFile); + if (newLen == 0) + { + fclose(pFile); + delete [] buffer; + TrueTypeHandle invalid = BGFX_INVALID_HANDLE; + return invalid; + } + fclose(pFile); + + uint16_t id = m_filesHandles.alloc(); + assert(id != bx::HandleAlloc::invalid); + m_cachedFiles[id].buffer = buffer; + m_cachedFiles[id].bufferSize = bufsize; + TrueTypeHandle ret = {id}; + return ret; + } + //TODO validate font + TrueTypeHandle invalid = BGFX_INVALID_HANDLE; + return invalid; +} + +TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* buffer, uint32_t size) +{ + uint16_t id = m_filesHandles.alloc(); + assert(id != bx::HandleAlloc::invalid); + m_cachedFiles[id].buffer = new uint8_t[size]; + m_cachedFiles[id].bufferSize = size; + memcpy(m_cachedFiles[id].buffer, buffer, size); + + //TODO validate font + TrueTypeHandle ret = {id}; + return ret; +} + +void FontManager::unloadTrueType(TrueTypeHandle handle) +{ + assert(bgfx::invalidHandle != handle.idx); + delete m_cachedFiles[handle.idx].buffer; + m_cachedFiles[handle.idx].bufferSize = 0; + m_cachedFiles[handle.idx].buffer = NULL; + m_filesHandles.free(handle.idx); +} + +FontHandle FontManager::createFontByPixelSize(TrueTypeHandle handle, uint32_t typefaceIndex, uint32_t pixelSize, FontType fontType) +{ + assert(bgfx::invalidHandle != handle.idx); + + TrueTypeFont* ttf = new TrueTypeFont(); + if(!ttf->init( m_cachedFiles[handle.idx].buffer, m_cachedFiles[handle.idx].bufferSize, typefaceIndex, pixelSize)) + { + delete ttf; + FontHandle invalid = BGFX_INVALID_HANDLE; + return invalid; + } + + uint16_t fontIdx = m_fontHandles.alloc(); + assert(fontIdx != bx::HandleAlloc::invalid); + + m_cachedFonts[fontIdx].trueTypeFont = ttf; + m_cachedFonts[fontIdx].fontInfo = ttf->getFontInfo(); + m_cachedFonts[fontIdx].fontInfo.fontType = fontType; + m_cachedFonts[fontIdx].fontInfo.pixelSize = pixelSize; + m_cachedFonts[fontIdx].cachedGlyphs.clear(); + m_cachedFonts[fontIdx].masterFontHandle.idx = -1; + FontHandle ret = {fontIdx}; + return ret; +} + +FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize) +{ + assert(bgfx::invalidHandle != _baseFontHandle.idx); + CachedFont& font = m_cachedFonts[_baseFontHandle.idx]; + FontInfo& fontInfo = font.fontInfo; + + FontInfo newFontInfo = fontInfo; + newFontInfo.pixelSize = _pixelSize; + newFontInfo.scale = (float)_pixelSize / (float) fontInfo.pixelSize; + newFontInfo.ascender = (newFontInfo.ascender * newFontInfo.scale); + newFontInfo.descender = (newFontInfo.descender * newFontInfo.scale); + newFontInfo.lineGap = (newFontInfo.lineGap * newFontInfo.scale); + newFontInfo.underline_thickness = (newFontInfo.underline_thickness * newFontInfo.scale); + newFontInfo.underline_position = (newFontInfo.underline_position * newFontInfo.scale); + + + uint16_t fontIdx = m_fontHandles.alloc(); + assert(fontIdx != bx::HandleAlloc::invalid); + m_cachedFonts[fontIdx].cachedGlyphs.clear(); + m_cachedFonts[fontIdx].fontInfo = newFontInfo; + m_cachedFonts[fontIdx].trueTypeFont = NULL; + m_cachedFonts[fontIdx].masterFontHandle = _baseFontHandle; + FontHandle ret = {fontIdx}; + return ret; +} + +FontHandle FontManager::loadBakedFontFromFile(const char* /*fontPath*/, const char* /*descriptorPath*/) +{ + assert(false); //TODO implement + FontHandle invalid = BGFX_INVALID_HANDLE; + return invalid; +} + +FontHandle FontManager::loadBakedFontFromMemory(const uint8_t* /*imageBuffer*/, uint32_t /*imageSize*/, const uint8_t* /*descriptorBuffer*/, uint32_t /*descriptorSize*/) +{ + assert(false); //TODO implement + FontHandle invalid = BGFX_INVALID_HANDLE; + return invalid; +} + +void FontManager::destroyFont(FontHandle _handle) +{ + assert(bgfx::invalidHandle != _handle.idx); + + if(m_cachedFonts[_handle.idx].trueTypeFont != NULL) + { + delete m_cachedFonts[_handle.idx].trueTypeFont; + m_cachedFonts[_handle.idx].trueTypeFont = NULL; + } + m_cachedFonts[_handle.idx].cachedGlyphs.clear(); + m_fontHandles.free(_handle.idx); +} + +bool FontManager::preloadGlyph(FontHandle handle, const wchar_t* _string) +{ + assert(bgfx::invalidHandle != handle.idx); + CachedFont& font = m_cachedFonts[handle.idx]; + + //if truetype present + if(font.trueTypeFont != NULL) + { + //parse string + for( size_t i=0, end = wcslen(_string) ; i < end; ++i ) + { + //if glyph cached, continue + CodePoint_t codePoint = _string[i]; + if(!preloadGlyph(handle, codePoint)) + { + return false; + } + } + return true; + } + + return false; +} + +bool FontManager::preloadGlyph(FontHandle handle, CodePoint_t codePoint) +{ + assert(bgfx::invalidHandle != handle.idx); + CachedFont& font = m_cachedFonts[handle.idx]; + FontInfo& fontInfo = font.fontInfo; + //check if glyph not already present + GlyphHash_t::iterator iter = font.cachedGlyphs.find(codePoint); + if(iter != font.cachedGlyphs.end()) + { + return true; + } + + //if truetype present + if(font.trueTypeFont != NULL) + { + GlyphInfo glyphInfo; + + //bake glyph as bitmap to buffer + switch(font.fontInfo.fontType) + { + case FONT_TYPE_ALPHA: + font.trueTypeFont->bakeGlyphAlpha(codePoint, glyphInfo, m_buffer); + break; + //case FONT_TYPE_LCD: + //font.trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); + //break; + case FONT_TYPE_DISTANCE: + font.trueTypeFont->bakeGlyphDistance(codePoint, glyphInfo, m_buffer); + break; + case FONT_TYPE_DISTANCE_SUBPIXEL: + font.trueTypeFont->bakeGlyphDistance(codePoint, glyphInfo, m_buffer); + break; + default: + assert(false && "TextureType not supported yet"); + }; + + //copy bitmap to texture + if(!addBitmap(glyphInfo, m_buffer) ) + { + return false; + } + + glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale); + glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale); + glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); + glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); + glyphInfo.height = (glyphInfo.height * fontInfo.scale); + glyphInfo.width = (glyphInfo.width * fontInfo.scale); + + // store cached glyph + font.cachedGlyphs[codePoint] = glyphInfo; + return true; + }else + { + //retrieve glyph from parent font if any + if(font.masterFontHandle.idx != bgfx::invalidHandle) + { + if(preloadGlyph(font.masterFontHandle, codePoint)) + { + GlyphInfo glyphInfo; + getGlyphInfo(font.masterFontHandle, codePoint, glyphInfo); + + glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale); + glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale); + glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); + glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); + glyphInfo.height = (glyphInfo.height * fontInfo.scale); + glyphInfo.width = (glyphInfo.width * fontInfo.scale); + + // store cached glyph + font.cachedGlyphs[codePoint] = glyphInfo; + return true; + } + } + } + + return false; +} + +const FontInfo& FontManager::getFontInfo(FontHandle handle) +{ + assert(handle.idx != bgfx::invalidHandle); + return m_cachedFonts[handle.idx].fontInfo; +} + +bool FontManager::getGlyphInfo(FontHandle fontHandle, CodePoint_t codePoint, GlyphInfo& outInfo) +{ + GlyphHash_t::iterator iter = m_cachedFonts[fontHandle.idx].cachedGlyphs.find(codePoint); + if(iter == m_cachedFonts[fontHandle.idx].cachedGlyphs.end()) + { + if(preloadGlyph(fontHandle, codePoint)) + { + iter = m_cachedFonts[fontHandle.idx].cachedGlyphs.find(codePoint); + }else + { + return false; + } + } + outInfo = iter->second; + return true; +} + +// **************************************************************************** + + +bool FontManager::addBitmap(GlyphInfo& glyphInfo, const uint8_t* data) +{ + glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(glyphInfo.width),(uint16_t) ceil(glyphInfo.height), data, bgfx::AtlasRegion::TYPE_GRAY); + return true; +} + + + + + +} diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h new file mode 100644 index 00000000..65c86e89 --- /dev/null +++ b/examples/common/font/font_manager.h @@ -0,0 +1,208 @@ +/* Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause +*/ +#pragma once +#include <bgfx.h> +#include <bx/handlealloc.h> + +namespace bgfx{ class Atlas; } + +namespace bgfx_font +{ + +enum FontType +{ + FONT_TYPE_ALPHA = 0x00000100 , // L8 + //FONT_TYPE_LCD = 0x00000200, // BGRA8 + //FONT_TYPE_RGBA = 0x00000300, // BGRA8 + FONT_TYPE_DISTANCE = 0x00000400, // L8 + FONT_TYPE_DISTANCE_SUBPIXEL = 0x00000500 // L8 +}; + +struct FontInfo +{ + //the font height in pixel + uint16_t pixelSize; + /// Rendering type used for the font + int16_t fontType; + + /// The pixel extents above the baseline in pixels (typically positive) + float ascender; + /// The extents below the baseline in pixels (typically negative) + float descender; + /// The spacing in pixels between one row's descent and the next row's ascent + float lineGap; + /// The thickness of the under/hover/striketrough line in pixels + float underline_thickness; + /// The position of the underline relatively to the baseline + float underline_position; + + //scale to apply to glyph data + float scale; +}; + +// Glyph metrics: +// -------------- +// +// xmin xmax +// | | +// |<-------- width -------->| +// | | +// | +-------------------------+----------------- ymax +// | | ggggggggg ggggg | ^ ^ +// | | g:::::::::ggg::::g | | | +// | | g:::::::::::::::::g | | | +// | | g::::::ggggg::::::gg | | | +// | | g:::::g g:::::g | | | +// offset_x -|-------->| g:::::g g:::::g | offset_y | +// | | g:::::g g:::::g | | | +// | | g::::::g g:::::g | | | +// | | g:::::::ggggg:::::g | | | +// | | g::::::::::::::::g | | height +// | | gg::::::::::::::g | | | +// baseline ---*---------|---- gggggggg::::::g-----*-------- | +// / | | g:::::g | | +// origin | | gggggg g:::::g | | +// | | g:::::gg gg:::::g | | +// | | g::::::ggg:::::::g | | +// | | gg:::::::::::::g | | +// | | ggg::::::ggg | | +// | | gggggg | v +// | +-------------------------+----------------- ymin +// | | +// |------------- advance_x ---------->| + +/// Unicode value of a character +typedef int32_t CodePoint_t; + +/// A structure that describe a glyph. +struct GlyphInfo +{ + /// Index for faster retrieval + int32_t glyphIndex; + + /// Glyph's width in pixels. + float width; + + /// Glyph's height in pixels. + float height; + + /// Glyph's left offset in pixels + float offset_x; + + /// Glyph's top offset in pixels + /// Remember that this is the distance from the baseline to the top-most + /// glyph scan line, upwards y coordinates being positive. + float offset_y; + + /// For horizontal text layouts, this is the unscaled horizontal distance in pixels + /// used to increment the pen position when the glyph is drawn as part of a string of text. + float advance_x; + + /// For vertical text layouts, this is the unscaled vertical distance in pixels + /// used to increment the pen position when the glyph is drawn as part of a string of text. + float advance_y; + + /// region index in the atlas storing textures + uint16_t regionIndex; + ///32 bits alignment + int16_t padding; +}; + +BGFX_HANDLE(TrueTypeHandle); +BGFX_HANDLE(FontHandle); + +class FontManager +{ +public: + /// create the font manager using an external cube atlas (doesn't take ownership of the atlas) + FontManager(bgfx::Atlas* atlas); + /// create the font manager and create the texture cube as BGRA8 with linear filtering + FontManager(uint32_t textureSideWidth = 512); + + ~FontManager(); + + /// retrieve the atlas used by the font manager (e.g. to add stuff to it) + bgfx::Atlas* getAtlas() { return m_atlas; } + + /// load a TrueType font from a file path + /// @return invalid handle if the loading fail + TrueTypeHandle loadTrueTypeFromFile(const char* fontPath); + + /// load a TrueType font from a given buffer. + /// the buffer is copied and thus can be freed or reused after this call + /// @return invalid handle if the loading fail + TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* buffer, uint32_t size); + + /// unload a TrueType font (free font memory) but keep loaded glyphs + void unloadTrueType(TrueTypeHandle handle); + + /// return a font whose height is a fixed pixel size + FontHandle createFontByPixelSize(TrueTypeHandle handle, uint32_t typefaceIndex, uint32_t pixelSize, FontType fontType = FONT_TYPE_ALPHA); + + /// return a scaled child font whose height is a fixed pixel size + FontHandle createScaledFontToPixelSize(FontHandle baseFontHandle, uint32_t pixelSize); + + /// load a baked font (the set of glyph is fixed) + /// @return INVALID_HANDLE if the loading fail + FontHandle loadBakedFontFromFile(const char* imagePath, const char* descriptorPath); + + /// load a baked font (the set of glyph is fixed) + /// @return INVALID_HANDLE if the loading fail + FontHandle loadBakedFontFromMemory(const uint8_t* imageBuffer, uint32_t imageSize, const uint8_t* descriptorBuffer, uint32_t descriptorSize); + + /// destroy a font (truetype or baked) + void destroyFont(FontHandle _handle); + + /// Preload a set of glyphs from a TrueType file + /// @return true if every glyph could be preloaded, false otherwise + /// if the Font is a baked font, this only do validation on the characters + bool preloadGlyph(FontHandle handle, const wchar_t* _string); + + /// Preload a single glyph, return true on success + bool preloadGlyph(FontHandle handle, CodePoint_t character); + + /// bake a font to disk (the set of preloaded glyph) + /// @return true if the baking succeed, false otherwise + bool saveBakedFont(FontHandle handle, const char* fontDirectory, const char* fontName ); + + /// return the font descriptor of a font + /// @remark the handle is required to be valid + const FontInfo& getFontInfo(FontHandle handle); + + /// Return the rendering informations about the glyph region + /// Load the glyph from a TrueType font if possible + /// @return true if the Glyph is available + bool getGlyphInfo(FontHandle fontHandle, CodePoint_t codePoint, GlyphInfo& outInfo); + + GlyphInfo& getBlackGlyph(){ return m_blackGlyph; } + + class TrueTypeFont; //public to shut off Intellisense warning +private: + + struct CachedFont; + struct CachedFile + { + uint8_t* buffer; + uint32_t bufferSize; + }; + + void init(); + bool addBitmap(GlyphInfo& glyphInfo, const uint8_t* data); + + bool m_ownAtlas; + (bgfx::Atlas* m_atlas; + + bx::HandleAlloc m_fontHandles; + CachedFont* m_cachedFonts; + + bx::HandleAlloc m_filesHandles; + CachedFile* m_cachedFiles; + + GlyphInfo m_blackGlyph; + + //temporary buffer to raster glyph + uint8_t* m_buffer; +}; + +} diff --git a/examples/common/font/fs_font_basic.sc b/examples/common/font/fs_font_basic.sc new file mode 100644 index 00000000..1d57655e --- /dev/null +++ b/examples/common/font/fs_font_basic.sc @@ -0,0 +1,16 @@ +$input v_color0, v_texcoord0 + +#include "../../common/common.sh" + +SAMPLERCUBE(u_texColor, 0); + +uniform float u_inverse_gamma; + +void main() +{ + vec4 color = textureCube(u_texColor, v_texcoord0.xyz); + int index = int(v_texcoord0.w*4.0 + 0.5); + float a = color.bgra[index]; + //a = pow(a, u_inverse_gamma); //I'll deal with gamma later + gl_FragColor = vec4(v_color0.rgb, v_color0.a * a); +} diff --git a/examples/common/font/fs_font_distance_field.sc b/examples/common/font/fs_font_distance_field.sc new file mode 100644 index 00000000..be311fa2 --- /dev/null +++ b/examples/common/font/fs_font_distance_field.sc @@ -0,0 +1,27 @@ +$input v_color0, v_texcoord0 + +#include "../../common/common.sh" + +SAMPLERCUBE(u_texColor, 0); + +uniform float u_inverse_gamma; + +void main() +{ + vec4 color = textureCube(u_texColor, v_texcoord0.xyz); + int index = int(v_texcoord0.w*4.0 + 0.5); + float distance = color.bgra[index]; + + float dx = length(dFdx(v_texcoord0.xyz)); + float dy = length(dFdy(v_texcoord0.xyz)); + float w = 16.0*0.5*(dx+dy); + + // alternatives that seems to give identical results + //float w = 16.0*max(dx,dy); + //float w = 16.0*length(vec2(dx,dy))/sqrt(2.0); + //float w = 16.0*length(fwidth(v_texcoord0.xyz))/sqrt(2.0); + + float a = smoothstep(0.5-w, 0.5+w, distance); + //a = pow(a, u_inverse_gamma); //I'll deal with gamma later + gl_FragColor = vec4(v_color0.rgb, v_color0.a*a); +} \ No newline at end of file diff --git a/examples/common/font/fs_font_distance_field_subpixel.sc b/examples/common/font/fs_font_distance_field_subpixel.sc new file mode 100644 index 00000000..5a2bd31a --- /dev/null +++ b/examples/common/font/fs_font_distance_field_subpixel.sc @@ -0,0 +1,40 @@ +$input v_color0, v_texcoord0 + +#include "../../common/common.sh" + +SAMPLERCUBE(u_texColor, 0); + +uniform float u_inverse_gamma; + +void main() +{ + int index = int(v_texcoord0.w*4.0 + 0.5); + vec3 dx3 = dFdx(v_texcoord0.xyz); + vec3 dy3 = dFdy(v_texcoord0.xyz); + vec3 decal = 0.166667 * dx3; + vec3 sampleLeft = v_texcoord0.xyz - decal; + vec3 sampleRight = v_texcoord0.xyz + decal; + + float left_dist = textureCube(u_texColor, sampleLeft).bgra[index]; + float right_dist = textureCube(u_texColor, sampleRight).bgra[index]; + + //vec3 centerUV = 0.5 * (sampleLeft + sampleRight); + //float dist = textureCube(u_texColor, centerUV).bgra[index]; + float dist = 0.5 * (left_dist + right_dist); + + float dx = length(dx3); + float dy = length(dy3); + float w = 16.0*0.5*(dx+dy); + + vec3 sub_color = smoothstep(0.5 -w, 0.5 + w, vec3(left_dist, dist, right_dist)); + gl_FragColor.rgb = sub_color*v_color0.a; + //gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(u_inverse_gamma,u_inverse_gamma,u_inverse_gamma)); + gl_FragColor.a = dist*v_color0.a; + + //AR,AG,AB are the intensities gotten from the subpixel rendering engine. + //BR,BG,BB are the old background pixels. + //DR,DG,DB are the new background pixels. + //DR = A*AR*R + (1-(A*AR))*BR + //DG = A*AG*G + (1-(A*AG))*BG + //DB = A*AB*B + (1-(A*AB))*BB +} diff --git a/examples/common/font/makefile b/examples/common/font/makefile new file mode 100644 index 00000000..5ae719f2 --- /dev/null +++ b/examples/common/font/makefile @@ -0,0 +1,17 @@ +# +# Copyright 2013 Roy Jeremie. All rights reserved. +# License: http://www.opensource.org/licenses/BSD-2-Clause +# + +BGFX_DIR=../../.. +RUNTIME_DIR=$(BGFX_DIR)/examples/runtime +BUILD_DIR=../../../.build + +include $(BGFX_DIR)/premake/shader.mk + +rebuild: + @make -s --no-print-directory TARGET=0 clean all + @make -s --no-print-directory TARGET=1 clean all + @make -s --no-print-directory TARGET=2 clean all + @make -s --no-print-directory TARGET=3 clean all + @make -s --no-print-directory TARGET=4 clean all diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp new file mode 100644 index 00000000..7265e2ee --- /dev/null +++ b/examples/common/font/text_buffer_manager.cpp @@ -0,0 +1,812 @@ +/* Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause +*/ +#include "text_buffer_manager.h" +#include "../cube_atlas.h" + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <stddef.h> /* offsetof */ + +namespace bgfx_font +{ + +const uint16_t MAX_TEXT_BUFFER_COUNT = 64; + +long int fsize(FILE* _file) +{ + long int pos = ftell(_file); + fseek(_file, 0L, SEEK_END); + long int size = ftell(_file); + fseek(_file, pos, SEEK_SET); + return size; +} + +static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shaderName) +{ + char out[512]; + strcpy(out, _shaderPath); + strcat(out, _shaderName); + strcat(out, ".bin"); + + FILE* file = fopen(out, "rb"); + if (NULL != file) + { + uint32_t size = (uint32_t)fsize(file); + const bgfx::Memory* mem = bgfx::alloc(size+1); + /*size_t ignore =*/ fread(mem->data, 1, size, file); + /*BX_UNUSED(ignore);*/ + fclose(file); + mem->data[mem->size-1] = '\0'; + return mem; + } + + return NULL; +} + + + +// Table from Flexible and Economical UTF-8 Decoder +// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> +// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. + +static const uint8_t utf8d[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df + 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef + 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff + 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 + 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 + 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 + 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 +}; + +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 1 + +inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) { + uint32_t type = utf8d[byte]; + + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); + + *state = utf8d[256 + *state*16 + type]; + return *state; +} + +inline int utf8_strlen(uint8_t* s, size_t* count) { + uint32_t codepoint; + uint32_t state = 0; + + for (*count = 0; *s; ++s) + if (!utf8_decode(&state, &codepoint, *s)) + *count += 1; + + return state != UTF8_ACCEPT; +} + + +class TextBuffer +{ +public: + + /// TextBuffer is bound to a fontManager for glyph retrieval + /// @remark the ownership of the manager is not taken + TextBuffer(FontManager* fontManager); + ~TextBuffer(); + + void setStyle(uint32_t flags = STYLE_NORMAL) { m_styleFlags = flags; } + void setTextColor(uint32_t rgba = 0x000000FF) { m_textColor = toABGR(rgba); } + void setBackgroundColor(uint32_t rgba = 0x000000FF) { m_backgroundColor = toABGR(rgba); } + + void setOverlineColor(uint32_t rgba = 0x000000FF) { m_overlineColor = toABGR(rgba); } + void setUnderlineColor(uint32_t rgba = 0x000000FF) { m_underlineColor = toABGR(rgba); } + void setStrikeThroughColor(uint32_t rgba = 0x000000FF) { m_strikeThroughColor = toABGR(rgba); } + + void setPenPosition(float x, float /*y*/) { m_penX = x; };// m_penY = y; } + + /// return the size of the text + //Rectangle measureText(FontHandle fontHandle, const char * _string); + //Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); + + /// append an ASCII/utf-8 string to the buffer using current pen position and color + void appendText(FontHandle fontHandle, const char * _string); + + /// append a wide char unicode string to the buffer using current pen position and color + void appendText(FontHandle fontHandle, const wchar_t * _string); + + /// Clear the text buffer and reset its state (pen/color) + void clearTextBuffer(); + + /// get pointer to the vertex buffer to submit it to the graphic card + const uint8_t* getVertexBuffer(){ return (uint8_t*) m_vertexBuffer; } + /// number of vertex in the vertex buffer + uint32_t getVertexCount(){ return m_vertexCount; } + /// size in bytes of a vertex + uint32_t getVertexSize(){ return sizeof(TextVertex); } + + /// get a pointer to the index buffer to submit it to the graphic + const uint16_t* getIndexBuffer(){ return m_indexBuffer; } + /// number of index in the index buffer + uint32_t getIndexCount(){ return m_indexCount; } + /// size in bytes of an index + uint32_t getIndexSize(){ return sizeof(uint16_t); } + + uint32_t getTextColor(){ return toABGR(m_textColor); } +private: + void appendGlyph(CodePoint_t codePoint, const FontInfo& font, const GlyphInfo& glyphInfo); + void verticalCenterLastLine(float txtDecalY, float top, float bottom); + uint32_t toABGR(uint32_t rgba) +{ + return (((rgba >> 0) & 0xff) << 24) | + (((rgba >> 8) & 0xff) << 16) | + (((rgba >> 16) & 0xff) << 8) | + (((rgba >> 24) & 0xff) << 0); +} + + static const size_t MAX_BUFFERED_CHARACTERS = 8192; + + uint32_t m_styleFlags; + + // color states + uint32_t m_textColor; + + uint32_t m_backgroundColor; + uint32_t m_overlineColor; + uint32_t m_underlineColor; + uint32_t m_strikeThroughColor; + + //position states + float m_penX; + float m_penY; + + float m_originX; + float m_originY; + + float m_lineAscender; + float m_lineDescender; + float m_lineGap; + + /// + FontManager* m_fontManager; + + void setVertex(size_t i, float x, float y, uint32_t rgba, uint8_t style = STYLE_NORMAL) + { + m_vertexBuffer[i].x = x; + m_vertexBuffer[i].y = y; + m_vertexBuffer[i].rgba = rgba; + m_styleBuffer[i] = style; + } + + struct TextVertex + { + float x,y; + int16_t u,v,w,t; + uint32_t rgba; + }; + + TextVertex* m_vertexBuffer; + uint16_t* m_indexBuffer; + uint8_t* m_styleBuffer; + + size_t m_vertexCount; + size_t m_indexCount; + size_t m_lineStartIndex; +}; + + + + + + +TextBuffer::TextBuffer(FontManager* fontManager) +{ + m_styleFlags = STYLE_NORMAL; + //0xAABBGGRR + m_textColor = 0xFFFFFFFF; + m_backgroundColor = 0xFFFFFFFF; + m_backgroundColor = 0xFFFFFFFF; + m_overlineColor = 0xFFFFFFFF; + m_underlineColor = 0xFFFFFFFF; + m_strikeThroughColor = 0xFFFFFFFF; + m_penX = 0; + m_penY = 0; + m_originX = 0; + m_originY = 0; + m_lineAscender = 0; + m_lineDescender = 0; + m_lineGap = 0; + m_fontManager = fontManager; + + + m_vertexBuffer = new TextVertex[MAX_BUFFERED_CHARACTERS * 4]; + m_indexBuffer = new uint16_t[MAX_BUFFERED_CHARACTERS * 6]; + m_styleBuffer = new uint8_t[MAX_BUFFERED_CHARACTERS * 4]; + m_vertexCount = 0; + m_indexCount = 0; + m_lineStartIndex = 0; + + +} + +TextBuffer::~TextBuffer() +{ + delete[] m_vertexBuffer; + delete[] m_indexBuffer; +} + +void TextBuffer::appendText(FontHandle fontHandle, const char * _string) +{ + GlyphInfo glyph; + const FontInfo& font = m_fontManager->getFontInfo(fontHandle); + + if(m_vertexCount == 0) + { + m_originX = m_penX; + m_originY = m_penY; + m_lineDescender = 0;// font.descender; + m_lineAscender = 0;//font.ascender; + } + + uint32_t codepoint; + uint32_t state = 0; + + for (; *_string; ++_string) + if (!utf8_decode(&state, &codepoint, *_string)) + { + if(m_fontManager->getGlyphInfo(fontHandle, (CodePoint_t)codepoint, glyph)) + { + appendGlyph((CodePoint_t)codepoint, font, glyph); + }else + { + assert(false && "Glyph not found"); + } + } + //printf("U+%04X\n", codepoint); + + if (state != UTF8_ACCEPT) + { + // assert(false && "The string is not well-formed"); + return; //"The string is not well-formed\n" + } +} + +void TextBuffer::appendText(FontHandle fontHandle, const wchar_t * _string) +{ + GlyphInfo glyph; + const FontInfo& font = m_fontManager->getFontInfo(fontHandle); + + if(m_vertexCount == 0) + { + m_originX = m_penX; + m_originY = m_penY; + m_lineDescender = 0;// font.descender; + m_lineAscender = 0;//font.ascender; + m_lineGap = 0; + } + + //parse string + for( size_t i=0, end = wcslen(_string) ; i < end; ++i ) + { + //if glyph cached, continue + uint32_t codePoint = _string[i]; + if(m_fontManager->getGlyphInfo(fontHandle, codePoint, glyph)) + { + appendGlyph(codePoint, font, glyph); + }else + { + assert(false && "Glyph not found"); + } + } +} +/* +TextBuffer::Rectangle TextBuffer::measureText(FontHandle fontHandle, const char * _string) +{ +} + +TextBuffer::Rectangle TextBuffer::measureText(FontHandle fontHandle, const wchar_t * _string) +{ +} +*/ + +void TextBuffer::clearTextBuffer() +{ + m_vertexCount = 0; + m_indexCount = 0; + m_lineStartIndex = 0; + m_lineAscender = 0; + m_lineDescender = 0; +} + +void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const GlyphInfo& glyphInfo) +{ + //handle newlines + if(codePoint == L'\n' ) + { + m_penX = m_originX; + m_penY -= m_lineDescender; + m_penY += m_lineGap; + m_lineDescender = 0; + m_lineAscender = 0; + m_lineStartIndex = m_vertexCount; + return; + } + + if( font.ascender > m_lineAscender || (font.descender < m_lineDescender) ) + { + if( font.descender < m_lineDescender ) + { + m_lineDescender = font.descender; + m_lineGap = font.lineGap; + } + + float txtDecals = (font.ascender - m_lineAscender); + m_lineAscender = font.ascender; + m_lineGap = font.lineGap; + + m_penY += txtDecals; + verticalCenterLastLine((txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender+m_lineGap)); + } + + //handle kerning + float kerning = 0; + /* + if( previous && markup->font->kerning ) + { + kerning = texture_glyph_get_kerning( glyph, previous ); + } + */ + m_penX += kerning * font.scale; + + GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph(); + + if( m_styleFlags & STYLE_BACKGROUND && m_backgroundColor & 0xFF000000) + { + float x0 = ( m_penX - kerning ); + float y0 = ( m_penY - m_lineAscender); + float x1 = ( (float)x0 + (glyphInfo.advance_x)); + float y1 = ( m_penY - m_lineDescender + m_lineGap ); + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + + setVertex(m_vertexCount+0, x0, y0, m_backgroundColor,STYLE_BACKGROUND); + setVertex(m_vertexCount+1, x0, y1, m_backgroundColor,STYLE_BACKGROUND); + setVertex(m_vertexCount+2, x1, y1, m_backgroundColor,STYLE_BACKGROUND); + setVertex(m_vertexCount+3, x1, y0, m_backgroundColor,STYLE_BACKGROUND); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if( m_styleFlags & STYLE_UNDERLINE && m_underlineColor & 0xFF000000) + { + float x0 = ( m_penX - kerning ); + float y0 = (m_penY - m_lineDescender/2 ); + float x1 = ( (float)x0 + (glyphInfo.advance_x)); + float y1 = y0+font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + + setVertex(m_vertexCount+0, x0, y0, m_underlineColor,STYLE_UNDERLINE); + setVertex(m_vertexCount+1, x0, y1, m_underlineColor,STYLE_UNDERLINE); + setVertex(m_vertexCount+2, x1, y1, m_underlineColor,STYLE_UNDERLINE); + setVertex(m_vertexCount+3, x1, y0, m_underlineColor,STYLE_UNDERLINE); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if( m_styleFlags & STYLE_OVERLINE && m_overlineColor & 0xFF000000) + { + float x0 = ( m_penX - kerning ); + float y0 = (m_penY - font.ascender ); + float x1 = ( (float)x0 + (glyphInfo.advance_x)); + float y1 = y0+font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + + setVertex(m_vertexCount+0, x0, y0, m_overlineColor,STYLE_OVERLINE); + setVertex(m_vertexCount+1, x0, y1, m_overlineColor,STYLE_OVERLINE); + setVertex(m_vertexCount+2, x1, y1, m_overlineColor,STYLE_OVERLINE); + setVertex(m_vertexCount+3, x1, y0, m_overlineColor,STYLE_OVERLINE); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + m_vertexCount += 4; + m_indexCount += 6; + } + + + if( m_styleFlags & STYLE_STRIKE_THROUGH && m_strikeThroughColor & 0xFF000000) + { + float x0 = ( m_penX - kerning ); + float y0 = (m_penY - font.ascender/3 ); + float x1 = ( (float)x0 + (glyphInfo.advance_x) ); + float y1 = y0+font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + + setVertex(m_vertexCount+0, x0, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount+1, x0, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount+2, x1, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount+3, x1, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + m_vertexCount += 4; + m_indexCount += 6; + } + + + //handle glyph + float x0_precise = m_penX + (glyphInfo.offset_x); + float x0 = ( x0_precise); + float y0 = ( m_penY + (glyphInfo.offset_y)); + float x1 = ( x0 + glyphInfo.width ); + float y1 = ( y0 + glyphInfo.height ); + + m_fontManager->getAtlas()->packUV(glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + + setVertex(m_vertexCount+0, x0, y0, m_textColor); + setVertex(m_vertexCount+1, x0, y1, m_textColor); + setVertex(m_vertexCount+2, x1, y1, m_textColor); + setVertex(m_vertexCount+3, x1, y0, m_textColor); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + m_vertexCount += 4; + m_indexCount += 6; + + //TODO see what to do when doing subpixel rendering + m_penX += glyphInfo.advance_x; +} + +void TextBuffer::verticalCenterLastLine(float dy, float top, float bottom) +{ + for( size_t i=m_lineStartIndex; i < m_vertexCount; i+=4 ) + { + if( m_styleBuffer[i] == STYLE_BACKGROUND) + { + m_vertexBuffer[i+0].y = top; + m_vertexBuffer[i+1].y = bottom; + m_vertexBuffer[i+2].y = bottom; + m_vertexBuffer[i+3].y = top; + }else{ + m_vertexBuffer[i+0].y += dy; + m_vertexBuffer[i+1].y += dy; + m_vertexBuffer[i+2].y += dy; + m_vertexBuffer[i+3].y += dy; + } + } +} + +// **************************************************************** + +TextBufferManager::TextBufferManager(FontManager* fontManager):m_fontManager(fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) +{ + m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT]; +} + +TextBufferManager::~TextBufferManager() +{ + assert(m_textBufferHandles.getNumHandles() == 0 && "All the text buffers must be destroyed before destroying the manager"); + delete[] m_textBuffers; + + bgfx::destroyUniform(m_u_texColor); + bgfx::destroyUniform(m_u_inverse_gamma); + + bgfx::destroyProgram(m_basicProgram); + bgfx::destroyProgram(m_distanceProgram); + bgfx::destroyProgram(m_distanceSubpixelProgram); +} + +void TextBufferManager::init(const char* shaderPath) +{ + m_vertexDecl.begin(); + m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); + m_vertexDecl.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true); + m_vertexDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); + m_vertexDecl.end(); + + m_u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); + m_u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); + + const bgfx::Memory* mem; + mem = loadShader(shaderPath, "vs_font_basic"); + bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); + mem = loadShader(shaderPath, "fs_font_basic"); + bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); + m_basicProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + mem = loadShader(shaderPath, "vs_font_distance_field"); + vsh = bgfx::createVertexShader(mem); + mem = loadShader(shaderPath, "fs_font_distance_field"); + fsh = bgfx::createFragmentShader(mem); + m_distanceProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + mem = loadShader(shaderPath, "vs_font_distance_field_subpixel"); + vsh = bgfx::createVertexShader(mem); + mem = loadShader(shaderPath, "fs_font_distance_field_subpixel"); + fsh = bgfx::createFragmentShader(mem); + m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); +} + +TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType bufferType) +{ + uint16_t textIdx = m_textBufferHandles.alloc(); + BufferCache& bc = m_textBuffers[textIdx]; + + bc.textBuffer = new TextBuffer(m_fontManager); + bc.fontType = _type; + bc.bufferType = bufferType; + bc.indexBufferHandle = bgfx::invalidHandle; + bc.vertexBufferHandle = bgfx::invalidHandle; + + TextBufferHandle ret = {textIdx}; + return ret; +} + +void TextBufferManager::destroyTextBuffer(TextBufferHandle handle) +{ + assert( bgfx::invalidHandle != handle.idx); + + BufferCache& bc = m_textBuffers[handle.idx]; + m_textBufferHandles.free(handle.idx); + delete bc.textBuffer; + bc.textBuffer = NULL; + + if(bc.vertexBufferHandle == bgfx::invalidHandle ) return; + + switch(bc.bufferType) + { + case STATIC: + { + bgfx::IndexBufferHandle ibh; + bgfx::VertexBufferHandle vbh; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + bgfx::destroyIndexBuffer(ibh); + bgfx::destroyVertexBuffer(vbh); + } + + break; + case DYNAMIC: + bgfx::DynamicIndexBufferHandle ibh; + bgfx::DynamicVertexBufferHandle vbh; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + bgfx::destroyDynamicIndexBuffer(ibh); + bgfx::destroyDynamicVertexBuffer(vbh); + + break; + case TRANSIENT: //naturally destroyed + break; + } +} + +void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth) +{ + assert(bgfx::invalidHandle != _handle.idx); + BufferCache& bc = m_textBuffers[_handle.idx]; + + size_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize(); + size_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize(); + const bgfx::Memory* mem; + + bgfx::setTexture(0, m_u_texColor, m_fontManager->getAtlas()->getTextureHandle()); + float inverse_gamme = 1.0f/2.2f; + bgfx::setUniform(m_u_inverse_gamma, &inverse_gamme); + + switch (bc.fontType) + { + case FONT_TYPE_ALPHA: + bgfx::setProgram(m_basicProgram); + bgfx::setState( BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); + break; + case FONT_TYPE_DISTANCE: + bgfx::setProgram(m_distanceProgram); + bgfx::setState( BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); + break; + case FONT_TYPE_DISTANCE_SUBPIXEL: + bgfx::setProgram(m_distanceSubpixelProgram); + bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.textBuffer->getTextColor()); + break; + } + + switch(bc.bufferType) + { + case STATIC: + { + bgfx::IndexBufferHandle ibh; + bgfx::VertexBufferHandle vbh; + + if(bc.vertexBufferHandle == bgfx::invalidHandle) + { + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + ibh = bgfx::createIndexBuffer(mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); + + bc.indexBufferHandle = ibh.idx ; + bc.vertexBufferHandle = vbh.idx; + }else + { + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + } + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); + }break; + case DYNAMIC: + { + bgfx::DynamicIndexBufferHandle ibh; + bgfx::DynamicVertexBufferHandle vbh; + + if(bc.vertexBufferHandle == bgfx::invalidHandle) + { + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + ibh = bgfx::createDynamicIndexBuffer(mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); + + bc.indexBufferHandle = ibh.idx ; + bc.vertexBufferHandle = vbh.idx; + }else + { + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + + static int i=0; + //if(i++ < 5) + { + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + bgfx::updateDynamicIndexBuffer(ibh, mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::updateDynamicVertexBuffer(vbh, mem); + } + } + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); + + }break; + case TRANSIENT: + { + bgfx::TransientIndexBuffer tib; + bgfx::TransientVertexBuffer tvb; + bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount()); + bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); + memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount()); + bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount()); + }break; + } + + bgfx::submit(_id, _depth); +} + +void TextBufferManager::submitTextBufferMask(TextBufferHandle /*_handle*/, uint32_t /*_viewMask*/, int32_t /*_depth*/) +{ + //TODO + assert(false); +} + +void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t flags ) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setStyle(flags); +} + +void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t rgba ) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setTextColor(rgba); +} + +void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t rgba ) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setBackgroundColor(rgba); +} + +void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t rgba ) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setOverlineColor(rgba); +} + +void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t rgba ) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setUnderlineColor(rgba); +} + +void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t rgba ) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setStrikeThroughColor(rgba); +} + +void TextBufferManager::setPenPosition(TextBufferHandle _handle, float x, float y) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setPenPosition(x,y); +} + +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle fontHandle, const char * _string) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->appendText(fontHandle, _string); +} + +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle fontHandle, const wchar_t * _string) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->appendText(fontHandle, _string); +} + +void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) +{ + assert( _handle.idx != bgfx::invalidHandle); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->clearTextBuffer(); +} + +} diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h new file mode 100644 index 00000000..2a386c71 --- /dev/null +++ b/examples/common/font/text_buffer_manager.h @@ -0,0 +1,90 @@ +/* Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause +*/ +#pragma once +#include "font_manager.h" + +namespace bgfx_font +{ + +BGFX_HANDLE(TextBufferHandle); + +/// type of vertex and index buffer to use with a TextBuffer +enum BufferType +{ + STATIC, + DYNAMIC , + TRANSIENT +}; + +/// special style effect (can be combined) +enum TextStyleFlags +{ + STYLE_NORMAL = 0, + STYLE_OVERLINE = 1, + STYLE_UNDERLINE = 1<<1, + STYLE_STRIKE_THROUGH = 1<<2, + STYLE_BACKGROUND = 1<<3, +}; + +class TextBuffer; +class TextBufferManager +{ +public: + TextBufferManager(FontManager* fontManager = NULL); + ~TextBufferManager(); + + void init(const char* shaderPath); + + TextBufferHandle createTextBuffer(FontType type, BufferType bufferType); + void destroyTextBuffer(TextBufferHandle handle); + void submitTextBuffer(TextBufferHandle handle, uint8_t id, int32_t depth = 0); + void submitTextBufferMask(TextBufferHandle handle, uint32_t viewMask, int32_t depth = 0); + + void setStyle(TextBufferHandle handle, uint32_t flags = STYLE_NORMAL); + void setTextColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + void setBackgroundColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + + void setOverlineColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + void setUnderlineColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + void setStrikeThroughColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + + void setPenPosition(TextBufferHandle handle, float x, float y); + + /// append an ASCII/utf-8 string to the buffer using current pen position and color + void appendText(TextBufferHandle _handle, FontHandle fontHandle, const char * _string); + + /// append a wide char unicode string to the buffer using current pen position and color + void appendText(TextBufferHandle _handle, FontHandle fontHandle, const wchar_t * _string); + + /// Clear the text buffer and reset its state (pen/color) + void clearTextBuffer(TextBufferHandle _handle); + + /// return the size of the text + //Rectangle measureText(FontHandle fontHandle, const char * _string); + //Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); + +private: + + struct BufferCache + { + uint16_t indexBufferHandle; + uint16_t vertexBufferHandle; + TextBuffer* textBuffer; + BufferType bufferType; + FontType fontType; + }; + + BufferCache* m_textBuffers; + bx::HandleAlloc m_textBufferHandles; + FontManager* m_fontManager; + bgfx::VertexDecl m_vertexDecl; + bgfx::UniformHandle m_u_texColor; + bgfx::UniformHandle m_u_inverse_gamma; + //shaders program + bgfx::ProgramHandle m_basicProgram; + bgfx::ProgramHandle m_distanceProgram; + bgfx::ProgramHandle m_distanceSubpixelProgram; +}; + +} diff --git a/examples/common/font/varying.def.sc b/examples/common/font/varying.def.sc new file mode 100644 index 00000000..720e9a73 --- /dev/null +++ b/examples/common/font/varying.def.sc @@ -0,0 +1,9 @@ +vec2 a_position : POSITION; +vec4 a_color0 : COLOR0; +vec4 a_texcoord0 : TEXCOORD0; + +vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0); +vec4 v_texcoord0 : TEXCOORD0 = vec4(0.0, 0.0, 0.0, 0.0); +vec4 v_sampleLeft : TEXCOORD1 = vec4(0.0, 0.0, 0.0, 0.0); +vec4 v_sampleRight : TEXCOORD2 = vec4(0.0, 0.0, 0.0, 0.0); + diff --git a/examples/common/font/vs_font_basic.sc b/examples/common/font/vs_font_basic.sc new file mode 100644 index 00000000..f17e6a6d --- /dev/null +++ b/examples/common/font/vs_font_basic.sc @@ -0,0 +1,11 @@ +$input a_position, a_color0, a_texcoord0 +$output v_color0, v_texcoord0 + +#include "../../common/common.sh" + +void main() +{ + gl_Position = mul(u_modelViewProj, vec4(a_position, 0.0, 1.0) ); + v_texcoord0 = a_texcoord0; + v_color0 = a_color0; +} diff --git a/examples/common/font/vs_font_distance_field.sc b/examples/common/font/vs_font_distance_field.sc new file mode 100644 index 00000000..e007d6c9 --- /dev/null +++ b/examples/common/font/vs_font_distance_field.sc @@ -0,0 +1,11 @@ +$input a_position, a_color0, a_texcoord0 +$output v_color0, v_texcoord0 + +#include "../../common/common.sh" + +void main() +{ + gl_Position = mul(u_modelViewProj, vec4(a_position, 0.0, 1.0) ); + v_texcoord0 = a_texcoord0; + v_color0 = a_color0; +} diff --git a/examples/common/font/vs_font_distance_field_subpixel.sc b/examples/common/font/vs_font_distance_field_subpixel.sc new file mode 100644 index 00000000..cfdfd938 --- /dev/null +++ b/examples/common/font/vs_font_distance_field_subpixel.sc @@ -0,0 +1,15 @@ +$input a_position, a_color0, a_texcoord0 +$output v_color0, v_texcoord0 + +#include "../../common/common.sh" + +void main() +{ + gl_Position = mul(u_modelViewProj, vec4(a_position, 0.0, 1.0) ); + v_texcoord0 = a_texcoord0; + v_color0 = a_color0; + + //vec3 decal = dFdx(a_texcoord0.xyz); + //v_sampleLeft = a_texcoord0 + decal; + //v_sampleRight = a_texcoord0 - decal; +} diff --git a/examples/makefile b/examples/makefile index 40c70255..5d8a1bb0 100644 --- a/examples/makefile +++ b/examples/makefile @@ -13,3 +13,4 @@ rebuild: @make -s --no-print-directory rebuild -C 07-callback @make -s --no-print-directory rebuild -C 08-update @make -s --no-print-directory rebuild -C 09-hdr + @make -s --no-print-directory rebuild -C common/font diff --git a/examples/runtime/shaders/dx11/fs_font_basic.bin b/examples/runtime/shaders/dx11/fs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..9c8e68466f98f818055d4bf2b6dfcb212b547ba3 GIT binary patch literal 898 zcma)3Jxjw-6uq^TR#B`4LC_(if)ranunxAGenM?DFG>-?uSQyEO^Fqpr05^e&B@WF zt2p>?#KleN;9Ad3@<36+3n%yH+<WdjFUg9$&v(^*CZe7PBqu8Vba_ops=-ijbN7C{ z@bWSC_VnmOui_`_N1g}X`5ojf@Y+YDr!(0Ha56yAB)<fDJ-Q)kqud3s;z#gq#tFbW zK4SprA&{KjF!I@6%RE=Dx@C)lMze0(Ul_wYZ=KmDt=Eoh>(n}KDO38ik}ry)BB}=! z(^gcg(X2tFB%<*|G_eqm&c$Le>U25<kt@})pS^{E4S<6^Nxvhg*}n|txj%x&p(K%+ z=Q}Vjw)ZwPQ7{TxiBzqq>11Tes;22_>S#D~26McF&r|>zU(du2V^z;(3>X#pw4R3` zg+U!y7$=H2qIS|r-yZ+xcG&iQ*in~fDL_rP-rB<5!sPFU!;Vi`^ZiU{x{5nj#g&<h z<F`e~<(8pg&X>Z2+9@|vast0s&J2398R)vG`CDWot}c7w?vcJm@tLIVc*vW*yC%6~ yi70sK`H>uZ;GK&&)AoA2pScxS6UM61LLCIyYXFe{52X`4`&azdlbp<dY3UOy*<*wN literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/fs_font_distance_field.bin b/examples/runtime/shaders/dx11/fs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..c1cd8756db8eae8ff11750f4b48968f05362148e GIT binary patch literal 1366 zcma)6O>Yum5FS2@wc3@7Up;I*sWC)Q40y0h7bryRHoIFxj7hC_n>L|BwlwL<5PS5Z z7h|IF4{-6|(SrvQul|L4^Q7Sq;4{1LP;98_gxPs{=9$lTq3YBkk^R8|5e=2X1X4(p zn+xWLPY3S%{bXV1+mBbj%D?jw_zDRkeCRgx4|E;iJLs1<kzKA-KLZnq;xNZw;=>`m zA?o4y7#f2f70%829LjNA;}moVfeCzPV0Tx$-k#ZRwS8x8yVLUgF~s%uy1Twd54N89 z?Va{USHEgs(`yZ<p*x#v>z=Qh?d{GMg7ji0SIiXixy-F>HcS0}zwRt9wUD2COF@^R zEZmdyJBu^-FTyzcXW@7%AS~lN1LMxa)n&`6yLD@cOsiqp<W`!dW!YuwTc~*hJkG&2 zb*RXAP2_M(_F~0FqfV`C&%tSc_#K+RK$H%Gdh>z#=W%lE5x4zB3!<AhDNdd6yt0DX zG>Q#0E$CCuJfDY{fgbWUF*0L!h>|{qST(KnO28PO!Ih5iXz0gtDlJ@vRh2yr{!isg zUetmd%)g?rw^LybvG>8xNiJnkc9efwVV9K6;q{VS;)@uFASx+456-mo2Tm{x6OQr# zrN(lNcv9;u@`yibfK7ZahblboX+iaO7yIVDg|&Ky^mG|>3g^1wRuDJ9ncpMqJcz5l z2=^m*dJa8G+{TRJetb=m1EHx&vx>i<AMR56#ZC}L^q*aR4f{5X!i2k!_(?vg!M>Mz ySV#E08=e*KTEbU8o}00ISefIN+%C@Np}a%<HBk)8zh4pN9w(E0f{8sYmi_{p%zTLe literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/dx11/fs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..8f9fa68bc575f61bc28b9b677443eb0945e63483 GIT binary patch literal 1622 zcma)6O-~bH5T0(K1uV4Iiys&_oRpZxR?*@Cw)BHGB1^hkLW~KbEP(_pSxZ7<Vw#$G z){F7v#hbly^q_x%f1npVnjXB?XZC%kZ3q}Ana;cO@ys*xZnxx=L!sB5??lwq3KK{+ zQdnEa*M3bUKixYXY1LkiH|Xb42(fI0Xc+bm^fz=9&JWNpa8?V&(h+<j1`d<_Fx2hR zJEA6zkD+1cNnvc(=TNTW9;47M1SW`$!yc?Ryu*Bbx9&R|d;7bdKj3k_!^VN{(Zii* ze*Hy#t6^TR-Z0Bc&XVbDZ)|$LnXm8d@1V$>O=V_Nvoo30?Q}X#?RLB3EH3W?pSg`d zSD-A+N%+QbX8t1V=Xe|iPsIt#ex4zY0%vu7#da!g#a^boy<}I(Ew1HlyIP>Ojh;7= z#~9qxgo+II1csZdE*4!7b;^b6<PedC#3%}9E)pe!qUOBR_U-@s9x?4FiJ)}t77fw9 zI@fBLEkWT{A`$T9a|dUh&qGbeRC(JNnK@^0ZAntT`#LXVF>KRPmgcYEdL?H}=bnS_ zhdxIxDSTj!`|$C8-bWM79K%2ii|E_u={ZrjsFYMSMfC6Jnv$VvORp3kneRN-&HWj7 zE2eWkz9r#;zA^60GomlUlVP3R6B*Gd<g-Y=SmDE1%qOs?@L3q(6XXo=L1~ovvP|nd z=F0rDx;LMNzwG%gQRG<HVW+|V7(0et_xuwImuHY3Z^Fta_5t!U8mFW!V0!t|_p*** ze`B%_#CrFpdF6!P;JYFiCv(szxGPu!eh*9XIWF(b>To|E8SU?<WvY3YAMc6ZOSTi> zDKi@u9K`>ZzDkd*Nl{<V7SUGj7c;~;#&~?cEQW<2qOSu=hJ`1x@GGkBPH?4GEZ^&C vG42z@Ow~*B|6EfX=I}Xj+??A$-c@KAiqA!0FTjd0&RN3m$XW8Qx}fGSWDb|D literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/vs_font_basic.bin b/examples/runtime/shaders/dx11/vs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..d0f3a44b337e23b2727c8614efdcf5f9a6fa4c43 GIT binary patch literal 1300 zcmah}zmF185FQS^fQ4LRcQIR7XhQ=2h$NQ_%8!EtZ^<qpXh?vAJ>jxsFC3?oCidr# z%EZPPJDMxB_fN3!58x_oY^bcn@7sNkBY4pX^JeCo@4cDbc}vYMhC(l9XLAw!e1(ya zoW|nE&4Jf-+*;pxRvCH+F_}gqGL7Ww53<{x!S~Jl=lR?9#~%g<-@q4SL@vSJhK|=n zen1;xkuGp6moID~Ca(yk-GoZy_gr3!M3LKKe1VWlxxV9idu{hfCX)%dm!U1_X$*^! ziXv~QxS?Vfme?vj25tb)Kq=1^{}pTtaRy4!_&eb52}HSwd{q2T#DQge^ql_%_*CI| z#Kk#Zfg9+1m461jbpig9=L5&9^yL>~%5n24reisskxW7ome7Ksb5&>TxQZu}FgTIF zIGiph{<P0IhF^i_EUv+_zr0Cbk-93x9R0R?*lSzPK2Bn9s%b<I`<<b8<n51)8`e#u zShmZC-D`K9p^^0lhkX}LI+02z(sxpcTghaSGcVaYyFLG;;PqEje>AvezQp4qHRaO~ zXVoyACIKbHIS=x)X4$l)V%nu@$=sD{zMeHrD<>xEx!{n?aqD{id59_4E)Cxc7G00{ z-U{y517_Eni(*0TMahX>%vo$WgCzs*BaFOoV!#u51I06hXB)vSrk{e(el*S+Pq1fZ z1RUlZ?m@illZSV?M(iFQZ>GMC+SP!kYraH2g-=cAHGTqoUDYmJ32Fg~>be@!e0<_^ s7k>}BkHWQJkH**!G1_g6%&y+Aj^M9D*&~HM^I9~n<Nw*^z5nF?0ZS{TdH?_b literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/vs_font_distance_field.bin b/examples/runtime/shaders/dx11/vs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..d0f3a44b337e23b2727c8614efdcf5f9a6fa4c43 GIT binary patch literal 1300 zcmah}zmF185FQS^fQ4LRcQIR7XhQ=2h$NQ_%8!EtZ^<qpXh?vAJ>jxsFC3?oCidr# z%EZPPJDMxB_fN3!58x_oY^bcn@7sNkBY4pX^JeCo@4cDbc}vYMhC(l9XLAw!e1(ya zoW|nE&4Jf-+*;pxRvCH+F_}gqGL7Ww53<{x!S~Jl=lR?9#~%g<-@q4SL@vSJhK|=n zen1;xkuGp6moID~Ca(yk-GoZy_gr3!M3LKKe1VWlxxV9idu{hfCX)%dm!U1_X$*^! ziXv~QxS?Vfme?vj25tb)Kq=1^{}pTtaRy4!_&eb52}HSwd{q2T#DQge^ql_%_*CI| z#Kk#Zfg9+1m461jbpig9=L5&9^yL>~%5n24reisskxW7ome7Ksb5&>TxQZu}FgTIF zIGiph{<P0IhF^i_EUv+_zr0Cbk-93x9R0R?*lSzPK2Bn9s%b<I`<<b8<n51)8`e#u zShmZC-D`K9p^^0lhkX}LI+02z(sxpcTghaSGcVaYyFLG;;PqEje>AvezQp4qHRaO~ zXVoyACIKbHIS=x)X4$l)V%nu@$=sD{zMeHrD<>xEx!{n?aqD{id59_4E)Cxc7G00{ z-U{y517_Eni(*0TMahX>%vo$WgCzs*BaFOoV!#u51I06hXB)vSrk{e(el*S+Pq1fZ z1RUlZ?m@illZSV?M(iFQZ>GMC+SP!kYraH2g-=cAHGTqoUDYmJ32Fg~>be@!e0<_^ s7k>}BkHWQJkH**!G1_g6%&y+Aj^M9D*&~HM^I9~n<Nw*^z5nF?0ZS{TdH?_b literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/vs_font_distance_field_subpixel.bin b/examples/runtime/shaders/dx11/vs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..d0f3a44b337e23b2727c8614efdcf5f9a6fa4c43 GIT binary patch literal 1300 zcmah}zmF185FQS^fQ4LRcQIR7XhQ=2h$NQ_%8!EtZ^<qpXh?vAJ>jxsFC3?oCidr# z%EZPPJDMxB_fN3!58x_oY^bcn@7sNkBY4pX^JeCo@4cDbc}vYMhC(l9XLAw!e1(ya zoW|nE&4Jf-+*;pxRvCH+F_}gqGL7Ww53<{x!S~Jl=lR?9#~%g<-@q4SL@vSJhK|=n zen1;xkuGp6moID~Ca(yk-GoZy_gr3!M3LKKe1VWlxxV9idu{hfCX)%dm!U1_X$*^! ziXv~QxS?Vfme?vj25tb)Kq=1^{}pTtaRy4!_&eb52}HSwd{q2T#DQge^ql_%_*CI| z#Kk#Zfg9+1m461jbpig9=L5&9^yL>~%5n24reisskxW7ome7Ksb5&>TxQZu}FgTIF zIGiph{<P0IhF^i_EUv+_zr0Cbk-93x9R0R?*lSzPK2Bn9s%b<I`<<b8<n51)8`e#u zShmZC-D`K9p^^0lhkX}LI+02z(sxpcTghaSGcVaYyFLG;;PqEje>AvezQp4qHRaO~ zXVoyACIKbHIS=x)X4$l)V%nu@$=sD{zMeHrD<>xEx!{n?aqD{id59_4E)Cxc7G00{ z-U{y517_Eni(*0TMahX>%vo$WgCzs*BaFOoV!#u51I06hXB)vSrk{e(el*S+Pq1fZ z1RUlZ?m@illZSV?M(iFQZ>GMC+SP!kYraH2g-=cAHGTqoUDYmJ32Fg~>be@!e0<_^ s7k>}BkHWQJkH**!G1_g6%&y+Aj^M9D*&~HM^I9~n<Nw*^z5nF?0ZS{TdH?_b literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/fs_font_basic.bin b/examples/runtime/shaders/dx9/fs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..911d8c15a305afeda1f98113aeac47e334a954dc GIT binary patch literal 445 zcmXv~y-EW?5dJnf@wD&?TfxIhn~)zY0zzUAB*j_i8L$hY5d)D6Nd(IkTZ=0#w~mc( zU@G53xF_%dT))}Xy&Y!u`<b1+ldP}Q^Y<6<u28l1$L=AyIPUEL$QXhtCOP8?NSW%4 zDnp@yBW76-!^P+^$tU>?ZvnQ*$>-N}K5Px^I2~Wl@_Bx{i1*JA;(nT?advlgGn&Oo zem@;gShQ=+cCCHbthE}A2F`#rATogNvQx)*(;dN;!=cH25MKe^)h<xkBtTCgHO-nj zS5xzfFfswat%%!#m;nZ6n_6!Apf4RCupaQWO9NO#lF#+L;9jGsk-J2*)L!$C4gSuN y(<qe2d*occNKf(g*q8Hhma;%tnhkf4%=Rfd&H1YcL)U|zg8#FEa9y~<S^&S)I#c!l literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/fs_font_distance_field.bin b/examples/runtime/shaders/dx9/fs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..786420d654b31178e77f4dfef71f518675c82a86 GIT binary patch literal 737 zcmY*WO=}ZT6g_V;Hd7Y~(yd@{)ow!5;36P2A0S!8g-r(v3PEg&fyjg;g3BjvT}*df zKDY5ln3cc4KOoF6aF<PA&wV#hJ2RJi-?`_WxpU^luy4$lKfi%r5lY_Q`lslfce;-O z3>ktMCOP9XFkm`nlo$pPo-@n!akLzN>Sfbxj_)xl?8&XyY%yw%j`4ExZk{c&t7Yx* z?5Nfs3<tI0`?r_ld99aym`$cETJ@7wz4h#*-fT1)cm+HFst&MiDxIpDJr&#p9G1Nw z#MeN3EqJ7OhnVmMZ$AN|ha^%fmztuM^Pwi^21(V$03So#=foV4x&w0ga1Qn&^kdd3 zU06B5J2q*9_61jtAxGXNoRwA14okP^YTy_YPG{s?d=*WZ>r$8dahD=TQn>x_9@*`u z@R((<3Uhw_W?KuM{M~0m-o}<gPxedg-hcIL)&}LEuQRdKA#^6@%xXKMwSI?cNl*Qf zUihYO5&cq3Ipouylp!9KM324|_x9j_VDC}T06qIR5Bjv?tar-U`3HOdoa#AAs3D&F OJb06oSr@tYMDGA$3xIwA literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/dx9/fs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..38798a5516bcd0991c1f6f8862b765928ee3e47f GIT binary patch literal 885 zcmYjOu}&L75Pf^+;3EYtQqV-gN|mIrFertkC>Sh76s92Nq)3TmAwmQa(IEp8<)X9{ zM@PA|&PRka`46P~0=hKWytm5*-`(hD-n@A;JNtgLY0UTgJK!Ki>iu8;0)w6PjpqPH zG+~B6#kc^5{4LW`nn8lM{OdUzpYERzilbtJ9}O%pr#C*wC*#%eGPVx)CdEnd^|bx+ z!>jh@a5QX>4tBrnPuhdx+wtKMonB|9*Xg}k>8y6UU2FqSfR+PnpGs>{&8`VI0f%Mo zC-GaLe=9tRxZ*zX@CZ+d|C+vjM_`>6w3dM6DFuM6l+R|Cy1^&s8d=LV0DgwJFNrxI zchAV>$2!=LA>W{%b30Q9c*i8y6Z66&$B?65;!JJi)L8xyw*tqYa<N8nbtz5NeWIvA zle1K%=1QV(+3ZHx2K(~-)T%79%FTz^F#atatD5w&#;GPFhc_k7V9n4&G3?xoFKzCS zy=Ju=jH7nKy!MpDvsvzvv;5xydx4ZN`_<<MUo)w{>g3CsAs6?e{xJvY);!%2!daMR z4Qz`1Cgpx~zM4<W345&5{nR=OtjjMFlwnR}8TE5wzMSo;GXRUkLHlE+ul;LI>QXy* UkrOfDv$1v>;;hd5(tE1?1K?|#NB{r; literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/vs_font_basic.bin b/examples/runtime/shaders/dx9/vs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..cbd66c14aea54218d79a654a7b656d1f133db4b0 GIT binary patch literal 335 zcmZ8cL2AN46n!&E7wsk&5DawFLJ3B3k)73z3k%YyT?WyJ5oJo$c5CScas-c-f+z3* z#`n_-#rgC2@Bex8{>&)sD)oK*QE;}=%1q<sD2YG&saf1Az{Zn;bt+E9JvxKub_Kv2 zAw3>LYJ35GrW&CMn`jZTt}J0OY=+#G^|6i`Q4KH2BsFU@+qe&}k8ZaY_S|qjp2n%$ zF{}4vNfLPVzzdpnui^VXsvLC(>;NYdPOBY%Q1Tmc{jX0=e$i7?@;^<^Z1J3T4||1S i#<z1j^pzSJGrdYpF5LR<Yw=;7QKLC4*W^XPSDXRwwnLi$ literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/vs_font_distance_field.bin b/examples/runtime/shaders/dx9/vs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..cbd66c14aea54218d79a654a7b656d1f133db4b0 GIT binary patch literal 335 zcmZ8cL2AN46n!&E7wsk&5DawFLJ3B3k)73z3k%YyT?WyJ5oJo$c5CScas-c-f+z3* z#`n_-#rgC2@Bex8{>&)sD)oK*QE;}=%1q<sD2YG&saf1Az{Zn;bt+E9JvxKub_Kv2 zAw3>LYJ35GrW&CMn`jZTt}J0OY=+#G^|6i`Q4KH2BsFU@+qe&}k8ZaY_S|qjp2n%$ zF{}4vNfLPVzzdpnui^VXsvLC(>;NYdPOBY%Q1Tmc{jX0=e$i7?@;^<^Z1J3T4||1S i#<z1j^pzSJGrdYpF5LR<Yw=;7QKLC4*W^XPSDXRwwnLi$ literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/vs_font_distance_field_subpixel.bin b/examples/runtime/shaders/dx9/vs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..cbd66c14aea54218d79a654a7b656d1f133db4b0 GIT binary patch literal 335 zcmZ8cL2AN46n!&E7wsk&5DawFLJ3B3k)73z3k%YyT?WyJ5oJo$c5CScas-c-f+z3* z#`n_-#rgC2@Bex8{>&)sD)oK*QE;}=%1q<sD2YG&saf1Az{Zn;bt+E9JvxKub_Kv2 zAw3>LYJ35GrW&CMn`jZTt}J0OY=+#G^|6i`Q4KH2BsFU@+qe&}k8ZaY_S|qjp2n%$ zF{}4vNfLPVzzdpnui^VXsvLC(>;NYdPOBY%Q1Tmc{jX0=e$i7?@;^<^Z1J3T4||1S i#<z1j^pzSJGrdYpF5LR<Yw=;7QKLC4*W^XPSDXRwwnLi$ literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/fs_font_basic.bin b/examples/runtime/shaders/gles/fs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..02a1f107dccfa0db8b977f24f4b12bab716cc993 GIT binary patch literal 389 zcmZXQO-{ow5QXX1rx>Xlryw^}WfgT*QCP6+5+TbZb~;jGN3Qc%#EO%01x|n+QZ*Gj zkKfEU@6B%iJez&}e9uv3Qo+*;f83MG$`p@iG#oHLRG<nYTtenjXQ*Jg9NS2(Q5jpp zQIu67?Y4fGP;)1{ttpI6NF!{II)_H4YiNRy8e_BgpOS|D@NF=IQlJJJkq-iZ+JP%8 z590TUug`DT1c_2Qp|Tbhux4=tw-B?3C<+6^>Tzl{A*@)}pFE}Ef4f6@CAVJm^id6H qZ{O8c4k_s+=G`<|z(nlSckS!h>f7KWFZj-id^n6JUmSfBa`OxGhJb(o literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/fs_font_distance_field.bin b/examples/runtime/shaders/gles/fs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..cfb5c3ceaf37b93867226852c49da5e342265c74 GIT binary patch literal 773 zcmZuv!ES;;5Up3fViGS)MMOYtVtO*QJ@nRN(-0~PZUQV_LD8nCerbQ9U(gu@U1Pbh zyEE^-o%eS6^3>~n|Nitv9Pt<)pM!@NqfmS$HbUmG7RkDRIF(^JH~Kt}L=2-*+h$a` zh^5M46J|xq)uMXmPz5Eg7c!M<Zfrxf7kL6(zVcy9g_V>la;_>X>ZfBVBFI9K12c_J z13=^@lv#m9!FZ1QZVmTTVvK35_6}~rw;dA(;Mfz>Bmhc#9m>@hTx5urQGG#B?+;fX zPXl>J(EeXgV^SyOYbYO4?9O)Zc5L&ZN*2iySUZVpbr9F2i(fT(rv}f&k9dztJW99| zOz5Cpk`4|I!;aF|+RI?t+$or1TNc*9GP0R5Or@+8Z^C2e^ejCvo1C!^`+E1<CGdta zt*!|pBqHU(Sy?Na7K||#3sZ4AfBmj=ra3hu9lYK)I6es4UX*t<;;Bk`Gn`BNd1&(x dnA^CGC9<rMOwwSf!lZeaNYYM$;$Mbw^9N|+?ymp< literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/gles/fs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..bc7057e81cdcaf0f780d88b8bf5991918c35ae4b GIT binary patch literal 1119 zcmb7D%Wm5+5NxjciUo2Z8;91@mSE%*#Oa~89E(CwElMF^NiHqhl7pW5rTv9`L3j1A z>H1Ja7gF4v8FF@a`SRuF=J)%bTa~3UgXgdD(~Gsya;3JaD&bY-uN%nLRZ=gkTUn+m zgXwfgvv#G*DqX-fDK=}VA9p__?BZHBkJY-;3u~X~R+TyI<;sUW1y)t1Q~N5iqI^28 zR0>6+N?_c2vj9|CLtSi;D0UY3KkngyLX0tkRUF_m_`>FJ2et?}Cjd%&Bg!=xTx3X> zX>&o)w8txuXMnsO)czOb8z3J+%offJzd7D;c!Jw0b<U1Qfq@DTg?`mLEjwG;+1CmD zs}J`hh0nP-w$0(&Xw-M&yil1LDzgu%+<ic0Zm7(A2LgON8}1cgjfU;4FVw{yLjxTW zIutgcw?B2w(yBi3xRa5_<y7~p1n-pKar}taY>CJaibO+p^xbCGA`<O6U_LAo$8(_b zwSR?7b7{v8HZ;Jvr&nNCo=X)Pmx-OeyK%+5B58mXGz4t)D?;4J#9@jN;yQU4ax=~+ z;NTcca0={BBwxo%o#fqA3T$$^3#&<tDl)7dT6_=8?VP4V@(UC8aX+2naLsifrol1l L?Tg%Bmi6f`3JqHa literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/vs_font_basic.bin b/examples/runtime/shaders/gles/vs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..46478bd820e738904145a91abda6ead8a9445543 GIT binary patch literal 414 zcmZvYv2MaJ5QfX@r#OivR8<lXThy^?hYm<ctd@!Ga47Lb#tEcVC!Um7;0Z7ZsY1(U z-RJ-JcU~<&Mx*2TG)66zhWAhYwq&JMDejOAY%trDpmP!~VPj<^YKWrSHC7qaWD6*S zn?uD5k}6-J+Al0^6IKh`pvj<C=^SeA)FCCZGX6(W%E|h%aL(eoa;l4nVdRd@K=6`w z=)B^CSl?F@O7DgSf(iR((AB!4^k#gT_(6XTzxMEY#j_v|;}@8Q@#Kyl8qbH10%SQ~ h+#Ea${;UtrzvXSyVE?vh@EhKXcgij4?SB}1x&ZxyicSCk literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/vs_font_distance_field.bin b/examples/runtime/shaders/gles/vs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..46478bd820e738904145a91abda6ead8a9445543 GIT binary patch literal 414 zcmZvYv2MaJ5QfX@r#OivR8<lXThy^?hYm<ctd@!Ga47Lb#tEcVC!Um7;0Z7ZsY1(U z-RJ-JcU~<&Mx*2TG)66zhWAhYwq&JMDejOAY%trDpmP!~VPj<^YKWrSHC7qaWD6*S zn?uD5k}6-J+Al0^6IKh`pvj<C=^SeA)FCCZGX6(W%E|h%aL(eoa;l4nVdRd@K=6`w z=)B^CSl?F@O7DgSf(iR((AB!4^k#gT_(6XTzxMEY#j_v|;}@8Q@#Kyl8qbH10%SQ~ h+#Ea${;UtrzvXSyVE?vh@EhKXcgij4?SB}1x&ZxyicSCk literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/vs_font_distance_field_subpixel.bin b/examples/runtime/shaders/gles/vs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..46478bd820e738904145a91abda6ead8a9445543 GIT binary patch literal 414 zcmZvYv2MaJ5QfX@r#OivR8<lXThy^?hYm<ctd@!Ga47Lb#tEcVC!Um7;0Z7ZsY1(U z-RJ-JcU~<&Mx*2TG)66zhWAhYwq&JMDejOAY%trDpmP!~VPj<^YKWrSHC7qaWD6*S zn?uD5k}6-J+Al0^6IKh`pvj<C=^SeA)FCCZGX6(W%E|h%aL(eoa;l4nVdRd@K=6`w z=)B^CSl?F@O7DgSf(iR((AB!4^k#gT_(6XTzxMEY#j_v|;}@8Q@#Kyl8qbH10%SQ~ h+#Ea${;UtrzvXSyVE?vh@EhKXcgij4?SB}1x&ZxyicSCk literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/fs_font_basic.bin b/examples/runtime/shaders/glsl/fs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..acd2c4b09ea2bd65a668eecfd5d8ea3fb7e40f01 GIT binary patch literal 350 zcmZXQu?~VT5QcT_Q(WTGs%e1eM4U*7yQ47#v63dxk^%)ZPClux;1k#)MvPmpU+=sB z8t%5!>HYbbX{Jgp1-PDrP%ZdbsvOEVFEXZr`pBS;D%J)vlgdXrRvi~9XqK!%TaZYp zPR<`m?0b7H`3drv3%~?j5daqzRC!@Uk?WiKbB2vY7~_$ZHZX@3bqFlLp=&~HLqB@x z@<s-aw%x^8bo8EW%OBhrXzT;EY7@Vz73;Ue-!+%x&8&vdOV>90Pt-%7Bh8{v#cBUB L#{5lmLum2>Vl8vO literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/fs_font_distance_field.bin b/examples/runtime/shaders/glsl/fs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..b1db0c0e27a8fe4cf5e817404a69bd25f2a95544 GIT binary patch literal 734 zcmZuv!ES;;5Up3fVv=5VD^dj1CZ;D7(|eCiLr_*i0<2vZ1e>1vrTv9|L1z$fjpf3^ z%zJO<y<NY)j7HzTKlhbThg23Y^<2v;i*zSd4u>e;XF{#Yjes)LqF%{Ns-;y$s!59k zDzOcqqQX{66}vZ;E%noHnZ}SuX#tE|pB6w`Xwdl{iNfg;zxy*hQ;9KVusTP0fWUD% zjKOtgoD%@0{T}5R3?4GX>$tumsGHLb$TvX#8Pxm>+GR2th7Al<fGGClxHug<d??Lg zseyHyc=j+Ir@?O;{Gq|;_z>?|NyLe8!x{bPj--Q&!=$GSjCLK)+nK^Sw&hU`EGL^8 z!&G#sL>nHvq-UFfIpmCUYU<-#pTIlHbh;cKk%*MX7iFW&ZJ1&#Hm2hC{sw*L!f<Lq zIyhbxo-YJ_UX_ou;!vf$8SZ7ge6)E2%xm4o5?R(tCRw;vQPN&aB<Z$5@h{7|`vbJy B;qCwc literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/glsl/fs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..d66589e293bce85f83c08736ca64baacdf07189a GIT binary patch literal 1080 zcmb7DO>crg5Up2!#U#D#R^9Tc5Ytl=(|eCiL#Uu35!SAVVAE57Y5zihL1*~TwH_L| zurTx9+j%oHe|{PazJ9)M%S3HcnS*7UhOx`jrBoSgqinNI)Z^|gfn8W6)uUWXH8aXc z)oH$hGFiA#QeYvaip`72g7WFNOk>ERGzZ3w4+9|03n;P;5{1?bzxy*hP>3<6v5Gz1 zfh$Z7LokKMIRQ}G=~1@EU?W33kE=6+sy<wR91Y~Op!#2stAShuF;iF*e5QEAt^~VL zTCQbutkBa?9-`2%VyBYER(A4r1b_8m+_Sozi$h)QUwWfniStZlqNz--QW;*MGSyV3 ztpgqw&$@eg*rV<^X&ZHRM_)txg!Y9==<T~ISS*Vpk3H&XY)*Z@NN|n`4#$Uh^^piP zp+Hn*M>}nLF9K1Y0(xPAIGh5FuWc1cyh_Z_!hr_p&r}6Y<*8M^cA3y>ryJjxmqit@ zjFy1)eg%l@nK;~Igt(3#`dp9m5m>keBisVB5m~Lnxr$cJRtg+)x(h2vj5^Z29kh51 g%x;{fpX3)NlwrG_Vt>iCC#KFZn(edPPs6zR1sE?*MgRZ+ literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/vs_font_basic.bin b/examples/runtime/shaders/glsl/vs_font_basic.bin new file mode 100644 index 0000000000000000000000000000000000000000..29f68c9ef1b1268bd95be2cdb209cc4e4b47da63 GIT binary patch literal 375 zcmZvY%L>9U5Jh#HuNZLCij=gtEACwig4+<=D3K;p(lows<(K*keu1&IQXji8hkJ8o zR?GQtc)j07PMAufhB%>w)LL%PC{Wx^p=JtmQLLocFAVNd;<!0Vy#*(-DL7`uAwx7d z{UI3^X#AL4Yvj7NqK)u=<bx%^S&5aj-sDfL>vJe`?<O?_AvqIhYpp818H-at=-$z3 z53?su0vgc?#1RcY_~Gbz|5Jc%!4@wE&w{V@Vf-#{ntJ;;O}%S)FV-qIq_e*eGI#(g C(tV8p literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/vs_font_distance_field.bin b/examples/runtime/shaders/glsl/vs_font_distance_field.bin new file mode 100644 index 0000000000000000000000000000000000000000..29f68c9ef1b1268bd95be2cdb209cc4e4b47da63 GIT binary patch literal 375 zcmZvY%L>9U5Jh#HuNZLCij=gtEACwig4+<=D3K;p(lows<(K*keu1&IQXji8hkJ8o zR?GQtc)j07PMAufhB%>w)LL%PC{Wx^p=JtmQLLocFAVNd;<!0Vy#*(-DL7`uAwx7d z{UI3^X#AL4Yvj7NqK)u=<bx%^S&5aj-sDfL>vJe`?<O?_AvqIhYpp818H-at=-$z3 z53?su0vgc?#1RcY_~Gbz|5Jc%!4@wE&w{V@Vf-#{ntJ;;O}%S)FV-qIq_e*eGI#(g C(tV8p literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/vs_font_distance_field_subpixel.bin b/examples/runtime/shaders/glsl/vs_font_distance_field_subpixel.bin new file mode 100644 index 0000000000000000000000000000000000000000..29f68c9ef1b1268bd95be2cdb209cc4e4b47da63 GIT binary patch literal 375 zcmZvY%L>9U5Jh#HuNZLCij=gtEACwig4+<=D3K;p(lows<(K*keu1&IQXji8hkJ8o zR?GQtc)j07PMAufhB%>w)LL%PC{Wx^p=JtmQLLocFAVNd;<!0Vy#*(-DL7`uAwx7d z{UI3^X#AL4Yvj7NqK)u=<bx%^S&5aj-sDfL>vJe`?<O?_AvqIhYpp818H-at=-$z3 z53?su0vgc?#1RcY_~Gbz|5Jc%!4@wE&w{V@Vf-#{ntJ;;O}%S)FV-qIq_e*eGI#(g C(tV8p literal 0 HcmV?d00001 diff --git a/premake/premake4.lua b/premake/premake4.lua index f75839c7..d9a4a1e6 100644 --- a/premake/premake4.lua +++ b/premake/premake4.lua @@ -116,6 +116,8 @@ exampleProject("06-bump", "ffb23e6c-167b-11e2-81df-94c4dd6a022f") exampleProject("07-callback", "acc53bbc-52f0-11e2-9781-ad8edd4b7d02") exampleProject("08-update", "e011e246-5862-11e2-b202-b7cb257a7926") exampleProject("09-hdr", "969a4626-67ee-11e2-9726-9023267a7926") +exampleProject("10-font_alpha" , "EF6FD5B3-B52A-41C2-A257-9DFE709AF9E1") +exampleProject("11-font_distance_field", "F4E6F96F-3DAA-4C68-8DF8-BF2A3ECD9092") dofile "makedisttex.lua" dofile "shaderc.lua" dofile "texturec.lua" From 62c9a457c1160d3c4092118e5a6df1c116cd809d Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 14:09:45 +0200 Subject: [PATCH 02/38] rename samples to shorter name --- examples/{10-font_alpha => 10-font}/basics.cpp | 0 .../distance_field_text.cpp | 0 premake/premake4.lua | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename examples/{10-font_alpha => 10-font}/basics.cpp (100%) rename examples/{11-font_distance_field => 11-fontdfs}/distance_field_text.cpp (100%) diff --git a/examples/10-font_alpha/basics.cpp b/examples/10-font/basics.cpp similarity index 100% rename from examples/10-font_alpha/basics.cpp rename to examples/10-font/basics.cpp diff --git a/examples/11-font_distance_field/distance_field_text.cpp b/examples/11-fontdfs/distance_field_text.cpp similarity index 100% rename from examples/11-font_distance_field/distance_field_text.cpp rename to examples/11-fontdfs/distance_field_text.cpp diff --git a/premake/premake4.lua b/premake/premake4.lua index d9a4a1e6..6164deee 100644 --- a/premake/premake4.lua +++ b/premake/premake4.lua @@ -116,8 +116,8 @@ exampleProject("06-bump", "ffb23e6c-167b-11e2-81df-94c4dd6a022f") exampleProject("07-callback", "acc53bbc-52f0-11e2-9781-ad8edd4b7d02") exampleProject("08-update", "e011e246-5862-11e2-b202-b7cb257a7926") exampleProject("09-hdr", "969a4626-67ee-11e2-9726-9023267a7926") -exampleProject("10-font_alpha" , "EF6FD5B3-B52A-41C2-A257-9DFE709AF9E1") -exampleProject("11-font_distance_field", "F4E6F96F-3DAA-4C68-8DF8-BF2A3ECD9092") +exampleProject("10-font" , "EF6FD5B3-B52A-41C2-A257-9DFE709AF9E1") +exampleProject("11-fontdfs", "F4E6F96F-3DAA-4C68-8DF8-BF2A3ECD9092") dofile "makedisttex.lua" dofile "shaderc.lua" dofile "texturec.lua" From 253d07435cd111b326ed62fa82b8e226c30f660c Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 14:10:53 +0200 Subject: [PATCH 03/38] rename font samples main cpp to the project name --- examples/10-font/{basics.cpp => font.cpp} | 0 examples/11-fontdfs/{distance_field_text.cpp => fontdfs.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename examples/10-font/{basics.cpp => font.cpp} (100%) rename examples/11-fontdfs/{distance_field_text.cpp => fontdfs.cpp} (100%) diff --git a/examples/10-font/basics.cpp b/examples/10-font/font.cpp similarity index 100% rename from examples/10-font/basics.cpp rename to examples/10-font/font.cpp diff --git a/examples/11-fontdfs/distance_field_text.cpp b/examples/11-fontdfs/fontdfs.cpp similarity index 100% rename from examples/11-fontdfs/distance_field_text.cpp rename to examples/11-fontdfs/fontdfs.cpp From 8ddda84cd71485683d018d485f80d7e4c286ffe9 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 14:28:31 +0200 Subject: [PATCH 04/38] restore pen position (did break it for debug previously) --- examples/common/font/text_buffer_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 7265e2ee..5d3399f9 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -112,7 +112,7 @@ public: void setUnderlineColor(uint32_t rgba = 0x000000FF) { m_underlineColor = toABGR(rgba); } void setStrikeThroughColor(uint32_t rgba = 0x000000FF) { m_strikeThroughColor = toABGR(rgba); } - void setPenPosition(float x, float /*y*/) { m_penX = x; };// m_penY = y; } + void setPenPosition(float x, float y) { m_penX = x; m_penY = y; } /// return the size of the text //Rectangle measureText(FontHandle fontHandle, const char * _string); From 7f6d441c27aa38baee8268ba7d6ac22d7e723102 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 14:29:35 +0200 Subject: [PATCH 05/38] add proper debug comment in the font sample using the text system (good demonstration) --- examples/10-font/font.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 6e594fdb..ffe8f37e 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -147,11 +147,26 @@ int _main_(int /*_argc*/, char** /*_argv*/) static int64_t last = now; const int64_t frameTime = now - last; last = now; - const double freq = double(bx::getHPFrequency() ); const double toMs = 1000.0/freq; - //float time = (float)(bx::getHPCounter()/double(bx::getHPFrequency() ) ); + + // Use debug font to print information about this example. + //bgfx::dbgTextClear(); + //bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/10-font"); + //bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use the font system to display text and styled text."); + //bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + //Use transient text to display debug information + //Code below is similar to commented code above + wchar_t fpsText[64]; + swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); + + textBufferManager->clearTextBuffer(transientText); + textBufferManager->setPenPosition(transientText, 20.0, 4.0f); + textBufferManager->appendText(transientText, consola_16, L"bgfx/examples/10-font\n"); + textBufferManager->appendText(transientText, consola_16, L"Description: Use the font system to display text and styled text.\n"); + textBufferManager->appendText(transientText, consola_16, fpsText); + float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; @@ -165,23 +180,12 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Set view and projection matrix for view 0. bgfx::setViewTransform(0, view, proj); + //submit the debug text + textBufferManager->submitTextBuffer(transientText, 0); + //submit the static text textBufferManager->submitTextBuffer(staticText, 0); - - - //submit some realtime text - wchar_t fpsText[64]; - swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); - - textBufferManager->clearTextBuffer(transientText); - textBufferManager->setPenPosition(transientText, 20.0, 4.0f); - - textBufferManager->appendText(transientText, consola_16, L"bgfx_font\\sample\\01_basics\n"); - textBufferManager->appendText(transientText, consola_16, L"Description: truetype, font, text and style\n"); - textBufferManager->appendText(transientText, consola_16, fpsText); - - textBufferManager->submitTextBuffer(transientText, 0); - + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); From 1f44b65ef6cf5f91853b3152819e930336b0cda7 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 14:32:31 +0200 Subject: [PATCH 06/38] proper debug text message in fontdfs --- examples/11-fontdfs/fontdfs.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/examples/11-fontdfs/fontdfs.cpp b/examples/11-fontdfs/fontdfs.cpp index ba00dcad..1d5b607f 100644 --- a/examples/11-fontdfs/fontdfs.cpp +++ b/examples/11-fontdfs/fontdfs.cpp @@ -89,7 +89,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) bgfx_font::TextBufferHandle staticText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_DISTANCE, bgfx_font::STATIC); - textBufferManager->setPenPosition(staticText, 10.0f, 10.0f); + textBufferManager->setPenPosition(staticText, 10.0f, 70.0f); textBufferManager->setTextColor(staticText, 0xFFFFFFFF); //textBufferManager->setTextColor(staticText, 0x000000FF); for(size_t i = 0; i< fontsCount; ++i) @@ -107,20 +107,19 @@ int _main_(int /*_argc*/, char** /*_argv*/) // if no other draw calls are submitted to view 0. bgfx::submit(0); - //int64_t now = bx::getHPCounter(); - //static int64_t last = now; - //const int64_t frameTime = now - last; - //last = now; - //const double freq = double(bx::getHPFrequency() ); - //const double toMs = 1000.0/freq; - //float time = (float)(bx::getHPCounter()/double(bx::getHPFrequency() ) ); - + int64_t now = bx::getHPCounter(); + static int64_t last = now; + const int64_t frameTime = now - last; + last = now; + const double freq = double(bx::getHPFrequency() ); + const double toMs = 1000.0/freq; + // Use debug font to print information about this example. bgfx::dbgTextClear(); - //bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/00-helloworld"); - //bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Initialization and debug text."); - //bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); - + bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontdfs"); + bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of different size."); + bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; From 7f3fb10f2accca7eda6e3877dce8889747a668e9 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 17:18:54 +0200 Subject: [PATCH 07/38] Remove namespace from font utility classes --- examples/10-font/font.cpp | 29 ++++++++++---------- examples/11-fontdfs/fontdfs.cpp | 14 +++++----- examples/common/cube_atlas.cpp | 5 ---- examples/common/cube_atlas.h | 5 +--- examples/common/font/font_manager.cpp | 18 ++---------- examples/common/font/font_manager.h | 14 +++------- examples/common/font/text_buffer_manager.cpp | 5 ---- examples/common/font/text_buffer_manager.h | 5 ---- 8 files changed, 29 insertions(+), 66 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index ffe8f37e..715dea2d 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -61,17 +61,16 @@ int _main_(int /*_argc*/, char** /*_argv*/) } //init the text rendering system - bgfx_font::FontManager* fontManager = new bgfx_font::FontManager(512); - bgfx_font::TextBufferManager* textBufferManager = new bgfx_font::TextBufferManager(fontManager); + FontManager* fontManager = new FontManager(512); + TextBufferManager* textBufferManager = new TextBufferManager(fontManager); textBufferManager->init(s_shaderPath); - - + //load some truetype files - bgfx_font::TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); - bgfx_font::TrueTypeHandle consola_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/consola.ttf"); + TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); + TrueTypeHandle consola_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/consola.ttf"); //create some usable font with of a specific size - bgfx_font::FontHandle times_24 = fontManager->createFontByPixelSize(times_tt, 0, 24); + FontHandle times_24 = fontManager->createFontByPixelSize(times_tt, 0, 24); //preload glyphs and blit them to atlas fontManager->preloadGlyph(times_24, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); @@ -81,11 +80,11 @@ int _main_(int /*_argc*/, char** /*_argv*/) //this font doesn't have any preloaded glyph's but the truetype file is loaded //so glyph will be generated as needed - bgfx_font::FontHandle consola_16 = fontManager->createFontByPixelSize(consola_tt, 0, 16); + FontHandle consola_16 = fontManager->createFontByPixelSize(consola_tt, 0, 16); //create a static text buffer compatible with alpha font //a static text buffer content cannot be modified after its first submit. - bgfx_font::TextBufferHandle staticText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_ALPHA, bgfx_font::STATIC); + TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, STATIC); //the pen position represent the top left of the box of the first line of text textBufferManager->setPenPosition(staticText, 20.0f, 100.0f); @@ -102,28 +101,28 @@ int _main_(int /*_argc*/, char** /*_argv*/) //text + bkg - textBufferManager->setStyle(staticText, bgfx_font::STYLE_BACKGROUND); + textBufferManager->setStyle(staticText, STYLE_BACKGROUND); textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); //text + strike-through - textBufferManager->setStyle(staticText, bgfx_font::STYLE_STRIKE_THROUGH); + textBufferManager->setStyle(staticText, STYLE_STRIKE_THROUGH); textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); //text + overline - textBufferManager->setStyle(staticText, bgfx_font::STYLE_OVERLINE); + textBufferManager->setStyle(staticText, STYLE_OVERLINE); textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); //text + underline - textBufferManager->setStyle(staticText, bgfx_font::STYLE_UNDERLINE); + textBufferManager->setStyle(staticText, STYLE_UNDERLINE); textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); //text + bkg + strike-through - textBufferManager->setStyle(staticText, bgfx_font::STYLE_BACKGROUND|bgfx_font::STYLE_STRIKE_THROUGH); + textBufferManager->setStyle(staticText, STYLE_BACKGROUND|STYLE_STRIKE_THROUGH); textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); //create a transient buffer for realtime data - bgfx_font::TextBufferHandle transientText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_ALPHA, bgfx_font::TRANSIENT); + TextBufferHandle transientText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, TRANSIENT); uint32_t w = 0,h = 0; diff --git a/examples/11-fontdfs/fontdfs.cpp b/examples/11-fontdfs/fontdfs.cpp index 1d5b607f..d7fc7d9c 100644 --- a/examples/11-fontdfs/fontdfs.cpp +++ b/examples/11-fontdfs/fontdfs.cpp @@ -62,18 +62,18 @@ int _main_(int /*_argc*/, char** /*_argv*/) } //init the text rendering system - bgfx_font::FontManager* fontManager = new bgfx_font::FontManager(512); - bgfx_font::TextBufferManager* textBufferManager = new bgfx_font::TextBufferManager(fontManager); + FontManager* fontManager = new FontManager(512); + TextBufferManager* textBufferManager = new TextBufferManager(fontManager); textBufferManager->init(s_shaderPath); //load a truetype files - bgfx_font::TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); - bgfx_font::FontHandle distance_font = fontManager->createFontByPixelSize(times_tt, 0, 48, bgfx_font::FONT_TYPE_DISTANCE); + TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); + FontHandle distance_font = fontManager->createFontByPixelSize(times_tt, 0, 48, FONT_TYPE_DISTANCE); //preload glyph and generate (generate bitmap's) fontManager->preloadGlyph(distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); uint32_t fontsCount = 0; - bgfx_font::FontHandle fonts[64]; + FontHandle fonts[64]; fonts[fontsCount++] = distance_font; //generate various sub distance field fonts at various size int step=4; @@ -81,13 +81,13 @@ int _main_(int /*_argc*/, char** /*_argv*/) { if(i<32) step = 2; //instantiate a usable font - bgfx_font::FontHandle font = fontManager->createScaledFontToPixelSize(distance_font, i); + FontHandle font = fontManager->createScaledFontToPixelSize(distance_font, i); fonts[fontsCount++] = font; } //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph fontManager->unloadTrueType(times_tt); - bgfx_font::TextBufferHandle staticText = textBufferManager->createTextBuffer(bgfx_font::FONT_TYPE_DISTANCE, bgfx_font::STATIC); + TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); textBufferManager->setPenPosition(staticText, 10.0f, 70.0f); textBufferManager->setTextColor(staticText, 0xFFFFFFFF); diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index 3f705807..baa95c53 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -7,9 +7,6 @@ #include <vector> #include "cube_atlas.h" -namespace bgfx -{ - //********** Rectangle packer implementation ************ class RectanglePacker { @@ -479,5 +476,3 @@ void Atlas::packUV( const AtlasRegion& region, uint8_t* vertexBuffer, uint32_t o break; } } - -} \ No newline at end of file diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 70b10eaf..7f8ca118 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -14,9 +14,6 @@ #include <bgfx.h> -namespace bgfx -{ - struct AtlasRegion { enum Type @@ -133,4 +130,4 @@ private: AtlasRegion* m_regions; uint8_t* m_textureBuffer; -};} \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index d12d96e2..4c607e3f 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -40,12 +40,6 @@ namespace stl { } #endif // BGFX_CONFIG_USE_TINYSTL - -#define BGFX_FONT_ASSERT(cond, message) assert((cond) && (message)); - -namespace bgfx_font -{ - class FontManager::TrueTypeFont { public: @@ -445,7 +439,7 @@ const uint16_t MAX_OPENED_FILES = 64; const uint16_t MAX_OPENED_FONT = 64; const uint32_t MAX_FONT_BUFFER_SIZE = 512*512*4; -FontManager::FontManager(bgfx::Atlas* atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(Atlas* atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { m_atlas = atlas; m_ownAtlas = false; @@ -454,7 +448,7 @@ FontManager::FontManager(bgfx::Atlas* atlas):m_filesHandles(MAX_OPENED_FILES), m FontManager::FontManager(uint32_t textureSideWidth):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { - m_atlas = new bgfx::Atlas(textureSideWidth); + m_atlas = new Atlas(textureSideWidth); m_ownAtlas = true; init(); } @@ -781,12 +775,6 @@ bool FontManager::getGlyphInfo(FontHandle fontHandle, CodePoint_t codePoint, Gly bool FontManager::addBitmap(GlyphInfo& glyphInfo, const uint8_t* data) { - glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(glyphInfo.width),(uint16_t) ceil(glyphInfo.height), data, bgfx::AtlasRegion::TYPE_GRAY); + glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(glyphInfo.width),(uint16_t) ceil(glyphInfo.height), data, AtlasRegion::TYPE_GRAY); return true; } - - - - - -} diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index 65c86e89..07a40870 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -5,11 +5,7 @@ #include <bgfx.h> #include <bx/handlealloc.h> -namespace bgfx{ class Atlas; } - -namespace bgfx_font -{ - +class Atlas; enum FontType { FONT_TYPE_ALPHA = 0x00000100 , // L8 @@ -116,14 +112,14 @@ class FontManager { public: /// create the font manager using an external cube atlas (doesn't take ownership of the atlas) - FontManager(bgfx::Atlas* atlas); + FontManager(Atlas* atlas); /// create the font manager and create the texture cube as BGRA8 with linear filtering FontManager(uint32_t textureSideWidth = 512); ~FontManager(); /// retrieve the atlas used by the font manager (e.g. to add stuff to it) - bgfx::Atlas* getAtlas() { return m_atlas; } + Atlas* getAtlas() { return m_atlas; } /// load a TrueType font from a file path /// @return invalid handle if the loading fail @@ -191,7 +187,7 @@ private: bool addBitmap(GlyphInfo& glyphInfo, const uint8_t* data); bool m_ownAtlas; - (bgfx::Atlas* m_atlas; + (Atlas* m_atlas; bx::HandleAlloc m_fontHandles; CachedFont* m_cachedFonts; @@ -204,5 +200,3 @@ private: //temporary buffer to raster glyph uint8_t* m_buffer; }; - -} diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 5d3399f9..b7b325b9 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -10,9 +10,6 @@ #include <math.h> #include <stddef.h> /* offsetof */ -namespace bgfx_font -{ - const uint16_t MAX_TEXT_BUFFER_COUNT = 64; long int fsize(FILE* _file) @@ -808,5 +805,3 @@ void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->clearTextBuffer(); } - -} diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 2a386c71..57720fbd 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -4,9 +4,6 @@ #pragma once #include "font_manager.h" -namespace bgfx_font -{ - BGFX_HANDLE(TextBufferHandle); /// type of vertex and index buffer to use with a TextBuffer @@ -86,5 +83,3 @@ private: bgfx::ProgramHandle m_distanceProgram; bgfx::ProgramHandle m_distanceSubpixelProgram; }; - -} From 3156a79257ac9cf7a6bd8ff97872dfee04bb4453 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 17:22:19 +0200 Subject: [PATCH 08/38] fix a typo in fontsdf name --- examples/{11-fontdfs/fontdfs.cpp => 11-fontsdf/fontsdf.cpp} | 0 premake/premake4.lua | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename examples/{11-fontdfs/fontdfs.cpp => 11-fontsdf/fontsdf.cpp} (100%) diff --git a/examples/11-fontdfs/fontdfs.cpp b/examples/11-fontsdf/fontsdf.cpp similarity index 100% rename from examples/11-fontdfs/fontdfs.cpp rename to examples/11-fontsdf/fontsdf.cpp diff --git a/premake/premake4.lua b/premake/premake4.lua index 6164deee..9e53ad56 100644 --- a/premake/premake4.lua +++ b/premake/premake4.lua @@ -117,7 +117,7 @@ exampleProject("07-callback", "acc53bbc-52f0-11e2-9781-ad8edd4b7d02") exampleProject("08-update", "e011e246-5862-11e2-b202-b7cb257a7926") exampleProject("09-hdr", "969a4626-67ee-11e2-9726-9023267a7926") exampleProject("10-font" , "EF6FD5B3-B52A-41C2-A257-9DFE709AF9E1") -exampleProject("11-fontdfs", "F4E6F96F-3DAA-4C68-8DF8-BF2A3ECD9092") +exampleProject("11-fontsdf", "F4E6F96F-3DAA-4C68-8DF8-BF2A3ECD9092") dofile "makedisttex.lua" dofile "shaderc.lua" dofile "texturec.lua" From 1f5db2d7dbd46d030cdc3cb66aec50cad5b1761d Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 17:23:00 +0200 Subject: [PATCH 09/38] fix typo in debug text --- examples/11-fontsdf/fontsdf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index d7fc7d9c..a1c4a66f 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -116,8 +116,8 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Use debug font to print information about this example. bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontdfs"); - bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of different size."); + bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontsdf"); + bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of various size."); bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); float at[3] = { 0, 0, 0.0f }; From 6b8b95acd8baddedb0afd1e8e9b2f954bfa81d06 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 20:36:07 +0200 Subject: [PATCH 10/38] update cube_atlas to bgfx naming style --- examples/common/cube_atlas.cpp | 270 ++++++++++++++++----------------- examples/common/cube_atlas.h | 54 +++---- 2 files changed, 162 insertions(+), 162 deletions(-) diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index baa95c53..c56ad3b9 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -12,13 +12,13 @@ class RectanglePacker { public: RectanglePacker(); - RectanglePacker(uint32_t width, uint32_t height); + RectanglePacker(uint32_t _width, uint32_t _height); /// non constructor initialization - void init(uint32_t width, uint32_t height); + void init(uint32_t _width, uint32_t _height); /// find a suitable position for the given rectangle /// @return true if the rectangle can be added, false otherwise - bool addRectangle(uint16_t width, uint16_t height, uint16_t& outX, uint16_t& outY ); + bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY ); /// return the used surface in squared unit uint32_t getUsedSurface() { return m_usedSpace; } /// return the total available surface in squared unit @@ -29,25 +29,25 @@ public: void clear(); private: - int32_t fit(uint32_t skylineNodeIndex, uint16_t width, uint16_t height); + int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height); /// Merges all skyline nodes that are at the same level. void merge(); struct Node { - Node(int16_t _x, int16_t _y, int16_t _width):x(_x), y(_y), width(_width) {} + Node(int16_t _x, int16_t _y, int16_t _width):m_x(_x), m_y(_y), m_width(_width) {} /// The starting x-coordinate (leftmost). - int16_t x; + int16_t m_x; /// The y-coordinate of the skyline level line. - int16_t y; - /// The line width. The ending coordinate (inclusive) will be x+width-1. - int32_t width; //32bit to avoid padding + int16_t m_y; + /// The line _width. The ending coordinate (inclusive) will be x+width-1. + int32_t m_width; //32bit to avoid padding }; - /// Width (in pixels) of the underlying texture + /// width (in pixels) of the underlying texture uint32_t m_width; - /// Height (in pixels) of the underlying texture + /// height (in pixels) of the underlying texture uint32_t m_height; /// Surface used in squared pixel uint32_t m_usedSpace; @@ -59,35 +59,35 @@ RectanglePacker::RectanglePacker(): m_width(0), m_height(0), m_usedSpace(0) { } -RectanglePacker::RectanglePacker(uint32_t width, uint32_t height):m_width(width), m_height(height), m_usedSpace(0) +RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height):m_width(_width), m_height(_height), m_usedSpace(0) { // We want a one pixel border around the whole atlas to avoid any artefact when // sampling texture - m_skyline.push_back(Node(1,1, width-2)); + m_skyline.push_back(Node(1,1, _width-2)); } -void RectanglePacker::init(uint32_t width, uint32_t height) +void RectanglePacker::init(uint32_t _width, uint32_t _height) { - assert(width > 2); - assert(height > 2); - m_width = width; - m_height = height; + assert(_width > 2); + assert(_height > 2); + m_width = _width; + m_height = _height; m_usedSpace = 0; m_skyline.clear(); // We want a one pixel border around the whole atlas to avoid any artifact when // sampling texture - m_skyline.push_back(Node(1,1, width-2)); + m_skyline.push_back(Node(1,1, _width-2)); } -bool RectanglePacker::addRectangle(uint16_t width, uint16_t height, uint16_t& outX, uint16_t& outY) +bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY) { int y, best_height, best_index; int32_t best_width; Node* node; Node* prev; - outX = 0; - outY = 0; + _outX = 0; + _outY = 0; size_t i; @@ -96,18 +96,18 @@ bool RectanglePacker::addRectangle(uint16_t width, uint16_t height, uint16_t& ou best_width = INT_MAX; for( i = 0; i < m_skyline.size(); ++i ) { - y = fit( i, width, height ); + y = fit( i, _width, _height ); if( y >= 0 ) { node = &m_skyline[i]; - if( ( (y + height) < best_height ) || - ( ((y + height) == best_height) && (node->width < best_width)) ) + if( ( (y + _height) < best_height ) || + ( ((y + _height) == best_height) && (node->m_width < best_width)) ) { - best_height = y + height; + best_height = y + _height; best_index = i; - best_width = node->width; - outX = node->x; - outY = y; + best_width = node->m_width; + _outX = node->m_x; + _outY = y; } } } @@ -117,19 +117,19 @@ bool RectanglePacker::addRectangle(uint16_t width, uint16_t height, uint16_t& ou return false; } - Node newNode(outX,outY + height, width); + Node newNode(_outX, _outY + _height, _width); m_skyline.insert(m_skyline.begin() + best_index, newNode); for(i = best_index+1; i < m_skyline.size(); ++i) { node = &m_skyline[i]; prev = &m_skyline[i-1]; - if (node->x < (prev->x + prev->width) ) + if (node->m_x < (prev->m_x + prev->m_width) ) { - int shrink = prev->x + prev->width - node->x; - node->x += shrink; - node->width -= shrink; - if (node->width <= 0) + int shrink = prev->m_x + prev->m_width - node->m_x; + node->m_x += shrink; + node->m_width -= shrink; + if (node->m_width <= 0) { m_skyline.erase(m_skyline.begin() + i); --i; @@ -146,7 +146,7 @@ bool RectanglePacker::addRectangle(uint16_t width, uint16_t height, uint16_t& ou } merge(); - m_usedSpace += width * height; + m_usedSpace += _width * _height; return true; } @@ -169,34 +169,34 @@ void RectanglePacker::clear() m_skyline.push_back(Node(1,1, m_width-2)); } -int32_t RectanglePacker::fit(uint32_t skylineNodeIndex, uint16_t _width, uint16_t _height) +int32_t RectanglePacker::fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height) { int32_t width = _width; int32_t height = _height; - const Node& baseNode = m_skyline[skylineNodeIndex]; + const Node& baseNode = m_skyline[_skylineNodeIndex]; - int32_t x = baseNode.x, y; - int32_t width_left = width; - int32_t i = skylineNodeIndex; + int32_t x = baseNode.m_x, y; + int32_t _width_left = width; + int32_t i = _skylineNodeIndex; if ( (x + width) > (int32_t)(m_width-1) ) { return -1; } - y = baseNode.y; - while( width_left > 0 ) + y = baseNode.m_y; + while( _width_left > 0 ) { const Node& node = m_skyline[i]; - if( node.y > y ) + if( node.m_y > y ) { - y = node.y; + y = node.m_y; } if( (y + height) > (int32_t)(m_height-1) ) { return -1; } - width_left -= node.width; + _width_left -= node.m_width; ++i; } return y; @@ -212,9 +212,9 @@ void RectanglePacker::merge() { node = (Node *) &m_skyline[i]; next = (Node *) &m_skyline[i+1]; - if( node->y == next->y ) + if( node->m_y == next->m_y ) { - node->width += next->width; + node->m_width += next->m_width; m_skyline.erase(m_skyline.begin() + i + 1); --i; } @@ -229,24 +229,24 @@ struct Atlas::PackedLayer AtlasRegion faceRegion; }; -Atlas::Atlas(uint16_t textureSize, uint16_t maxRegionsCount ) +Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) { - assert(textureSize >= 64 && textureSize <= 4096 && "suspicious texture size" ); - assert(maxRegionsCount >= 64 && maxRegionsCount <= 32000 && "suspicious regions count" ); + assert(_textureSize >= 64 && _textureSize <= 4096 && "suspicious texture size" ); + assert(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000 && "suspicious _regions count" ); m_layers = new PackedLayer[24]; for(int i=0; i<24;++i) { - m_layers[i].packer.init(textureSize, textureSize); + m_layers[i].packer.init(_textureSize, _textureSize); } m_usedLayers = 0; m_usedFaces = 0; - m_textureSize = textureSize; + m_textureSize = _textureSize; m_regionCount = 0; - m_maxRegionCount = maxRegionsCount; - m_regions = new AtlasRegion[maxRegionsCount]; - m_textureBuffer = new uint8_t[ textureSize * textureSize * 6 * 4 ]; - memset(m_textureBuffer, 0, textureSize * textureSize * 6 * 4); + m_maxRegionCount = _maxRegionsCount; + m_regions = new AtlasRegion[_maxRegionsCount]; + m_textureBuffer = new uint8_t[ _textureSize * _textureSize * 6 * 4 ]; + memset(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4); //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP @@ -257,7 +257,7 @@ Atlas::Atlas(uint16_t textureSize, uint16_t maxRegionsCount ) //memset(mem->data, 255, mem->size); const bgfx::Memory* mem = NULL; m_textureHandle = bgfx::createTextureCube(6 - , textureSize + , _textureSize , 1 , bgfx::TextureFormat::BGRA8 , flags @@ -265,29 +265,29 @@ Atlas::Atlas(uint16_t textureSize, uint16_t maxRegionsCount ) ); } -Atlas::Atlas(uint16_t textureSize, const uint8_t* textureBuffer , uint16_t regionCount, const uint8_t* regionBuffer, uint16_t maxRegionsCount) +Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount) { - assert(regionCount <= 64 && maxRegionsCount <= 4096); + assert(_regionCount <= 64 && _maxRegionsCount <= 4096); //layers are frozen m_usedLayers = 24; m_usedFaces = 6; - m_textureSize = textureSize; - m_regionCount = regionCount; + m_textureSize = _textureSize; + m_regionCount = _regionCount; //regions are frozen - m_maxRegionCount = regionCount; - m_regions = new AtlasRegion[regionCount]; + m_maxRegionCount = _regionCount; + m_regions = new AtlasRegion[_regionCount]; m_textureBuffer = new uint8_t[getTextureBufferSize()]; //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP uint32_t flags = 0;//BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; - memcpy(m_regions, regionBuffer, regionCount * sizeof(AtlasRegion)); - memcpy(m_textureBuffer, textureBuffer, getTextureBufferSize()); + memcpy(m_regions, _regionBuffer, _regionCount * sizeof(AtlasRegion)); + memcpy(m_textureBuffer, _textureBuffer, getTextureBufferSize()); m_textureHandle = bgfx::createTextureCube(6 - , textureSize + , _textureSize , 1 , bgfx::TextureFormat::BGRA8 , flags @@ -302,7 +302,7 @@ Atlas::~Atlas() delete[] m_textureBuffer; } -uint16_t Atlas::addRegion(uint16_t width, uint16_t height, const uint8_t* bitmapBuffer, AtlasRegion::Type type) +uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type) { if (m_regionCount >= m_maxRegionCount) { @@ -315,9 +315,9 @@ uint16_t Atlas::addRegion(uint16_t width, uint16_t height, const uint8_t* bitmap uint32_t idx = 0; while(idx<m_usedLayers) { - if(m_layers[idx].faceRegion.getType() == type) + if(m_layers[idx].faceRegion.getType() == _type) { - if(m_layers[idx].packer.addRectangle(width+1,height+1,x,y)) break; + if(m_layers[idx].packer.addRectangle(_width+1,_height+1,x,y)) break; } idx++; } @@ -325,154 +325,154 @@ uint16_t Atlas::addRegion(uint16_t width, uint16_t height, const uint8_t* bitmap if(idx >= m_usedLayers) { //do we have still room to add layers ? - if( (idx + type) > 24 || m_usedFaces>=6) + if( (idx + _type) > 24 || m_usedFaces>=6) { return UINT16_MAX; } //create new layers - for(int i=0; i < type;++i) + for(int i=0; i < _type;++i) { - m_layers[idx+i].faceRegion.setMask(type, m_usedFaces, i); + m_layers[idx+i].faceRegion.setMask(_type, m_usedFaces, i); } - m_usedLayers += type; + m_usedLayers += _type; m_usedFaces++; //add it to the created layer - if(!m_layers[idx].packer.addRectangle(width+1,height+1,x,y)) + if(!m_layers[idx].packer.addRectangle(_width+1, _height+1, x, y)) { return UINT16_MAX; } } AtlasRegion& region = m_regions[m_regionCount]; - region.x = x; - region.y = y; - region.width = width; - region.height = height; - region.mask = m_layers[idx].faceRegion.mask; + region.m_x = x; + region.m_y = y; + region.m_width = _width; + region.m_height = _height; + region.m_mask = m_layers[idx].faceRegion.m_mask; - updateRegion(region, bitmapBuffer); + updateRegion(region, _bitmapBuffer); return m_regionCount++; } -void Atlas::updateRegion(const AtlasRegion& region, const uint8_t* bitmapBuffer) +void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer) { - const bgfx::Memory* mem = bgfx::alloc(region.width * region.height * 4); + const bgfx::Memory* mem = bgfx::alloc(_region.m_width * _region.m_height * 4); //BAD! memset(mem->data,0, mem->size); - if(region.getType() == AtlasRegion::TYPE_BGRA8) + if(_region.getType() == AtlasRegion::TYPE_BGRA8) { - const uint8_t* inLineBuffer = bitmapBuffer; - uint8_t* outLineBuffer = m_textureBuffer + region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((region.y *m_textureSize)+region.x)*4); + const uint8_t* inLineBuffer = _bitmapBuffer; + uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4); //update the cpu buffer - for(int y = 0; y < region.height; ++y) + for(int y = 0; y < _region.m_height; ++y) { - memcpy(outLineBuffer, inLineBuffer, region.width * 4); - inLineBuffer += region.width*4; + memcpy(outLineBuffer, inLineBuffer, _region.m_width * 4); + inLineBuffer += _region.m_width*4; outLineBuffer += m_textureSize*4; } //update the GPU buffer - memcpy(mem->data, bitmapBuffer, mem->size); + memcpy(mem->data, _bitmapBuffer, mem->size); }else { - uint32_t layer = region.getComponentIndex(); - uint32_t face = region.getFaceIndex(); - const uint8_t* inLineBuffer = bitmapBuffer; - uint8_t* outLineBuffer = (m_textureBuffer + region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((region.y *m_textureSize)+region.x)*4)); + uint32_t layer = _region.getComponentIndex(); + uint32_t face = _region.getFaceIndex(); + const uint8_t* inLineBuffer = _bitmapBuffer; + uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4)); //update the cpu buffer - for(int y = 0; y<region.height; ++y) + for(int y = 0; y<_region.m_height; ++y) { - for(int x = 0; x<region.width; ++x) + for(int x = 0; x<_region.m_width; ++x) { outLineBuffer[(x*4) + layer] = inLineBuffer[x]; } //update the GPU buffer - memcpy(mem->data + y*region.width*4, outLineBuffer, region.width*4); - inLineBuffer += region.width; + memcpy(mem->data + y*_region.m_width*4, outLineBuffer, _region.m_width*4); + inLineBuffer += _region.m_width; outLineBuffer += m_textureSize*4; } } - bgfx::updateTextureCube(m_textureHandle, (uint8_t)region.getFaceIndex(), 0, region.x, region.y, region.width, region.height, mem); + bgfx::updateTextureCube(m_textureHandle, (uint8_t)_region.getFaceIndex(), 0, _region.m_x, _region.m_y, _region.m_width, _region.m_height, mem); } -void Atlas::packFaceLayerUV(uint32_t idx, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ) +void Atlas::packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) { - packUV(m_layers[idx].faceRegion, vertexBuffer, offset, stride); + packUV(m_layers[_idx].faceRegion, _vertexBuffer, _offset, _stride); } -void Atlas::packUV( uint16_t handle, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ) +void Atlas::packUV( uint16_t handle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) { const AtlasRegion& region = m_regions[handle]; - packUV(region, vertexBuffer, offset, stride); + packUV(region, _vertexBuffer, _offset, _stride); } -void Atlas::packUV( const AtlasRegion& region, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ) +void Atlas::packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) { float texMult = 65535.0f / ((float)(m_textureSize)); static const int16_t minVal = -32768; static const int16_t maxVal = 32767; - int16_t x0 = (int16_t)(region.x * texMult)-32768; - int16_t y0 = (int16_t)(region.y * texMult)-32768; - int16_t x1 = (int16_t)((region.x + region.width)* texMult)-32768; - int16_t y1 = (int16_t)((region.y + region.height)* texMult)-32768; - int16_t w = (int16_t) ((32767.0f/4.0f) * region.getComponentIndex()); + int16_t x0 = (int16_t)(_region.m_x * texMult)-32768; + int16_t y0 = (int16_t)(_region.m_y * texMult)-32768; + int16_t x1 = (int16_t)((_region.m_x + _region.m_width)* texMult)-32768; + int16_t y1 = (int16_t)((_region.m_y + _region.m_height)* texMult)-32768; + int16_t w = (int16_t) ((32767.0f/4.0f) * _region.getComponentIndex()); - vertexBuffer+=offset; - switch(region.getFaceIndex()) + _vertexBuffer+=_offset; + switch(_region.getFaceIndex()) { case 0: // +X x0= -x0; x1= -x1; y0= -y0; y1= -y1; - writeUV(vertexBuffer, maxVal, y0, x0, w); vertexBuffer+=stride; - writeUV(vertexBuffer, maxVal, y1, x0, w); vertexBuffer+=stride; - writeUV(vertexBuffer, maxVal, y1, x1, w); vertexBuffer+=stride; - writeUV(vertexBuffer, maxVal, y0, x1, w); vertexBuffer+=stride; + writeUV(_vertexBuffer, maxVal, y0, x0, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, maxVal, y1, x0, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, maxVal, y1, x1, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, maxVal, y0, x1, w); _vertexBuffer+=_stride; break; case 1: // -X y0= -y0; y1= -y1; - writeUV(vertexBuffer, minVal, y0, x0, w); vertexBuffer+=stride; - writeUV(vertexBuffer, minVal, y1, x0, w); vertexBuffer+=stride; - writeUV(vertexBuffer, minVal, y1, x1, w); vertexBuffer+=stride; - writeUV(vertexBuffer, minVal, y0, x1, w); vertexBuffer+=stride; + writeUV(_vertexBuffer, minVal, y0, x0, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, minVal, y1, x0, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, minVal, y1, x1, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, minVal, y0, x1, w); _vertexBuffer+=_stride; break; case 2: // +Y - writeUV(vertexBuffer, x0, maxVal, y0, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x0, maxVal, y1, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, maxVal, y1, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, maxVal, y0, w); vertexBuffer+=stride; + writeUV(_vertexBuffer, x0, maxVal, y0, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x0, maxVal, y1, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, maxVal, y1, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, maxVal, y0, w); _vertexBuffer+=_stride; break; case 3: // -Y y0= -y0; y1= -y1; - writeUV(vertexBuffer, x0, minVal, y0, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x0, minVal, y1, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, minVal, y1, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, minVal, y0, w); vertexBuffer+=stride; + writeUV(_vertexBuffer, x0, minVal, y0, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x0, minVal, y1, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, minVal, y1, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, minVal, y0, w); _vertexBuffer+=_stride; break; case 4: // +Z y0= -y0; y1= -y1; - writeUV(vertexBuffer, x0, y0, maxVal, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x0, y1, maxVal, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, y1, maxVal, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, y0, maxVal, w); vertexBuffer+=stride; + writeUV(_vertexBuffer, x0, y0, maxVal, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x0, y1, maxVal, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, y1, maxVal, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, y0, maxVal, w); _vertexBuffer+=_stride; break; case 5: // -Z x0= -x0; x1= -x1; y0= -y0; y1= -y1; - writeUV(vertexBuffer, x0, y0, minVal, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x0, y1, minVal, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, y1, minVal, w); vertexBuffer+=stride; - writeUV(vertexBuffer, x1, y0, minVal, w); vertexBuffer+=stride; + writeUV(_vertexBuffer, x0, y0, minVal, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x0, y1, minVal, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, y1, minVal, w); _vertexBuffer+=_stride; + writeUV(_vertexBuffer, x1, y0, minVal, w); _vertexBuffer+=_stride; break; } } diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 7f8ca118..15734e02 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -22,14 +22,14 @@ struct AtlasRegion TYPE_BGRA8 = 4 // 4 components }; - uint16_t x, y; - uint16_t width, height; - uint32_t mask; //encode the region type, the face index and the component index in case of a gray region + uint16_t m_x, m_y; + uint16_t m_width, m_height; + uint32_t m_mask; //encode the region type, the face index and the component index in case of a gray region - Type getType()const { return (Type) ((mask >> 0) & 0x0000000F); } - uint32_t getFaceIndex()const { return (mask >> 4) & 0x0000000F; } - uint32_t getComponentIndex()const { return (mask >> 8) & 0x0000000F; } - void setMask(Type type, uint32_t faceIndex, uint32_t componentIndex) { mask = (componentIndex << 8) + (faceIndex << 4) + (uint32_t)type; } + Type getType()const { return (Type) ((m_mask >> 0) & 0x0000000F); } + uint32_t getFaceIndex()const { return (m_mask >> 4) & 0x0000000F; } + uint32_t getComponentIndex()const { return (m_mask >> 8) & 0x0000000F; } + void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex) { m_mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type; } }; class Atlas @@ -38,7 +38,7 @@ public: /// create an empty dynamic atlas (region can be updated and added) /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) /// @param maxRegionCount maximum number of region allowed in the atlas - Atlas(uint16_t textureSize, uint16_t _maxRegionsCount = 4096); + Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount = 4096); /// initialize a static atlas with serialized data (region can be updated but not added) /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) @@ -46,14 +46,14 @@ public: /// @param regionCount number of region in the Atlas /// @param regionBuffer buffer containing the region (will be copied) /// @param maxRegionCount maximum number of region allowed in the atlas - Atlas(uint16_t textureSize, const uint8_t * textureBuffer, uint16_t regionCount, const uint8_t* regionBuffer, uint16_t maxRegionsCount = 4096); + Atlas(uint16_t _textureSize, const uint8_t * _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount = 4096); ~Atlas(); /// add a region to the atlas, and copy the content of mem to the underlying texture - uint16_t addRegion(uint16_t width, uint16_t height, const uint8_t* bitmapBuffer, AtlasRegion::Type type = AtlasRegion::TYPE_BGRA8); + uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8); /// update a preallocated region - void updateRegion(const AtlasRegion& region, const uint8_t* bitmapBuffer); + void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer); /// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format. /// v0 -- v3 @@ -65,28 +65,28 @@ public: /// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first. /// @param offset byte offset to the first uv coordinate of the vertex in the buffer /// @param stride stride between tho UV coordinates, usually size of a Vertex. - void packUV( uint16_t regionHandle, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ); - void packUV( const AtlasRegion& region, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ); + void packUV( uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); + void packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); /// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas - void packFaceLayerUV(uint32_t idx, uint8_t* vertexBuffer, uint32_t offset, uint32_t stride ); + void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); /// Pack the vertex index of the region as 2 quad into an index buffer - void packIndex(uint16_t* indexBuffer, uint32_t startIndex, uint32_t startVertex ) + void packIndex(uint16_t* _indexBuffer, uint32_t _startIndex, uint32_t _startVertex ) { - indexBuffer[startIndex+0] = startVertex+0; - indexBuffer[startIndex+1] = startVertex+1; - indexBuffer[startIndex+2] = startVertex+2; - indexBuffer[startIndex+3] = startVertex+0; - indexBuffer[startIndex+4] = startVertex+2; - indexBuffer[startIndex+5] = startVertex+3; + _indexBuffer[_startIndex+0] = _startVertex+0; + _indexBuffer[_startIndex+1] = _startVertex+1; + _indexBuffer[_startIndex+2] = _startVertex+2; + _indexBuffer[_startIndex+3] = _startVertex+0; + _indexBuffer[_startIndex+4] = _startVertex+2; + _indexBuffer[_startIndex+5] = _startVertex+3; } /// return the TextureHandle (cube) of the atlas bgfx::TextureHandle getTextureHandle() const { return m_textureHandle; } //retrieve a region info - const AtlasRegion& getRegion(uint16_t handle) const { return m_regions[handle]; } + const AtlasRegion& getRegion(uint16_t _handle) const { return m_regions[_handle]; } /// retrieve the size of side of a texture in pixels uint16_t getTextureSize(){ return m_textureSize; } @@ -108,12 +108,12 @@ public: private: - void writeUV( uint8_t* vertexBuffer, int16_t x, int16_t y, int16_t z, int16_t w) + void writeUV( uint8_t* _vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w) { - ((uint16_t*) vertexBuffer)[0] = x; - ((uint16_t*) vertexBuffer)[1] = y; - ((uint16_t*) vertexBuffer)[2] = z; - ((uint16_t*) vertexBuffer)[3] = w; + ((uint16_t*) _vertexBuffer)[0] = _x; + ((uint16_t*) _vertexBuffer)[1] = _y; + ((uint16_t*) _vertexBuffer)[2] = _z; + ((uint16_t*) _vertexBuffer)[3] = _w; } struct PackedLayer; PackedLayer* m_layers; From 6c956ee0c96355be1f407bf82f91129140db2e67 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 20:58:57 +0200 Subject: [PATCH 11/38] update font_manager to bgfx coding style --- examples/common/font/font_manager.cpp | 330 +++++++++++++------------- examples/common/font/font_manager.h | 66 +++--- 2 files changed, 198 insertions(+), 198 deletions(-) diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 4c607e3f..8b22a60c 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -49,25 +49,25 @@ public: /// Initialize from an external buffer /// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime /// @return true if the initialization succeed - bool init(const uint8_t* buffer, uint32_t bufferSize, int32_t fontIndex, uint32_t pixelHeight ); + bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight ); /// return the font descriptor of the current font FontInfo getFontInfo(); /// raster a glyph as 8bit alpha to a memory buffer /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.width * glyphInfo * height * sizeof(char) - bool bakeGlyphAlpha(CodePoint_t codePoint, GlyphInfo& outGlyphInfo, uint8_t* outBuffer); + /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) + bool bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); /// raster a glyph as 32bit subpixel rgba to a memory buffer /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.width * glyphInfo * height * sizeof(uint32_t) - bool bakeGlyphSubpixel(CodePoint_t codePoint, GlyphInfo& outGlyphInfo, uint8_t* outBuffer); + /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t) + bool bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); /// raster a glyph as 8bit signed distance to a memory buffer /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.width * glyphInfo * height * sizeof(char) - bool bakeGlyphDistance(CodePoint_t codePoint, GlyphInfo& outGlyphInfo, uint8_t* outBuffer); + /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) + bool bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); private: void* m_font; }; @@ -75,8 +75,8 @@ private: struct FTHolder { - FT_Library library; - FT_Face face; + FT_Library m_library; + FT_Face m_face; }; FontManager::TrueTypeFont::TrueTypeFont(): m_font(NULL) { @@ -87,36 +87,36 @@ FontManager::TrueTypeFont::~TrueTypeFont() if(m_font!=NULL) { FTHolder* holder = (FTHolder*) m_font; - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); + FT_Done_Face( holder->m_face ); + FT_Done_FreeType( holder->m_library ); delete m_font; m_font = NULL; } } -bool FontManager::TrueTypeFont::init(const uint8_t* buffer, uint32_t bufferSize, int32_t fontIndex, uint32_t pixelHeight) +bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight) { - assert((bufferSize > 256 && bufferSize < 100000000) && "TrueType buffer size is suspicious"); - assert((pixelHeight > 4 && pixelHeight < 128) && "TrueType buffer size is suspicious"); + assert((_bufferSize > 256 && _bufferSize < 100000000) && "TrueType buffer size is suspicious"); + assert((_pixelHeight > 4 && _pixelHeight < 128) && "TrueType buffer size is suspicious"); assert(m_font == NULL && "TrueTypeFont already initialized" ); FTHolder* holder = new FTHolder(); // Initialize Freetype library - FT_Error error = FT_Init_FreeType( &holder->library ); + FT_Error error = FT_Init_FreeType( &holder->m_library ); if( error) { delete holder; return false; } - error = FT_New_Memory_Face( holder->library, buffer, bufferSize, fontIndex, &holder->face ); + error = FT_New_Memory_Face( holder->m_library, _buffer, _bufferSize, _fontIndex, &holder->m_face ); if ( error == FT_Err_Unknown_File_Format ) { // the font file could be opened and read, but it appears //that its font format is unsupported - FT_Done_FreeType( holder->library ); + FT_Done_FreeType( holder->m_library ); delete holder; return false; } @@ -124,25 +124,25 @@ bool FontManager::TrueTypeFont::init(const uint8_t* buffer, uint32_t bufferSize, { // another error code means that the font file could not // be opened or read, or simply that it is broken... - FT_Done_FreeType( holder->library ); + FT_Done_FreeType( holder->m_library ); delete holder; return false; } // Select unicode charmap - error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE ); + error = FT_Select_Charmap( holder->m_face, FT_ENCODING_UNICODE ); if( error ) { - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); + FT_Done_Face( holder->m_face ); + FT_Done_FreeType( holder->m_library ); return false; } //set size in pixels - error = FT_Set_Pixel_Sizes( holder->face, 0, pixelHeight ); + error = FT_Set_Pixel_Sizes( holder->m_face, 0, _pixelHeight ); if( error ) { - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); + FT_Done_Face( holder->m_face ); + FT_Done_FreeType( holder->m_library ); return false; } @@ -155,31 +155,31 @@ FontInfo FontManager::TrueTypeFont::getFontInfo() assert(m_font != NULL && "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - assert(FT_IS_SCALABLE (holder->face)); + assert(FT_IS_SCALABLE (holder->m_face)); - FT_Size_Metrics metrics = holder->face->size->metrics; + FT_Size_Metrics metrics = holder->m_face->size->metrics; //todo manage unscalable font FontInfo outFontInfo; - outFontInfo.scale = 1.0f; - outFontInfo.ascender = metrics.ascender /64.0f; - outFontInfo.descender = metrics.descender /64.0f; - outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; + outFontInfo.m_scale = 1.0f; + outFontInfo.m_ascender = metrics.ascender /64.0f; + outFontInfo.m_descender = metrics.descender /64.0f; + outFontInfo.m_lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; - outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f; - outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f; + outFontInfo.m_underline_position = FT_MulFix(holder->m_face->underline_position, metrics.y_scale) /64.0f; + outFontInfo.m_underline_thickness= FT_MulFix(holder->m_face->underline_thickness,metrics.y_scale) /64.0f; return outFontInfo; } -bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer) +bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { assert(m_font != NULL && "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint ); + _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); - FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); + FT_GlyphSlot slot = holder->m_face->glyph; + FT_Error error = FT_Load_Glyph( holder->m_face, _glyphInfo.m_glyphIndex, FT_LOAD_DEFAULT ); if(error) { return false; } FT_Glyph glyph; @@ -196,34 +196,34 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t codePoint, GlyphInfo& int w = bitmap->bitmap.width; int h = bitmap->bitmap.rows; - glyphInfo.offset_x = (float) x; - glyphInfo.offset_y = (float) y; - glyphInfo.width = (float) w; - glyphInfo.height = (float) h; - glyphInfo.advance_x = (float)slot->advance.x /64.0f; - glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.m_offset_x = (float) x; + _glyphInfo.m_offset_y = (float) y; + _glyphInfo.m_width = (float) w; + _glyphInfo.m_height = (float) h; + _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; + _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; int charsize = 1; int depth=1; int stride = bitmap->bitmap.pitch; for( int i=0; i<h; ++i ) { - memcpy(outBuffer+(i*w) * charsize * depth, + memcpy(_outBuffer+(i*w) * charsize * depth, bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); } FT_Done_Glyph(glyph); return true; } -bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer) +bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { assert(m_font != NULL && "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint ); + _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); - FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); + FT_GlyphSlot slot = holder->m_face->glyph; + FT_Error error = FT_Load_Glyph( holder->m_face, _glyphInfo.m_glyphIndex, FT_LOAD_DEFAULT ); if(error) { return false; } FT_Glyph glyph; @@ -239,18 +239,18 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t codePoint, GlyphIn int w = bitmap->bitmap.width; int h = bitmap->bitmap.rows; - glyphInfo.offset_x = (float) x; - glyphInfo.offset_y = (float) y; - glyphInfo.width = (float) w; - glyphInfo.height = (float) h; - glyphInfo.advance_x = (float)slot->advance.x /64.0f; - glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.m_offset_x = (float) x; + _glyphInfo.m_offset_y = (float) y; + _glyphInfo.m_width = (float) w; + _glyphInfo.m_height = (float) h; + _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; + _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; int charsize = 1; int depth=3; int stride = bitmap->bitmap.pitch; for( int i=0; i<h; ++i ) { - memcpy(outBuffer+(i*w) * charsize * depth, + memcpy(_outBuffer+(i*w) * charsize * depth, bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); } FT_Done_Glyph(glyph); @@ -335,18 +335,18 @@ void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int } -bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t codePoint, GlyphInfo& glyphInfo, uint8_t* outBuffer) +bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { assert(m_font != NULL && "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, codePoint ); + _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING; FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL; - FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, glyphInfo.glyphIndex, loadMode ); + FT_GlyphSlot slot = holder->m_face->glyph; + FT_Error error = FT_Load_Glyph( holder->m_face, _glyphInfo.m_glyphIndex, loadMode ); if(error) { return false; } FT_Glyph glyph; @@ -363,12 +363,12 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t codePoint, GlyphIn int w = bitmap->bitmap.width; int h = bitmap->bitmap.rows; - glyphInfo.offset_x = (float) x; - glyphInfo.offset_y = (float) y; - glyphInfo.width = (float) w; - glyphInfo.height = (float) h; - glyphInfo.advance_x = (float)slot->advance.x /64.0f; - glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.m_offset_x = (float) x; + _glyphInfo.m_offset_y = (float) y; + _glyphInfo.m_width = (float) w; + _glyphInfo.m_height = (float) h; + _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; + _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; int charsize = 1; int depth=1; @@ -377,7 +377,7 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t codePoint, GlyphIn for( int i=0; i<h; ++i ) { - memcpy(outBuffer+(i*w) * charsize * depth, + memcpy(_outBuffer+(i*w) * charsize * depth, bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); } FT_Done_Glyph(glyph); @@ -400,16 +400,16 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t codePoint, GlyphIn //copy the original buffer to the temp one for(uint32_t i= dh; i< nh-dh; ++i) { - memcpy(alphaImg+i*nw+dw, outBuffer+(i-dh)*w, w); + memcpy(alphaImg+i*nw+dw, _outBuffer+(i-dh)*w, w); } - make_distance_map(alphaImg, outBuffer, nw, nh); + make_distance_map(alphaImg, _outBuffer, nw, nh); free(alphaImg); - glyphInfo.offset_x -= (float) dw; - glyphInfo.offset_y -= (float) dh; - glyphInfo.width = (float) nw ; - glyphInfo.height = (float) nh; + _glyphInfo.m_offset_x -= (float) dw; + _glyphInfo.m_offset_y -= (float) dh; + _glyphInfo.m_width = (float) nw ; + _glyphInfo.m_height = (float) nh; } return true; @@ -423,13 +423,13 @@ typedef stl::unordered_map<CodePoint_t, GlyphInfo> GlyphHash_t; // cache font data struct FontManager::CachedFont { - CachedFont(){ trueTypeFont = NULL; masterFontHandle.idx = -1; } - FontInfo fontInfo; - GlyphHash_t cachedGlyphs; - FontManager::TrueTypeFont* trueTypeFont; + CachedFont(){ m_trueTypeFont = NULL; m_masterFontHandle.idx = -1; } + FontInfo m_fontInfo; + GlyphHash_t m_cachedGlyphs; + FontManager::TrueTypeFont* m_trueTypeFont; // an handle to a master font in case of sub distance field font - FontHandle masterFontHandle; - int16_t __padding__; + FontHandle m_masterFontHandle; + int16_t m_padding; }; @@ -439,16 +439,16 @@ const uint16_t MAX_OPENED_FILES = 64; const uint16_t MAX_OPENED_FONT = 64; const uint32_t MAX_FONT_BUFFER_SIZE = 512*512*4; -FontManager::FontManager(Atlas* atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(Atlas* _atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { - m_atlas = atlas; + m_atlas = _atlas; m_ownAtlas = false; init(); } -FontManager::FontManager(uint32_t textureSideWidth):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(uint32_t _textureSideWidth):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { - m_atlas = new Atlas(textureSideWidth); + m_atlas = new Atlas(_textureSideWidth); m_ownAtlas = true; init(); } @@ -463,8 +463,8 @@ void FontManager::init() uint8_t buffer[4*4*4]; memset( buffer, 255, 4 * 4 * 4); - m_blackGlyph.width=3; - m_blackGlyph.height=3; + m_blackGlyph.m_width=3; + m_blackGlyph.m_height=3; assert( addBitmap(m_blackGlyph, buffer) ); //make sure the black glyph doesn't bleed @@ -494,10 +494,10 @@ FontManager::~FontManager() -TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* fontPath) +TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) { FILE * pFile; - pFile = fopen (fontPath, "rb"); + pFile = fopen (_fontPath, "rb"); if (pFile==NULL) { TrueTypeHandle invalid = BGFX_INVALID_HANDLE; @@ -544,34 +544,34 @@ TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* fontPath) return invalid; } -TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* buffer, uint32_t size) +TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size) { uint16_t id = m_filesHandles.alloc(); assert(id != bx::HandleAlloc::invalid); - m_cachedFiles[id].buffer = new uint8_t[size]; - m_cachedFiles[id].bufferSize = size; - memcpy(m_cachedFiles[id].buffer, buffer, size); + m_cachedFiles[id].buffer = new uint8_t[_size]; + m_cachedFiles[id].bufferSize = _size; + memcpy(m_cachedFiles[id].buffer, _buffer, _size); //TODO validate font TrueTypeHandle ret = {id}; return ret; } -void FontManager::unloadTrueType(TrueTypeHandle handle) +void FontManager::unloadTrueType(TrueTypeHandle _handle) { - assert(bgfx::invalidHandle != handle.idx); - delete m_cachedFiles[handle.idx].buffer; - m_cachedFiles[handle.idx].bufferSize = 0; - m_cachedFiles[handle.idx].buffer = NULL; - m_filesHandles.free(handle.idx); + assert(bgfx::invalidHandle != _handle.idx); + delete m_cachedFiles[_handle.idx].buffer; + m_cachedFiles[_handle.idx].bufferSize = 0; + m_cachedFiles[_handle.idx].buffer = NULL; + m_filesHandles.free(_handle.idx); } -FontHandle FontManager::createFontByPixelSize(TrueTypeHandle handle, uint32_t typefaceIndex, uint32_t pixelSize, FontType fontType) +FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType) { - assert(bgfx::invalidHandle != handle.idx); + assert(bgfx::invalidHandle != _tt_handle.idx); TrueTypeFont* ttf = new TrueTypeFont(); - if(!ttf->init( m_cachedFiles[handle.idx].buffer, m_cachedFiles[handle.idx].bufferSize, typefaceIndex, pixelSize)) + if(!ttf->init( m_cachedFiles[_tt_handle.idx].buffer, m_cachedFiles[_tt_handle.idx].bufferSize, _typefaceIndex, _pixelSize)) { delete ttf; FontHandle invalid = BGFX_INVALID_HANDLE; @@ -581,12 +581,12 @@ FontHandle FontManager::createFontByPixelSize(TrueTypeHandle handle, uint32_t ty uint16_t fontIdx = m_fontHandles.alloc(); assert(fontIdx != bx::HandleAlloc::invalid); - m_cachedFonts[fontIdx].trueTypeFont = ttf; - m_cachedFonts[fontIdx].fontInfo = ttf->getFontInfo(); - m_cachedFonts[fontIdx].fontInfo.fontType = fontType; - m_cachedFonts[fontIdx].fontInfo.pixelSize = pixelSize; - m_cachedFonts[fontIdx].cachedGlyphs.clear(); - m_cachedFonts[fontIdx].masterFontHandle.idx = -1; + m_cachedFonts[fontIdx].m_trueTypeFont = ttf; + m_cachedFonts[fontIdx].m_fontInfo = ttf->getFontInfo(); + m_cachedFonts[fontIdx].m_fontInfo.m_fontType = _fontType; + m_cachedFonts[fontIdx].m_fontInfo.m_pixelSize = _pixelSize; + m_cachedFonts[fontIdx].m_cachedGlyphs.clear(); + m_cachedFonts[fontIdx].m_masterFontHandle.idx = -1; FontHandle ret = {fontIdx}; return ret; } @@ -595,24 +595,24 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, { assert(bgfx::invalidHandle != _baseFontHandle.idx); CachedFont& font = m_cachedFonts[_baseFontHandle.idx]; - FontInfo& fontInfo = font.fontInfo; + FontInfo& fontInfo = font.m_fontInfo; FontInfo newFontInfo = fontInfo; - newFontInfo.pixelSize = _pixelSize; - newFontInfo.scale = (float)_pixelSize / (float) fontInfo.pixelSize; - newFontInfo.ascender = (newFontInfo.ascender * newFontInfo.scale); - newFontInfo.descender = (newFontInfo.descender * newFontInfo.scale); - newFontInfo.lineGap = (newFontInfo.lineGap * newFontInfo.scale); - newFontInfo.underline_thickness = (newFontInfo.underline_thickness * newFontInfo.scale); - newFontInfo.underline_position = (newFontInfo.underline_position * newFontInfo.scale); + newFontInfo.m_pixelSize = _pixelSize; + newFontInfo.m_scale = (float)_pixelSize / (float) fontInfo.m_pixelSize; + newFontInfo.m_ascender = (newFontInfo.m_ascender * newFontInfo.m_scale); + newFontInfo.m_descender = (newFontInfo.m_descender * newFontInfo.m_scale); + newFontInfo.m_lineGap = (newFontInfo.m_lineGap * newFontInfo.m_scale); + newFontInfo.m_underline_thickness = (newFontInfo.m_underline_thickness * newFontInfo.m_scale); + newFontInfo.m_underline_position = (newFontInfo.m_underline_position * newFontInfo.m_scale); uint16_t fontIdx = m_fontHandles.alloc(); assert(fontIdx != bx::HandleAlloc::invalid); - m_cachedFonts[fontIdx].cachedGlyphs.clear(); - m_cachedFonts[fontIdx].fontInfo = newFontInfo; - m_cachedFonts[fontIdx].trueTypeFont = NULL; - m_cachedFonts[fontIdx].masterFontHandle = _baseFontHandle; + m_cachedFonts[fontIdx].m_cachedGlyphs.clear(); + m_cachedFonts[fontIdx].m_fontInfo = newFontInfo; + m_cachedFonts[fontIdx].m_trueTypeFont = NULL; + m_cachedFonts[fontIdx].m_masterFontHandle = _baseFontHandle; FontHandle ret = {fontIdx}; return ret; } @@ -635,29 +635,29 @@ void FontManager::destroyFont(FontHandle _handle) { assert(bgfx::invalidHandle != _handle.idx); - if(m_cachedFonts[_handle.idx].trueTypeFont != NULL) + if(m_cachedFonts[_handle.idx].m_trueTypeFont != NULL) { - delete m_cachedFonts[_handle.idx].trueTypeFont; - m_cachedFonts[_handle.idx].trueTypeFont = NULL; + delete m_cachedFonts[_handle.idx].m_trueTypeFont; + m_cachedFonts[_handle.idx].m_trueTypeFont = NULL; } - m_cachedFonts[_handle.idx].cachedGlyphs.clear(); + m_cachedFonts[_handle.idx].m_cachedGlyphs.clear(); m_fontHandles.free(_handle.idx); } -bool FontManager::preloadGlyph(FontHandle handle, const wchar_t* _string) +bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) { - assert(bgfx::invalidHandle != handle.idx); - CachedFont& font = m_cachedFonts[handle.idx]; + assert(bgfx::invalidHandle != _handle.idx); + CachedFont& font = m_cachedFonts[_handle.idx]; //if truetype present - if(font.trueTypeFont != NULL) + if(font.m_trueTypeFont != NULL) { //parse string for( size_t i=0, end = wcslen(_string) ; i < end; ++i ) { //if glyph cached, continue CodePoint_t codePoint = _string[i]; - if(!preloadGlyph(handle, codePoint)) + if(!preloadGlyph(_handle, codePoint)) { return false; } @@ -668,37 +668,37 @@ bool FontManager::preloadGlyph(FontHandle handle, const wchar_t* _string) return false; } -bool FontManager::preloadGlyph(FontHandle handle, CodePoint_t codePoint) +bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) { - assert(bgfx::invalidHandle != handle.idx); - CachedFont& font = m_cachedFonts[handle.idx]; - FontInfo& fontInfo = font.fontInfo; + assert(bgfx::invalidHandle != _handle.idx); + CachedFont& font = m_cachedFonts[_handle.idx]; + FontInfo& fontInfo = font.m_fontInfo; //check if glyph not already present - GlyphHash_t::iterator iter = font.cachedGlyphs.find(codePoint); - if(iter != font.cachedGlyphs.end()) + GlyphHash_t::iterator iter = font.m_cachedGlyphs.find(_codePoint); + if(iter != font.m_cachedGlyphs.end()) { return true; } //if truetype present - if(font.trueTypeFont != NULL) + if(font.m_trueTypeFont != NULL) { GlyphInfo glyphInfo; //bake glyph as bitmap to buffer - switch(font.fontInfo.fontType) + switch(font.m_fontInfo.m_fontType) { case FONT_TYPE_ALPHA: - font.trueTypeFont->bakeGlyphAlpha(codePoint, glyphInfo, m_buffer); + font.m_trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer); break; //case FONT_TYPE_LCD: - //font.trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); + //font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); //break; case FONT_TYPE_DISTANCE: - font.trueTypeFont->bakeGlyphDistance(codePoint, glyphInfo, m_buffer); + font.m_trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; case FONT_TYPE_DISTANCE_SUBPIXEL: - font.trueTypeFont->bakeGlyphDistance(codePoint, glyphInfo, m_buffer); + font.m_trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; default: assert(false && "TextureType not supported yet"); @@ -710,35 +710,35 @@ bool FontManager::preloadGlyph(FontHandle handle, CodePoint_t codePoint) return false; } - glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale); - glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale); - glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); - glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); - glyphInfo.height = (glyphInfo.height * fontInfo.scale); - glyphInfo.width = (glyphInfo.width * fontInfo.scale); + glyphInfo.m_advance_x = (glyphInfo.m_advance_x * fontInfo.m_scale); + glyphInfo.m_advance_y = (glyphInfo.m_advance_y * fontInfo.m_scale); + glyphInfo.m_offset_x = (glyphInfo.m_offset_x * fontInfo.m_scale); + glyphInfo.m_offset_y = (glyphInfo.m_offset_y * fontInfo.m_scale); + glyphInfo.m_height = (glyphInfo.m_height * fontInfo.m_scale); + glyphInfo.m_width = (glyphInfo.m_width * fontInfo.m_scale); // store cached glyph - font.cachedGlyphs[codePoint] = glyphInfo; + font.m_cachedGlyphs[_codePoint] = glyphInfo; return true; }else { //retrieve glyph from parent font if any - if(font.masterFontHandle.idx != bgfx::invalidHandle) + if(font.m_masterFontHandle.idx != bgfx::invalidHandle) { - if(preloadGlyph(font.masterFontHandle, codePoint)) + if(preloadGlyph(font.m_masterFontHandle, _codePoint)) { GlyphInfo glyphInfo; - getGlyphInfo(font.masterFontHandle, codePoint, glyphInfo); + getGlyphInfo(font.m_masterFontHandle, _codePoint, glyphInfo); - glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale); - glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale); - glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); - glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); - glyphInfo.height = (glyphInfo.height * fontInfo.scale); - glyphInfo.width = (glyphInfo.width * fontInfo.scale); + glyphInfo.m_advance_x = (glyphInfo.m_advance_x * fontInfo.m_scale); + glyphInfo.m_advance_y = (glyphInfo.m_advance_y * fontInfo.m_scale); + glyphInfo.m_offset_x = (glyphInfo.m_offset_x * fontInfo.m_scale); + glyphInfo.m_offset_y = (glyphInfo.m_offset_y * fontInfo.m_scale); + glyphInfo.m_height = (glyphInfo.m_height * fontInfo.m_scale); + glyphInfo.m_width = (glyphInfo.m_width * fontInfo.m_scale); // store cached glyph - font.cachedGlyphs[codePoint] = glyphInfo; + font.m_cachedGlyphs[_codePoint] = glyphInfo; return true; } } @@ -747,34 +747,34 @@ bool FontManager::preloadGlyph(FontHandle handle, CodePoint_t codePoint) return false; } -const FontInfo& FontManager::getFontInfo(FontHandle handle) +const FontInfo& FontManager::getFontInfo(FontHandle _handle) { - assert(handle.idx != bgfx::invalidHandle); - return m_cachedFonts[handle.idx].fontInfo; + assert(_handle.idx != bgfx::invalidHandle); + return m_cachedFonts[_handle.idx].m_fontInfo; } -bool FontManager::getGlyphInfo(FontHandle fontHandle, CodePoint_t codePoint, GlyphInfo& outInfo) +bool FontManager::getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo) { - GlyphHash_t::iterator iter = m_cachedFonts[fontHandle.idx].cachedGlyphs.find(codePoint); - if(iter == m_cachedFonts[fontHandle.idx].cachedGlyphs.end()) + GlyphHash_t::iterator iter = m_cachedFonts[_handle.idx].m_cachedGlyphs.find(_codePoint); + if(iter == m_cachedFonts[_handle.idx].m_cachedGlyphs.end()) { - if(preloadGlyph(fontHandle, codePoint)) + if(preloadGlyph(_handle, _codePoint)) { - iter = m_cachedFonts[fontHandle.idx].cachedGlyphs.find(codePoint); + iter = m_cachedFonts[_handle.idx].m_cachedGlyphs.find(_codePoint); }else { return false; } } - outInfo = iter->second; + _outInfo = iter->second; return true; } // **************************************************************************** -bool FontManager::addBitmap(GlyphInfo& glyphInfo, const uint8_t* data) +bool FontManager::addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data) { - glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(glyphInfo.width),(uint16_t) ceil(glyphInfo.height), data, AtlasRegion::TYPE_GRAY); + _glyphInfo.m_regionIndex = m_atlas->addRegion((uint16_t) ceil(_glyphInfo.m_width),(uint16_t) ceil(_glyphInfo.m_height), _data, AtlasRegion::TYPE_GRAY); return true; } diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index 07a40870..43d83ef7 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -18,23 +18,23 @@ enum FontType struct FontInfo { //the font height in pixel - uint16_t pixelSize; + uint16_t m_pixelSize; /// Rendering type used for the font - int16_t fontType; + int16_t m_fontType; /// The pixel extents above the baseline in pixels (typically positive) - float ascender; + float m_ascender; /// The extents below the baseline in pixels (typically negative) - float descender; + float m_descender; /// The spacing in pixels between one row's descent and the next row's ascent - float lineGap; + float m_lineGap; /// The thickness of the under/hover/striketrough line in pixels - float underline_thickness; + float m_underline_thickness; /// The position of the underline relatively to the baseline - float underline_position; + float m_underline_position; //scale to apply to glyph data - float scale; + float m_scale; }; // Glyph metrics: @@ -75,34 +75,34 @@ typedef int32_t CodePoint_t; struct GlyphInfo { /// Index for faster retrieval - int32_t glyphIndex; + int32_t m_glyphIndex; /// Glyph's width in pixels. - float width; + float m_width; /// Glyph's height in pixels. - float height; + float m_height; /// Glyph's left offset in pixels - float offset_x; + float m_offset_x; /// Glyph's top offset in pixels /// Remember that this is the distance from the baseline to the top-most /// glyph scan line, upwards y coordinates being positive. - float offset_y; + float m_offset_y; /// For horizontal text layouts, this is the unscaled horizontal distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. - float advance_x; + float m_advance_x; /// For vertical text layouts, this is the unscaled vertical distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. - float advance_y; + float m_advance_y; /// region index in the atlas storing textures - uint16_t regionIndex; + uint16_t m_regionIndex; ///32 bits alignment - int16_t padding; + int16_t m_padding; }; BGFX_HANDLE(TrueTypeHandle); @@ -112,9 +112,9 @@ class FontManager { public: /// create the font manager using an external cube atlas (doesn't take ownership of the atlas) - FontManager(Atlas* atlas); + FontManager(Atlas* _atlas); /// create the font manager and create the texture cube as BGRA8 with linear filtering - FontManager(uint32_t textureSideWidth = 512); + FontManager(uint32_t _textureSideWidth = 512); ~FontManager(); @@ -123,29 +123,29 @@ public: /// load a TrueType font from a file path /// @return invalid handle if the loading fail - TrueTypeHandle loadTrueTypeFromFile(const char* fontPath); + TrueTypeHandle loadTrueTypeFromFile(const char* _fontPath); /// load a TrueType font from a given buffer. /// the buffer is copied and thus can be freed or reused after this call /// @return invalid handle if the loading fail - TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* buffer, uint32_t size); + TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size); /// unload a TrueType font (free font memory) but keep loaded glyphs - void unloadTrueType(TrueTypeHandle handle); + void unloadTrueType(TrueTypeHandle _handle); /// return a font whose height is a fixed pixel size - FontHandle createFontByPixelSize(TrueTypeHandle handle, uint32_t typefaceIndex, uint32_t pixelSize, FontType fontType = FONT_TYPE_ALPHA); + FontHandle createFontByPixelSize(TrueTypeHandle _handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType = FONT_TYPE_ALPHA); /// return a scaled child font whose height is a fixed pixel size - FontHandle createScaledFontToPixelSize(FontHandle baseFontHandle, uint32_t pixelSize); + FontHandle createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize); /// load a baked font (the set of glyph is fixed) /// @return INVALID_HANDLE if the loading fail - FontHandle loadBakedFontFromFile(const char* imagePath, const char* descriptorPath); + FontHandle loadBakedFontFromFile(const char* _imagePath, const char* _descriptorPath); /// load a baked font (the set of glyph is fixed) /// @return INVALID_HANDLE if the loading fail - FontHandle loadBakedFontFromMemory(const uint8_t* imageBuffer, uint32_t imageSize, const uint8_t* descriptorBuffer, uint32_t descriptorSize); + FontHandle loadBakedFontFromMemory(const uint8_t* _imageBuffer, uint32_t _imageSize, const uint8_t* _descriptorBuffer, uint32_t _descriptorSize); /// destroy a font (truetype or baked) void destroyFont(FontHandle _handle); @@ -153,23 +153,23 @@ public: /// Preload a set of glyphs from a TrueType file /// @return true if every glyph could be preloaded, false otherwise /// if the Font is a baked font, this only do validation on the characters - bool preloadGlyph(FontHandle handle, const wchar_t* _string); + bool preloadGlyph(FontHandle _handle, const wchar_t* _string); /// Preload a single glyph, return true on success - bool preloadGlyph(FontHandle handle, CodePoint_t character); + bool preloadGlyph(FontHandle _handle, CodePoint_t _character); /// bake a font to disk (the set of preloaded glyph) /// @return true if the baking succeed, false otherwise - bool saveBakedFont(FontHandle handle, const char* fontDirectory, const char* fontName ); + bool saveBakedFont(FontHandle _handle, const char* _fontDirectory, const char* _fontName ); /// return the font descriptor of a font /// @remark the handle is required to be valid - const FontInfo& getFontInfo(FontHandle handle); + const FontInfo& getFontInfo(FontHandle _handle); /// Return the rendering informations about the glyph region /// Load the glyph from a TrueType font if possible /// @return true if the Glyph is available - bool getGlyphInfo(FontHandle fontHandle, CodePoint_t codePoint, GlyphInfo& outInfo); + bool getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo); GlyphInfo& getBlackGlyph(){ return m_blackGlyph; } @@ -184,10 +184,10 @@ private: }; void init(); - bool addBitmap(GlyphInfo& glyphInfo, const uint8_t* data); + bool addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data); bool m_ownAtlas; - (Atlas* m_atlas; + Atlas* m_atlas; bx::HandleAlloc m_fontHandles; CachedFont* m_cachedFonts; From e851f5dec683a20772f4dd76d9428fea21a3f1d2 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 21:49:24 +0200 Subject: [PATCH 12/38] update text_buffer_manager to bgfx naming style --- examples/common/font/text_buffer_manager.cpp | 312 +++++++++---------- examples/common/font/text_buffer_manager.h | 40 +-- 2 files changed, 174 insertions(+), 178 deletions(-) diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index b7b325b9..e6b30f93 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -43,8 +43,6 @@ static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shad return NULL; } - - // Table from Flexible and Economical UTF-8 Decoder // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. @@ -98,28 +96,28 @@ public: /// TextBuffer is bound to a fontManager for glyph retrieval /// @remark the ownership of the manager is not taken - TextBuffer(FontManager* fontManager); + TextBuffer(FontManager* _fontManager); ~TextBuffer(); - void setStyle(uint32_t flags = STYLE_NORMAL) { m_styleFlags = flags; } - void setTextColor(uint32_t rgba = 0x000000FF) { m_textColor = toABGR(rgba); } - void setBackgroundColor(uint32_t rgba = 0x000000FF) { m_backgroundColor = toABGR(rgba); } + void setStyle(uint32_t _flags = STYLE_NORMAL) { m_styleFlags = _flags; } + void setTextColor(uint32_t _rgba = 0x000000FF) { m_textColor = toABGR(_rgba); } + void setBackgroundColor(uint32_t _rgba = 0x000000FF) { m_backgroundColor = toABGR(_rgba); } - void setOverlineColor(uint32_t rgba = 0x000000FF) { m_overlineColor = toABGR(rgba); } - void setUnderlineColor(uint32_t rgba = 0x000000FF) { m_underlineColor = toABGR(rgba); } - void setStrikeThroughColor(uint32_t rgba = 0x000000FF) { m_strikeThroughColor = toABGR(rgba); } + void setOverlineColor(uint32_t _rgba = 0x000000FF) { m_overlineColor = toABGR(_rgba); } + void setUnderlineColor(uint32_t _rgba = 0x000000FF) { m_underlineColor = toABGR(_rgba); } + void setStrikeThroughColor(uint32_t _rgba = 0x000000FF) { m_strikeThroughColor = toABGR(_rgba); } - void setPenPosition(float x, float y) { m_penX = x; m_penY = y; } + void setPenPosition(float _x, float _y) { m_penX = _x; m_penY = _y; } /// return the size of the text - //Rectangle measureText(FontHandle fontHandle, const char * _string); - //Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); + //Rectangle measureText(FontHandle _fontHandle, const char * _string); + //Rectangle measureText(FontHandle _fontHandle, const wchar_t * _string); /// append an ASCII/utf-8 string to the buffer using current pen position and color - void appendText(FontHandle fontHandle, const char * _string); + void appendText(FontHandle _fontHandle, const char * _string); /// append a wide char unicode string to the buffer using current pen position and color - void appendText(FontHandle fontHandle, const wchar_t * _string); + void appendText(FontHandle _fontHandle, const wchar_t * _string); /// Clear the text buffer and reset its state (pen/color) void clearTextBuffer(); @@ -140,14 +138,14 @@ public: uint32_t getTextColor(){ return toABGR(m_textColor); } private: - void appendGlyph(CodePoint_t codePoint, const FontInfo& font, const GlyphInfo& glyphInfo); - void verticalCenterLastLine(float txtDecalY, float top, float bottom); - uint32_t toABGR(uint32_t rgba) + void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); + void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); + uint32_t toABGR(uint32_t _rgba) { - return (((rgba >> 0) & 0xff) << 24) | - (((rgba >> 8) & 0xff) << 16) | - (((rgba >> 16) & 0xff) << 8) | - (((rgba >> 24) & 0xff) << 0); + return (((_rgba >> 0) & 0xff) << 24) | + (((_rgba >> 8) & 0xff) << 16) | + (((_rgba >> 16) & 0xff) << 8) | + (((_rgba >> 24) & 0xff) << 0); } static const size_t MAX_BUFFERED_CHARACTERS = 8192; @@ -176,12 +174,12 @@ private: /// FontManager* m_fontManager; - void setVertex(size_t i, float x, float y, uint32_t rgba, uint8_t style = STYLE_NORMAL) + void setVertex(size_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) { - m_vertexBuffer[i].x = x; - m_vertexBuffer[i].y = y; - m_vertexBuffer[i].rgba = rgba; - m_styleBuffer[i] = style; + m_vertexBuffer[_i].x = _x; + m_vertexBuffer[_i].y = _y; + m_vertexBuffer[_i].rgba = _rgba; + m_styleBuffer[_i] = _style; } struct TextVertex @@ -203,9 +201,7 @@ private: - - -TextBuffer::TextBuffer(FontManager* fontManager) +TextBuffer::TextBuffer(FontManager* _fontManager) { m_styleFlags = STYLE_NORMAL; //0xAABBGGRR @@ -222,7 +218,7 @@ TextBuffer::TextBuffer(FontManager* fontManager) m_lineAscender = 0; m_lineDescender = 0; m_lineGap = 0; - m_fontManager = fontManager; + m_fontManager = _fontManager; m_vertexBuffer = new TextVertex[MAX_BUFFERED_CHARACTERS * 4]; @@ -241,17 +237,17 @@ TextBuffer::~TextBuffer() delete[] m_indexBuffer; } -void TextBuffer::appendText(FontHandle fontHandle, const char * _string) +void TextBuffer::appendText(FontHandle _fontHandle, const char * _string) { GlyphInfo glyph; - const FontInfo& font = m_fontManager->getFontInfo(fontHandle); + const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); if(m_vertexCount == 0) { m_originX = m_penX; m_originY = m_penY; - m_lineDescender = 0;// font.descender; - m_lineAscender = 0;//font.ascender; + m_lineDescender = 0;// font.m_descender; + m_lineAscender = 0;//font.m_ascender; } uint32_t codepoint; @@ -260,7 +256,7 @@ void TextBuffer::appendText(FontHandle fontHandle, const char * _string) for (; *_string; ++_string) if (!utf8_decode(&state, &codepoint, *_string)) { - if(m_fontManager->getGlyphInfo(fontHandle, (CodePoint_t)codepoint, glyph)) + if(m_fontManager->getGlyphInfo(_fontHandle, (CodePoint_t)codepoint, glyph)) { appendGlyph((CodePoint_t)codepoint, font, glyph); }else @@ -277,17 +273,17 @@ void TextBuffer::appendText(FontHandle fontHandle, const char * _string) } } -void TextBuffer::appendText(FontHandle fontHandle, const wchar_t * _string) +void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) { GlyphInfo glyph; - const FontInfo& font = m_fontManager->getFontInfo(fontHandle); + const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); if(m_vertexCount == 0) { m_originX = m_penX; m_originY = m_penY; - m_lineDescender = 0;// font.descender; - m_lineAscender = 0;//font.ascender; + m_lineDescender = 0;// font.m_descender; + m_lineAscender = 0;//font.m_ascender; m_lineGap = 0; } @@ -295,10 +291,10 @@ void TextBuffer::appendText(FontHandle fontHandle, const wchar_t * _string) for( size_t i=0, end = wcslen(_string) ; i < end; ++i ) { //if glyph cached, continue - uint32_t codePoint = _string[i]; - if(m_fontManager->getGlyphInfo(fontHandle, codePoint, glyph)) + uint32_t _codePoint = _string[i]; + if(m_fontManager->getGlyphInfo(_fontHandle, _codePoint, glyph)) { - appendGlyph(codePoint, font, glyph); + appendGlyph(_codePoint, font, glyph); }else { assert(false && "Glyph not found"); @@ -306,11 +302,11 @@ void TextBuffer::appendText(FontHandle fontHandle, const wchar_t * _string) } } /* -TextBuffer::Rectangle TextBuffer::measureText(FontHandle fontHandle, const char * _string) +TextBuffer::Rectangle TextBuffer::measureText(FontHandle _fontHandle, const char * _string) { } -TextBuffer::Rectangle TextBuffer::measureText(FontHandle fontHandle, const wchar_t * _string) +TextBuffer::Rectangle TextBuffer::measureText(FontHandle _fontHandle, const wchar_t * _string) { } */ @@ -324,10 +320,10 @@ void TextBuffer::clearTextBuffer() m_lineDescender = 0; } -void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const GlyphInfo& glyphInfo) +void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo) { //handle newlines - if(codePoint == L'\n' ) + if(_codePoint == L'\n' ) { m_penX = m_originX; m_penY -= m_lineDescender; @@ -338,17 +334,17 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const return; } - if( font.ascender > m_lineAscender || (font.descender < m_lineDescender) ) + if( _font.m_ascender > m_lineAscender || (_font.m_descender < m_lineDescender) ) { - if( font.descender < m_lineDescender ) + if( _font.m_descender < m_lineDescender ) { - m_lineDescender = font.descender; - m_lineGap = font.lineGap; + m_lineDescender = _font.m_descender; + m_lineGap = _font.m_lineGap; } - float txtDecals = (font.ascender - m_lineAscender); - m_lineAscender = font.ascender; - m_lineGap = font.lineGap; + float txtDecals = (_font.m_ascender - m_lineAscender); + m_lineAscender = _font.m_ascender; + m_lineGap = _font.m_lineGap; m_penY += txtDecals; verticalCenterLastLine((txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender+m_lineGap)); @@ -362,7 +358,7 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const kerning = texture_glyph_get_kerning( glyph, previous ); } */ - m_penX += kerning * font.scale; + m_penX += kerning * _font.m_scale; GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph(); @@ -370,10 +366,10 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const { float x0 = ( m_penX - kerning ); float y0 = ( m_penY - m_lineAscender); - float x1 = ( (float)x0 + (glyphInfo.advance_x)); + float x1 = ( (float)x0 + (_glyphInfo.m_advance_x)); float y1 = ( m_penY - m_lineDescender + m_lineGap ); - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_backgroundColor,STYLE_BACKGROUND); setVertex(m_vertexCount+1, x0, y1, m_backgroundColor,STYLE_BACKGROUND); @@ -394,10 +390,10 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const { float x0 = ( m_penX - kerning ); float y0 = (m_penY - m_lineDescender/2 ); - float x1 = ( (float)x0 + (glyphInfo.advance_x)); - float y1 = y0+font.underline_thickness; + float x1 = ( (float)x0 + (_glyphInfo.m_advance_x)); + float y1 = y0+_font.m_underline_thickness; - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_underlineColor,STYLE_UNDERLINE); setVertex(m_vertexCount+1, x0, y1, m_underlineColor,STYLE_UNDERLINE); @@ -417,11 +413,11 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const if( m_styleFlags & STYLE_OVERLINE && m_overlineColor & 0xFF000000) { float x0 = ( m_penX - kerning ); - float y0 = (m_penY - font.ascender ); - float x1 = ( (float)x0 + (glyphInfo.advance_x)); - float y1 = y0+font.underline_thickness; + float y0 = (m_penY - _font.m_ascender ); + float x1 = ( (float)x0 + (_glyphInfo.m_advance_x)); + float y1 = y0+_font.m_underline_thickness; - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_overlineColor,STYLE_OVERLINE); setVertex(m_vertexCount+1, x0, y1, m_overlineColor,STYLE_OVERLINE); @@ -442,11 +438,11 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const if( m_styleFlags & STYLE_STRIKE_THROUGH && m_strikeThroughColor & 0xFF000000) { float x0 = ( m_penX - kerning ); - float y0 = (m_penY - font.ascender/3 ); - float x1 = ( (float)x0 + (glyphInfo.advance_x) ); - float y1 = y0+font.underline_thickness; + float y0 = (m_penY - _font.m_ascender/3 ); + float x1 = ( (float)x0 + (_glyphInfo.m_advance_x) ); + float y1 = y0+_font.m_underline_thickness; - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); setVertex(m_vertexCount+1, x0, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); @@ -465,13 +461,13 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const //handle glyph - float x0_precise = m_penX + (glyphInfo.offset_x); + float x0_precise = m_penX + (_glyphInfo.m_offset_x); float x0 = ( x0_precise); - float y0 = ( m_penY + (glyphInfo.offset_y)); - float x1 = ( x0 + glyphInfo.width ); - float y1 = ( y0 + glyphInfo.height ); + float y0 = ( m_penY + (_glyphInfo.m_offset_y)); + float x1 = ( x0 + _glyphInfo.m_width ); + float y1 = ( y0 + _glyphInfo.m_height ); - m_fontManager->getAtlas()->packUV(glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(_glyphInfo.m_regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_textColor); setVertex(m_vertexCount+1, x0, y1, m_textColor); @@ -488,31 +484,31 @@ void TextBuffer::appendGlyph(CodePoint_t codePoint, const FontInfo& font, const m_indexCount += 6; //TODO see what to do when doing subpixel rendering - m_penX += glyphInfo.advance_x; + m_penX += _glyphInfo.m_advance_x; } -void TextBuffer::verticalCenterLastLine(float dy, float top, float bottom) +void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) { for( size_t i=m_lineStartIndex; i < m_vertexCount; i+=4 ) { if( m_styleBuffer[i] == STYLE_BACKGROUND) { - m_vertexBuffer[i+0].y = top; - m_vertexBuffer[i+1].y = bottom; - m_vertexBuffer[i+2].y = bottom; - m_vertexBuffer[i+3].y = top; + m_vertexBuffer[i+0].y = _top; + m_vertexBuffer[i+1].y = _bottom; + m_vertexBuffer[i+2].y = _bottom; + m_vertexBuffer[i+3].y = _top; }else{ - m_vertexBuffer[i+0].y += dy; - m_vertexBuffer[i+1].y += dy; - m_vertexBuffer[i+2].y += dy; - m_vertexBuffer[i+3].y += dy; + m_vertexBuffer[i+0].y += _dy; + m_vertexBuffer[i+1].y += _dy; + m_vertexBuffer[i+2].y += _dy; + m_vertexBuffer[i+3].y += _dy; } } } // **************************************************************** -TextBufferManager::TextBufferManager(FontManager* fontManager):m_fontManager(fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) +TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) { m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT]; } @@ -530,7 +526,7 @@ TextBufferManager::~TextBufferManager() bgfx::destroyProgram(m_distanceSubpixelProgram); } -void TextBufferManager::init(const char* shaderPath) +void TextBufferManager::init(const char* _shaderPath) { m_vertexDecl.begin(); m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); @@ -542,65 +538,65 @@ void TextBufferManager::init(const char* shaderPath) m_u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); const bgfx::Memory* mem; - mem = loadShader(shaderPath, "vs_font_basic"); + mem = loadShader(_shaderPath, "vs_font_basic"); bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); - mem = loadShader(shaderPath, "fs_font_basic"); + mem = loadShader(_shaderPath, "fs_font_basic"); bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); m_basicProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); - mem = loadShader(shaderPath, "vs_font_distance_field"); + mem = loadShader(_shaderPath, "vs_font_distance_field"); vsh = bgfx::createVertexShader(mem); - mem = loadShader(shaderPath, "fs_font_distance_field"); + mem = loadShader(_shaderPath, "fs_font_distance_field"); fsh = bgfx::createFragmentShader(mem); m_distanceProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); - mem = loadShader(shaderPath, "vs_font_distance_field_subpixel"); + mem = loadShader(_shaderPath, "vs_font_distance_field_subpixel"); vsh = bgfx::createVertexShader(mem); - mem = loadShader(shaderPath, "fs_font_distance_field_subpixel"); + mem = loadShader(_shaderPath, "fs_font_distance_field_subpixel"); fsh = bgfx::createFragmentShader(mem); m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); } -TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType bufferType) +TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType _bufferType) { uint16_t textIdx = m_textBufferHandles.alloc(); BufferCache& bc = m_textBuffers[textIdx]; - bc.textBuffer = new TextBuffer(m_fontManager); - bc.fontType = _type; - bc.bufferType = bufferType; - bc.indexBufferHandle = bgfx::invalidHandle; - bc.vertexBufferHandle = bgfx::invalidHandle; + bc.m_textBuffer = new TextBuffer(m_fontManager); + bc.m_fontType = _type; + bc.m_bufferType = _bufferType; + bc.m_indexBufferHandle = bgfx::invalidHandle; + bc.m_vertexBufferHandle = bgfx::invalidHandle; TextBufferHandle ret = {textIdx}; return ret; } -void TextBufferManager::destroyTextBuffer(TextBufferHandle handle) +void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) { - assert( bgfx::invalidHandle != handle.idx); + assert( bgfx::invalidHandle != _handle.idx); - BufferCache& bc = m_textBuffers[handle.idx]; - m_textBufferHandles.free(handle.idx); - delete bc.textBuffer; - bc.textBuffer = NULL; + BufferCache& bc = m_textBuffers[_handle.idx]; + m_textBufferHandles.free(_handle.idx); + delete bc.m_textBuffer; + bc.m_textBuffer = NULL; - if(bc.vertexBufferHandle == bgfx::invalidHandle ) return; + if(bc.m_vertexBufferHandle == bgfx::invalidHandle ) return; - switch(bc.bufferType) + switch(bc.m_bufferType) { case STATIC: { bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; + ibh.idx = bc.m_indexBufferHandle; + vbh.idx = bc.m_vertexBufferHandle; bgfx::destroyIndexBuffer(ibh); bgfx::destroyVertexBuffer(vbh); } @@ -609,8 +605,8 @@ void TextBufferManager::destroyTextBuffer(TextBufferHandle handle) case DYNAMIC: bgfx::DynamicIndexBufferHandle ibh; bgfx::DynamicVertexBufferHandle vbh; - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; + ibh.idx = bc.m_indexBufferHandle; + vbh.idx = bc.m_vertexBufferHandle; bgfx::destroyDynamicIndexBuffer(ibh); bgfx::destroyDynamicVertexBuffer(vbh); @@ -625,15 +621,15 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, assert(bgfx::invalidHandle != _handle.idx); BufferCache& bc = m_textBuffers[_handle.idx]; - size_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize(); - size_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize(); + size_t indexSize = bc.m_textBuffer->getIndexCount() * bc.m_textBuffer->getIndexSize(); + size_t vertexSize = bc.m_textBuffer->getVertexCount() * bc.m_textBuffer->getVertexSize(); const bgfx::Memory* mem; bgfx::setTexture(0, m_u_texColor, m_fontManager->getAtlas()->getTextureHandle()); float inverse_gamme = 1.0f/2.2f; bgfx::setUniform(m_u_inverse_gamma, &inverse_gamme); - switch (bc.fontType) + switch (bc.m_fontType) { case FONT_TYPE_ALPHA: bgfx::setProgram(m_basicProgram); @@ -645,85 +641,85 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, break; case FONT_TYPE_DISTANCE_SUBPIXEL: bgfx::setProgram(m_distanceSubpixelProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.textBuffer->getTextColor()); + bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.m_textBuffer->getTextColor()); break; } - switch(bc.bufferType) + switch(bc.m_bufferType) { case STATIC: { bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; - if(bc.vertexBufferHandle == bgfx::invalidHandle) + if(bc.m_vertexBufferHandle == bgfx::invalidHandle) { mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); ibh = bgfx::createIndexBuffer(mem); mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); - bc.indexBufferHandle = ibh.idx ; - bc.vertexBufferHandle = vbh.idx; + bc.m_indexBufferHandle = ibh.idx ; + bc.m_vertexBufferHandle = vbh.idx; }else { - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; + ibh.idx = bc.m_indexBufferHandle; + vbh.idx = bc.m_vertexBufferHandle; } - bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); + bgfx::setVertexBuffer(vbh, bc.m_textBuffer->getVertexCount()); + bgfx::setIndexBuffer(ibh, bc.m_textBuffer->getIndexCount()); }break; case DYNAMIC: { bgfx::DynamicIndexBufferHandle ibh; bgfx::DynamicVertexBufferHandle vbh; - if(bc.vertexBufferHandle == bgfx::invalidHandle) + if(bc.m_vertexBufferHandle == bgfx::invalidHandle) { mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); ibh = bgfx::createDynamicIndexBuffer(mem); mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); - bc.indexBufferHandle = ibh.idx ; - bc.vertexBufferHandle = vbh.idx; + bc.m_indexBufferHandle = ibh.idx ; + bc.m_vertexBufferHandle = vbh.idx; }else { - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; + ibh.idx = bc.m_indexBufferHandle; + vbh.idx = bc.m_vertexBufferHandle; static int i=0; //if(i++ < 5) { mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); bgfx::updateDynamicIndexBuffer(ibh, mem); mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); bgfx::updateDynamicVertexBuffer(vbh, mem); } } - bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); + bgfx::setVertexBuffer(vbh, bc.m_textBuffer->getVertexCount()); + bgfx::setIndexBuffer(ibh, bc.m_textBuffer->getIndexCount()); }break; case TRANSIENT: { bgfx::TransientIndexBuffer tib; bgfx::TransientVertexBuffer tvb; - bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount()); - bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); - memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); - memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); - bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount()); + bgfx::allocTransientIndexBuffer(&tib, bc.m_textBuffer->getIndexCount()); + bgfx::allocTransientVertexBuffer(&tvb, bc.m_textBuffer->getVertexCount(), m_vertexDecl); + memcpy(tib.data, bc.m_textBuffer->getIndexBuffer(), indexSize); + memcpy(tvb.data, bc.m_textBuffer->getVertexBuffer(), vertexSize); + bgfx::setVertexBuffer(&tvb, bc.m_textBuffer->getVertexCount()); + bgfx::setIndexBuffer(&tib, bc.m_textBuffer->getIndexCount()); }break; } @@ -736,72 +732,72 @@ void TextBufferManager::submitTextBufferMask(TextBufferHandle /*_handle*/, uint3 assert(false); } -void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t flags ) +void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags ) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setStyle(flags); + bc.m_textBuffer->setStyle(_flags); } -void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t rgba ) +void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba ) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setTextColor(rgba); + bc.m_textBuffer->setTextColor(_rgba); } -void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t rgba ) +void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba ) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setBackgroundColor(rgba); + bc.m_textBuffer->setBackgroundColor(_rgba); } -void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t rgba ) +void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba ) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setOverlineColor(rgba); + bc.m_textBuffer->setOverlineColor(_rgba); } -void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t rgba ) +void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba ) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setUnderlineColor(rgba); + bc.m_textBuffer->setUnderlineColor(_rgba); } -void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t rgba ) +void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba ) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setStrikeThroughColor(rgba); + bc.m_textBuffer->setStrikeThroughColor(_rgba); } -void TextBufferManager::setPenPosition(TextBufferHandle _handle, float x, float y) +void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setPenPosition(x,y); + bc.m_textBuffer->setPenPosition(_x,_y); } -void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle fontHandle, const char * _string) +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->appendText(fontHandle, _string); + bc.m_textBuffer->appendText(_fontHandle, _string); } -void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle fontHandle, const wchar_t * _string) +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->appendText(fontHandle, _string); + bc.m_textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) { assert( _handle.idx != bgfx::invalidHandle); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->clearTextBuffer(); + bc.m_textBuffer->clearTextBuffer(); } diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 57720fbd..37fae3a3 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -28,31 +28,31 @@ class TextBuffer; class TextBufferManager { public: - TextBufferManager(FontManager* fontManager = NULL); + TextBufferManager(FontManager* _fontManager = NULL); ~TextBufferManager(); - void init(const char* shaderPath); + void init(const char* _shaderPath); - TextBufferHandle createTextBuffer(FontType type, BufferType bufferType); - void destroyTextBuffer(TextBufferHandle handle); - void submitTextBuffer(TextBufferHandle handle, uint8_t id, int32_t depth = 0); - void submitTextBufferMask(TextBufferHandle handle, uint32_t viewMask, int32_t depth = 0); + TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); + void destroyTextBuffer(TextBufferHandle _handle); + void submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth = 0); + void submitTextBufferMask(TextBufferHandle _handle, uint32_t _viewMask, int32_t _depth = 0); - void setStyle(TextBufferHandle handle, uint32_t flags = STYLE_NORMAL); - void setTextColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); - void setBackgroundColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + void setStyle(TextBufferHandle _handle, uint32_t _flags = STYLE_NORMAL); + void setTextColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); + void setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setOverlineColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); - void setUnderlineColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); - void setStrikeThroughColor(TextBufferHandle handle, uint32_t rgba = 0x000000FF); + void setOverlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); + void setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); + void setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setPenPosition(TextBufferHandle handle, float x, float y); + void setPenPosition(TextBufferHandle _handle, float _x, float _y); /// append an ASCII/utf-8 string to the buffer using current pen position and color - void appendText(TextBufferHandle _handle, FontHandle fontHandle, const char * _string); + void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string); /// append a wide char unicode string to the buffer using current pen position and color - void appendText(TextBufferHandle _handle, FontHandle fontHandle, const wchar_t * _string); + void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string); /// Clear the text buffer and reset its state (pen/color) void clearTextBuffer(TextBufferHandle _handle); @@ -65,11 +65,11 @@ private: struct BufferCache { - uint16_t indexBufferHandle; - uint16_t vertexBufferHandle; - TextBuffer* textBuffer; - BufferType bufferType; - FontType fontType; + uint16_t m_indexBufferHandle; + uint16_t m_vertexBufferHandle; + TextBuffer* m_textBuffer; + BufferType m_bufferType; + FontType m_fontType; }; BufferCache* m_textBuffers; From 5096f82d12d4097780b256fd42304776cee29aee Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 22:32:39 +0200 Subject: [PATCH 13/38] convert size_t to uint32_t and int to int32 --- examples/common/cube_atlas.cpp | 2 +- examples/common/font/font_manager.cpp | 52 ++++++++++---------- examples/common/font/text_buffer_manager.cpp | 26 +++++----- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index c56ad3b9..e18c6911 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -89,7 +89,7 @@ bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX = 0; _outY = 0; - size_t i; + uint32_t i; best_height = INT_MAX; best_index = -1; diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 8b22a60c..4642c9dc 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -191,10 +191,10 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - int x = bitmap->left; - int y = -bitmap->top; - int w = bitmap->bitmap.width; - int h = bitmap->bitmap.rows; + int32_t x = bitmap->left; + int32_t y = -bitmap->top; + int32_t w = bitmap->bitmap.width; + int32_t h = bitmap->bitmap.rows; _glyphInfo.m_offset_x = (float) x; _glyphInfo.m_offset_y = (float) y; @@ -203,10 +203,10 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; - int charsize = 1; - int depth=1; - int stride = bitmap->bitmap.pitch; - for( int i=0; i<h; ++i ) + int32_t charsize = 1; + int32_t depth=1; + int32_t stride = bitmap->bitmap.pitch; + for( int32_t i=0; i<h; ++i ) { memcpy(_outBuffer+(i*w) * charsize * depth, bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); @@ -234,10 +234,10 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI if(error){ return false; } FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - int x = bitmap->left; - int y = -bitmap->top; - int w = bitmap->bitmap.width; - int h = bitmap->bitmap.rows; + int32_t x = bitmap->left; + int32_t y = -bitmap->top; + int32_t w = bitmap->bitmap.width; + int32_t h = bitmap->bitmap.rows; _glyphInfo.m_offset_x = (float) x; _glyphInfo.m_offset_y = (float) y; @@ -245,10 +245,10 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI _glyphInfo.m_height = (float) h; _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; - int charsize = 1; - int depth=3; - int stride = bitmap->bitmap.pitch; - for( int i=0; i<h; ++i ) + int32_t charsize = 1; + int32_t depth=3; + int32_t stride = bitmap->bitmap.pitch; + for( int32_t i=0; i<h; ++i ) { memcpy(_outBuffer+(i*w) * charsize * depth, bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); @@ -358,10 +358,10 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - int x = bitmap->left; - int y = -bitmap->top; - int w = bitmap->bitmap.width; - int h = bitmap->bitmap.rows; + int32_t x = bitmap->left; + int32_t y = -bitmap->top; + int32_t w = bitmap->bitmap.width; + int32_t h = bitmap->bitmap.rows; _glyphInfo.m_offset_x = (float) x; _glyphInfo.m_offset_y = (float) y; @@ -370,11 +370,11 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; - int charsize = 1; - int depth=1; - int stride = bitmap->bitmap.pitch; + int32_t charsize = 1; + int32_t depth=1; + int32_t stride = bitmap->bitmap.pitch; - for( int i=0; i<h; ++i ) + for(int32_t i=0; i<h; ++i ) { memcpy(_outBuffer+(i*w) * charsize * depth, @@ -522,7 +522,7 @@ TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) fseek(pFile, 0L, SEEK_SET); // Read the entire file into memory. - size_t newLen = fread((void*)buffer, sizeof(char), bufsize, pFile); + uint32_t newLen = fread((void*)buffer, sizeof(char), bufsize, pFile); if (newLen == 0) { fclose(pFile); @@ -653,7 +653,7 @@ bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) if(font.m_trueTypeFont != NULL) { //parse string - for( size_t i=0, end = wcslen(_string) ; i < end; ++i ) + for( uint32_t i=0, end = wcslen(_string) ; i < end; ++i ) { //if glyph cached, continue CodePoint_t codePoint = _string[i]; diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index e6b30f93..d38800c1 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -148,7 +148,7 @@ private: (((_rgba >> 24) & 0xff) << 0); } - static const size_t MAX_BUFFERED_CHARACTERS = 8192; + static const uint32_t MAX_BUFFERED_CHARACTERS = 8192; uint32_t m_styleFlags; @@ -174,7 +174,7 @@ private: /// FontManager* m_fontManager; - void setVertex(size_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) + void setVertex(uint32_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) { m_vertexBuffer[_i].x = _x; m_vertexBuffer[_i].y = _y; @@ -193,9 +193,9 @@ private: uint16_t* m_indexBuffer; uint8_t* m_styleBuffer; - size_t m_vertexCount; - size_t m_indexCount; - size_t m_lineStartIndex; + uint32_t m_vertexCount; + uint32_t m_indexCount; + uint32_t m_lineStartIndex; }; @@ -288,7 +288,7 @@ void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) } //parse string - for( size_t i=0, end = wcslen(_string) ; i < end; ++i ) + for( uint32_t i=0, end = wcslen(_string) ; i < end; ++i ) { //if glyph cached, continue uint32_t _codePoint = _string[i]; @@ -489,7 +489,7 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) { - for( size_t i=m_lineStartIndex; i < m_vertexCount; i+=4 ) + for( uint32_t i=m_lineStartIndex; i < m_vertexCount; i+=4 ) { if( m_styleBuffer[i] == STYLE_BACKGROUND) { @@ -621,8 +621,8 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, assert(bgfx::invalidHandle != _handle.idx); BufferCache& bc = m_textBuffers[_handle.idx]; - size_t indexSize = bc.m_textBuffer->getIndexCount() * bc.m_textBuffer->getIndexSize(); - size_t vertexSize = bc.m_textBuffer->getVertexCount() * bc.m_textBuffer->getVertexSize(); + uint32_t indexSize = bc.m_textBuffer->getIndexCount() * bc.m_textBuffer->getIndexSize(); + uint32_t vertexSize = bc.m_textBuffer->getVertexCount() * bc.m_textBuffer->getVertexSize(); const bgfx::Memory* mem; bgfx::setTexture(0, m_u_texColor, m_fontManager->getAtlas()->getTextureHandle()); @@ -692,11 +692,8 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, }else { ibh.idx = bc.m_indexBufferHandle; - vbh.idx = bc.m_vertexBufferHandle; - - static int i=0; - //if(i++ < 5) - { + vbh.idx = bc.m_vertexBufferHandle; + mem = bgfx::alloc(indexSize); memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); bgfx::updateDynamicIndexBuffer(ibh, mem); @@ -704,7 +701,6 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, mem = bgfx::alloc(vertexSize); memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); bgfx::updateDynamicVertexBuffer(vbh, mem); - } } bgfx::setVertexBuffer(vbh, bc.m_textBuffer->getVertexCount()); bgfx::setIndexBuffer(ibh, bc.m_textBuffer->getIndexCount()); From 119317686c863f69e2c76375a9233565adebec64 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 22:48:34 +0200 Subject: [PATCH 14/38] use ii instead of i in for loop --- examples/11-fontsdf/fontsdf.cpp | 16 ++--- examples/common/cube_atlas.cpp | 50 +++++++-------- examples/common/font/font_manager.cpp | 66 ++++++++++---------- examples/common/font/text_buffer_manager.cpp | 24 +++---- 4 files changed, 78 insertions(+), 78 deletions(-) diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index a1c4a66f..21a38ebc 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -76,12 +76,12 @@ int _main_(int /*_argc*/, char** /*_argv*/) FontHandle fonts[64]; fonts[fontsCount++] = distance_font; //generate various sub distance field fonts at various size - int step=4; - for(int i = 64; i>1 ; i-=step) + int32_t step=4; + for(int32_t ii = 64; ii>1 ; ii-=step) { - if(i<32) step = 2; + if(ii<32) step = 2; //instantiate a usable font - FontHandle font = fontManager->createScaledFontToPixelSize(distance_font, i); + FontHandle font = fontManager->createScaledFontToPixelSize(distance_font, ii); fonts[fontsCount++] = font; } //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph @@ -92,9 +92,9 @@ int _main_(int /*_argc*/, char** /*_argv*/) textBufferManager->setPenPosition(staticText, 10.0f, 70.0f); textBufferManager->setTextColor(staticText, 0xFFFFFFFF); //textBufferManager->setTextColor(staticText, 0x000000FF); - for(size_t i = 0; i< fontsCount; ++i) + for(uint32_t ii = 0; ii< fontsCount; ++ii) { - textBufferManager->appendText(staticText, fonts[i], L"The quick brown fox jumps over the lazy dog\n"); + textBufferManager->appendText(staticText, fonts[ii], L"The quick brown fox jumps over the lazy dog\n"); //textBufferManager->appendText(staticText, fonts[i], L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); } @@ -144,9 +144,9 @@ int _main_(int /*_argc*/, char** /*_argv*/) } //destroy the fonts - for(size_t i=0; i<fontsCount;++i) + for(uint32_t ii=0; ii<fontsCount;++ii) { - fontManager->destroyFont(fonts[i]); + fontManager->destroyFont(fonts[ii]); } textBufferManager->destroyTextBuffer(staticText); diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index e18c6911..e76d6bf8 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -89,22 +89,22 @@ bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX = 0; _outY = 0; - uint32_t i; + uint32_t ii; best_height = INT_MAX; best_index = -1; best_width = INT_MAX; - for( i = 0; i < m_skyline.size(); ++i ) + for( ii = 0; ii < m_skyline.size(); ++ii ) { - y = fit( i, _width, _height ); + y = fit( ii, _width, _height ); if( y >= 0 ) { - node = &m_skyline[i]; + node = &m_skyline[ii]; if( ( (y + _height) < best_height ) || ( ((y + _height) == best_height) && (node->m_width < best_width)) ) { best_height = y + _height; - best_index = i; + best_index = ii; best_width = node->m_width; _outX = node->m_x; _outY = y; @@ -120,10 +120,10 @@ bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& Node newNode(_outX, _outY + _height, _width); m_skyline.insert(m_skyline.begin() + best_index, newNode); - for(i = best_index+1; i < m_skyline.size(); ++i) + for(ii = best_index+1; ii < m_skyline.size(); ++ii) { - node = &m_skyline[i]; - prev = &m_skyline[i-1]; + node = &m_skyline[ii]; + prev = &m_skyline[ii-1]; if (node->m_x < (prev->m_x + prev->m_width) ) { int shrink = prev->m_x + prev->m_width - node->m_x; @@ -131,8 +131,8 @@ bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& node->m_width -= shrink; if (node->m_width <= 0) { - m_skyline.erase(m_skyline.begin() + i); - --i; + m_skyline.erase(m_skyline.begin() + ii); + --ii; } else { @@ -206,17 +206,17 @@ void RectanglePacker::merge() { Node* node; Node* next; - uint32_t i; + uint32_t ii; - for( i=0; i < m_skyline.size()-1; ++i ) + for( ii=0; ii < m_skyline.size()-1; ++ii ) { - node = (Node *) &m_skyline[i]; - next = (Node *) &m_skyline[i+1]; + node = (Node *) &m_skyline[ii]; + next = (Node *) &m_skyline[ii+1]; if( node->m_y == next->m_y ) { node->m_width += next->m_width; - m_skyline.erase(m_skyline.begin() + i + 1); - --i; + m_skyline.erase(m_skyline.begin() + ii + 1); + --ii; } } } @@ -234,9 +234,9 @@ Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) assert(_textureSize >= 64 && _textureSize <= 4096 && "suspicious texture size" ); assert(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000 && "suspicious _regions count" ); m_layers = new PackedLayer[24]; - for(int i=0; i<24;++i) + for(int ii=0; ii<24;++ii) { - m_layers[i].packer.init(_textureSize, _textureSize); + m_layers[ii].packer.init(_textureSize, _textureSize); } m_usedLayers = 0; m_usedFaces = 0; @@ -330,9 +330,9 @@ uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bit return UINT16_MAX; } //create new layers - for(int i=0; i < _type;++i) + for(int ii=0; ii < _type; ++ii) { - m_layers[idx+i].faceRegion.setMask(_type, m_usedFaces, i); + m_layers[idx+ii].faceRegion.setMask(_type, m_usedFaces, ii); } m_usedLayers += _type; m_usedFaces++; @@ -367,7 +367,7 @@ void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffe uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4); //update the cpu buffer - for(int y = 0; y < _region.m_height; ++y) + for(int yy = 0; yy < _region.m_height; ++yy) { memcpy(outLineBuffer, inLineBuffer, _region.m_width * 4); inLineBuffer += _region.m_width*4; @@ -383,14 +383,14 @@ void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffe uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4)); //update the cpu buffer - for(int y = 0; y<_region.m_height; ++y) + for(int yy = 0; yy<_region.m_height; ++yy) { - for(int x = 0; x<_region.m_width; ++x) + for(int xx = 0; xx<_region.m_width; ++xx) { - outLineBuffer[(x*4) + layer] = inLineBuffer[x]; + outLineBuffer[(xx*4) + layer] = inLineBuffer[xx]; } //update the GPU buffer - memcpy(mem->data + y*_region.m_width*4, outLineBuffer, _region.m_width*4); + memcpy(mem->data + yy*_region.m_width*4, outLineBuffer, _region.m_width*4); inLineBuffer += _region.m_width; outLineBuffer += m_textureSize*4; } diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 4642c9dc..64edc1d5 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -206,10 +206,10 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo int32_t charsize = 1; int32_t depth=1; int32_t stride = bitmap->bitmap.pitch; - for( int32_t i=0; i<h; ++i ) + for( int32_t ii=0; ii<h; ++ii ) { - memcpy(_outBuffer+(i*w) * charsize * depth, - bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); + memcpy(_outBuffer+(ii*w) * charsize * depth, + bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); } FT_Done_Glyph(glyph); return true; @@ -248,10 +248,10 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI int32_t charsize = 1; int32_t depth=3; int32_t stride = bitmap->bitmap.pitch; - for( int32_t i=0; i<h; ++i ) + for( int32_t ii=0; ii<h; ++ii ) { - memcpy(_outBuffer+(i*w) * charsize * depth, - bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); + memcpy(_outBuffer+(ii*w) * charsize * depth, + bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); } FT_Done_Glyph(glyph); return true; @@ -267,61 +267,61 @@ void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int double * data = (double *) calloc( width * height, sizeof(double) ); double * outside = (double *) calloc( width * height, sizeof(double) ); double * inside = (double *) calloc( width * height, sizeof(double) ); - uint32_t i; + uint32_t ii; // Convert img into double (data) double img_min = 255, img_max = -255; - for( i=0; i<width*height; ++i) + for( ii=0; ii<width*height; ++ii) { - double v = img[i]; - data[i] = v; + double v = img[ii]; + data[ii] = v; if (v > img_max) img_max = v; if (v < img_min) img_min = v; } // Rescale image levels between 0 and 1 - for( i=0; i<width*height; ++i) + for( ii=0; ii<width*height; ++ii) { - data[i] = (img[i]-img_min)/(img_max-img_min); + data[ii] = (img[ii]-img_min)/(img_max-img_min); } // Compute outside = edtaa3(bitmap); % Transform background (0's) computegradient( data, width, height, gx, gy); edtaa3(data, gx, gy, width, height, xdist, ydist, outside); - for( i=0; i<width*height; ++i) - if( outside[i] < 0 ) - outside[i] = 0.0; + for( ii=0; ii<width*height; ++ii) + if( outside[ii] < 0 ) + outside[ii] = 0.0; // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) memset(gx, 0, sizeof(double)*width*height ); memset(gy, 0, sizeof(double)*width*height ); - for( i=0; i<width*height; ++i) - data[i] = 1.0 - data[i]; + for( ii=0; ii<width*height; ++ii) + data[ii] = 1.0 - data[ii]; computegradient( data, width, height, gx, gy); edtaa3(data, gx, gy, width, height, xdist, ydist, inside); - for( i=0; i<width*height; ++i) - if( inside[i] < 0 ) - inside[i] = 0.0; + for( ii=0; ii<width*height; ++ii) + if( inside[ii] < 0 ) + inside[ii] = 0.0; // distmap = outside - inside; % Bipolar distance field unsigned char *out = outImg;//(unsigned char *) malloc( width * height * sizeof(unsigned char) ); - for( i=0; i<width*height; ++i) + for( ii=0; ii<width*height; ++ii) { //out[i] = 127 - outside[i]*8; //if(out[i]<0) out[i] = 0; //out[i] += inside[i]*16; //if(out[i]>255) out[i] = 255; - outside[i] -= inside[i]; - outside[i] = 128 + outside[i]*16; + outside[ii] -= inside[ii]; + outside[ii] = 128 + outside[ii]*16; //if(outside[i] > 8) outside[i] = 8; //if(inside[i] > 8) outside[i] = 8; //outside[i] = 128 - inside[i]*8 + outside[i]*8; - if( outside[i] < 0 ) outside[i] = 0; - if( outside[i] > 255 ) outside[i] = 255; - out[i] = 255 - (unsigned char) outside[i]; + if( outside[ii] < 0 ) outside[ii] = 0; + if( outside[ii] > 255 ) outside[ii] = 255; + out[ii] = 255 - (unsigned char) outside[ii]; //out[i] = (unsigned char) outside[i]; } @@ -374,11 +374,11 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI int32_t depth=1; int32_t stride = bitmap->bitmap.pitch; - for(int32_t i=0; i<h; ++i ) + for(int32_t ii=0; ii<h; ++ii ) { - memcpy(_outBuffer+(i*w) * charsize * depth, - bitmap->bitmap.buffer + (i*stride) * charsize, w * charsize * depth ); + memcpy(_outBuffer+(ii*w) * charsize * depth, + bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); } FT_Done_Glyph(glyph); @@ -398,9 +398,9 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI memset(alphaImg, 0, nw*nh*sizeof(uint8_t)); //copy the original buffer to the temp one - for(uint32_t i= dh; i< nh-dh; ++i) + for(uint32_t ii= dh; ii< nh-dh; ++ii) { - memcpy(alphaImg+i*nw+dw, _outBuffer+(i-dh)*w, w); + memcpy(alphaImg+ii*nw+dw, _outBuffer+(ii-dh)*w, w); } make_distance_map(alphaImg, _outBuffer, nw, nh); @@ -653,10 +653,10 @@ bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) if(font.m_trueTypeFont != NULL) { //parse string - for( uint32_t i=0, end = wcslen(_string) ; i < end; ++i ) + for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) { //if glyph cached, continue - CodePoint_t codePoint = _string[i]; + CodePoint_t codePoint = _string[ii]; if(!preloadGlyph(_handle, codePoint)) { return false; diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index d38800c1..2112bb68 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -288,10 +288,10 @@ void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) } //parse string - for( uint32_t i=0, end = wcslen(_string) ; i < end; ++i ) + for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) { //if glyph cached, continue - uint32_t _codePoint = _string[i]; + uint32_t _codePoint = _string[ii]; if(m_fontManager->getGlyphInfo(_fontHandle, _codePoint, glyph)) { appendGlyph(_codePoint, font, glyph); @@ -489,19 +489,19 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) { - for( uint32_t i=m_lineStartIndex; i < m_vertexCount; i+=4 ) + for( uint32_t ii=m_lineStartIndex; ii < m_vertexCount; ii+=4 ) { - if( m_styleBuffer[i] == STYLE_BACKGROUND) + if( m_styleBuffer[ii] == STYLE_BACKGROUND) { - m_vertexBuffer[i+0].y = _top; - m_vertexBuffer[i+1].y = _bottom; - m_vertexBuffer[i+2].y = _bottom; - m_vertexBuffer[i+3].y = _top; + m_vertexBuffer[ii+0].y = _top; + m_vertexBuffer[ii+1].y = _bottom; + m_vertexBuffer[ii+2].y = _bottom; + m_vertexBuffer[ii+3].y = _top; }else{ - m_vertexBuffer[i+0].y += _dy; - m_vertexBuffer[i+1].y += _dy; - m_vertexBuffer[i+2].y += _dy; - m_vertexBuffer[i+3].y += _dy; + m_vertexBuffer[ii+0].y += _dy; + m_vertexBuffer[ii+1].y += _dy; + m_vertexBuffer[ii+2].y += _dy; + m_vertexBuffer[ii+3].y += _dy; } } } From 1d5c813806b8dc549addb2dc998ae8d069a25006 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 22:51:59 +0200 Subject: [PATCH 15/38] remove Sleep() in demo function --- examples/10-font/font.cpp | 2 -- examples/11-fontsdf/fontsdf.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 715dea2d..8906cf86 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -188,8 +188,6 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); - //just to prevent my CG Fan to howl - Sleep(2); } diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index 21a38ebc..4eecaff4 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -139,8 +139,6 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); - //just to prevent my CG Fan to howl - Sleep(2); } //destroy the fonts From d4a695a181f3c10cbe4073bb397e3e20348fe823 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 23 Apr 2013 23:14:32 +0200 Subject: [PATCH 16/38] convert assert to BX_CHECK --- examples/common/cube_atlas.cpp | 26 +++++---- examples/common/font/font_manager.cpp | 61 ++++++++++---------- examples/common/font/text_buffer_manager.cpp | 34 +++++------ 3 files changed, 63 insertions(+), 58 deletions(-) diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index e76d6bf8..8b0b7946 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -2,10 +2,11 @@ * License: http://www.opensource.org/licenses/BSD-2-Clause */ #pragma once -#include <bgfx.h> -#include <assert.h> -#include <vector> #include "cube_atlas.h" +#include <bx/bx.h> +#include <bgfx.h> +#include <vector> + //********** Rectangle packer implementation ************ class RectanglePacker @@ -68,8 +69,8 @@ RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height):m_width(_wid void RectanglePacker::init(uint32_t _width, uint32_t _height) { - assert(_width > 2); - assert(_height > 2); + BX_CHECK(_width > 2, "_width must be > 2"); + BX_CHECK(_height > 2, "_height must be > 2"); m_width = _width; m_height = _height; m_usedSpace = 0; @@ -231,8 +232,8 @@ struct Atlas::PackedLayer Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) { - assert(_textureSize >= 64 && _textureSize <= 4096 && "suspicious texture size" ); - assert(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000 && "suspicious _regions count" ); + BX_CHECK(_textureSize >= 64 && _textureSize <= 4096, "suspicious texture size" ); + BX_CHECK(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000, "suspicious _regions count" ); m_layers = new PackedLayer[24]; for(int ii=0; ii<24;++ii) { @@ -267,7 +268,7 @@ Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount) { - assert(_regionCount <= 64 && _maxRegionsCount <= 4096); + BX_CHECK(_regionCount <= 64 && _maxRegionsCount <= 4096, "suspicious initialization"); //layers are frozen m_usedLayers = 24; m_usedFaces = 6; @@ -275,7 +276,10 @@ Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _re m_textureSize = _textureSize; m_regionCount = _regionCount; //regions are frozen - m_maxRegionCount = _regionCount; + if(_regionCount < _maxRegionsCount) + m_maxRegionCount = _regionCount; + else + m_maxRegionCount = _maxRegionsCount; m_regions = new AtlasRegion[_regionCount]; m_textureBuffer = new uint8_t[getTextureBufferSize()]; @@ -309,7 +313,7 @@ uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bit return UINT16_MAX; } - uint16_t x,y; + uint16_t x=0,y=0; // We want each bitmap to be separated by at least one black pixel // TODO manage mipmaps uint32_t idx = 0; @@ -378,7 +382,7 @@ void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffe }else { uint32_t layer = _region.getComponentIndex(); - uint32_t face = _region.getFaceIndex(); + //uint32_t face = _region.getFaceIndex(); const uint8_t* inLineBuffer = _bitmapBuffer; uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4)); diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 64edc1d5..6ffaaeea 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -15,7 +15,7 @@ #include "../../../3rdparty/edtaa3/edtaa3func.h" #include "../../../3rdparty/edtaa3/edtaa3func.cpp" #include <math.h> -#include <assert.h> +#include <bx/bx.h> #if BGFX_CONFIG_USE_TINYSTL @@ -96,10 +96,10 @@ FontManager::TrueTypeFont::~TrueTypeFont() bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight) { - assert((_bufferSize > 256 && _bufferSize < 100000000) && "TrueType buffer size is suspicious"); - assert((_pixelHeight > 4 && _pixelHeight < 128) && "TrueType buffer size is suspicious"); + BX_CHECK((_bufferSize > 256 && _bufferSize < 100000000), "TrueType buffer size is suspicious"); + BX_CHECK((_pixelHeight > 4 && _pixelHeight < 128), "TrueType buffer size is suspicious"); - assert(m_font == NULL && "TrueTypeFont already initialized" ); + BX_CHECK(m_font == NULL, "TrueTypeFont already initialized" ); FTHolder* holder = new FTHolder(); @@ -152,14 +152,15 @@ bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSiz FontInfo FontManager::TrueTypeFont::getFontInfo() { - assert(m_font != NULL && "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - assert(FT_IS_SCALABLE (holder->m_face)); + //todo manage unscalable font + BX_CHECK(FT_IS_SCALABLE (holder->m_face), "Font is unscalable"); FT_Size_Metrics metrics = holder->m_face->size->metrics; - //todo manage unscalable font + FontInfo outFontInfo; outFontInfo.m_scale = 1.0f; outFontInfo.m_ascender = metrics.ascender /64.0f; @@ -173,7 +174,7 @@ FontInfo FontManager::TrueTypeFont::getFontInfo() bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { - assert(m_font != NULL && "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); @@ -217,7 +218,7 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { - assert(m_font != NULL && "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); @@ -337,7 +338,7 @@ void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { - assert(m_font != NULL && "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); @@ -391,7 +392,7 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI uint32_t nw = w + dw*2; uint32_t nh = h + dh*2; - assert(nw*nh < 128*128); + BX_CHECK(nw*nh < 128*128, "buffer overflow"); uint32_t buffSize = nw*nh*sizeof(uint8_t); uint8_t * alphaImg = (uint8_t *) malloc( buffSize ); @@ -465,7 +466,7 @@ void FontManager::init() m_blackGlyph.m_width=3; m_blackGlyph.m_height=3; - assert( addBitmap(m_blackGlyph, buffer) ); + BX_CHECK( addBitmap(m_blackGlyph, buffer), "unable to add white glyph" ); //make sure the black glyph doesn't bleed /*int16_t texUnit = 65535 / m_textureWidth; @@ -478,10 +479,10 @@ void FontManager::init() FontManager::~FontManager() { - assert(m_fontHandles.getNumHandles() == 0 && "All the fonts must be destroyed before destroying the manager"); + BX_CHECK(m_fontHandles.getNumHandles() == 0, "All the fonts must be destroyed before destroying the manager"); delete [] m_cachedFonts; - assert(m_filesHandles.getNumHandles() == 0 && "All the font files must be destroyed before destroying the manager"); + BX_CHECK(m_filesHandles.getNumHandles() == 0, "All the font files must be destroyed before destroying the manager"); delete [] m_cachedFiles; delete [] m_buffer; @@ -533,7 +534,7 @@ TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) fclose(pFile); uint16_t id = m_filesHandles.alloc(); - assert(id != bx::HandleAlloc::invalid); + BX_CHECK(id != bx::HandleAlloc::invalid, "No more room for files"); m_cachedFiles[id].buffer = buffer; m_cachedFiles[id].bufferSize = bufsize; TrueTypeHandle ret = {id}; @@ -546,8 +547,8 @@ TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size) { - uint16_t id = m_filesHandles.alloc(); - assert(id != bx::HandleAlloc::invalid); + uint16_t id = m_filesHandles.alloc(); + BX_CHECK(id != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFiles[id].buffer = new uint8_t[_size]; m_cachedFiles[id].bufferSize = _size; memcpy(m_cachedFiles[id].buffer, _buffer, _size); @@ -559,7 +560,7 @@ TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* _buffer, uint3 void FontManager::unloadTrueType(TrueTypeHandle _handle) { - assert(bgfx::invalidHandle != _handle.idx); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); delete m_cachedFiles[_handle.idx].buffer; m_cachedFiles[_handle.idx].bufferSize = 0; m_cachedFiles[_handle.idx].buffer = NULL; @@ -568,7 +569,7 @@ void FontManager::unloadTrueType(TrueTypeHandle _handle) FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType) { - assert(bgfx::invalidHandle != _tt_handle.idx); + BX_CHECK(bgfx::invalidHandle != _tt_handle.idx, "Invalid handle used"); TrueTypeFont* ttf = new TrueTypeFont(); if(!ttf->init( m_cachedFiles[_tt_handle.idx].buffer, m_cachedFiles[_tt_handle.idx].bufferSize, _typefaceIndex, _pixelSize)) @@ -579,7 +580,7 @@ FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_ } uint16_t fontIdx = m_fontHandles.alloc(); - assert(fontIdx != bx::HandleAlloc::invalid); + BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFonts[fontIdx].m_trueTypeFont = ttf; m_cachedFonts[fontIdx].m_fontInfo = ttf->getFontInfo(); @@ -593,7 +594,7 @@ FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize) { - assert(bgfx::invalidHandle != _baseFontHandle.idx); + BX_CHECK(bgfx::invalidHandle != _baseFontHandle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_baseFontHandle.idx]; FontInfo& fontInfo = font.m_fontInfo; @@ -608,7 +609,7 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, uint16_t fontIdx = m_fontHandles.alloc(); - assert(fontIdx != bx::HandleAlloc::invalid); + BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFonts[fontIdx].m_cachedGlyphs.clear(); m_cachedFonts[fontIdx].m_fontInfo = newFontInfo; m_cachedFonts[fontIdx].m_trueTypeFont = NULL; @@ -619,21 +620,21 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, FontHandle FontManager::loadBakedFontFromFile(const char* /*fontPath*/, const char* /*descriptorPath*/) { - assert(false); //TODO implement + //assert(false); //TODO implement FontHandle invalid = BGFX_INVALID_HANDLE; return invalid; } FontHandle FontManager::loadBakedFontFromMemory(const uint8_t* /*imageBuffer*/, uint32_t /*imageSize*/, const uint8_t* /*descriptorBuffer*/, uint32_t /*descriptorSize*/) { - assert(false); //TODO implement + //assert(false); //TODO implement FontHandle invalid = BGFX_INVALID_HANDLE; return invalid; } void FontManager::destroyFont(FontHandle _handle) { - assert(bgfx::invalidHandle != _handle.idx); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); if(m_cachedFonts[_handle.idx].m_trueTypeFont != NULL) { @@ -645,8 +646,8 @@ void FontManager::destroyFont(FontHandle _handle) } bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) -{ - assert(bgfx::invalidHandle != _handle.idx); +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_handle.idx]; //if truetype present @@ -670,7 +671,7 @@ bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) { - assert(bgfx::invalidHandle != _handle.idx); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_handle.idx]; FontInfo& fontInfo = font.m_fontInfo; //check if glyph not already present @@ -701,7 +702,7 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) font.m_trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; default: - assert(false && "TextureType not supported yet"); + BX_CHECK(false, "TextureType not supported yet"); }; //copy bitmap to texture @@ -749,7 +750,7 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) const FontInfo& FontManager::getFontInfo(FontHandle _handle) { - assert(_handle.idx != bgfx::invalidHandle); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); return m_cachedFonts[_handle.idx].m_fontInfo; } diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 2112bb68..915eb970 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -4,7 +4,7 @@ #include "text_buffer_manager.h" #include "../cube_atlas.h" -#include <assert.h> +#include <bx/bx.h> #include <stdio.h> #include <string.h> #include <math.h> @@ -261,7 +261,7 @@ void TextBuffer::appendText(FontHandle _fontHandle, const char * _string) appendGlyph((CodePoint_t)codepoint, font, glyph); }else { - assert(false && "Glyph not found"); + BX_CHECK(false, "Glyph not found"); } } //printf("U+%04X\n", codepoint); @@ -297,7 +297,7 @@ void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) appendGlyph(_codePoint, font, glyph); }else { - assert(false && "Glyph not found"); + BX_CHECK(false, "Glyph not found"); } } } @@ -515,7 +515,7 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f TextBufferManager::~TextBufferManager() { - assert(m_textBufferHandles.getNumHandles() == 0 && "All the text buffers must be destroyed before destroying the manager"); + BX_CHECK(m_textBufferHandles.getNumHandles() == 0, "All the text buffers must be destroyed before destroying the manager"); delete[] m_textBuffers; bgfx::destroyUniform(m_u_texColor); @@ -580,7 +580,7 @@ TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) { - assert( bgfx::invalidHandle != _handle.idx); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; m_textBufferHandles.free(_handle.idx); @@ -618,7 +618,7 @@ void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth) { - assert(bgfx::invalidHandle != _handle.idx); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; uint32_t indexSize = bc.m_textBuffer->getIndexCount() * bc.m_textBuffer->getIndexSize(); @@ -725,75 +725,75 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, void TextBufferManager::submitTextBufferMask(TextBufferHandle /*_handle*/, uint32_t /*_viewMask*/, int32_t /*_depth*/) { //TODO - assert(false); + BX_CHECK(false, "TODO TODO"); } void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags ) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setStyle(_flags); } void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba ) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setTextColor(_rgba); } void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba ) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setBackgroundColor(_rgba); } void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba ) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setOverlineColor(_rgba); } void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba ) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setUnderlineColor(_rgba); } void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba ) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setStrikeThroughColor(_rgba); } void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->setPenPosition(_x,_y); } void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) { - assert( _handle.idx != bgfx::invalidHandle); + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->clearTextBuffer(); } From 1a1b4a9baf2a040ce026be0d8a7ad7e778520e3f Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 24 Apr 2013 12:07:47 +0200 Subject: [PATCH 17/38] Better disable warning for Freetype --- examples/common/font/font_manager.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 6ffaaeea..5193778a 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -4,13 +4,18 @@ #include "font_manager.h" #include "../cube_atlas.h" -#pragma warning( push ) -#pragma warning( disable: 4146 ) -#pragma warning( disable: 4700 ) -#pragma warning( disable: 4100 ) -#pragma warning( disable: 4701 ) -#include "../../../3rdparty/freetype/freetype.h" -#pragma warning( pop ) +#if BX_COMPILER_MSVC +# pragma warning(push) +# pragma warning(disable: 4100) // DISABLE warning C4100: '' : unreferenced formal parameter +# pragma warning(disable: 4146) // DISABLE warning C4146: unary minus operator applied to unsigned type, result still unsigned +# pragma warning(disable: 4700) // DISABLE warning C4700: uninitialized local variable 'temp' used +# pragma warning(disable: 4701) // DISABLE warning C4701: potentially uninitialized local variable '' used +# include "../../../3rdparty/freetype/freetype.h" +# pragma warning(pop) +#else +# include "../../../3rdparty/freetype/freetype.h" +#endif // BX_COMPILER_MSVC + #include "../../../3rdparty/edtaa3/edtaa3func.h" #include "../../../3rdparty/edtaa3/edtaa3func.cpp" From 83f176a5dc575bc55db4940bc5aea8cabaedef06 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 24 Apr 2013 12:10:41 +0200 Subject: [PATCH 18/38] convert m_u_xxx to u_xxx for uniforms handle naming. --- examples/common/font/text_buffer_manager.cpp | 12 ++++++------ examples/common/font/text_buffer_manager.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 915eb970..ced0f4a9 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -518,8 +518,8 @@ TextBufferManager::~TextBufferManager() BX_CHECK(m_textBufferHandles.getNumHandles() == 0, "All the text buffers must be destroyed before destroying the manager"); delete[] m_textBuffers; - bgfx::destroyUniform(m_u_texColor); - bgfx::destroyUniform(m_u_inverse_gamma); + bgfx::destroyUniform(u_texColor); + bgfx::destroyUniform(u_inverse_gamma); bgfx::destroyProgram(m_basicProgram); bgfx::destroyProgram(m_distanceProgram); @@ -534,8 +534,8 @@ void TextBufferManager::init(const char* _shaderPath) m_vertexDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); m_vertexDecl.end(); - m_u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); - m_u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); + u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); + u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); const bgfx::Memory* mem; mem = loadShader(_shaderPath, "vs_font_basic"); @@ -625,9 +625,9 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, uint32_t vertexSize = bc.m_textBuffer->getVertexCount() * bc.m_textBuffer->getVertexSize(); const bgfx::Memory* mem; - bgfx::setTexture(0, m_u_texColor, m_fontManager->getAtlas()->getTextureHandle()); + bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle()); float inverse_gamme = 1.0f/2.2f; - bgfx::setUniform(m_u_inverse_gamma, &inverse_gamme); + bgfx::setUniform(u_inverse_gamma, &inverse_gamme); switch (bc.m_fontType) { diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 37fae3a3..4d662b3b 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -76,8 +76,8 @@ private: bx::HandleAlloc m_textBufferHandles; FontManager* m_fontManager; bgfx::VertexDecl m_vertexDecl; - bgfx::UniformHandle m_u_texColor; - bgfx::UniformHandle m_u_inverse_gamma; + bgfx::UniformHandle u_texColor; + bgfx::UniformHandle u_inverse_gamma; //shaders program bgfx::ProgramHandle m_basicProgram; bgfx::ProgramHandle m_distanceProgram; From fc5f5d3ec27eaf7bc93d9a245daca45b5ef46e81 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 24 Apr 2013 12:15:40 +0200 Subject: [PATCH 19/38] convert static const to #define --- examples/common/font/text_buffer_manager.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index ced0f4a9..4d0b9b13 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -10,7 +10,8 @@ #include <math.h> #include <stddef.h> /* offsetof */ -const uint16_t MAX_TEXT_BUFFER_COUNT = 64; +#define MAX_TEXT_BUFFER_COUNT 64 +#define MAX_BUFFERED_CHARACTERS 8192 long int fsize(FILE* _file) { @@ -141,15 +142,13 @@ private: void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); uint32_t toABGR(uint32_t _rgba) -{ - return (((_rgba >> 0) & 0xff) << 24) | - (((_rgba >> 8) & 0xff) << 16) | - (((_rgba >> 16) & 0xff) << 8) | - (((_rgba >> 24) & 0xff) << 0); -} - - static const uint32_t MAX_BUFFERED_CHARACTERS = 8192; - + { + return (((_rgba >> 0) & 0xff) << 24) | + (((_rgba >> 8) & 0xff) << 16) | + (((_rgba >> 16) & 0xff) << 8) | + (((_rgba >> 24) & 0xff) << 0); + } + uint32_t m_styleFlags; // color states From b661d50b6930b92758871672061a78dc2b4f8f67 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 24 Apr 2013 12:23:47 +0200 Subject: [PATCH 20/38] Fix bug involving assert a function call. --- examples/common/font/font_manager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 5193778a..7e5adf85 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -471,7 +471,9 @@ void FontManager::init() m_blackGlyph.m_width=3; m_blackGlyph.m_height=3; - BX_CHECK( addBitmap(m_blackGlyph, buffer), "unable to add white glyph" ); + bool addResult = addBitmap(m_blackGlyph, buffer); + BX_UNUSED(addResult); + BX_CHECK( addResult , "unable to add white glyph" ); //make sure the black glyph doesn't bleed /*int16_t texUnit = 65535 / m_textureWidth; From e4712b2641f025d14e693e9b1d01b03966b3c5b3 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 7 May 2013 14:26:31 +0200 Subject: [PATCH 21/38] use embedded shaders --- examples/common/font/makefile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/common/font/makefile b/examples/common/font/makefile index 5ae719f2..b38ac842 100644 --- a/examples/common/font/makefile +++ b/examples/common/font/makefile @@ -7,11 +7,12 @@ BGFX_DIR=../../.. RUNTIME_DIR=$(BGFX_DIR)/examples/runtime BUILD_DIR=../../../.build -include $(BGFX_DIR)/premake/shader.mk +include $(BGFX_DIR)/premake/shader-embeded.mk rebuild: - @make -s --no-print-directory TARGET=0 clean all - @make -s --no-print-directory TARGET=1 clean all - @make -s --no-print-directory TARGET=2 clean all - @make -s --no-print-directory TARGET=3 clean all - @make -s --no-print-directory TARGET=4 clean all + @make -s --no-print-directory clean all +# @make -s --no-print-directory TARGET=0 clean all +# @make -s --no-print-directory TARGET=1 clean all +# @make -s --no-print-directory TARGET=2 clean all +# @make -s --no-print-directory TARGET=3 clean all +# @make -s --no-print-directory TARGET=4 clean all From d470ac2567a95f4734f6e1576d814f6a3fbcfcc8 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 7 May 2013 14:26:49 +0200 Subject: [PATCH 22/38] remove explicit filesystem dependency --- examples/10-font/font.cpp | 31 ++++++++++++++++++++ examples/common/font/text_buffer_manager.cpp | 31 -------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 8906cf86..5c9cb165 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -12,7 +12,38 @@ #include <stdio.h> #include <string.h> + static const char* s_shaderPath = NULL; +long int fsize(FILE* _file) +{ + long int pos = ftell(_file); + fseek(_file, 0L, SEEK_END); + long int size = ftell(_file); + fseek(_file, pos, SEEK_SET); + return size; +} + +static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shaderName) +{ + char out[512]; + strcpy(out, _shaderPath); + strcat(out, _shaderName); + strcat(out, ".bin"); + + FILE* file = fopen(out, "rb"); + if (NULL != file) + { + uint32_t size = (uint32_t)fsize(file); + const bgfx::Memory* mem = bgfx::alloc(size+1); + /*size_t ignore =*/ fread(mem->data, 1, size, file); + /*BX_UNUSED(ignore);*/ + fclose(file); + mem->data[mem->size-1] = '\0'; + return mem; + } + + return NULL; +} int _main_(int /*_argc*/, char** /*_argv*/) { diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 4d0b9b13..1891d9ca 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -13,37 +13,6 @@ #define MAX_TEXT_BUFFER_COUNT 64 #define MAX_BUFFERED_CHARACTERS 8192 -long int fsize(FILE* _file) -{ - long int pos = ftell(_file); - fseek(_file, 0L, SEEK_END); - long int size = ftell(_file); - fseek(_file, pos, SEEK_SET); - return size; -} - -static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shaderName) -{ - char out[512]; - strcpy(out, _shaderPath); - strcat(out, _shaderName); - strcat(out, ".bin"); - - FILE* file = fopen(out, "rb"); - if (NULL != file) - { - uint32_t size = (uint32_t)fsize(file); - const bgfx::Memory* mem = bgfx::alloc(size+1); - /*size_t ignore =*/ fread(mem->data, 1, size, file); - /*BX_UNUSED(ignore);*/ - fclose(file); - mem->data[mem->size-1] = '\0'; - return mem; - } - - return NULL; -} - // Table from Flexible and Economical UTF-8 Decoder // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. From 6cf5f67eae8ba4e4ef10a0559b2dfe019e2e54da Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Tue, 7 May 2013 15:51:19 +0200 Subject: [PATCH 23/38] load shaders explicitely inside the samples --- examples/10-font/font.cpp | 39 ++++++++++-- examples/11-fontsdf/fontsdf.cpp | 63 +++++++++++++++++++- examples/common/font/makefile | 16 ++--- examples/common/font/text_buffer_manager.cpp | 26 ++++++-- examples/common/font/text_buffer_manager.h | 5 +- 5 files changed, 130 insertions(+), 19 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 5c9cb165..802ef7af 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -12,7 +12,6 @@ #include <stdio.h> #include <string.h> - static const char* s_shaderPath = NULL; long int fsize(FILE* _file) { @@ -45,6 +44,7 @@ static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shad return NULL; } + int _main_(int /*_argc*/, char** /*_argv*/) { uint32_t width = 1280; @@ -52,8 +52,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) uint32_t debug = BGFX_DEBUG_TEXT; uint32_t reset = 0; - bgfx::init(); - + bgfx::init(); bgfx::reset(width, height); @@ -91,11 +90,37 @@ int _main_(int /*_argc*/, char** /*_argv*/) break; } + const bgfx::Memory* mem; + mem = loadShader(s_shaderPath, "vs_font_basic"); + bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); + mem = loadShader(s_shaderPath, "fs_font_basic"); + bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); + bgfx::ProgramHandle _basicProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + mem = loadShader(s_shaderPath, "vs_font_distance_field"); + vsh = bgfx::createVertexShader(mem); + mem = loadShader(s_shaderPath, "fs_font_distance_field"); + fsh = bgfx::createFragmentShader(mem); + bgfx::ProgramHandle _distanceProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + mem = loadShader(s_shaderPath, "vs_font_distance_field_subpixel"); + vsh = bgfx::createVertexShader(mem); + mem = loadShader(s_shaderPath, "fs_font_distance_field_subpixel"); + fsh = bgfx::createFragmentShader(mem); + bgfx::ProgramHandle _distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); - textBufferManager->init(s_shaderPath); - + textBufferManager->init(_basicProgram, _distanceProgram, _distanceSubpixelProgram); + //load some truetype files TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); TrueTypeHandle consola_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/consola.ttf"); @@ -229,6 +254,10 @@ int _main_(int /*_argc*/, char** /*_argv*/) textBufferManager->destroyTextBuffer(staticText); textBufferManager->destroyTextBuffer(transientText); + bgfx::destroyProgram(_basicProgram); + bgfx::destroyProgram(_distanceProgram); + bgfx::destroyProgram(_distanceSubpixelProgram); + delete textBufferManager; delete fontManager; diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index 4eecaff4..7df4aedd 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -13,6 +13,37 @@ #include <string.h> static const char* s_shaderPath = NULL; +long int fsize(FILE* _file) +{ + long int pos = ftell(_file); + fseek(_file, 0L, SEEK_END); + long int size = ftell(_file); + fseek(_file, pos, SEEK_SET); + return size; +} + +static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shaderName) +{ + char out[512]; + strcpy(out, _shaderPath); + strcat(out, _shaderName); + strcat(out, ".bin"); + + FILE* file = fopen(out, "rb"); + if (NULL != file) + { + uint32_t size = (uint32_t)fsize(file); + const bgfx::Memory* mem = bgfx::alloc(size+1); + /*size_t ignore =*/ fread(mem->data, 1, size, file); + /*BX_UNUSED(ignore);*/ + fclose(file); + mem->data[mem->size-1] = '\0'; + return mem; + } + + return NULL; +} + int _main_(int /*_argc*/, char** /*_argv*/) { @@ -61,10 +92,35 @@ int _main_(int /*_argc*/, char** /*_argv*/) break; } + const bgfx::Memory* mem; + mem = loadShader(s_shaderPath, "vs_font_basic"); + bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); + mem = loadShader(s_shaderPath, "fs_font_basic"); + bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); + bgfx::ProgramHandle _basicProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + mem = loadShader(s_shaderPath, "vs_font_distance_field"); + vsh = bgfx::createVertexShader(mem); + mem = loadShader(s_shaderPath, "fs_font_distance_field"); + fsh = bgfx::createFragmentShader(mem); + bgfx::ProgramHandle _distanceProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + mem = loadShader(s_shaderPath, "vs_font_distance_field_subpixel"); + vsh = bgfx::createVertexShader(mem); + mem = loadShader(s_shaderPath, "fs_font_distance_field_subpixel"); + fsh = bgfx::createFragmentShader(mem); + bgfx::ProgramHandle _distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); - textBufferManager->init(s_shaderPath); + textBufferManager->init(_basicProgram, _distanceProgram, _distanceSubpixelProgram); //load a truetype files TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); @@ -148,6 +204,11 @@ int _main_(int /*_argc*/, char** /*_argv*/) } textBufferManager->destroyTextBuffer(staticText); + + bgfx::destroyProgram(_basicProgram); + bgfx::destroyProgram(_distanceProgram); + bgfx::destroyProgram(_distanceSubpixelProgram); + delete textBufferManager; delete fontManager; // Shutdown bgfx. diff --git a/examples/common/font/makefile b/examples/common/font/makefile index b38ac842..c9953f66 100644 --- a/examples/common/font/makefile +++ b/examples/common/font/makefile @@ -7,12 +7,14 @@ BGFX_DIR=../../.. RUNTIME_DIR=$(BGFX_DIR)/examples/runtime BUILD_DIR=../../../.build -include $(BGFX_DIR)/premake/shader-embeded.mk +# include $(BGFX_DIR)/premake/shader-embeded.mk +include $(BGFX_DIR)/premake/shader.mk rebuild: - @make -s --no-print-directory clean all -# @make -s --no-print-directory TARGET=0 clean all -# @make -s --no-print-directory TARGET=1 clean all -# @make -s --no-print-directory TARGET=2 clean all -# @make -s --no-print-directory TARGET=3 clean all -# @make -s --no-print-directory TARGET=4 clean all +# @make -s --no-print-directory clean all + @make -s --no-print-directory TARGET=0 clean all + @make -s --no-print-directory TARGET=1 clean all + @make -s --no-print-directory TARGET=2 clean all + @make -s --no-print-directory TARGET=3 clean all + @make -s --no-print-directory TARGET=4 clean all + diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 1891d9ca..2e391f31 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -489,11 +489,27 @@ TextBufferManager::~TextBufferManager() bgfx::destroyUniform(u_texColor); bgfx::destroyUniform(u_inverse_gamma); - bgfx::destroyProgram(m_basicProgram); - bgfx::destroyProgram(m_distanceProgram); - bgfx::destroyProgram(m_distanceSubpixelProgram); + //bgfx::destroyProgram(m_basicProgram); + //bgfx::destroyProgram(m_distanceProgram); + //bgfx::destroyProgram(m_distanceSubpixelProgram); } +void TextBufferManager::init(bgfx::ProgramHandle _basicProgram, bgfx::ProgramHandle _distanceProgram, bgfx::ProgramHandle _distanceSubpixelProgram) +{ + m_basicProgram = _basicProgram; + m_distanceProgram = _distanceProgram; + m_distanceSubpixelProgram = _distanceSubpixelProgram; + + m_vertexDecl.begin(); + m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); + m_vertexDecl.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true); + m_vertexDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); + m_vertexDecl.end(); + + u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); + u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); +} +/* void TextBufferManager::init(const char* _shaderPath) { m_vertexDecl.begin(); @@ -514,7 +530,7 @@ void TextBufferManager::init(const char* _shaderPath) bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); - mem = loadShader(_shaderPath, "vs_font_distance_field"); + mem = loadShader(_shaderPath, "vs_font_distance_field"); vsh = bgfx::createVertexShader(mem); mem = loadShader(_shaderPath, "fs_font_distance_field"); fsh = bgfx::createFragmentShader(mem); @@ -529,7 +545,7 @@ void TextBufferManager::init(const char* _shaderPath) m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); -} +}*/ TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType _bufferType) { diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 4d662b3b..662974e2 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -31,7 +31,10 @@ public: TextBufferManager(FontManager* _fontManager = NULL); ~TextBufferManager(); - void init(const char* _shaderPath); + //shaders program + + void init(bgfx::ProgramHandle _basicProgram, bgfx::ProgramHandle _distanceProgram, bgfx::ProgramHandle _distanceSubpixelProgram); + //void init(const char* _shaderPath); TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); void destroyTextBuffer(TextBufferHandle _handle); From 67ebcebd21747e6feb53c089f7d693ae2c782209 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:45:58 +0200 Subject: [PATCH 24/38] add inner outline in order to avoid texture bleeding --- examples/common/cube_atlas.cpp | 12 +++++++++--- examples/common/cube_atlas.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index 8b0b7946..f1ee2081 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -306,7 +306,7 @@ Atlas::~Atlas() delete[] m_textureBuffer; } -uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type) +uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type, uint16_t outline) { if (m_regionCount >= m_maxRegionCount) { @@ -350,13 +350,19 @@ uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bit } AtlasRegion& region = m_regions[m_regionCount]; - region.m_x = x; - region.m_y = y; + region.m_x = x ; + region.m_y = y ; region.m_width = _width; region.m_height = _height; region.m_mask = m_layers[idx].faceRegion.m_mask; updateRegion(region, _bitmapBuffer); + + region.m_x += outline; + region.m_y += outline; + region.m_width -= (outline*2); + region.m_height -= (outline*2); + return m_regionCount++; } diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 15734e02..3f981227 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -50,7 +50,7 @@ public: ~Atlas(); /// add a region to the atlas, and copy the content of mem to the underlying texture - uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8); + uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8, uint16_t outline = 0); /// update a preallocated region void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer); From d63a452161abab0d4073f11f064edb9057a67d65 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:46:51 +0200 Subject: [PATCH 25/38] commit embedded shaders --- examples/common/font/fs_font_basic.bin.h | 119 +++++++++ .../common/font/fs_font_distance_field.bin.h | 191 ++++++++++++++ .../fs_font_distance_field_subpixel.bin.h | 237 ++++++++++++++++++ examples/common/font/vs_font_basic.bin.h | 138 ++++++++++ .../common/font/vs_font_distance_field.bin.h | 138 ++++++++++ .../vs_font_distance_field_subpixel.bin.h | 138 ++++++++++ 6 files changed, 961 insertions(+) create mode 100644 examples/common/font/fs_font_basic.bin.h create mode 100644 examples/common/font/fs_font_distance_field.bin.h create mode 100644 examples/common/font/fs_font_distance_field_subpixel.bin.h create mode 100644 examples/common/font/vs_font_basic.bin.h create mode 100644 examples/common/font/vs_font_distance_field.bin.h create mode 100644 examples/common/font/vs_font_distance_field_subpixel.bin.h diff --git a/examples/common/font/fs_font_basic.bin.h b/examples/common/font/fs_font_basic.bin.h new file mode 100644 index 00000000..8b000fb8 --- /dev/null +++ b/examples/common/font/fs_font_basic.bin.h @@ -0,0 +1,119 @@ +static const uint8_t fs_font_basic_dx9[445] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x03, 0xff, 0xff, // FSH............. + 0xfe, 0xff, 0x22, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, // ..".CTAB....S... + 0x00, 0x03, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, // ................ + 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, // L...0........... + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, // <.......u_texCol + 0x6f, 0x72, 0x00, 0xab, 0x04, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, // or.............. + 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, // ....ps_3_0.Micro + 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, // soft (R) HLSL Sh + 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, // ader Compiler 9. + 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, // 29.952.3111.Q... + 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, // .......@...?.... + 0x00, 0x00, 0x80, 0x3f, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x80, // ...?Q........... + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0xc0, 0x1f, 0x00, 0x00, 0x02, // ..........@..... + 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, // ................ + 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x98, 0x00, 0x08, 0x0f, 0xa0, // ................ + 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0x90, 0x00, 0x00, 0x00, 0xa0, // ................ + 0x00, 0x00, 0x55, 0xa0, 0x13, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, // ..U............. + 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x55, 0x81, 0x00, 0x00, 0xaa, 0xa0, // X.........U..... + 0x00, 0x00, 0xff, 0xa0, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, // ................ + 0x00, 0x00, 0x55, 0x81, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, // ..U.X........... + 0x00, 0x00, 0xaa, 0xa0, 0x00, 0x00, 0xaa, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, // ................ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, // ......U......... + 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, // ........X....... + 0x00, 0x00, 0xe4, 0x8c, 0x00, 0x00, 0xff, 0xa0, 0x00, 0x00, 0xaa, 0xa0, 0x42, 0x00, 0x00, 0x03, // ............B... + 0x01, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0x90, 0x00, 0x08, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0xc6, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0x00, 0x03, // ................ + 0x00, 0x08, 0x08, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xff, 0x90, 0x01, 0x00, 0x00, 0x02, // ................ + 0x00, 0x08, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ............. +}; +static const uint8_t fs_font_basic_dx11[898] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, // FSH............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x03, 0x44, 0x58, 0x42, // ...........d.DXB + 0x43, 0x3f, 0x43, 0x07, 0x08, 0x07, 0x51, 0x5c, 0xa6, 0x18, 0x49, 0xe3, 0xf6, 0x15, 0xef, 0xba, // C?C...Q...I..... + 0xb6, 0x01, 0x00, 0x00, 0x00, 0x64, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, // .....d.......4.. + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0xe8, 0x02, 0x00, // .....d.......... + 0x00, 0x52, 0x44, 0x45, 0x46, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .RDEF........... + 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0x00, 0x91, 0x00, // ................ + 0x00, 0x80, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, // .....n.......... + 0x00, 0x09, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, // .....u_texColorS + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, // ampler.u_texColo + 0x72, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, // rTexture.Microso + 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, // ft (R) HLSL Shad + 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, // er Compiler 9.29 + 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab, 0x49, 0x53, 0x47, // .952.3111....ISG + 0x4e, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, // Nl...........P.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x62, 0x00, 0x00, // .............b.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, // .....SV_POSITION + 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, // .COLOR.TEXCOORD. + 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, // .OSGN,.......... + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // . .............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, // .........SV_TARG + 0x45, 0x54, 0x00, 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0x48, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, // ET...SHDRH...@.. + 0x00, 0x52, 0x00, 0x00, 0x00, 0x35, 0x18, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // .R...5.......... + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?............... + 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....?........... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........?....... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x5a, 0x00, 0x00, // ............?Z.. + 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x30, 0x00, 0x04, 0x00, 0x70, 0x10, // ..`......X0...p. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xf2, 0x10, 0x10, // .....UU..b...... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, // .....b.......... + 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, // .e.... ......h.. + 0x02, 0x02, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // .....2.......... + 0x00, 0x3a, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, // .:........@..... + 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x1b, 0x00, 0x00, 0x05, 0x12, 0x00, 0x10, // @.@.....?....... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, // .............E.. + 0x09, 0xf2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, 0x02, 0x00, 0x00, // .........F...... + 0x00, 0x46, 0x7e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, // .F~.......`..... + 0x00, 0x11, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0c, 0x10, // .............f.. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x9e, 0x90, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // .....F.......... + 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, // .8.... ......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, // .....:.......6.. + 0x05, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, 0x01, 0x00, 0x00, // .r ......F...... + 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, // .>...STATt...... + 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, // .. +}; +static const uint8_t fs_font_basic_glsl[389] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, // FSH.....#ifdef G + 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, // L_ES.precision h + 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, // ighp float;.#end + 0x69, 0x66, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x0a, 0x75, 0x6e, 0x69, // if // GL_ES..uni + 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x43, 0x75, 0x62, 0x65, // form samplerCube + 0x20, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x76, 0x61, 0x72, // u_texColor;.var + 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, // ying vec4 v_texc + 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, // oord0;.varying v + 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x6f, // ec4 v_color0;.vo + 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x69, // id main ().{. i + 0x6e, 0x74, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, // nt tmpvar_1;. t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x28, 0x28, // mpvar_1 = int((( + 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x77, 0x20, 0x2a, 0x20, // v_texcoord0.w * + 0x34, 0x2e, 0x30, 0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, // 4.0) + 0.5));. + 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, 0x0a, 0x20, // vec4 tmpvar_2;. + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x3d, 0x20, // tmpvar_2.xyz = + 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x3b, 0x0a, 0x20, 0x20, // v_color0.xyz;. + 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x2e, 0x77, 0x20, 0x3d, 0x20, 0x28, 0x76, 0x5f, // tmpvar_2.w = (v_ + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x2e, 0x77, 0x20, 0x2a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, // color0.w * textu + 0x72, 0x65, 0x43, 0x75, 0x62, 0x65, 0x20, 0x28, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, // reCube (u_texCol + 0x6f, 0x72, 0x2c, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, // or, v_texcoord0. + 0x78, 0x79, 0x7a, 0x29, 0x2e, 0x7a, 0x79, 0x78, 0x77, 0x5b, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // xyz).zyxw[tmpvar + 0x5f, 0x31, 0x5d, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, // _1]);. gl_FragC + 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, // olor = tmpvar_2; + 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // .}... +}; diff --git a/examples/common/font/fs_font_distance_field.bin.h b/examples/common/font/fs_font_distance_field.bin.h new file mode 100644 index 00000000..aaf2f772 --- /dev/null +++ b/examples/common/font/fs_font_distance_field.bin.h @@ -0,0 +1,191 @@ +static const uint8_t fs_font_distance_field_dx9[737] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x03, 0xff, 0xff, // FSH............. + 0xfe, 0xff, 0x22, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, // ..".CTAB....S... + 0x00, 0x03, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, // ................ + 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, // L...0........... + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, // <.......u_texCol + 0x6f, 0x72, 0x00, 0xab, 0x04, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, // or.............. + 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, // ....ps_3_0.Micro + 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, // soft (R) HLSL Sh + 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, // ader Compiler 9. + 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, // 29.952.3111.Q... + 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, // .......@...?.... + 0x00, 0x00, 0x80, 0x3f, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x80, // ...?Q........... + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0xc0, 0x51, 0x00, 0x00, 0x05, // ..........@.Q... + 0x02, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xc0, // .......A...?.... + 0x00, 0x00, 0x40, 0x40, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90, // ..@@............ + 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x00, 0x98, 0x00, 0x08, 0x0f, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x80, // ................ + 0x01, 0x00, 0xff, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x55, 0xa0, 0x13, 0x00, 0x00, 0x02, // ..........U..... + 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x80, // ........X....... + 0x00, 0x00, 0x55, 0x81, 0x00, 0x00, 0xaa, 0xa0, 0x00, 0x00, 0xff, 0xa0, 0x02, 0x00, 0x00, 0x03, // ..U............. + 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0x81, 0x58, 0x00, 0x00, 0x04, // ..........U.X... + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xaa, 0xa0, 0x00, 0x00, 0xaa, 0x80, // ................ + 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0x80, // ..............U. + 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xe4, 0xa0, // ................ + 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x8c, 0x00, 0x00, 0xff, 0xa0, // X............... + 0x00, 0x00, 0xaa, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0x90, // ....B........... + 0x00, 0x08, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0xc6, 0x80, // ................ + 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0e, 0x80, 0x01, 0x00, 0x90, 0x91, // ................ + 0x5c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x08, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0xf9, 0x80, 0x00, 0x00, 0xf9, 0x80, 0x07, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x55, 0x80, 0x06, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x80, // ......U......... + 0x00, 0x00, 0x55, 0x80, 0x5b, 0x00, 0x00, 0x02, 0x01, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x90, // ..U.[........... + 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0x80, // ................ + 0x07, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0xaa, 0x80, 0x06, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0xaa, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x80, // ................ + 0x00, 0x00, 0x55, 0x80, 0x00, 0x00, 0xaa, 0x80, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x80, // ..U............. + 0x00, 0x00, 0x55, 0x80, 0x02, 0x00, 0x00, 0xa1, 0x02, 0x00, 0x55, 0xa0, 0x04, 0x00, 0x00, 0x04, // ..U.......U..... + 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x55, 0x80, 0x02, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x55, 0xa0, // ......U.......U. + 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0xaa, 0x81, 0x00, 0x00, 0xe4, 0x80, // ................ + 0x06, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x55, 0x80, 0x05, 0x00, 0x00, 0x03, // ..........U..... + 0x00, 0x00, 0x11, 0x80, 0x00, 0x00, 0x55, 0x80, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x04, // ......U......... + 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xaa, 0xa0, 0x02, 0x00, 0xff, 0xa0, // ................ + 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, // ................ + 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0x80, // ..............U. + 0x05, 0x00, 0x00, 0x03, 0x00, 0x08, 0x08, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xff, 0x90, // ................ + 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, // ................ + 0x00, // . +}; +static const uint8_t fs_font_distance_field_dx11[1366] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, // FSH............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x05, 0x44, 0x58, 0x42, // ...........8.DXB + 0x43, 0x9c, 0xb0, 0xe1, 0x54, 0x9b, 0x83, 0x06, 0x38, 0x73, 0xc4, 0xd0, 0x8b, 0xe9, 0x44, 0xef, // C...T...8s....D. + 0x35, 0x01, 0x00, 0x00, 0x00, 0x38, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, // 5....8.......4.. + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0xbc, 0x04, 0x00, // .....d.......... + 0x00, 0x52, 0x44, 0x45, 0x46, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .RDEF........... + 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0x00, 0x91, 0x00, // ................ + 0x00, 0x80, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, // .....n.......... + 0x00, 0x09, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, // .....u_texColorS + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, // ampler.u_texColo + 0x72, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, // rTexture.Microso + 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, // ft (R) HLSL Shad + 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, // er Compiler 9.29 + 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab, 0x49, 0x53, 0x47, // .952.3111....ISG + 0x4e, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, // Nl...........P.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x62, 0x00, 0x00, // .............b.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, // .....SV_POSITION + 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, // .COLOR.TEXCOORD. + 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, // .OSGN,.......... + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // . .............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, // .........SV_TARG + 0x45, 0x54, 0x00, 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0x1c, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, // ET...SHDR....@.. + 0x00, 0xc7, 0x00, 0x00, 0x00, 0x35, 0x18, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // .....5.......... + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?............... + 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....?........... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........?....... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x5a, 0x00, 0x00, // ............?Z.. + 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x30, 0x00, 0x04, 0x00, 0x70, 0x10, // ..`......X0...p. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xf2, 0x10, 0x10, // .....UU..b...... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, // .....b.......... + 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, // .e.... ......h.. + 0x02, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x06, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // .....6...r...... + 0x00, 0x46, 0x12, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, // .F...A.......... + 0x05, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, // .r.......F...... + 0x00, 0x10, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, // .............F.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, // .....F.......... + 0x05, 0xe2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x10, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x10, 0x00, 0x00, 0x07, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, // .....".......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, // .............K.. + 0x05, 0x32, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // .2.......F...... + 0x00, 0x00, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, // .............2.. + 0x09, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // .".............. + 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // ..@.....A.@..... + 0x3f, 0x32, 0x00, 0x00, 0x0a, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, // ?2.............. + 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // .A........@..... + 0x41, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x22, 0x00, 0x10, // A.@.....?....".. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .........A...... + 0x00, 0x1a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x0a, 0x22, 0x00, 0x10, // .............".. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, // ......@.....?... + 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x1a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ?...?...?....... + 0x00, 0x32, 0x00, 0x00, 0x09, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x10, // .2...B.......:.. + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x01, 0x40, 0x00, // ......@.....@.@. + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x1b, 0x00, 0x00, 0x05, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ....?....B...... + 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xf2, 0x00, 0x10, // .*.......E...... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7e, 0x10, // .....F.......F~. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, // ......`......... + 0x08, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0c, 0x10, 0x00, 0x01, 0x00, 0x00, // .B.......f...... + 0x00, 0x46, 0x9e, 0x90, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .F...*.......... + 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x80, 0x41, 0x00, 0x00, // .............A.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x20, 0x00, // .....*.......8 . + 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, 0x22, 0x00, 0x10, // .........2...".. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, // ..............@. + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x38, 0x00, 0x00, // ......@....@@8.. + 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, // .........8...... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x10, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, // .....8.... ..... + 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, // .........:...... + 0x00, 0x36, 0x00, 0x00, 0x05, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, // .6...r ......F.. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, // .....>...STATt.. + 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...... +}; +static const uint8_t fs_font_distance_field_glsl[773] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, // FSH.....#ifdef G + 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, // L_ES.precision h + 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, // ighp float;.#end + 0x69, 0x66, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x0a, 0x75, 0x6e, 0x69, // if // GL_ES..uni + 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x43, 0x75, 0x62, 0x65, // form samplerCube + 0x20, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x76, 0x61, 0x72, // u_texColor;.var + 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, // ying vec4 v_texc + 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, // oord0;.varying v + 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x6f, // ec4 v_color0;.vo + 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x69, // id main ().{. i + 0x6e, 0x74, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, // nt tmpvar_1;. t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x28, 0x28, // mpvar_1 = int((( + 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x77, 0x20, 0x2a, 0x20, // v_texcoord0.w * + 0x34, 0x2e, 0x30, 0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, // 4.0) + 0.5));. + 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, 0x0a, 0x20, // vec3 tmpvar_2;. + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x20, 0x3d, 0x20, 0x64, 0x46, 0x64, 0x78, // tmpvar_2 = dFdx + 0x28, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x78, 0x79, 0x7a, // (v_texcoord0.xyz + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // );. vec3 tmpvar + 0x5f, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x33, 0x20, 0x3d, // _3;. tmpvar_3 = + 0x20, 0x64, 0x46, 0x64, 0x79, 0x28, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // dFdy(v_texcoord + 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, // 0.xyz);. float + 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, // tmpvar_4;. tmpv + 0x61, 0x72, 0x5f, 0x34, 0x20, 0x3d, 0x20, 0x28, 0x38, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x73, // ar_4 = (8.0 * (s + 0x71, 0x72, 0x74, 0x28, 0x64, 0x6f, 0x74, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // qrt(dot (tmpvar_ + 0x32, 0x2c, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x29, 0x29, 0x20, 0x2b, 0x20, // 2, tmpvar_2)) + + 0x73, 0x71, 0x72, 0x74, 0x28, 0x64, 0x6f, 0x74, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // sqrt(dot (tmpvar + 0x5f, 0x33, 0x2c, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x33, 0x29, 0x29, 0x29, 0x29, // _3, tmpvar_3)))) + 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x65, 0x64, 0x67, 0x65, 0x30, 0x5f, // ;. float edge0_ + 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x65, 0x64, 0x67, 0x65, 0x30, 0x5f, 0x35, 0x20, 0x3d, 0x20, 0x28, // 5;. edge0_5 = ( + 0x30, 0x2e, 0x35, 0x20, 0x2d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x34, 0x29, 0x3b, // 0.5 - tmpvar_4); + 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x74, 0x5f, 0x36, 0x3b, 0x0a, 0x20, 0x20, // . float t_6;. + 0x74, 0x5f, 0x36, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x28, 0x6d, 0x69, 0x6e, 0x20, 0x28, // t_6 = max (min ( + 0x28, 0x28, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x43, 0x75, 0x62, 0x65, 0x20, 0x28, 0x75, // ((textureCube (u + 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, // _texColor, v_tex + 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x29, 0x2e, 0x7a, 0x79, 0x78, 0x77, // coord0.xyz).zyxw + 0x5b, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x5d, 0x20, 0x2d, 0x20, 0x65, 0x64, 0x67, // [tmpvar_1] - edg + 0x65, 0x30, 0x5f, 0x35, 0x29, 0x20, 0x2f, 0x20, 0x28, 0x28, 0x30, 0x2e, 0x35, 0x20, 0x2b, 0x20, // e0_5) / ((0.5 + + 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x34, 0x29, 0x20, 0x2d, 0x20, 0x65, 0x64, 0x67, 0x65, // tmpvar_4) - edge + 0x30, 0x5f, 0x35, 0x29, 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x30, 0x2e, 0x30, // 0_5)), 1.0), 0.0 + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // );. vec4 tmpvar + 0x5f, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x37, 0x2e, 0x78, // _7;. tmpvar_7.x + 0x79, 0x7a, 0x20, 0x3d, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x2e, 0x78, 0x79, // yz = v_color0.xy + 0x7a, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x37, 0x2e, 0x77, 0x20, // z;. tmpvar_7.w + 0x3d, 0x20, 0x28, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x2e, 0x77, 0x20, 0x2a, 0x20, // = (v_color0.w * + 0x28, 0x74, 0x5f, 0x36, 0x20, 0x2a, 0x20, 0x28, 0x74, 0x5f, 0x36, 0x20, 0x2a, 0x20, 0x28, 0x33, // (t_6 * (t_6 * (3 + 0x2e, 0x30, 0x20, 0x2d, 0x20, 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x74, 0x5f, 0x36, 0x29, // .0 - (2.0 * t_6) + 0x29, 0x29, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, // ))));. gl_FragC + 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x37, 0x3b, // olor = tmpvar_7; + 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // .}... +}; diff --git a/examples/common/font/fs_font_distance_field_subpixel.bin.h b/examples/common/font/fs_font_distance_field_subpixel.bin.h new file mode 100644 index 00000000..89f0bdbc --- /dev/null +++ b/examples/common/font/fs_font_distance_field_subpixel.bin.h @@ -0,0 +1,237 @@ +static const uint8_t fs_font_distance_field_subpixel_dx9[885] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x68, 0x03, 0x00, 0x03, 0xff, 0xff, // FSH.......h..... + 0xfe, 0xff, 0x22, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, // ..".CTAB....S... + 0x00, 0x03, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, // ................ + 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, // L...0........... + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, // <.......u_texCol + 0x6f, 0x72, 0x00, 0xab, 0x04, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, // or.............. + 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, // ....ps_3_0.Micro + 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, // soft (R) HLSL Sh + 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, // ader Compiler 9. + 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x51, 0x00, 0x00, 0x05, // 29.952.3111.Q... + 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, // .......@...?.... + 0x00, 0x00, 0x80, 0x3f, 0x51, 0x00, 0x00, 0x05, 0x01, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0x80, // ...?Q........... + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0xc0, 0x51, 0x00, 0x00, 0x05, // ..........@.Q... + 0x02, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, // ..........@@.... + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x05, 0x03, 0x00, 0x0f, 0xa0, 0xc1, 0xaa, 0x2a, 0x3e, // ....Q.........*> + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, // ...A...?........ + 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x08, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, // ................ + 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x98, 0x00, 0x08, 0x0f, 0xa0, // ................ + 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0x90, 0x00, 0x00, 0x00, 0xa0, // ................ + 0x00, 0x00, 0x55, 0xa0, 0x13, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, // ..U............. + 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x55, 0x81, 0x00, 0x00, 0xaa, 0xa0, // X.........U..... + 0x00, 0x00, 0xff, 0xa0, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x80, // ................ + 0x00, 0x00, 0x55, 0x81, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, // ..U.X........... + 0x00, 0x00, 0xaa, 0xa0, 0x00, 0x00, 0xaa, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, // ................ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, // ......U......... + 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, // ........X....... + 0x00, 0x00, 0xe4, 0x8c, 0x00, 0x00, 0xff, 0xa0, 0x00, 0x00, 0xaa, 0xa0, 0x5b, 0x00, 0x00, 0x02, // ............[... + 0x01, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x90, 0x04, 0x00, 0x00, 0x04, 0x02, 0x00, 0x07, 0x80, // ................ + 0x01, 0x00, 0xe4, 0x80, 0x03, 0x00, 0x00, 0xa1, 0x01, 0x00, 0xe4, 0x90, 0x42, 0x00, 0x00, 0x03, // ............B... + 0x02, 0x00, 0x0f, 0x80, 0x02, 0x00, 0xe4, 0x80, 0x00, 0x08, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, // ................ + 0x02, 0x00, 0x01, 0x80, 0x02, 0x00, 0xc6, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0x00, 0x04, // ................ + 0x03, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x03, 0x00, 0x00, 0xa0, 0x01, 0x00, 0xe4, 0x90, // ................ + 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0x80, // ................ + 0x07, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x02, // ................ + 0x01, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x80, 0x42, 0x00, 0x00, 0x03, 0x03, 0x00, 0x0f, 0x80, // ........B....... + 0x03, 0x00, 0xe4, 0x80, 0x00, 0x08, 0xe4, 0xa0, 0x09, 0x00, 0x00, 0x03, 0x02, 0x00, 0x04, 0x80, // ................ + 0x03, 0x00, 0xc6, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, // ................ + 0x02, 0x00, 0xaa, 0x80, 0x02, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x03, 0x02, 0x00, 0x02, 0x80, // ................ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x07, 0x80, // ......U......... + 0x01, 0x00, 0xe4, 0x91, 0x5c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80, // ................ + 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x80, // ................ + 0x07, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, // ................ + 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x80, // ................ + 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x55, 0xa1, 0x03, 0x00, 0xaa, 0xa0, 0x04, 0x00, 0x00, 0x04, // ......U......... + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x55, 0xa0, 0x03, 0x00, 0xaa, 0xa0, // ..........U..... + 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x55, 0x81, 0x00, 0x00, 0x00, 0x80, // ..........U..... + 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x55, 0x81, 0x02, 0x00, 0x90, 0x80, // ..........U..... + 0x05, 0x00, 0x00, 0x03, 0x00, 0x08, 0x08, 0x80, 0x02, 0x00, 0x55, 0x80, 0x00, 0x00, 0xff, 0x90, // ..........U..... + 0x06, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xf9, 0x80, 0x04, 0x00, 0x00, 0x04, // ................ + 0x01, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x02, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x55, 0xa0, // ..............U. + 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x80, // ................ + 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0x80, // ................ + 0x05, 0x00, 0x00, 0x03, 0x00, 0x08, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xff, 0x90, // ................ + 0xff, 0xff, 0x00, 0x00, 0x00, // ..... +}; +static const uint8_t fs_font_distance_field_subpixel_dx11[1622] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, // FSH............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x06, 0x44, 0x58, 0x42, // ...........8.DXB + 0x43, 0x55, 0xe8, 0x22, 0x12, 0xa3, 0x37, 0xd2, 0x08, 0x82, 0x55, 0x7b, 0x0d, 0x74, 0x00, 0xe7, // CU."..7...U{.t.. + 0xb4, 0x01, 0x00, 0x00, 0x00, 0x38, 0x06, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, // .....8.......4.. + 0x00, 0xf0, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0xbc, 0x05, 0x00, // .....d.......... + 0x00, 0x52, 0x44, 0x45, 0x46, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .RDEF........... + 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0x00, 0x91, 0x00, // ................ + 0x00, 0x80, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, // .....n.......... + 0x00, 0x09, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, // .....u_texColorS + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x00, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, // ampler.u_texColo + 0x72, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, // rTexture.Microso + 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, // ft (R) HLSL Shad + 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, // er Compiler 9.29 + 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab, 0x49, 0x53, 0x47, // .952.3111....ISG + 0x4e, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, // Nl...........P.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x62, 0x00, 0x00, // .............b.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, // .....SV_POSITION + 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, // .COLOR.TEXCOORD. + 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, // .OSGN,.......... + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // . .............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, // .........SV_TARG + 0x45, 0x54, 0x00, 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0x1c, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, // ET...SHDR....@.. + 0x00, 0x07, 0x01, 0x00, 0x00, 0x35, 0x18, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // .....5.......... + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?............... + 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....?........... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........?....... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x5a, 0x00, 0x00, // ............?Z.. + 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x30, 0x00, 0x04, 0x00, 0x70, 0x10, // ..`......X0...p. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x82, 0x10, 0x10, // .....UU..b...... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, // .....b.......... + 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, // .e.... ......h.. + 0x02, 0x03, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x09, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // .....2.......... + 0x00, 0x3a, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, // .:........@..... + 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x1b, 0x00, 0x00, 0x05, 0x12, 0x00, 0x10, // @.@.....?....... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, // ................ + 0x05, 0xe2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x10, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x32, 0x00, 0x00, 0x0d, 0x72, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, // .2...r.......... + 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0xc1, 0xaa, 0x2a, // .A........@....* + 0x3e, 0xc1, 0xaa, 0x2a, 0x3e, 0xc1, 0xaa, 0x2a, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, // >..*>..*>....F.. + 0x00, 0x02, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xf2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, // .....E.......... + 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x7e, 0x10, 0x00, 0x00, 0x00, 0x00, // .F.......F~..... + 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, // ..`............. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0x0c, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x9e, 0x90, // .....f.......F.. + 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0c, 0x72, 0x00, 0x10, // .........2...r.. + 0x00, 0x02, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, // ..............@. + 0x00, 0xc1, 0xaa, 0x2a, 0x3e, 0xc1, 0xaa, 0x2a, 0x3e, 0xc1, 0xaa, 0x2a, 0x3e, 0x00, 0x00, 0x00, // ...*>..*>..*>... + 0x00, 0x46, 0x12, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x22, 0x00, 0x10, // .F...........".. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xf2, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, // .....E.......... + 0x00, 0x46, 0x02, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7e, 0x10, 0x00, 0x00, 0x00, 0x00, // .F.......F~..... + 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x08, 0x42, 0x00, 0x10, // ..`..........B.. + 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0x0c, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x9e, 0x90, // .....f.......F.. + 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, // .....*.......... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x22, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, // .....8..."...... + 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // ..........@..... + 0x3f, 0x36, 0x00, 0x00, 0x06, 0xd2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x10, // ?6.............. + 0x80, 0x41, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x05, 0xd2, 0x00, 0x10, // .A.............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, // ................ + 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x86, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x05, 0x32, 0x00, 0x10, // .........K...2.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....F.......... + 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x1a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0x22, 0x00, 0x10, // .........2...".. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .........A...... + 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // ..@.....A.@..... + 0x3f, 0x32, 0x00, 0x00, 0x09, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, // ?2.............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0x40, 0x00, // ......@.....A.@. + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ....?........... + 0x00, 0x1a, 0x00, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, // .....A.......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x56, 0x05, 0x10, 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x09, 0x10, // .V...A.......... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, // .....8.... ..... + 0x00, 0x1a, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, // .........:...... + 0x00, 0x0e, 0x00, 0x00, 0x0a, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, // ..............@. + 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, // ....?...?...?... + 0x3f, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x20, 0x00, 0x07, 0x72, 0x00, 0x10, // ?........8 ..r.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0f, 0x72, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, // .....2...r...... + 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // .F........@..... + 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, // ..............@. + 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, // ...@@..@@..@@... + 0x00, 0x38, 0x00, 0x00, 0x07, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, // .8...r.......F.. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, // .....F.......8.. + 0x07, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, // .r.......F...... + 0x00, 0x46, 0x02, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x72, 0x20, 0x10, // .F.......8...r . + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x1f, 0x10, // .....F.......... + 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, // .....>...STATt.. + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, // ................ + 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...... +}; +static const uint8_t fs_font_distance_field_subpixel_glsl[1119] = +{ + 0x46, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, // FSH.....#ifdef G + 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, // L_ES.precision h + 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, // ighp float;.#end + 0x69, 0x66, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x0a, 0x75, 0x6e, 0x69, // if // GL_ES..uni + 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x43, 0x75, 0x62, 0x65, // form samplerCube + 0x20, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x76, 0x61, 0x72, // u_texColor;.var + 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, // ying vec4 v_texc + 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, // oord0;.varying v + 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x6f, // ec4 v_color0;.vo + 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x69, // id main ().{. i + 0x6e, 0x74, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, // nt tmpvar_1;. t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x28, 0x28, // mpvar_1 = int((( + 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x77, 0x20, 0x2a, 0x20, // v_texcoord0.w * + 0x34, 0x2e, 0x30, 0x29, 0x20, 0x2b, 0x20, 0x30, 0x2e, 0x35, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, // 4.0) + 0.5));. + 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, 0x0a, 0x20, // vec3 tmpvar_2;. + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x20, 0x3d, 0x20, 0x64, 0x46, 0x64, 0x78, // tmpvar_2 = dFdx + 0x28, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x78, 0x79, 0x7a, // (v_texcoord0.xyz + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // );. vec3 tmpvar + 0x5f, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x33, 0x20, 0x3d, // _3;. tmpvar_3 = + 0x20, 0x64, 0x46, 0x64, 0x79, 0x28, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // dFdy(v_texcoord + 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, // 0.xyz);. vec3 t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // mpvar_4;. tmpva + 0x72, 0x5f, 0x34, 0x20, 0x3d, 0x20, 0x28, 0x30, 0x2e, 0x31, 0x36, 0x36, 0x36, 0x36, 0x37, 0x20, // r_4 = (0.166667 + 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x66, // * tmpvar_2);. f + 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x35, 0x3b, 0x0a, 0x20, // loat tmpvar_5;. + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x35, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, // tmpvar_5 = text + 0x75, 0x72, 0x65, 0x43, 0x75, 0x62, 0x65, 0x20, 0x28, 0x75, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, // ureCube (u_texCo + 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x28, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // lor, (v_texcoord + 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x34, // 0.xyz - tmpvar_4 + 0x29, 0x29, 0x2e, 0x7a, 0x79, 0x78, 0x77, 0x5b, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, // )).zyxw[tmpvar_1 + 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // ];. float tmpva + 0x72, 0x5f, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x36, 0x20, // r_6;. tmpvar_6 + 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x43, 0x75, 0x62, 0x65, 0x20, 0x28, 0x75, // = textureCube (u + 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x28, 0x76, 0x5f, 0x74, 0x65, // _texColor, (v_te + 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2b, 0x20, 0x74, 0x6d, // xcoord0.xyz + tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x34, 0x29, 0x29, 0x2e, 0x7a, 0x79, 0x78, 0x77, 0x5b, 0x74, 0x6d, // pvar_4)).zyxw[tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x5d, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, // pvar_1];. float + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, // tmpvar_7;. tmp + 0x76, 0x61, 0x72, 0x5f, 0x37, 0x20, 0x3d, 0x20, 0x28, 0x30, 0x2e, 0x35, 0x20, 0x2a, 0x20, 0x28, // var_7 = (0.5 * ( + 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x35, 0x20, 0x2b, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // tmpvar_5 + tmpva + 0x72, 0x5f, 0x36, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x74, // r_6));. float t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // mpvar_8;. tmpva + 0x72, 0x5f, 0x38, 0x20, 0x3d, 0x20, 0x28, 0x38, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x28, 0x73, 0x71, // r_8 = (8.0 * (sq + 0x72, 0x74, 0x28, 0x64, 0x6f, 0x74, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, // rt(dot (tmpvar_2 + 0x2c, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x29, 0x29, 0x20, 0x2b, 0x20, 0x73, // , tmpvar_2)) + s + 0x71, 0x72, 0x74, 0x28, 0x64, 0x6f, 0x74, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // qrt(dot (tmpvar_ + 0x33, 0x2c, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x33, 0x29, 0x29, 0x29, 0x29, 0x3b, // 3, tmpvar_3)))); + 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x39, // . vec3 tmpvar_9 + 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x39, 0x2e, 0x78, 0x20, 0x3d, // ;. tmpvar_9.x = + 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, // tmpvar_5;. tmp + 0x76, 0x61, 0x72, 0x5f, 0x39, 0x2e, 0x79, 0x20, 0x3d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, // var_9.y = tmpvar + 0x5f, 0x37, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x39, 0x2e, 0x7a, // _7;. tmpvar_9.z + 0x20, 0x3d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x36, 0x3b, 0x0a, 0x20, 0x20, 0x66, // = tmpvar_6;. f + 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x65, 0x64, 0x67, 0x65, 0x30, 0x5f, 0x31, 0x30, 0x3b, 0x0a, 0x20, // loat edge0_10;. + 0x20, 0x65, 0x64, 0x67, 0x65, 0x30, 0x5f, 0x31, 0x30, 0x20, 0x3d, 0x20, 0x28, 0x30, 0x2e, 0x35, // edge0_10 = (0.5 + 0x20, 0x2d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x38, 0x29, 0x3b, 0x0a, 0x20, 0x20, // - tmpvar_8);. + 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x5f, 0x31, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x5f, 0x31, // vec3 t_11;. t_1 + 0x31, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x20, 0x28, 0x6d, 0x69, 0x6e, 0x20, 0x28, 0x28, 0x28, // 1 = max (min ((( + 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x39, 0x20, 0x2d, 0x20, 0x65, 0x64, 0x67, 0x65, 0x30, // tmpvar_9 - edge0 + 0x5f, 0x31, 0x30, 0x29, 0x20, 0x2f, 0x20, 0x28, 0x28, 0x30, 0x2e, 0x35, 0x20, 0x2b, 0x20, 0x74, // _10) / ((0.5 + t + 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x38, 0x29, 0x20, 0x2d, 0x20, 0x65, 0x64, 0x67, 0x65, 0x30, // mpvar_8) - edge0 + 0x5f, 0x31, 0x30, 0x29, 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x30, 0x2e, 0x30, // _10)), 1.0), 0.0 + 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, // );. gl_FragColo + 0x72, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x74, 0x5f, 0x31, 0x31, 0x20, 0x2a, // r.xyz = ((t_11 * + 0x20, 0x28, 0x74, 0x5f, 0x31, 0x31, 0x20, 0x2a, 0x20, 0x28, 0x33, 0x2e, 0x30, 0x20, 0x2d, 0x20, // (t_11 * (3.0 - + 0x28, 0x32, 0x2e, 0x30, 0x20, 0x2a, 0x20, 0x74, 0x5f, 0x31, 0x31, 0x29, 0x29, 0x29, 0x29, 0x20, // (2.0 * t_11)))) + 0x2a, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x2e, 0x77, 0x29, 0x3b, 0x0a, 0x20, // * v_color0.w);. + 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2e, 0x77, 0x20, // gl_FragColor.w + 0x3d, 0x20, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x37, 0x20, 0x2a, 0x20, 0x76, 0x5f, // = (tmpvar_7 * v_ + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x2e, 0x77, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // color0.w);.}... +}; diff --git a/examples/common/font/vs_font_basic.bin.h b/examples/common/font/vs_font_basic.bin.h new file mode 100644 index 00000000..d3ec37ee --- /dev/null +++ b/examples/common/font/vs_font_basic.bin.h @@ -0,0 +1,138 @@ +static const uint8_t vs_font_basic_dx9[335] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, 0x64, // VSH........u_mod + 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x01, 0x00, 0x00, 0x04, 0x00, // elViewProj...... + 0x2c, 0x01, 0x00, 0x03, 0xfe, 0xff, 0xfe, 0xff, 0x23, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, // ,.......#.CTAB.. + 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, // ..W............. + 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, // ......P...0..... + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, // ......@.......u_ + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x03, 0x00, // modelViewProj... + 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, // ..............vs + 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, // _3_0.Microsoft ( + 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, // R) HLSL Shader C + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, // ompiler 9.29.952 + 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, // .3111........... + 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, // ................ + 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x80, 0x00, 0x00, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x01, 0x00, // ................ + 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0xe0, 0x05, 0x00, // ................ + 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x55, 0x90, 0x04, 0x00, // ............U... + 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, // ................ + 0xe4, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, // ................ + 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x90, 0x01, 0x00, // ................ + 0x00, 0x02, 0x02, 0x00, 0x0f, 0xe0, 0x02, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ............... +}; +static const uint8_t vs_font_basic_dx11[1300] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, // VSH............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x09, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, // ............u_mo + 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x00, 0xe0, 0x08, 0x04, // delViewProj..... + 0x00, 0xe0, 0x04, 0x44, 0x58, 0x42, 0x43, 0x3e, 0x63, 0x6d, 0xe7, 0x1c, 0x45, 0xb5, 0xff, 0x98, // ...DXBC>cm..E... + 0x06, 0x5a, 0xa2, 0x6d, 0x6a, 0xd4, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x05, // .Z.mj........... + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x5c, // ...4...x........ + 0x03, 0x00, 0x00, 0x64, 0x04, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x3c, 0x02, 0x00, 0x00, 0x01, // ...d...RDEF<.... + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, // ...H............ + 0x04, 0xfe, 0xff, 0x00, 0x91, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, // ...........<.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x47, 0x6c, 0x6f, 0x62, // ...........$Glob + 0x61, 0x6c, 0x73, 0x00, 0xab, 0xab, 0xab, 0x3c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x60, // als....<.......` + 0x00, 0x00, 0x00, 0xb0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, // ...............P + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, // ................ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, // .......l........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, // ...............x + 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // ... ...@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, // ...........`...@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, // ................ + 0x01, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, // ................ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x40, // ...............@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, // ................ + 0x01, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, // .......@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x40, // ........... ...@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, // ................ + 0x01, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // ...`...@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0x01, 0x00, 0x00, 0xa0, 0x09, 0x00, 0x00, 0x04, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // ...............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x74, 0x00, 0xab, 0x01, 0x00, 0x03, 0x00, 0x01, // _viewRect....... + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, // ...........u_vie + 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x00, 0xab, 0x03, // wTexel.u_view... + 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // ...............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, // _viewProj.u_mode + 0x6c, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // l.......... .... + 0x00, 0x00, 0x00, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x00, 0x75, // ...u_modelView.u + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x75, // _modelViewProj.u + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x58, 0x00, // _modelViewProjX. + 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x58, 0x00, 0x75, 0x5f, 0x61, 0x6c, // u_viewProjX.u_al + 0x70, 0x68, 0x61, 0x52, 0x65, 0x66, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // phaRef.......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, // .......Microsoft + 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, // (R) HLSL Shader + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, // Compiler 9.29.9 + 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x68, // 52.3111....ISGNh + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, // ...........P.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x0f, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ...V............ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, // ..........._.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x0f, 0x00, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, // ...COLOR.POSITIO + 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x4f, 0x53, 0x47, 0x4e, 0x6c, // N.TEXCOORD.OSGNl + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, // ...........P.... + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, // ...........b.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, // ...SV_POSITION.C + 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0x53, // OLOR.TEXCOORD..S + 0x48, 0x44, 0x52, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x59, // HDR....@...@...Y + 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x5f, // ...F. ........._ + 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x32, // ..........._...2 + 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x02, // ......._........ + 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ...g.... ....... + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, // ...e.... ......e + 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, // .... ......h.... + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, // ...8...........V + 0x15, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, // .......F. ...... + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // ...2...........F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00, 0x01, // . .............. + 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf2, // ...F............ + 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // ......F.......F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xf2, // . .........6.... + 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, // ......F.......6 + 0x00, 0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x02, // .... ......F.... + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x06, // ...>...STATt.... + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, // .... +}; +static const uint8_t vs_font_basic_glsl[414] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, // VSH.....#ifdef G + 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, // L_ES.precision h + 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, // ighp float;.#end + 0x69, 0x66, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x0a, 0x75, 0x6e, 0x69, // if // GL_ES..uni + 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, // form mat4 u_mode + 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // lViewProj;.varyi + 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // ng vec4 v_texcoo + 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, // rd0;.varying vec + 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, // 4 v_color0;.attr + 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, // ibute vec4 a_tex + 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, // coord0;.attribut + 0x65, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, // e vec2 a_positio + 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, // n;.attribute vec + 0x34, 0x20, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, // 4 a_color0;.void + 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, // main ().{. vec + 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, // 4 tmpvar_1;. tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, // pvar_1.zw = vec2 + 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, // (0.0, 1.0);. tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, // pvar_1.xy = a_po + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, // sition;. gl_Pos + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, // ition = (u_model + 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // ViewProj * tmpva + 0x72, 0x5f, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // r_1);. v_texcoo + 0x72, 0x64, 0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // rd0 = a_texcoord + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x3d, 0x20, // 0;. v_color0 = + 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // a_color0;.}... +}; diff --git a/examples/common/font/vs_font_distance_field.bin.h b/examples/common/font/vs_font_distance_field.bin.h new file mode 100644 index 00000000..e66f5bf0 --- /dev/null +++ b/examples/common/font/vs_font_distance_field.bin.h @@ -0,0 +1,138 @@ +static const uint8_t vs_font_distance_field_dx9[335] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, 0x64, // VSH........u_mod + 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x01, 0x00, 0x00, 0x04, 0x00, // elViewProj...... + 0x2c, 0x01, 0x00, 0x03, 0xfe, 0xff, 0xfe, 0xff, 0x23, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, // ,.......#.CTAB.. + 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, // ..W............. + 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, // ......P...0..... + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, // ......@.......u_ + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x03, 0x00, // modelViewProj... + 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, // ..............vs + 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, // _3_0.Microsoft ( + 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, // R) HLSL Shader C + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, // ompiler 9.29.952 + 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, // .3111........... + 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, // ................ + 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x80, 0x00, 0x00, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x01, 0x00, // ................ + 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0xe0, 0x05, 0x00, // ................ + 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x55, 0x90, 0x04, 0x00, // ............U... + 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, // ................ + 0xe4, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, // ................ + 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x90, 0x01, 0x00, // ................ + 0x00, 0x02, 0x02, 0x00, 0x0f, 0xe0, 0x02, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ............... +}; +static const uint8_t vs_font_distance_field_dx11[1300] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, // VSH............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x09, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, // ............u_mo + 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x00, 0xe0, 0x08, 0x04, // delViewProj..... + 0x00, 0xe0, 0x04, 0x44, 0x58, 0x42, 0x43, 0x3e, 0x63, 0x6d, 0xe7, 0x1c, 0x45, 0xb5, 0xff, 0x98, // ...DXBC>cm..E... + 0x06, 0x5a, 0xa2, 0x6d, 0x6a, 0xd4, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x05, // .Z.mj........... + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x5c, // ...4...x........ + 0x03, 0x00, 0x00, 0x64, 0x04, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x3c, 0x02, 0x00, 0x00, 0x01, // ...d...RDEF<.... + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, // ...H............ + 0x04, 0xfe, 0xff, 0x00, 0x91, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, // ...........<.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x47, 0x6c, 0x6f, 0x62, // ...........$Glob + 0x61, 0x6c, 0x73, 0x00, 0xab, 0xab, 0xab, 0x3c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x60, // als....<.......` + 0x00, 0x00, 0x00, 0xb0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, // ...............P + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, // ................ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, // .......l........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, // ...............x + 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // ... ...@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, // ...........`...@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, // ................ + 0x01, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, // ................ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x40, // ...............@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, // ................ + 0x01, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, // .......@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x40, // ........... ...@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, // ................ + 0x01, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // ...`...@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0x01, 0x00, 0x00, 0xa0, 0x09, 0x00, 0x00, 0x04, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // ...............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x74, 0x00, 0xab, 0x01, 0x00, 0x03, 0x00, 0x01, // _viewRect....... + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, // ...........u_vie + 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x00, 0xab, 0x03, // wTexel.u_view... + 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // ...............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, // _viewProj.u_mode + 0x6c, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // l.......... .... + 0x00, 0x00, 0x00, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x00, 0x75, // ...u_modelView.u + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x75, // _modelViewProj.u + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x58, 0x00, // _modelViewProjX. + 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x58, 0x00, 0x75, 0x5f, 0x61, 0x6c, // u_viewProjX.u_al + 0x70, 0x68, 0x61, 0x52, 0x65, 0x66, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // phaRef.......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, // .......Microsoft + 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, // (R) HLSL Shader + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, // Compiler 9.29.9 + 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x68, // 52.3111....ISGNh + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, // ...........P.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x0f, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ...V............ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, // ..........._.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x0f, 0x00, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, // ...COLOR.POSITIO + 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x4f, 0x53, 0x47, 0x4e, 0x6c, // N.TEXCOORD.OSGNl + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, // ...........P.... + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, // ...........b.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, // ...SV_POSITION.C + 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0x53, // OLOR.TEXCOORD..S + 0x48, 0x44, 0x52, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x59, // HDR....@...@...Y + 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x5f, // ...F. ........._ + 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x32, // ..........._...2 + 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x02, // ......._........ + 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ...g.... ....... + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, // ...e.... ......e + 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, // .... ......h.... + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, // ...8...........V + 0x15, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, // .......F. ...... + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // ...2...........F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00, 0x01, // . .............. + 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf2, // ...F............ + 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // ......F.......F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xf2, // . .........6.... + 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, // ......F.......6 + 0x00, 0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x02, // .... ......F.... + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x06, // ...>...STATt.... + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, // .... +}; +static const uint8_t vs_font_distance_field_glsl[414] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, // VSH.....#ifdef G + 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, // L_ES.precision h + 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, // ighp float;.#end + 0x69, 0x66, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x0a, 0x75, 0x6e, 0x69, // if // GL_ES..uni + 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, // form mat4 u_mode + 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // lViewProj;.varyi + 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // ng vec4 v_texcoo + 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, // rd0;.varying vec + 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, // 4 v_color0;.attr + 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, // ibute vec4 a_tex + 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, // coord0;.attribut + 0x65, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, // e vec2 a_positio + 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, // n;.attribute vec + 0x34, 0x20, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, // 4 a_color0;.void + 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, // main ().{. vec + 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, // 4 tmpvar_1;. tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, // pvar_1.zw = vec2 + 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, // (0.0, 1.0);. tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, // pvar_1.xy = a_po + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, // sition;. gl_Pos + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, // ition = (u_model + 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // ViewProj * tmpva + 0x72, 0x5f, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // r_1);. v_texcoo + 0x72, 0x64, 0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // rd0 = a_texcoord + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x3d, 0x20, // 0;. v_color0 = + 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // a_color0;.}... +}; diff --git a/examples/common/font/vs_font_distance_field_subpixel.bin.h b/examples/common/font/vs_font_distance_field_subpixel.bin.h new file mode 100644 index 00000000..73f52ef1 --- /dev/null +++ b/examples/common/font/vs_font_distance_field_subpixel.bin.h @@ -0,0 +1,138 @@ +static const uint8_t vs_font_distance_field_subpixel_dx9[335] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, 0x64, // VSH........u_mod + 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x01, 0x00, 0x00, 0x04, 0x00, // elViewProj...... + 0x2c, 0x01, 0x00, 0x03, 0xfe, 0xff, 0xfe, 0xff, 0x23, 0x00, 0x43, 0x54, 0x41, 0x42, 0x1c, 0x00, // ,.......#.CTAB.. + 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, // ..W............. + 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, // ......P...0..... + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, // ......@.......u_ + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x03, 0x00, // modelViewProj... + 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x73, // ..............vs + 0x5f, 0x33, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, // _3_0.Microsoft ( + 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, // R) HLSL Shader C + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, // ompiler 9.29.952 + 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, // .3111........... + 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0f, 0x90, 0x1f, 0x00, // ................ + 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, // ................ + 0x00, 0x80, 0x00, 0x00, 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x80, 0x01, 0x00, // ................ + 0x0f, 0xe0, 0x1f, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x80, 0x02, 0x00, 0x0f, 0xe0, 0x05, 0x00, // ................ + 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x55, 0x90, 0x04, 0x00, // ............U... + 0x00, 0x04, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, // ................ + 0xe4, 0x80, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x80, 0x03, 0x00, // ................ + 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xe4, 0x90, 0x01, 0x00, // ................ + 0x00, 0x02, 0x02, 0x00, 0x0f, 0xe0, 0x02, 0x00, 0xe4, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, // ............... +}; +static const uint8_t vs_font_distance_field_subpixel_dx11[1300] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, // VSH............. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x09, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, // ............u_mo + 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x09, 0x00, 0xe0, 0x08, 0x04, // delViewProj..... + 0x00, 0xe0, 0x04, 0x44, 0x58, 0x42, 0x43, 0x3e, 0x63, 0x6d, 0xe7, 0x1c, 0x45, 0xb5, 0xff, 0x98, // ...DXBC>cm..E... + 0x06, 0x5a, 0xa2, 0x6d, 0x6a, 0xd4, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x05, // .Z.mj........... + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x5c, // ...4...x........ + 0x03, 0x00, 0x00, 0x64, 0x04, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x3c, 0x02, 0x00, 0x00, 0x01, // ...d...RDEF<.... + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, // ...H............ + 0x04, 0xfe, 0xff, 0x00, 0x91, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, // ...........<.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x47, 0x6c, 0x6f, 0x62, // ...........$Glob + 0x61, 0x6c, 0x73, 0x00, 0xab, 0xab, 0xab, 0x3c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x60, // als....<.......` + 0x00, 0x00, 0x00, 0xb0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, // ...............P + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, // ................ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, // .......l........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, // ...............x + 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // ... ...@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, // ...........`...@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, // ................ + 0x01, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, // ................ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x40, // ...............@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, // ................ + 0x01, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, // .......@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x40, // ........... ...@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, // ................ + 0x01, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, // ...`...@........ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0x01, 0x00, 0x00, 0xa0, 0x09, 0x00, 0x00, 0x04, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // ...............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x63, 0x74, 0x00, 0xab, 0x01, 0x00, 0x03, 0x00, 0x01, // _viewRect....... + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, // ...........u_vie + 0x77, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x00, 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x00, 0xab, 0x03, // wTexel.u_view... + 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, // ...............u + 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, // _viewProj.u_mode + 0x6c, 0x00, 0xab, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // l.......... .... + 0x00, 0x00, 0x00, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x00, 0x75, // ...u_modelView.u + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x00, 0x75, // _modelViewProj.u + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x58, 0x00, // _modelViewProjX. + 0x75, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x58, 0x00, 0x75, 0x5f, 0x61, 0x6c, // u_viewProjX.u_al + 0x70, 0x68, 0x61, 0x52, 0x65, 0x66, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // phaRef.......... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, // .......Microsoft + 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, // (R) HLSL Shader + 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, // Compiler 9.29.9 + 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab, 0x49, 0x53, 0x47, 0x4e, 0x68, // 52.3111....ISGNh + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, // ...........P.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x0f, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ...V............ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, // ..........._.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x0f, 0x00, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, // ...COLOR.POSITIO + 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x4f, 0x53, 0x47, 0x4e, 0x6c, // N.TEXCOORD.OSGNl + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, // ...........P.... + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // ................ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, // ...........b.... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, // ................ + 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, // ...SV_POSITION.C + 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0x53, // OLOR.TEXCOORD..S + 0x48, 0x44, 0x52, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x59, // HDR....@...@...Y + 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x5f, // ...F. ........._ + 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x32, // ..........._...2 + 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x02, // ......._........ + 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // ...g.... ....... + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, // ...e.... ......e + 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, // .... ......h.... + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, // ...8...........V + 0x15, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, // .......F. ...... + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // ...2...........F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00, 0x01, // . .............. + 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf2, // ...F............ + 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, // ......F.......F + 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xf2, // . .........6.... + 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, // ......F.......6 + 0x00, 0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x02, // .... ......F.... + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x06, // ...>...STATt.... + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + 0x00, 0x00, 0x00, 0x00, // .... +}; +static const uint8_t vs_font_distance_field_subpixel_glsl[414] = +{ + 0x56, 0x53, 0x48, 0x01, 0x01, 0x83, 0xf2, 0xe1, 0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, // VSH.....#ifdef G + 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x68, // L_ES.precision h + 0x69, 0x67, 0x68, 0x70, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, // ighp float;.#end + 0x69, 0x66, 0x20, 0x2f, 0x2f, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a, 0x0a, 0x75, 0x6e, 0x69, // if // GL_ES..uni + 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, // form mat4 u_mode + 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // lViewProj;.varyi + 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // ng vec4 v_texcoo + 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, // rd0;.varying vec + 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, // 4 v_color0;.attr + 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, // ibute vec4 a_tex + 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, // coord0;.attribut + 0x65, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, // e vec2 a_positio + 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, // n;.attribute vec + 0x34, 0x20, 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, // 4 a_color0;.void + 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, // main ().{. vec + 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, // 4 tmpvar_1;. tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x7a, 0x77, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x63, 0x32, // pvar_1.zw = vec2 + 0x28, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, // (0.0, 1.0);. tm + 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, // pvar_1.xy = a_po + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, // sition;. gl_Pos + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, // ition = (u_model + 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // ViewProj * tmpva + 0x72, 0x5f, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, // r_1);. v_texcoo + 0x72, 0x64, 0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // rd0 = a_texcoord + 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x20, 0x3d, 0x20, // 0;. v_color0 = + 0x61, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // a_color0;.}... +}; From a69a483de39995ad06bdbdce9f0f06b6cfd737f2 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:52:47 +0200 Subject: [PATCH 26/38] Add some fonts to display text --- examples/runtime/font/FONT_LICENSE.txt | 50 +++++++++++++++++++++ examples/runtime/font/bleeding_cowboys.ttf | Bin 0 -> 148896 bytes examples/runtime/font/chp-fire.ttf | Bin 0 -> 46812 bytes examples/runtime/font/five_minutes.otf | Bin 0 -> 27156 bytes examples/runtime/font/mias_scribblings.ttf | Bin 0 -> 102032 bytes examples/runtime/font/ruritania.ttf | Bin 0 -> 126500 bytes examples/runtime/font/signika-regular.ttf | Bin 0 -> 141132 bytes examples/runtime/font/visitor1.ttf | Bin 0 -> 27552 bytes 8 files changed, 50 insertions(+) create mode 100644 examples/runtime/font/FONT_LICENSE.txt create mode 100644 examples/runtime/font/bleeding_cowboys.ttf create mode 100644 examples/runtime/font/chp-fire.ttf create mode 100644 examples/runtime/font/five_minutes.otf create mode 100644 examples/runtime/font/mias_scribblings.ttf create mode 100644 examples/runtime/font/ruritania.ttf create mode 100644 examples/runtime/font/signika-regular.ttf create mode 100644 examples/runtime/font/visitor1.ttf diff --git a/examples/runtime/font/FONT_LICENSE.txt b/examples/runtime/font/FONT_LICENSE.txt new file mode 100644 index 00000000..15ee267a --- /dev/null +++ b/examples/runtime/font/FONT_LICENSE.txt @@ -0,0 +1,50 @@ +droidsans.ttf +------------- +http://www.fontsquirrel.com/fonts/Droid-Sans +by Google Android +Free + +bleeding_cowboys.ttf +-------------------- +http://www.dafont.com/bleeding-cowboys.font +by Segments Design (aka Last Soundtrack) +Free for personal use +For commercial usage, please contact me at: gyom.typo@gmail.com + + +chp-fire.ttf +------------ +http://www.dafont.com/cheap-fire.font +by Richard D. Collins +Free + + +five_minutes.otf +---------------- +http://www.fonts2u.com/fiveminutes.font +by Jovanny Lemonad and Oleg Zhuravlev +Freeware + +mias_scribblings.ttf +-------------------- +http://www.dafont.com/mias-scribblings.font +by Amelia +Free + +ruritania.ttf +------------- +http://www.dafont.com/ruritania.font +by Paul Lloyd +Free + +signika-regular.ttf +------------------- +http://fontfabric.com/signika-font/ +by Anna GiedryÅ›, Poland +Free + +visitor1.ttf +------------ +http://www.dafont.com/visitor.font +by Ænigma +Free \ No newline at end of file diff --git a/examples/runtime/font/bleeding_cowboys.ttf b/examples/runtime/font/bleeding_cowboys.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a3ec7e8655f73664906227ce20284c9634fc8067 GIT binary patch literal 148896 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≺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 LX8q(RA^ZOTjMGY= literal 0 HcmV?d00001 diff --git a/examples/runtime/font/chp-fire.ttf b/examples/runtime/font/chp-fire.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c47d146af0cd2a3e4e3b3e2b5aec2011eb02052e GIT binary patch literal 46812 zcmd?Rdwd(!xi&g$Ml%{&k~OmKzG^JXvTVzeY)i5n%eo|XY$cX$B~ctDksUj6E>7$u zPU3{nI2XVP0c=Q092!WVTnuf&(3U2&g`}m0bZ-i2OH10aA?)22INfYY_eZ%zlk={T z9Snv2ednL^`<>shtjml>x3!-4d7t;PhCl>CWD_oeBF?ujaaQL(&;B0v{1vXTj`@q1 z-u!XS9|;0Az_zz<%bKmrp2_<Fws#N&mD{&#hdF<3(LREZOu+Nz{;lh`9IE+AJ8VzG zws!sIJ^l5MJfDQ^=LzDmr#7rxv-TAy(@hXh?8fi60e0kXmi;Si<Ks&<Y}v8<%HJ!8 zVEZ@l8TV`+>RUrt^0fr<<W|@|vt`Zht*Dy3l_0*$;m;dfvt^z2cE<(Sb`b>Gvvp{A zhwK+Jc>Mhdc>evZ+t+RVHUCyIK|H-5wpS5^v>HtiG(7&&KT^&RG)0o6<V&9p5$5;F z?3ParS6|L<k-T&LnEgkn%M9MyASa0VYlb%u4VuG)J2r0Hxz23927kV5*95cp_vxp% zWL`#P?noDb$DbhbVf^6{Y%?VMUih{2%rkf+^M~M=%pW;(|5bOH_oN63{8omL5-cGj zvIse$Ae1oIDuN@_L=K@Lw1ke(69&Ran21~=557eKQAiXKW`ZY*2@6p|Scy`?MwAhD zqMWE8DhUTsMK}R1Zlao~A!-Q^;U#=T9pNYHiFrf=5g;0gAQ2+MM1+`6EFhYQW?~`H zLbMW5ViB>JXd_}oJJCUO5^-V)v6NUwB#7li7qNm!5-VYbRud_ro9H3deAQ3;|Iz+l zqK{ZhtRwni9^ZxE&A>e(NMfIvyLJt>%`^7^7I^L_u&?+3(=(23n)vkSwLi$tDBe&` zq9sTmeolOd`iLKrR`M;Dpj5Oagow&rP3CFJ+GJU?!D!jgv%o=+81Paey9F#nN+d#N z#Ihk7DV5MLGBlVpEnx{M!y*!anIWQim(yn?f(_0FE{*?@vmp%|=?22>LaiIl!Mm}o z8`eyR;$3xW-#LQ4cD`-}ujbVVZt!4#3Ilx=KJRa55us>-&j*X77-bpQMu=DwDn;RN zC=v`5<PpI-O_hU|l+$dPjaKNGVt!sdTWzXFNHg;-oHJj*311-%H&s<t1YE0TzKVtj z&;2T4{8dn~t<+O%E47vSyq?<3L$A;4%kkwHyfxJZy+NmyBdt`em1>y+q}4DMcm-U% z^H8-fN2eu;RDo70RZ0{rpI0d1q|*5-6suSIit<^B#9?Jw-o$(St2XG#Y|eeIx2=)9 z;<s(=Ugq5C?G5XKp9I%^`+P^`%}4$V&6}6LHuSgi`TWt#!dc-1yGghZu{VAcG#*VC zbA`pF+Mx@-6#jMPIN)|v`Vn<NeioRgl!%4$k<At=D>O<eB~9yfbfKIjaxKMpf~d^M zI1LRjHb@*7JSZ~*LJ_vP17Z^g#6sF&By4yP^g6AS(P=fMHgSjEAnuS_;P<1h#E_O{ z3-V11?=}|viDV?&$24w-zu25Al$)d<q0M_)d%d>LU3u4?f3BO~QTiTYY?^5+cl7a- zc1LvL%GkKoy#;8R7)3{<U5fL-sxh=Z^aN^e4|RkVw=~a>go5*Y-r6c#F<)4a%VjY% zMYJt$4u=}&xvDBH#k|R=Rm&(fr_RYzskrQHl}4MT)hQJUB}rvbl5%^QjpvKaMW%|1 zN~5ttr`74R^oB3)c2s43aTombx~#^=U?9-QFnM$}Z7*9Wk;<deSX-V>ODigkYLyEN z3FXZIFX(J&aKa#C&}A$jJyyj&pM8~mUc7%k8!oUtd%2qZrTf{hIGz=chj*BL9UO-+ zu)pvpg8d8o#Lb!c&Li6A&Ud>w-zr1}ku-=jHe{1hQkzs0L_DQ}ZP;n>X?(oLr^zw+ zJb9!X`80rsnrfdx6C~k<2A@u9Q<3mI?9*AOzf2n)Ki|zhYA@(UU86?3ef?lSW)}F~ z;3Gp*m)Q%0eSWR5cVxHmgvo7wp(s4DL7yk*Ua+%UPg_my7bng?X|%G>hNKJS$`R={ z*`P2YJ$oMgC(4qgo$MK5R2UsaPfuM)KYmA$D&n|{&K488H+fNob_<79>yyZa^ytp? zHi57q^JGUCXF#^mbEnUKC`_ANZ?f!_OHEQ#CR}7Mf;T@Z{E~iLo(4}|L_9_Ol=uyi z4(&p(z8d<i_oe60Kli=wKJxH`r;i;P=;@BOMyg%Ts>%vWv0f>^^zy&_;^GTG|H=91 ze)xl@pZw0Z9(nkI`|mw9d1CMIwyo>?qOA)8E~nk9RmpN`pLbz19SXL`=p~EkWxr-t zB7&~!rB~*t>7gyObnKk;o<}>;${8DVV$PaD58#M{Eo`tEKK-&;{nCA3iGjI5SV_D( z7YMJ4K=5$3QcE#5c-o7KrFtE3p1uZnAj6M{kplJA;>`*qrF<07qefqVIJ#I0M*}xn zialN*9PFOmv{h$bs)knqT^0e4GVs2@Bfe6f#xwKAm`uUqfO9e50+8@yc!kefqc>E; z`_@zkP;Cu7(i^-!x5&zr$VI58+M}+u6a!1^4Q}|h6dYM<^WlB)Ia*3jp5aZNWGab# zQDk!~SytV&?&j^1yx%TE`zsc3hm8t0!1C;yY-xVAHX%I7sbg9;5SK{&RU8}laN5zT z(4Qp*dyO}0C2VmSJ8x$Lh+0nKZdkI)^-ZOUl%!1dJgZV^Taa7i3Ckoblg-LxQir?V z<5zYT8q0Moqt&i1w5H!?-SIYx%4SHG<Kq;~`rS&IT_J^U_WU-}?%~xRp5W3qzj(V! zcu>ua==N?rtSETlfv_ZdF>_g4P+*MnS0~O16TQN}{@Z1{P(R6z@Zsj(FkcW&DB>n= zG8~;6YBE*+4ypP4iywM;uCkj{J;qS4)f_+@Pbd|2Rdp4v(jN))x4hNQdr*^QgDSg% z<F)mbY9*4C#OwLt{H6(|`IcpO8<q&;t4p0-%LM&2X&Svy_T$CDZu{6LvEgr2tat}y zcdz%a9~D3&(ZtZTrCDRjt)Nj?6T`&q#Dm1+p-%MBL!pNUPafIRG(TA5b~@~~BL@aM z+G8yX=LhCl<#D?AUV7L4^vJG52kD7XdSVs5{U|-rODCf2=A<-r`wr<HW9%K4o)ij@ ztOQNWvMk69XIj)5*ic0K;P5us2)_TEJ$%j%X83P{cxW!{9};1o!Jan{RT~(9XXZiz z+OJ;#_5e){091qFISWyMFNJx}i}YX=YR*zjF;b8VA{qgaHE@8zWieATpWyRq2rwx| zN+Pcb!QnHXU{J$L;C<lpY7COuqcteUkdrxF$}pEKYr71bqiMa}7s{{CUEw?uyepdc zyYTlidu`6LBRRI5io&v_!knkg*>vNNVhX<4@2aRMZO+eD(X1z;%w9z19q^T3xHFq9 zVkrrdNNB$?N*dI{sGX*mJi}6xx&P0|CuNc5A3vVHkjgJ&NV%F~6_nn-sSKeSqtIJI zQ?x-V)1O1K@8)+)C^~y_g8d+Q>|j;VstNR4VR`rBlQl<Lf4ux(H$I)dCfwxj-B<j; z<2jur$;dF75{^y@=pfnh;%n}zWkG#~>h7n|kkF`E|8dt}5W0nY9c>fX@Nu?JQ{CX) zCtG!&RiX(0hCHQTb8gdtzdNiW=w-ou^>s^dL1Fq<`XLrM$#>AsvE#2VbhZ?+!iSFI z*3pxls}IY_!=}-fyB5{$M;>%8eRZwyxbW+SDpNrC=(`s|-;WX|*<*_LiHC^sP$PQy z;m{+?AGrUPo7xw*G<j>vO0#6-_#OM!_H;M8T~)c+w4{?>eww+fpRTN=H)wL$$r5(! z-CNNT678FXB}gmL?*jxeC_e|oi~yapYX*w@h==Dw@nI2)K);yestusLM5$E)Jj_Tb zU^b9mnB)K_;EMrsq9F4C&oNkyfriB-+K7NNfo3svR*TTYjv0$M@q(eLs|AqGT<8+~ z%Ig;_dcC427Xb^L3v$?3Lgn!AxkU(nA*_9A8&`FV+so@ZCnWCB;*!5UzS9<9X+BTM z6|IfbooQPy8~M@CA`-e;*Qx8(866UumAEVA(yR)1Jf5i18nU|=)W=n}kjdU_YA%U7 z6lGO1iK4Kx*Sf6l2H~JEY+ZNb_Pz=*r2@Z0k|UMXS*sW7DU_0BZ|wCSLaVtDavHrQ zPN`{<Ee$V}J<eXSM%!dvU3QMEsq~NcJSV)WP@C6wdYY3@t#zR>A*BEI_kR3Tut4jG za|$(=R47@ldRbe2Rg*#?`NeYKwa#VeYWi)r>!I>WLru{<))QS;%?Te4y%PzySN4}W z3ymy4(CgMYik9rzxWrcbYg9bcicSk}kax&bH7+mfJm<VJ86vs#d1Z;QjLCOQ+Wn0< zo}6N*$g@fpWCzxVY{*~;89~T$*-EWWo|Pq+$+Gm2PCyE|Tp?u`tp+J(!x^Vj6a!;b zbA?~FDExrjW^kk-40Ca05OE|<qCuyU*gQcn6SzU!x>fhc<#w|yHJ*$G?5#20-6(gG zDE%Cj1UA2+oAWpG?xsk*KVrq-dg!W@HYxW*-eEb!fK5%IW-VxOw=-K2v}n0(DN{r< zHiMt4ks!-;I}kZp#QH4z&U{M?(KPp4Hi_Sop`@fiuhGLzjUIF*hw%;J6(J&$f}qS( zs{x?<N-_2N0Q!^$WP~0J01nKcntEZ3bD1U5N{6zZBn$3VePaztZuF-Gg*REA?Nv)8 zRt3ujyj#EV081Zbw^X#M&823ORv{~>U9vVy_MY&y*MvhOzZM3MUw!de8j<II^+5WQ z!rJP(CFsn@hYveHM#_ex>-kz#xO#)pGmY}D{x7t&43SR?1*J497T!>1IgA>6aUdLn zQQLA=MjMm|Ay?BDGNI<?(87}XI-jT7m8}Ssz_8J^Mx>pUdov1tcBp1&R7*6^9jj(> ztn?Z~j+CJoxUn#lUdLe@#%w@{YDpu?G75*UUaHha+F%$pRA~ibC=wr;aZ2d9FBvRv zjX#b4`~PUP<X=5n6=na=hYQB5U)n?alrKYmt2<PJ7Ay!gx#m}u8*~bq2-NvpYK5FB zrSnSYf=07MP9pV}APwO5#Sv5!3+9gCf(+WEj0)NCXnEWKEhh>>{Eh{sNTr@UBti;+ zh1u0tgl0$*j~r}ZNLt9tOF|1QO~+aFjXTdhuQf&d{N1+~<bs}Kdt+*jlW5iEk&VkN z5f3NbTyr3<NUhbdLt$@Q#LiwRyzT4Rd7H`-w~Q8=YrK}qlkC7hByuJvGJ2mS4?Q59 zs0_@H-d1hOQy&>R^!M+%^m;{pj$iFxw>ed|&7^z!UTl?<1jkOwdcZ253ME9Vq=K$0 zTd5T^Fzd71N(%F|Dhd&eLAivYB*8Faf>^`o2d}|pGfKM3VJ<4jWlVwjQVGGzq)dgB zH_NkVT2f6KA$CF~vm+c7quB;5tRSL=$QCjPVuA<LQ8vV(bK}qJ6L6iDO1{kCbuf?? zsl_I>SyV`80Iei7z??{J9-kBWY#!cfvH1+XOoXWhaOZ(D#D=aff)Eo3g0E&rI5oe1 zEPf^7pSH@>YMD%JVq1q;Bgb+aWKAx9z>Qv<q#o+MmoMrFB1l%L;W{|=CW+X3$+*AS z?Urb@6032jcY37PI*>3f?BK0Y_v@F&&#=?=Eg$6>9}AEdmXpoGIj;MAL%pvn>NlA< zw4yLy_?5_u*BEk?eE<JdHs?SbexA*JYff=FcAia5B-_H)=D67%Mt7oaVI`dy@b{1O zs{K*k5e>xGhwXrx6!kLIL%#;u=Q!kw%F04^eTjuH;#91Zk?0Af)M_r4=gsEwoK8q) zq+xphc~%LcY_4IIVZ#D$2C-rA86bmzC5M<Z(_<;ELQb4cuvx%*Qbi=IH<YxLg}Qc| zH|6u35%P)>_=AXy_4H1$6Yi8-%_$}Eb}7qFPO?VC2|v|Af~i1jvfIJJShlkZo?`3s z;TH{E`-q&RwnDDGC1gOkxuHDTsMl&JQmauZX+kz9C78kK%x}5wG;`<vj$Dx-a&#G~ zgf$KhNWuMNVomhoMz*_W(c0!{LJr^9lppF)F{`MpLagc1N@uCHvQeF#-K>?ZLD?7~ z3E>WQR9Od{)*i|gIgM*<sCHGBOUQ=$^0HDctHgpzXPiKT^DDeS>6dZXb#;bE8f0Qd z$B~fdn_(+4L<d3><C09Y0>8xPRo6lUBR-;^wgy^#B?ZML<-u~dl4}eX=h=r^pL}bd zkQRQr&|+JASJ6D5A-_-2*sy9%W#z5mzyg<dd95i`t6QN)NTyxQzP*E7EObw|wXZ@) zgg;19ol8ci2Hz825&n^WUAW;FeXY+tQF`k^*(TRt|AOun{Hsw3*?33uwwps+8xj4; zM}iEI`H{mo_t$^z2_~xKpa!y%7z#Pis#T%Y@#w;E5Qa-b5~X<t9qVGc7`iKqUJ@^6 z{DlSdyrvpR`TA#w3I-4-NzxDk;?VGO;sZ8jCfrY~nmggEG82wtHy9bXk~sH)vmfAE z#T*4>9e{cC*mL3}gb!<!YJ<gWE2SVkiiL6}^wW^=CK*9u$SFX8c?j<)k~(}_lS&={ zPU_md)nxd{z;b$umC$6VJP0Y;qHL4ntfGJyK6voy&_X#W&GI>v&W#nd-+5m8wnqCV zU2STgZ*Y^0Oo~)D-A47KpU%A<Dc;*Vjv!;*zXBC?wQOLoKHQ%utZc~T_%Tbcsqm)# zRzpBezA6-S9>4PK=MebQDb+tv*GrF3r-Xyy*U;<f-$>A5LH&c(t-;g6!~gz4Ze6^n zSda@p5vE1o!cy-md!XL5E#yRzNN7IMP+wWDRxwp2mO`b1$ga)GHZ(Fi9bKDGyNiql zy0%QhlIXesYyh#DhD0dLL*^pR#&sT<nF|XMnL8H|JQr52R2+V3vCSJmUI?=RtePB1 z?%-*$`S1-0K@tBN2xv(BFX}~{gTiu<dVlCxD$n$t#=|VDD{s}3WL~Zb0$pm}Li@yS z)g#|onzg)ov75Ksr8GkF7D*Q8R>vC^>UOfX9+)VMcK!z<t57?NY$hH2n&IfHd$(t~ z%6x2PeFJ&#)t3?1bR_-8kyGirP6?CmmO~=(^!k@Stu?~Pja|FSun<vhB5n-Tpn-wV zX4j_PH7k}c2sJiTf^XKTAt4|2dTLxndYy)pD;ddZ+CVp>2&zMf{LJNw`WaU(X8z_d z@a(RcK_rQRxq~<$GBKttaG5pL){L5l>{zW$gJmPo10iZaug_ri>G41sU>F&QDRq#x zvlU~(2v@UsKa-COLL8an!IOb=A9xC8Qx=v>jS5?RS&O0QA$0qBbpJfQDyxT;{`-Qj zmv0pMH_G-aa_f-O^b1!>u~cTXOC-D0Tw`^eZBh2~0pXpk3;gwF-b58^)uzO_Yr|Pu zQdF5-#21+@ou6`%W7A$rC(mX_wBA)erMPsDWHUO?n}vt=I}`Q>q2v84!pTRUaP3e3 zBb={7>fC!@J6zgWMc$L%BB?JPE3)(b!;(-=Wcl({YK24RFRqM?U0M7Lie^_J>K4=- z`E6hFlG(qYgKe_H+%;bN71OOW6NiZ7p$NL^rqIo;2lsDWy>i8ZNJG7&q`2_Ly&Jo| zo?N4TfLS(7w@Mk>-PcPm+rqZ3XFIc%Qgdl%J8DA}q>)6+u1}?yse%;lY|%wDirG25 zZV@v(X6AGmansy6y-6e~k+dNc$99m(2Ea_gRD#r>ak%;#Go`_WD!m3QLW~UXR7<f} z#->rNAv3`{$!DgxWY&^=Kz6vMg}H4euMZ#R;UI+y7qCNc9q<%&-%(!2MaT4Y?P<@B zGLx^;5+!M+xlZ{9r@yKUwMyMv?g$1sZ;s-7ql&h8VYyKyl`FGYJI%11Ra%oiP+e=# z3-4VJg!OGza*xqmryf>ozV<UdnWg*IB3>BNw=6MRB_^$NVOYgXw=DG<w*`%xzLURv zuUcMhFOfn4CKOzRekSb90m2caFZ8WNWJh|VPUjJlF?))wtMT1FUvDmzBcv00TgIyb zxrJAsVbHmwf`5G*>J<j#?Y-J|Eq_b9f+T-?^XqikP4&yjL&(7Cj3%vBre!6+Jq#Wx zb?qbOqH+?n(qZDU&|-AtNa)tleK&6EU)7c9?5OkFtbhq1!<%=HY~Q+h(}u;N`dVj2 znYqxECEGX3K(;6*p@*gP@camUC|}yLaIGXoR=W{eJnOK6P%N4$#o>Gr=<DmanDgLE zOn=syEhdi4#mSM+aDpusXXi_=%K=D8!VJzxYJ;~1i8c@O4p_2bgy850Pd9#{t<;Xd z2V(J)hiyMo))5H+iwF(qP&f!eP$@`qDFyN840tG96$O?7xJgVm<tY_N%2KphU9;G3 z%;|4z-7XoDsO_(sJ2iGC=g~8ymzQZ3!(-Ejd3yoRNsxiclF)X8@Lc-e{ZTb5$!1%$ zwkN+I>|wUpyj^7ym$Tix$h@d7LS{=yhSN|cQkE5F=o*-A&pZvuAbl3?Q#Td=K(}eH z(>c&A-QLLM_=|f^NcOsU_eb02_sSG(nk@Z#sd-6l{V3P#ZafrqXTOlU+GFosw51Vb zXx%GlBK_Z8R}oc1m8Va4cA<{rxA+eF$maCrKiS>FW?w<8r1$NX^xM|?t>$=X8HH8~ z(Y?Zzd?kB>S5$u2-e4M)M(D#h5UNAVmxsFS^L(~al~M-L){=^%+8U-|Stp~;DW&ZT zXh#F>T@+<WKkGKK@{rW629(syphQe5&ZZT`OgEH)GEkX=j2YsnA(qbt#Bvc3pb$l0 zfGrqbHKG>~6{DqCg##-{Hs>LnVg}Nn2;NKqFJNIQMqQ#d!lH=eu^`6t4p%Rl@Gl5Q zeVk#zK3%M78zb4!Mk<F#C4tn^H3#`26DQ5pYZBza`&zs@?qfj^zLmbqdRG}A^DeTs z4)EMBe{eBsJ8)HaGj1+(f;>_v&I=6sm9T+rDd!P-EB!AO_NA1Wm74g8R832O8xi^` zHvJpn!V3eD^TNZzJHi{N!*tpNiMCCsQHXUaC1;*MQY1gvG=MZ3eg0$=Z9Nk`ngm;3 zcI^k!jfykSYcojP9I8h{L!qsKWY_W~o%MA!&ME*axvrRFlgyeeOuK>(tfY&w=s-3d zC}G+v3AU+cCAqK(q4w*Ro9QnQjTRg3Y_fOGj9?3%nU!{8Xzr{G;aRal_7;yU9?F@k z$m^0BgVl=Bu1MSZ8f3tS)>K1wOq>*rer5`xreH0haDc*zZ<mvYO7bA}>w{aE*Gy(i zN<ca6F9%vuYvqa|U9OUA+5F?Zy}WRBzFw9sk#QVLm0K9w#=X0QM{Y9)R^Cuw@$HJe zOHRuj^I25Re*d<04<1zu4+$R#e@#frDS5=IkX>4mkMfNLx2$>w6}ik^YRRSFK63Q9 z@W14Wk4cpfX6l}b?=qAZmeslkddB&vu~@F>rOMX4O?iDK4Vzb#AG~pb_GlFxcOThu z_43z*pB4)j8t)jaPtg}&LW={vuKm!I6B1gS=+~0LtLy(p8in@t3-?r`DPb!zOC*(R z*Z0Ps7w&t!8a#JDFtte;f}W=>5IJ;pg;rQwn-`dk>@vSK%TvRIeM}_0oL~#{7qP)& zeGmoEJd{hJ@MlgMH?83MD$cXc@bJuB&dgz$=$bo+U7}^p)NL|EiHQ+U5(p}hAi>nk zP)eG~PKwDlOq4i@Au25(N-S`3G=_zh$g5ap)mo^RTfTPghT^SjjdqqQ$d$@Xg@J6j zKNdLDQ}&!vSzLq`*GsD#B3a>^rz)0IDj#V^WUjitpuBO@yXx?2o}tu+qVT4w)$ByX zKi)5UK*AKs>T3(+iy~!<Pd=!Ypr59nVgHN>p^l`<n)H8pTpM<{UKCywb`SsI?fJs| zXBw4CZ^)kORv2TPhx%IjDkVc(%YVA`FMeb@Jc#t8ebAaij9z=0`2gZu19Ys75Qjs4 zw0n1GPvgkO4QqRQQf-SG>b;H%o7H60K<F^CEgA1L$g_w7y0zL(H%g=fb~dtQegvV` zS+f$kE)&IFcYt3osoDKA)6z=po;xkO#c2`!7*?pWiY8-e2=Bt>Vtm2#l)3sK&ZxDK zIC!Y3R_CZWTEgS-4lXls^Ni@i+~=$P>}B(?z{U}uSes*{^qm{Go~<l@c<1S}dlJve z`3<hdWV(f2wB|joK#`?Ul}fWZZm(#psGWCz$ENfBZ@(|O!<rX62t@YZ!UOff`1yr- zhHOQFE9RMh%s*eQ-nQJWudb<ERCc49n>u8!sr+r;&b8g%s)PL!cI??B6KYBK!E^TW z4=zKG3MK2m{>0Uz&EFP;z`%;-&32aDlU{`u2<!UCUSjV#0?|cd;Gqh%TF4Scg!}*P z)ps`i>{~umi0=GV&w!CFHJ6su-L>^Q@%I$uO+o=VU-&-lF_2~H&O2`v_T16FV9`7m zuxKCH*(;!sOJTNefcOT_c64Cl+69q-eq`q`1Ug-ITb6>ZE1;uV=*KcjD=Ye?-Bv;x z3N~~jR5$C=u%%_}ZKirVJFB0inr7y=?#t#^bX}R~JTsY@>BMbVqKE-L1@Qv91q2XG zIZS)04GLUTsSo(k%L9p;H4w&wOeR6UK$t$mx#C+&z?z}jkcs9qW|?7WANAOx6KBeJ ztx3X2sFDJOu`lF2s8}B7Pu2zOj-j<XH7Hkwcw<v=OJUf)XO-}OZC$}o`778JThLSd z-X65X#2&D<a7NZ|F6A12o0lce-mmGkv<QE^#ji+Y4L7c-lR2Ts#^ou9L$We!Od{vz z`)=8&<ZjGc<!`NzP99uJK9nx|#?<RKCAwXY-9Gy9%g!ubp<@*V%inwoH9ygVTojp( z|ICg)NcTL}bemiFqhP#85olc^{N$w8RihZJ=PI4*l5xAlNLmEXA=D-O$Fa`+x0S4| zwe!$b1+#n;WYnHw--NE#0-`fifC>vkMUp%@X_7JUrIZ9K)v*QHoD?!ZbLLY_4nwxE z0o&`$<jIJ_xyD&28YfP*>$IRTO2LveSYqHA!sg}!NB7u{xTOF*&4+60rkZZ<veHcY z!jqH1c`|BgUpIR8hS$bT=TT7=Iwt&CvXXq^YSjW?ctP+~)urY5yH7$+_7Zy@x^T-N zci}*Gd#Ic)(`z{uMMC=*r;^L)Qk&dXmY-jcmzQrcGNo22OXL(HYv#8=$}`h=gPXN* zlhyU)_AC$0{5C6LpZnYFncpTR4k5S#=!r=~O%4Td_?(QbPlH}KtxgL6`Fjm5&o78Y z%3Qbfx_ZR?ZLHBAjhWp+#uWeA^mtB*mNzQ5ldq>&d^(bY?htzJ{z5_*)q(FDBHoww zWOaZ|?hkpy?mxoHoAV5E8AB5$gATel5t&t3P*5m7D26t;Y$fyqGG;SlEy+f@+20Mc z%Ry>Clhnt}YB;$+(_A+D+drFH-Iw(Xs*ywqePJ0^)Hz68TM@JMHPyk4E&**K?fHa9 zM%0W}gj#a-twphCg#E&!!Xq#8fBHMxt?2SB86uTs>;CQgyV(wC^g5j`T5<0AH-$HC z=n0{E>9Z5xKRTGRZs0Z2cyo{N@hZ<Z(Tl>bH&u|YrT2sKh8{xl6X`bTYtV7+B#wg8 zbGbrpR0*+KVZJe225D}}&KKqy<%m#bXR%T#n<JHImC)NDr6o?OrK-XqE#)joK07Qp zjU`f*0q)R0l|1H*%x8lmCtP!};S#Zd>l+rU)Fy>7slf_?&xmocnBk*}5IoQ0XQ9>3 zN?WBHWTxn@57WV^%hPt&?!R!~6zYkzbE-dBB`B7ob-85f_^wayhi9cBegy3&C(s_c zC1GM&&Io_d?Ia~b=^q0CUa?z+Qz-qnV6uQ^6$(YK%c;&mERItK0X^L!db&bIB6@V6 zp~s-hRswv?j0tcu)830K(X(w0bAJ1bQ4n8(3XO;g8wExV6-YpZ&l^NGT)4CpJ5h-o z*&tN64bpE2Zwt=|kIaGs?MKVeiWg1qeJ}%x^xywyP-JiX3Q*wO@+<T*#U%8}_Yns} zKD2giXkBh%X}r!`TT@{&XjHI7p|`7}+3hTqFuC?J+7YG6Ae~!6#}>?&=E&5k&vJ86 z62U4_RQ!OA>#as}219gaGb2J0Yv)2?tq6sgxEkyPxDal^D#Qw|$c5M+i7iK%Cb6;v zYV<<68|x12h#)JI$^XDhvBT2T+Mpv20(wztiZ6i|pzLobS){tF#XNt(`n)45Wk<1V zYf-O8yJ(S-R%Tm@n6Pk5L$1Rkk=T=3NW+(wNSZoxiW~FH-!@%XxkY_hLFGcVa0A;k zR3Fi2A+C4C;fA7%>55eOLvr*Q;c}6xEHohOfB$Na1{I~<_pROJaT=}>!gDosYkqFc zPt+eb7E}!GLC*<){{#BH@L=%y5%X9vQrsH;QU3aFx7%v|=v=_$c0XY+P`*|<&F2sB z*n*SS#^r0XUEqBlCEg2dM~^)g`qs@4ee?b^6G!*&yK(pM_RalkmoAD%!d2yEyt$|_ zTahJ0k3Mqp<^%gZmF1<DoGd9Se6+AgR%9-*SW0%#!=udb7N&QY*-bIwd?s8&FAdT? zdUltTpxI-7>Bz1&X>v#MQK;r^AyLnaQ-kCTmZM@LFE;(ml*1k|=;NTP7dK=4bNB5R zfgqw`?#&D`dWgs7BI7X;88}-D)67(Wc)>I(%9)v5YYx&Fz?T3vuyV<iM!h*uog%HJ z7Bj44!F>||AzA{MGKg>?f~1B5KtV{4N+=SVFLPkO7^jF)BIJNIIYm&d6H!QJS}8I7 zutRo2DG8h<zCaIVP7r~10_lVkKa!5a$_*@S%|fab+1Y#Vk9tEpj^8!VoKSGo#@2E3 zsy5-(Y=-p|9H#=D_Sm1)S!BW0A0Pa>U=!{ZPE|{Wyvh_RL)jnYyZgpEI*dlLdc=Ll zZq7dbXJK#pFG87cSa@k_T%wKjStR7f3Vm@w?}0x)daTD)cYE{gWfSuozPnHT@|K>V zUWrw3{O+SQi#nBD^C{tz7T+`5*Rcvo>{!?2=E&=OUSAIR5m|QUfbeUSm1Sno`~UIO zjVm@?xZ~Wv|BLW9>Su^-MH_@aNj|;TyQW>mqUW0HK2q;R-+gYtLB9JNUYHi17V>P1 zg%3X@_g;Pf<)<FBNE9HMo+(6zCtH2UC7f)%_K5H&B>z3?MippjX$VCm+36jm<Tw9$ z0~$^*N{+O3b1tgu>T41beVBf`K1NPoJ%c6%W5;{HdRx($epa|}EZMUl-uF86i#pFe z^vguP6?JUrLGKIaOI4RvjAEa5?ai!F=!+jACQ(jk6rDU7x@XlLw;sN6?@0f;uEhMv zJWq8+xiMRLeB!o42M_Goy?xu}fen4Dx|YT}+M&}j==bSW@-3UU49XTqW38>R`~o>N zDX1w)7S;p%4`kWx<z;1dClgr1B%A0HlPBm%u2g&1G3hSCS5J1Qv<PgxcTEmL`Wf?R zXb8fk0gOb{@?aj=O~NJ9?T)+JGu;87yT@JcUt%+J&EvBW;B$LttVU0qoNF~FMXO;{ zvLfU&s7RaCY7>bvsMHv+pMeH;(D{(}wiq-xAznmkpkQQx_5-k?A_VuiAqJ<sIUh)O z8?+?AD{!Zj&nfXZAqOheKu3Z_C4mM7J)l3c5&{Ue#^8f?DthCkRMf<mn1IF<+Gtmu z$&@%fAUw9mw6&y~%h{UjkEz}EL6bXSvOAr2WeLv(KxZ?q&1{`xuhQ%Gv!i9wNFv8& zv@7cUETivJe1i=LuTM>0*0w?CFw2?p*`$dzTA^Om-x;!V^#K#d`#~z2v^t}#rbt3k z1&$trEMG0T$eF_3$)?C)e4;<u*gZXjtL0oQ3Q3b4l|Pv})6_SeI^TTuw*C>cXR6=Q zlR$Ou!-pA!#?$7tXvZ(_6#i(7T}+_g3Hd)?!Ve5yF27;^#waA!LxoV%@NJ9>f20F$ zmUG*0*%Y5>bqoX!HOB3MIJ8oPsp6QO=Odop>FzzH5?c5B^VJ+lQY`9@3?&mdTQG9% zZ|taIKdgRhB_1I@h7S9wsnDahoSYopw`J3Y{<W)DCYLW;+S%F?Xn;<sGFxe`UYnzY zULWHAZ`^bD_N}o<xUz!hl#M~zp543m@WrwN`}ZHXaW8W^m)T)vZYgATxLpiIGp8ZD z`rtRu+$%XPqwh1a<K4&5@jKDPI2t5TY?j?Ie1YFFtwT!-U>A3_Wa^bO8u&8^UylJY zi2UC&JRCLy*BCK17p_wxTrIFpLMPUft9`J#0<ee)7_LFaNl|zeg;>r9aO$Aj1(2PG zf|SQeTdbIiF%MT8a0WhzYM{Xr2pzMx$oFtK)&!s>869o#X>g1S8>|InWky;0JVDZ? z21t9HB)u_uc0IsFmSb7BP;KTC-laxgt*6E_nGCpPMmDS-j6dlak0*GOM9G<WPTk*9 zwlYxXTF@}!2NZaX?nLC%E{;`d-A;Q;V6=8bCfhaAH(KXf95^E(D@qIeQi)KXzld@d zu#QN|?v6B}Y`zW>@M^gpv_xB^dDEpcW3Rv4JN03IZ&=k{Z-)YGfm*@3qx1t-wP*Uu z;fT%qg78LnG8I;#kZ?aoqOkBo(pZ%|F`7)hJM>Dm<X>46+dQ1o_(B^}@uo;3DtYK3 zjht*t|5`WFJMwPRu*2@R&NC_%T009bez5>86K*0+tSkpj2q`TI>p*r=7aKSH!0S4@ zWPNIHf;U&^+ud)qJt6$rksqz!v_8J;Nw;>ONe$Kn{YBQun<r8$^AEi=C1Lyelar%^ z5v-+0uRWV}R(S?iS^glj6!rFo`ZPVM)zSHZdVgJoy$o7xVBy^I#ImJfTWK+`$x+AJ zV(qdjhoefC1?`_kqsd?}dYG~<#!RsgY_q1ti=^HlRV%TPxd`#I$OU17+Z<*!$!wsS z;n^?fkuQPj3^IA5cP=t}MPz1B2n0yupcNt(T7{IziL3}Dx;jYNL|G9etx#UVZE|^t zFCsB=DL|JMdVHXp3#lZ~&jlC+<YAQ38!8u+)z!JW7M+^7;he``XSUfnzwq(-A>mcw zlPj+ZF9}mG4RHQ?ke6|N`Du+d-h{di*Vg)-Uf%*ca-P53QD!T%v5x4F@S%O`^?|@} z(`8}IYO<SMb*>Q0Mv||dXtA5n#19ZUD}*TO#eb0mlJAZNA%XQ~>E8D?H69AM?J`sR z3}R3YTJxXCBAiL~f7C;s5oFT%;HU`}ax6}tl}M0LcvIG9%^@A>DO36xUiQkX@#;3U z+Uyk$PlV5W@N~=8ZPQcJeLo5!pYR9p%>4wBHKaHT>vbp4{Lm?M=bfRu`o?a#ab#C_ zYSpqOov~>1f-rPg6;LD)&>gqmdgSmeHysK#`b<WHHb<q9vtZF>vdsenn?1E2uWaSY zRmtSanp#=!nl-&Tz5LL@gNO19vUUs)?|_ADOXBe*8s^5mZhB=!In%#xCEcB?=BO;@ zwxb6t={_gDwy%iYzK`8aNP~-S*p2q=L_5&%cC?a2jkD-!2x7l2E}p>bhqK+d$xCEE zkq2Sd=Un#8f-~Ic_u2m01#SPMJO2{!i3B=>z((TExd^;dL?Ad|l?0jtbwGmPa=~Fs zb#Q~}4LfEM9J)s%CSpr%lud@53@kJfpZCp>ARI;qQ4y`l@qxA_)$mqwaO}AEOlrd{ z397*6DTM`V9vl3_yV3U?kBz(Q9j!86Ewig+;LuGRJT|hi6Ae|10u2p;z^;i)Tq4QJ zvjU2dxDfsH2y2u<k94%0U9zCJ%x3rHs2Vg@mr6a)j#R5EU6(G6PVM)xlP<0$SzsD6 zj=CL@@KD5Y=+*T5lT+JMZ>5s3Y+<!J$L;3oRVz$(&S*DfB@|l7o9<c}NS;ZKwugq| zFa9~Yd_~i6VC8uaPmZUzF&BT#G@d{U`p=|L#gx0oRZ|f_hB4G2JRgt8>@ho+ta{~5 znGQWJ#3B3rl2BPCd~D6S`hg@GZ|fn)uD-~jH`Dv8-r6O!z4PAbfx$?@CT_%J*G75P z$jf9g^p@~Lc@h<k?~S1qzlg^BM-R7-Ar0<m9wk`lX6qnsM_gz>y5o+}_@4cvdv^|R z9on*aU}OK<-udBq(A;J<fYXM^fw=AHt%t{M-m`LPM|-rj(NkMfRaumu2X#TZ%r5hJ zy}nzI$}ysE8IzA4?n)%OIu|dZT9|BgHWO=;&@yvj0khB|tv_^7y1^#(bxZ0|puvyo zeCRrwMFkqfx--LuxZ^0JM>C16+0~MB!TSYgK38OZ6<{;RT!-x)b76aj2-_e<<$;vM zu^X_aM(UJczYcA!7{TD8gOZuZ4yaLuAPr=d^3Z`S!jaV2pyL&z(H11Z!#iOSCOngo z1)>@?U=fgU^1!LkOo^;GQ3PZQpMj0VAmOL`BLSwaj`hmqN?E=&Hf){VI~rrHoI|bE zT2CBb*zO(ZKWug^mCRRZSUazdo=AT*BE(M#r}lDgm!ncbg-u#kEvv3Ksnxul%9a_8 zFU9$J4PEAj!lH%dCDm((`cI8JLnG4x8M~t1oR?=ed3qhfbaFB|l8W=Zy4k@Rjf`LI zG4&#^@DY0D*0sW??1F(NVOLWu8Hk%q(Zr$WBZ>I*#Zgv)HVfz2f>Wu*=<4!?!W*h{ zo=d|CnHm(bzX07Pyhz6S(GS~h>K}s_jJA#pZ7Sd8pG=(TY-U+foqhv^0%{eeXqkou zpM2$tT@6ij)#*vIS$JoYI+=Qs<L$gXH9U0X#QJzYC{Wxp&9W)wH1RcrLc7tveWB6R z;5umVS)N$h*%4bDZEjlNc9oY{bR5gj5{kHS&#s+)Yf{ku<A=;kO;u@8A*76z@+^{) zWx;X{37thV_`!nt3!1Vb;cz5dA!C|#Or@Er%wuZz-oP|(9g;3v5^s?>D$6JvLRB+7 zYykC%v*kE$x~@AvmwcUz-LJ;%{}E)Xh<$S*yDtM-(f~119!3wwBp{Xq(#3!RC>x{} zCnO|iq9Mwr0oe&_M{E=ZClsSa!78HNSK~9lRg|9)f#Ec!6VQz#rVNEsADtai*Oj^I z>WWP!s5QIeiOAS^JjU8(W;Zlzo9y!}CZl`maw^_@$!s=OSFPaG5kJSmf_W?J9y6t? zo6Bk&%RN;!PPO5}=%LZeqa*Epra_mNuVqb~$sYmbU~*gCQDG{U^w=W-P7N7T*3P8V z#%(@iI9~^WdidPMfIl8H*%Jf(Zq^?=Hgd+_n2b#&n>>)j>TaqB5oxM#x;))=56ZrR z>MjpXjBZK{z^dW?;U?3iOXQLCR)kPe*zR%UL$|pWeO>U?#SX<<FQg(MSDXFrX3m{p zwLDj!*z579&H&Z{b3NDY&bkPlAh#2L4GoE`sXj7xVBd{5^epdeZ(F>uX<ogzR;9?2 zGPfN%uzgu=wHu^?K1WThPRT$ZE?(T$zGzYVkz2FOMMdTvL&HqfwylhFa0^qjVLjuA zMQN0h%{8*-o7rMkO3a6{7vy>hP(DJnvo3#*!*_zC&p-|<NcjI;tOFH~e`@H*-1k)= zn_<LS;!7CONd`&q*RWc=25U(brGpzpLvVxp{;fcB8LspAaQiIyWDuRedYBUpG|-($ ze;KxuS{W4$OPFv#WRU8LXg#0}g8NJgtO$V`wMl<B7O_@UT5Br9Egh|i4=v7!I&3wW zk_q8Qsf2$rdGXa3g(>@mk)%XfqAHhxkS}r+<|vG+K#hCqrKzudt)<Ml!VC*m&1WZV z3rfK2S7}*=DS4vV&BYy0re8RJ$!dq3B>>J2P=OpfYl<BjcNJM9Qb{w_R9N181{H-P zZt@yyj0DJ!{+lv=B>X$gqFaSs+JXLXWaxZ<+{#8F>@lkAUvz)}(3HEZ&)R=sr2mkU zY!M#1!H+gvj3&;FCyR<mlfY&%5byk+(b}6|_=nm^_M~@eBEq|$L`-L<{6N)_l>b4l zelX6*;xTu?9u1s3>If(J`1I>fCROCySO0^A(93nju4LV9zkf%JPu`IK4&sw3R1-RZ z9(^?QSpCV#6L%j2UAn%1`GWbOlH#HQP^41y&HGQ?ar@!1L!)2Yxp7TTHxOfZUVSYr zf~+XFTl1m4UZ<Do4KAnC)x1!?um$__N2X*q-*nT>Eejb>tf-CgdLHUsMXhA^?0e+l zGt_G4mYWYy`-9Rg5;n0cp3QcW?2=9prrXdE+JYLPAEN=9I?(Oc5gWvRnZ>-ACb3e@ zEIbjFD)1)w`_DsnMxK7IWH;Bhf9~=B2GF+?kIv=GM@7Cg_<;2QkPvPIIB|cS7sBWu z0wBXSAlK^CV3cDH#MGw-1cQWyl$11+QxaF;As-IBZN*sUQlM->Bj7bHm~k1KwA6-+ zL{8)lO1xMP;5B<lZNs^!8u$dTCj(d$a4ZFkEjoVcfk0m{*cjg6cQqdyiu8}$S)DAO zH*!XPdxCZKtSso*ghExVrlBP0JENL6vEcgc_K{R`?|EVRCA%ZHE-BG+ihRKI_@wad z{^WOhW2e=yFr9UCoKamiZZnth_M88j=z1)$vI!PogeRd-&%|0KS~g$H;Z--LM<Vee zXX~ZzPM^zB0l5G!5(~3zv{%L(nTXni_6cKP2&KX$yPab_16ohs;>789Q>}-2{~L!D z<c;Z3Cg&aD&rNZYC+bNiPQ}hn^;f%3Tz%)nlf7;SuQs_^NAi^?`lHR4!hF-EW_Nu* z2Y<#uxG#2^kK_;A9qWG4%OSIH&S2`4vbub;OzjRdZc@V{#?<+dqlfohNb$qy>1dNZ zGBOBRh%Dh63#Vi`_b56kEYV4#Zu{t;l9MU7J9Y{yh4t57k$9DF!nu`x7Fvbc+Cs5N zb5l4JYz)-b)mG;k7e$=*QaA^Mf|VdymO`)7>CL<h&T>Ts=y~(#5Z10_MY)wKVF;dX zZGqJ_q^*dKDx~TLi3X{`OKP(ba?SuAf->lu#mT4!aj_M!G~gTfIa6l%O8NSE9M90P zlW3cZ-nL9!B?1Nj2MH$tnV1d|oi_M&A4VEn@X{-flk$o5iaVLGJOI4m%qnP2oknV) zS|9}iZk%P^&2iKCCkZ#?lZVW1r@m5Wis2`;tV349*7v6PiI6&fUKTrVqcJZPsVg&^ z{m|B6*SbxB7|E|TCH8v5ljH8u(Sd+pZGzNFC}iv~qgRCPuA{GCj*m}_M+QeP4~-og zJrjl8kp$hF{%=yYP+}$jmS!PPpY}CJn(D)2)53Wk!f-?kr@zL054ym*i6=vgP)|>2 zjkYTh49xRGs)bW!%d@&yCEB8`-g0{}l#TN9av=nV)27LDO{QF$k>O>xD?2+FOL7Up z*a{04)1_9n7I`yMlv#l*O16J;n_pZ5cb#fJKRvTKK`+rWcYb=r`Ek-P)&^|bRv7Ub z7;%`e%(^(86ePb6QY_#<85If5FIFe24Q85;z;&`zkc3n;E)`J_1H)`ON$P1x(!x0u zmWSNlg{8g}C^?IxEY|d-nS*m&uske7go(79jHJsk-_=n!^*iCY>AJXGpVO?g#N<l< z)|)t8uhHQ!Sy_{Zl~%rZe4d431DwMo`=0f5WnCA@rn`g`jhw>I8C3%s7H$vTv#`Ex z-S?utU#*ZoG=HgZ@8QZvRtlGQZ9g#FxpraAcjqnUb0#K9=#QUBKadUK=H|}rKU#*= zCwdOFx}wjiw60b(_3?@u9`CaT@qCUDT-Igi*}NAKp%HZ7eWBA$r@nFQuJPNC9vQp& zrbD|&Hf>znw<sEF^!v>Dc}7TlDkO07mE#BY-?(?r$j<HCw)A(WR<Byw-quuY$x)Gk zMtK{^spDVII(FAx$JR1icQEz!%s>`1(8Fx~1~agc8KBwZiaR$Cpbcmt$|BMJ&-@W& zOvF}g9Ba<5Y56Q2lBsljwMzdVG}Lvl%)(<oao=2c+$X{Vvpt+$0%Q`*FfLDk3dbi& z5yL}}OyCl-ak3ZJk|BwQ^LRyw1_<FQ9`;hWoLB0USVXlCr3?eeEZlGaeke#%VEGyw zWJGXUnDPJ;t?*8wq!-^269Bk0ADps8!LzY=1TEdv$V-;T@8OIdb<nuN#@}EpXlb9a zmU_!vJWwnM@wQ0xdG|nSdcBG7uPhBYay&o#Q_Afsu}mP63lHu6&(Sl(0j--&zB)b- zbMtKzakt52V#9pG#D&9&q;TckT@iac#YNRgjy0@d!!olq?#_4AqimC|O<7s1Qfas@ z>2i0yf8{QoRqbw-ZWsjhFNvcd??&sNeI(Y~yvcdy(Z30QRJ`~*2T7t^geh}R*kOt{ zRfl8#L?qcibTO=JU58494Ut2_&mvjmZRxgxD^mfxOwI8onWL3&K6K`MEX79?t?t1K ziHnC~ZAr9H=*o6O)ETIEPoZBv8J<AQCrGtnXfl3wFlu#2EGS>N#Oom~^QJ+G?iNPf zBmVl)(QxDaXN13CY>!_1h&`LlLjLgOP#;>qKD5EqyJl&;v!lJOwZ&0s$da+WJ*!tO zZ;FJyo{GW(U@MbEPa7%5?OMak17I_a0jSf~R5R<=F`=NJs#CDVK%(Ys*1X7GhO8yf z?Fh5ZQ)YxJW^fEar+9(72e_9RQ6*+iaMA>L4eqXYcYFrSf7bsqo~D9WKNqU&Gdc-q zs)&Mgg@~V;Aas_CJO;aYNP2+!$FU`pH1Np?0C3=dFhIcpVQGY`8<|%c#J2!oL+K4N zfl$GOwE-`KEP>>O5NU69Ww$7l=i|*LqtouRgB<723YSOIFHa|i$47?y?Wk-zf+NUA zUIFI@bEw(CWEq?AyM0D&t19Q%)Y9@WSLf#@{JdQfW%siY@a6oO(Rk{pBa(Rb7Yuq$ zuqp$S_EbLkY<i(-q$%ou-L8gnxN*j60MZZkCQ_#o{{D-pL+3nPU;pUjr7?fJe|@}3 zhMp9f;iO|%U$U|e&<Cr9DV56K*EEp$VAuNT6%$hnKe&i7aN^qA$_XV)oJao9Np#^t z=qGhQdgh78zx}O8?>Twf(czv>ucxTcWXyqN1Z0oD`_$B#`%Zo1<kvy3-+Ex*-jQ89 zH*Q$B79vPEJz8CLWtpvnXJ|NQ9;F!Av}xd}@5-KdV*2sNpLpoOhaS%Q*0;X>*kj*9 zOx1CE&mQ{j3MSf0S1pRtHRT=cwDs%{m~C6<N&R_ax7>unA()KAHy@$`$dAy}ECT{` zFm^KMjsvh@r6S(V5@M$8J9Cn=>$&1Dlq2R~>I)CQ;3_}&><rqbhzoPkb|Hf{01|=- z6030y1do^=B~bYS`UBjFUQ{Qga8?4=HsPuS6vcoLMFnI5eNBQkhk6)JZ`f1}ZY-r# zI55Rd)I-@wphJALMygk9@Z0GzYf6DPF@)hWfjvPrIq~_=L>N1zq8k@IIec1<K_@aP z{%mr-r6=U}$1PIIW+`io7R|3xYTQ=8|6Em_t3AH3%&k7*hJ1)oEpta$I5CA?=H6gi z(Q~rtt-++)+!!_{lCX;{<4oG7NVCx%izcnHq<_lpaM#$1I(T-%c*(SVNa5yF?rN3? zPY*`H^5bzfo^r1gKIpIK%&GDOU!axwdDf&Z>Kf(!>Ux%qvF-^t9|&)M&+WgE+OW~+ zRu7)am&qHuC9O?L>Q)|CgmsPN-vlSccCSFb#3^$1)shqtxPl?g0t+WG>K5+zCytN) z>A2@mf$-kgnX?Jq^QT6v;pn@<lxstjh2A0PN^9=rzc)2~@hrM)I&jIJs#l-or$>e9 z(eJ&oL-@A!G<#=P)06f@e<X}lqbO%Q;)yohq*Ww^caj%{y~3+a1I_Wa<D*tHR{xv_ zLhJLUqem}|?mZJoCeDTt_o%%-ki3wH4?@zAt#2c<1cL*mgom~0VPP}rzA%*({v3_V z(cbhO(~rREa`B4IH{?OZo5V5V_o04t{CMc=V>cf<FbWc4UGJLi)yb~J($*HRF{t7g z?i#;s4Em3@ZXSSo_2MX;l(63KaoY4cRd%6?t|=;@z3b_TJBH}njdX2IUM^kdgHt0B z3n&MwL_kQW95P6s)BM1IGlqnjSEOI8{67c(&u@ISp<I{$$LE^Kacm}5h%7x$3Dy9h z^)b9DA4CBLwUh#G)?izKXcFg?MX})Z;R-QWg&N?W!L!c*niNWUB*=@5Gyt9kv58xf zz^Fut0Vbot3PJ+$@JzZIM-cEj2s$(rgbx~NmOVba*KD_+v2PlVY;v%sy{GREUSgYj zjc&J0CNr`2F@N)M*8ltSiAZ8P$)AYwRtPX<TKgHlt9?=Pf}p2Gs8<^;`h*|JSyr|% z;fR#Ei=-N}&lYbF*}+DPMkr>0qu_Z~9r$*@9ty2Vj2Sp9Qx|lXwVT~d6X4qM`69qP zs&&mxNmF1V{>^AInMl~{o_WHHI-+({a$LChmT)0e-7kEY8bbe;KG6*6A1DeLd4FJF zIzaLh$tkqsR19SwT0dCdiEP4U3Hp2bTGn@849D!rSYlYX<Y&+mX&X`td%FHhIGlh6 zpwol(k-?Eev3Nf?1hjc&+i;?{(I0vCaIT4+hbo1SvP;n!!S0W8!j<tc;gaxbx+5_l zT!8#FNsM26Suw778_o&5k9Z@r35|}1_AlP|wHt5PvT0!?-01T{nYp+qPtC1s^LY#M zbZ(csS|0D{h*#IhJKEbjfQ5`Qqp7>QCza~ft8<vOHB5VKF`UV?mt)pCOzd)omNt~K zUAw6vvI`|wEJqt!NVIOo31I#g<5a*bfE1uBf>&HH1IZZNFFo5gJX<ULjQ_tBw=<Ak zM~u#e?5N1>fKn$YhD^kx0zhHuimT0;G7I1e@CO_$$_(7-0}cKL3J{J;d>UGWr5-dg z6c8Z`1Mi~50Ef(DDTof}ICUaiAH)b2orjpuQRD3zpRA?rJIi;C3c~pN2Sy`>7O$D@ zB27G7aO}hIdS<1HYnay{Wn05Ffim^6hEBvlRLgo~U0jyJeRTxs>s!&?&T5CNd(Hfg z>cw`>Za11njMK2r<K2r_E_~<~KBy56jE%HC#B#E@7fwc~P;hm2hFVcMoErF3Xh*hc zypFv%^2pMiCi|Ahrp_*DSk>^!`77gRrzX#SFwT-EzrI^2R*>E4lb|ksD!4fGwlETg zm2W2#r~0EPdm5Fk>Gn`H-22yv=?e6%^tFmaSK>{<GdwVOas9_ndOqQVch1D2QP`A+ z6qoyNM>@1^Yy>f*=s$!vIUw{&l1dfySKC#v?5dY}8)I+i+MDc<@-;Y{^$z0A&_=X# zXJ}Wrf9;Cpi&_>!aSu-IS6N}#L8E=PQn6!r>z2*&_O|(98*eU<XUS+&t}Gl1h5MLT zk}1?M5jbN&gq2E|!Wc79RM^36-!@1}y=pev+Kbkpo^G@fHIP*j)Hka?u=>EOWyS7% zxD%6tSh4~V@ntp^`;r*!OOXepIs?8wV&`1&?VJH0jf)~U-3&Sui&d;MAUMKe!GjqT zGajZnQLe%RKqf5$5~uW3lm(<N4&Whl2dfjG0BS9@;ZxpVks>xhd$9Px1?ZPod|$Y1 z4-}Z~{3S1(X`nN9iYc=+%Z!7OPd7p;uA$s*H${VW(_CE_Ur|}<iJhH1yLUSxbs9@i zt`<l1BTb(SofmdNk&PFdR6O-cWo1Q9r2m8YdBd^uNtvgLQ`w<*CX+!TP@TnEY7~(d zFT^%Y#r8Tz$52rCAzeI%MufL_JEKEWD;m>e4Bh3AooOhxSz5i9E*K^!pvk_SMH_`l z8Ke;%YRB{2(RQIdbtQGQIXN<E<Wif?r3B$pLD=npQwRxRzfle6H*?pcT|$x7U!RzU zI^KtI#MI-?iEB?Q+>ovDL7e}5Xoa|zX!Xt=+qNc`b#^S6AFlU9+XS4VC{L@Av1kj# z@zK_nDo2@`%T`o6<Sot3EjniN(j`n$5zUt}i<Hb}nVi`=n8ge=tnEX+s2hbyv}F!{ zoS3jg&5DUj41m4@HD868>zLW{Wvh}vKia^XQXu=FQi0tfOuXm-fu-OdY4Dj7M73Dz zq^&;uloIEB@IR!A4U|fP(`*Jfc^~Y;?Kck4nmmRLRNib*d4o1^D+VHSp>KM$e=<JR zw4If4Mw2@1_lDWS$we(ai+!P%q1NEGt&11KiuQQ6wL)Ps75Ec&*$vI(E7KoOPWQBg zU^y81(h9Dqvy9h4M%M1&?fnC77oua4fAn{N6^;sT2``;_Nl=`gIRByWgO<@acxLJL z|GT%hfotPB)5Xt>G@}up5(tnC0tpZ>U;zW@(+DKl2#^iNvLj<T#u$eW8ym1mj2)85 z4oPt0G>|&2Nt;b*noUWzw{_BNgWGIsx7&?<w`r2Sn>KDYZPISrB)iR~*=?I9X8eE7 zNZ7>n_TKyZ|9;n4(x8vgaL#+)^L{+<^PXht54(?#rM#>6XvMgAe&NUm7e?f>r-D-F zyHWPhOTSsL*VeDA+zGtl;oDRjE}e<9^GnlhtjJ_N*VwwHWFpXcaWLSuj7ECSTXYtn zU@fP1Pcs*m-tYjIHMVE%Pv_p2btB<;&||+iXz}Gf=wOb@-P6;<R=o!qm(Hf=n2N)U z_!uijXH`d*#$NxJ4am$^i?TPqBfOe^6dv^n@}xh^+<(9SGtoPb-gfKZ;oX}zHT&F% zkJU@|it^OshYm*9uUq4>nG05Br>lvI<>6-C4Cc$;o%}|vCSx1pQB|t-Oco-v%Y5Q1 zBeV(i^Jhld^`$1MWwOcrE49r1ik3mqJZz$bL6xT|vz2q@z*r$8mJRcaT4}(Ux`0ll zDF++8VyGe*Tyz7>b5cr&>;&x(4Gv|&h;z~uK_>hW`a$^8@Me@lJZ36vHuNntX{)fR zG_y2f$f{~QFvsfi^fhUg?utF~PfyEl&YF7q>a<D@z@pAEbx7KDdlVsxfG@)2wYG=a z!jaCF@GjK(<yPv&30=(=r+a#Lfg><2)`e=UYwT|0@pq=T7kKwqnoiB$Q{2w{F|^4h z4cKg6(IPbDAMEiD#WHl=Mz@7iwVQRNMe6xSPDW;e^5U8@CRJW2jOa79qUiGsFTDBT z3@b5@GVHV|X0_NtqQfq*4=f$DnozZnD*rNNV&)b3LkoMyW0Ug1BHL_0{++z_mi6s+ zk0^TN7v#`rCCfzRXZf+Cy={S=8*Y2&!HEm+hV+?5>dV==DZJWf?)fm#ls13!IbO;G z7<?qf$yEM;QO%eFdgBC>4<8|V`G>+l+G#RP9`Ubbjvx2mJ3e{q$o}Cy-O<i)TMLRC zy$H|%t*S%ZhF4GDbN5|aw``6$8yHf|kN4liyL)#EaMZiv%ndBVEbAnNT`QT6U1{WB zUyzdTNXipKj<1xb<5Zq#l3p=spgnRqs1zCu1Y{pacmmEUs9O}_u+{L2Y&ptkMF6#d z@?51>n%Gx9uIyII&X=uGq!3UOlu;t{3c6a5;bX7M%H}D*5w9tscVL}^-R~-&u<ESV ze1CeT(c^uPsoTs8W?zNHkfG&t7SMfF?=iV_HeI;>NWc6iQ|IEb-e{Izs#obZaxRBH z%UaRO+{}iy)>iDc=hoz!HJUniZG};AGt!);=62!l;_(k|J+V%VwzETBwJvi*!v^bX z1*KtWQ|pF@y}h4tfAWWy<%<(WosM0w>@+gJTl!w!IBf4@<IfcrvP_q}nD!Y>*=;(e zO@2p+9j)lze`rcHh1Py8WYoK>O}pw(K3oHc3UkMfarxV2O!<6F77ia}1o<nQG|X1H zqHSaN)S}!|aQGhcHZES;9=SL*D23#gEbqt{3Qqj8u@91WZtCwmhn#EtR)bKjoz!&> zJakCGh7Mf*KzjhllRL?8{KL%Dl>e@q#t)9{8-$0sJ+`eI2oVYf2)Bh=T(!uPbLu;f z-GpRQ;~I|}v_VA(0A^<)xI+qyfQM$-Z5$9*B@_a9$E`<Hhxn3GO9_9}3TWWr+b8&n z0F)P)H&(!;l71$&pJ?h7Xg>w`_m|8jMc)3RC|=nPo5<8kVVqKwTMo)pDA*nbIIM06 z3HXDktRZm^6<4mxrr^5-yEhd|n%jWx!;45p(RX6&q{#g&CD8%JM~x<$8=-m-xB5J! zPZbr(Yf!8LeoOe6RA_1V5e2<gtJpeMZwXt)LlN2Y=D0^R7B(63N_a{Yi2Rkv0Y9XY z^zFkD>7t`fY6<J$f7XR7ij6tOr%)B;s&Cr4YRG677aN*a*D*x{l@%_J%YC3NBc_iv zMcftM&*;Lr{>nz19tIdaE5ImvE&G~j@nj2IA%F4d=`69+3N0#nd?KrtTkQ4gMk9_` zC)3S*%l_WLl*yjno?WxIr_-Y|BdO~17@g9gaB$iovd5O<xI8rsyrrL{Klnn5y0gcw zW3@{^N`a5~U9BF~A%mmxhZiiyXVz?KVN(#hRFBB*f#C0VzaY&8<T|tmQV_|h{{RM? z8S<LHmzkaQKUn?1#G%nWLxa0_?S!vbUP?1zS`B)6ko)dDHhE-h&miDXk*;w28gET? zVU8|6E!D|o4|DyX!e}(+Wpf_)y~pq3H>{uLJ8$Q1*m6L#f4e#aW{hn~r3P4&f+|gz zT1t$N-cfsNrHcF1@qaI5NoBW<%&wHLSw+6GsM!QT$t%r<9nF@5M+0F9kRQ{8JmduC zIgEDflQ74ql7f8bsCZClDgB*8339nZrLZN_ebzxgmvk;6YuFnpqEG2?koa^tC9GG9 zuaL5*j9EArM3HlHi)-w)?yi=6x0flNw8W4c1)qsgC`v8)>mHNW<=)s8*eMPK{pIeO zMnnGYPFsGJ$!=C7mVDr`9lw{y<?~C={=igV(xn-YR2MDYMNyj5{lM9>(epXO(O%Vb z24Z;!Z8n=^x2KyN>A=tDAYHFBu8)i{seaWvmoDm223y-Uz<A|1GCP@#_uJ1-d{qt> zyf!=#S@>mMyVu%oXM*xs_G?d>_002fZ)8n%Uv8z<S^n&x{N6)<|K4jo3*)DL{n$X` z0W0&bznW!+W;(~mqn6o`sdGEec1$_hBM%;s_n8a66Y7;8Wr{0G{-|n4cs)&oBM`nd zXDVc|+9DonRQkRYIekw4oBO_fS0*IzIHGHN5aXUCcln*nZMXSvH{UWoyoW;WfR5hS zu|C{x%*#S}d*YV;!-M_15Vp{z@8H{7RmgAT*Dy?LQm$aUQ?u(+LiFFrO;TuD$!#lz z<~BuWATzLgs8VslKvDt#xoZ%|g(zth=9NqoU{IDc0NQ!Q22%oB5Dmn^thvxg_%IYv zy|Qg8^_QC5Y;atHK270Pf*XjJ6}88`>hTxu77HAm4<V0QH!WJ3z#-S$?#PYRzGlfN zztUY>T;R0_r3s_`Czi-)Pb>_AOPwePcBkYpOxmT<P~ee)pjBjCwp5qYo>@_vkrDUk z>vPRs{h^@wi&|qEqtfpv(g;?T&5G1AHbM1c9rK{P0PlVVEim}`;D4<RcgCX3Ci!_C zD$xE@E)rYrxx0NZx+o1kCcisABS*G<B7b#QAD<ED+L1C2O&{qxG5y*L)^qRv_+EQ( zfT@)KsQ&&1L0~-c$;P+k%e5Y#KGGL^SN^@NqgpR8FTB2|*0k5g|3E&oJwvcYVT(^( z{#u3v2F%ms@5nC^D|qom|977F)|tg;zx3Fn_umKe=-?PtLIcQmxttREX=J|ew~stL z2gK2Bx2(q|*zC1u>C@Ai{i$UjZYV7au1y}?#djUxpLmwv9pSo$x&2%D_#OM|zpS2D z84*~uUr|8_6e!{XwUco5uGXYoAK;cyNB@mHC3RI&tnB2)m16ZG6)P^W5h=D33~v}l zRL9U9Lm3hXAY@ko)JtEb;Q|O9lKgaw!cUP3m4sBMX!5ckLU<Kc8k+1R>@>PBIvojR zM*YcpmlCI?rk4tzq1<lxU_PVlm-rw=Te0$#JQ_V2G*~7}zlnuNGv&F6;L>;o4F43V zucy#dl&)_vIr3Yj=nN=V2U~2>adku7StmHGf3>5kYSKQHv7s(CytSfsta~G5A-mLM zm3--0`Bn=+9^(i!q#?o99xTvH8&v}yyVbWLS7_PUwI=8Q)%N6IY-Xs&I}v~Fpgk1p zF}yjY&%fJZ?6jGq+Ewn5s5gU~(d;madP{m>Ra^TRqh<TFtLwu%Ooo?Dmf<H#TEDQR zyh@IYrOcb6R<|px3ySM+`zw3nzM>ne?+8bQ`QJk0oO#n{Ju$eGd2-i7j=)1t{FsS7 zcJ6{h%o%BO<!C^0^O1#p<I;y(qh#vy1uZ$|&bZV!z4ni5C9B6CoRvRBYY(<%>B+sf z?VV;)x8M1Acl*{C9_!S%hX6WazA1YRYW5FH8G<2;xg_Ulr+uAMedY4EPV}6K5A=1c z?Q3Qimm)28)*ufvs&#kINk~1OZvX!4<ACJ><NSBB)5Lm~j=en{HZ9$EVf<yeMgFJH z{8;-R)03s%>C*!*KK<sXJ&}ia3ph~%3-KR;IHDHf?UP3ijgR%;w0j%Xm0c8rTx~DT z$^f07T6H_zkDl!t8br`MtC=!XhNXHuUboxhYf34z*~(BCQBlr2f;^Ahc}HyxW6Wbr zV0FIAJ%?y+vi^<6(3T@1%W1r8;%I+yX(U(1hU-~@5Yr^(Toyc6sydYn8ZAh3DTtMF z8k?oIB9(qHXJC=gHA2y#2$v+BS(<Bu^h2}KZ9SWHL89>intPz~uB4Hn!l~w^Z$yZM zI>uNfi(*h3DQQrvU%Mw%SFj-^wPeI`@#4Ao#ZvpN?H8k?;lVGbnL<XX(_68WHx&!i zg^QXum}|n(*lDA4Z?u2yE8iOEf4Hhf?-8RDkF3h^Wwo9?(k8SElWA&c?=v+uc6)ty zzsqV}aIEqcmlj#XisrpcSB+oFxc3XSBm8Xa<-LFUkEzEP`JDVp855Etg5k77uh*M= z;nDWB4=_)9Mc>Ka9Bc|~%e5B()YNNAi-ei4$a~5e<L`8_xj*zphkyU?4>B)2dd@dt zZD|7IAtGRn%x~pYW-SVlPYF$Zvwg8I%4ZGC&GIR0`~6>P-#d!D8S^bUw62yJkQZ6O zigp?^ShwreD89%jv8KG6VL@NOQ~n^cV~4+o7Ntcx)(099BB_(Av$Il!t?lbPE-~MP z)K*%GldoFMRc++D)O>-t0NLo(U1}d|(CZjRTvoa?JWG`>WGSI@|92){Qffr9W2HXb zp={H<Mo%Xgi6+E4u#8J=B{Vbw+0Z96X$^X#P>LQ%1N8|IDuYs`jzOM_B%^GKuqk)Y zc#s8X<pcU2oruOe#odM-foJ5`W{{x~M<xWLUf=kzUL4u^z}T;J3)0z|O3gl9w!e+3 z+2hX?9J<A{NH6a+cSM*2E$T|^F1xjdZ_6vRo9$VKJO9vLF}g?Ie>cD2ctjS?zy6_$ zIr;Z@$-hd8B4Pzp`a*bM;S}?|bMcOd^Zl>i_uX(*8obQBd+FEu-^m|`P<yy1;BAo~ zJ1xPy|F_8Mn+4YX(7>AN=5PyRmCqEjH!OKZo6>x{3;LHXep9jPiAh*ccuK$L->&eK zP98pV%Yo7T*irktyVeK&jce-bpeoFO>gE{wcC`DQwpGTgv=nmNWCpt{qq!MVSSW~{ z!o>JK)o^6vCSlJO;pV-2j_g)BYFDeOU^y(~-kO_frNWhPyVBPzQ8ji=n)3fdLpZNT zYfASq8lXbloGw|KqDPbqmba_kM#Ju)=Rg@Y1<aOEI)V}&%<x$B2!$$%f5oB9!d6QI zUmCm$FEY^r1<83#KizVzdG*wN)WhsU@B+#tFX0hrcwSPg*R-V}9jTX0`!-A(k9*sr z-kH<sH&igD*=WEo6bZWM>ydHCurDmiZ)g5OK7Ga`2!nk>Pvq@T(VCjVRi=~TB$Hu8 z-Kk?S7L5&F80Zsh=o_Wg!YLDs?(#s;>1SRUe?hbu1L2<TQ7JI$c6lo9yj!#nj`0`t zI;o}SmI~eLqGSzi{!Wkm`^fDBG@HA{`?=JN$#|6YF1=7CN24g7FsgFcT%**J6F-8? z&yPMl`!*Vn{OHKd_xPC4qOp}P4QY0r&N>G`xWjDBu?9rZewz8Cyz#*2QIYd=t=h(9 zUnXg(=5Ic(W^<Q*ZHVpv+i&;h|MfRut9M`Ws|V5+&{_1W{!XT?&EH<#Pz7?96mV9y zAR@oU1xpR=x7lzC!6lTIXjziNw}w28oW;U57a-53HgLg0E|{T77d5EHcGj^d9ACEK z6%ZZu58(~cf<veZ<Z+gbvum~-=#Q&1l~fik(za4rv{7Y&>M5!y^mN+*m>Pj9n%D;G zE%pd%%ID}{pCc5Z>^(F&Qv#9zfH>&xqgeRBjg;%l^>ezjS^Ami(V^OTr2AgpJJkdt zSX_N-2CvT1`HE}ucX*21UAaz>pa{SElDsH<<(Mv(A_@%nMzr9r7k)L49!Xm+-JZ>i z$@A~LA$&<=tk~p~|M}UDH905W|EodydmkK^?~vyMc^Nw9Ir)ZPeyj-_@=}b)A7#hx z{hGJ=!m|Z?*28z0dyx6Yx6o1-b22Btji~k;;H`}Mix|7zUoBMGO7cw^Aa^OZ<q3pi zc_B5`4Bph`K~`YIRQdkd=;aan%F(kcs+I;+==g!32aAg~3{jO~cAYLI_<~I~sfDRF z=Ef>|pL(mWqpvBG-6p7wu3H`&Kh-2hmmZY=xTQ)X<QJKAw|)NxZ~~~`>Z+^aPcv^_ zGX7fjzQnA*^u~l*ZTum_{hF!iWxuTY7uJtDXO?+LzC-<EdF+2Mb&>T;&z}6`Q*t=v zZ&2jWh1!EEF)4~{E6TLi1`ryf@@Of5M4~SxWD?PC$lG#-Rm~MX{ZDN~%fDP59QsUB zysEDwUg$<anTz!0sDOsCT}KP*u{(jUCl5DDDgo0P{vr#?6e@X|`aBzSjEiywDvAo3 z8^9^_>azbk`C{7sU&z;}_FmP2R2O;|H~X^~z22Y2p%N(_h3Z)2=?Rg-NH$_^(h*CJ zQ##SF6ePVONcBZ3=;*R?juwqMnWq7!SoCV!&2M|<pCAK1Tbb$-LVpUGY|oixQ^9-} zVJ?5LB%~gYXVF0;>MvIMA<>#>tpPlAhHSKeK%t$0`ZNvbOLMOhP*DQ|RZMi=lvzw( z6uD0OBbCdVv_3g2swWWOcI8<$oK9dyA7(#Wx|-={%UZ^N<&HeRbr&<HU-B;*k6d1r z_ubUI*4DhmS5BQeCMdSKwoApPHlxe4%b&qyX8I8-WYu6DN)omwWNo>XDoZj~j!vec zq?B~A8tbd9{B7v@aLdQhuryhBk7Fu@VoNO*?*j%>(rw;EbL}Sy;fjP=bc7CoKiH)( z@aM1bNR<_!+Q$HaNFdPU%i;6+5(iM~&9#Ix7&yP5H@XCi-b(Agt}yX0Tlos)GZBiT zBez03D8D8LvE(|8{7g9&@MP&URRiEo1Rf5-U9hKU%E~n*ltvsrC|;sFvqM=B^cQ-A zjs>|{^s~OP;if^&x^&&y57N>%Z&5ka2D@0RiU{%fc>MGe@~=2c?dqUo-An76Y!AA9 z>E+f^bA7AXx(d|-Tz7D7PPy8{&dRO&A$J<vu(a=qC4QmB$@t{I5husf(!f%3&S0AQ zB9r>Sj<MT^zAmeS>o-39<lnz(drR`2z?dE;I({C#jB}77{A+)^g1IfeVT-R(swn~= z9H3B~dZ522whg9mxUIFh$&2!ioU~L6@8@`bI%mt{)&_6f&iQxsavRqBw>i;=l3~2d z=C5M>D%S6Exbyk}Peo#t5l`GD$K889BrWY~pln+RPP#z)g&;bw$<C`s2+E~~S(A%d zST<y^@0FFqNTL&hAMAx7ZBiN~<e+l`+F;UW!Ht7jfoy%A9(yBNRN!=Z?7VK~scyqS zuBoxg7~U)YdfyFOX?^gFPKtxw$zOEiev>}M<It>IxBmGa&xHZ=$tPC#dO(7yal5wy zWvJr74B~Dzr+K#OdJlJv=><`T@VOwU4#<mh=dJAVrEll^?+pwxt&hK>vmC$wR(3+_ zVvjC;U62ZySC{_1PM-L1vZbPTn=@{&+a&1BJ{51yF(6zvFCRZHS_6~Ab<KMLcK+%U zhuH1W3el9~@iC9chuvLWs;)~@*-IZq_uk*rVz!Ak0sBY%@;lrYv~K`e(CfD`Znxi4 z?5MF@Etut8wzyzb2H~p=LYYQW?*c>NRdh5BU0-MOTvmEj#JzG^yA`FEtHH3=(2-O@ z`BOV1Dfh`hay@lKt0?zYc2;646=Xfft51T0zGwbO^Gzjcy&4UqdIp-dXhZr5FFREe zFzTz{`sR6`91a7eqb(k+bp8!9Qd0B}P28=A(s|&(d(@6C^1oRoBTbg~BKQ31UG|9I zBRhQ3<2QyUm=s{3Gz`bSy!5Nsebsp?SQ0EbgjVNg(R;1{E8%a!Pjcjl|JIEYhsH+s z4xvH<q{A6$BOq4m+vxXs8tQ8EI72qqzLv|)<w7lG+?v(gn!p;av{EeP8e`k|t|Eb? z2s_+8JHXO+!xkpOFayb@K!G|mvY^;`6rcl-5dW#INAIo$H(s+KlIvlB99cQoN0h-X zRZ+Hiz$&1ElAtZ*i)geA&@U%Vi047(8=OAIK%b)BT!6KKT}Yh@jZQ-YZOFLeUIFE* z;8)N-7NC1A=Q*mHRp^*TU0@m@OJa(hu5733X?Y|7RE^g?&~n7Ety#tGv>^Pht<%*y z9gmcHW9v*eN_xGJRblZ?bNxGB@LJlPTAj&=RHV)Xa943@^I8pfplo|1O&uVimoJ81 zKQT2|QIt}gTauN%LFCxDp}<#u7k7l0vn0`SE_D1}=1cNEhADq?D(1B@V^QmdRR*SA zaOVu`IwPK6drqd$`O1oF9E{W$lJ8DkV4Ie{bawY|6<6|9=!t{&VCUI|hgv8?C&K|p z#3Y48-SMVaoI#c#dt2ZZXYrXAnVzMKtm@mVn|?39QctC1f|$4i+F7(A3@SY7YuEbM z<@syuRRxB0byMS-D%4Jq9Ns4x^LTW6^p%!y9v~O9%7um$O(D?~HnEO|6)ky`C8f-| z0(6A{P;pq+e^=%{IqM#>cIB+ERc0OYqGX?QbDa6Cvc91CFpVX}9A2OnR}Nitm}~HE z!}4NLWuVM{cA~V{r6$J1MK$I1zfBXKudDT+JDHa~nqRA}>v&mydomy)<*Pl|<@=6$ zbN^el71}!a8Nd*JaCk?j+H4dyJ=wgTbI(~;Wm)HS);#9Rh`G#JNA;{}slplx=)8J; zPjvkEzbIk0)w$&%OZP|bb;=iXmizX-{dq<lw{zA@<99(Pog#wzPie1`edH;0lGwlB zKN3N@<ECg^(C=<2$T930?A>`|WQ`Nej>>hZT85zgVNpMCL$nVKFZwuNnN7tC8#!S^ zY@0yIzq?e0-~=kVy8Y0Vl^kgJR5TEi_;q=#uRLBEbmf`k$QP0QD@T66GV+MK@Yqo3 zdNF8}E~GR@m!oVoycH=k{P<|MHmo}O3!Nv_uDWvTVf`YEtz>&$%EDA4HCa>{B2<oC zttJm7Y&bED2-?5Im8*`JCXF@#2u+9z8^T|0YxPCyejA^ZKMbOQUKPkCfY^l?d%Ti4 zptGm8_DPbp(vY>oTD9AZ7*(1+R8Sgg)os&ff^{ht@;HTbbbL!2?`Ff9HR=3>!wY9T z&E|E8r{tY6`yXZ|FqMNLK!kPH@a9sz(H86Zc;MV=Tf1a7TMGnJEbz^H>jomv{VV&J zT<?uMvwb5vjxd*(-deb;)NZhBpNQaU-z;tIv!m?vU(_md{oSvE<t%(D!i(DT#7OGN zedN5qhdFV=e}CJ3_Z+%;Y_NY_(A!X1S_~HSBZtR&c5L0^s4gqD6c*&@_YL!X2l>A3 zd<z)O`ciq2v~sQM+OoMj)ZFgAyQYMZbfL~Im@0(Mjt#?X9ka^BFk7z7zrw?(Xjux( zr3qK1R#CC~=(cuEw1&?8rv-sNlN5$6<itv0IH3pw4b3R~+p<ZL=vz>x!lWx{Q7C2j z+Vxn9FabfZV=acSjeHpr`N|LVF%5ayly4ha7uEkNR~BVSrm0u@;7DwcrP+F<RB8N& z8j#dTp^}Ghw?Y&V9xhR_Cv31fiu1Bsp73Y(0hZQmGQ}U6Zy8L}#f^bA+cvOYG@HM2 z(=O|X{H{m-&}8k4MXZJQJk+wG)o66N;nKhV)_Zl)Qx`l@DK3nDMFe|9pgoudU~pTR zov9xBEK@3O(&wU%D#tF0;zsx{_CD>Y?X|oRnedEA+nYD|wlk;XN7;feOLZ;5>A3yl zG+=<IUOvodY*zV4>ft?4RWyCb`W#_Tx?Z!Yz?9#-m3dvhZ_AVN+yC;T3lQ*5DG1y! z)7lw~^x5V+5T`yJiZQ1VunkUbhE?;1u~^F-`R>rfyT1ro#g5?k!O_6@n|fV=9@=CS zd-;d3W$z?E^zTw~1$q1ScD4i>#PTAvT+uS|+b2;1wfn~ChIMPb<t2IP-ZiP9lIYCj zw^Z9XeHE7t>C&&^wm3OhyvMj*z1^xUHng1W5{%90RCCbEgxk#~HPUL!34=r!5OSnQ z7mWid5L`v;C>#882H`J-aj1|jOWAeP1@O@nwE`8Nz`12*19hY+p{fN+UE@?Xb*flk z+(O78Hwi}nM7Y?6V4|k11XYdDLkax@*`ne|qdiVN9$>BE8<uqwzK7~JXd`-$8#^aS z=E{HGgqjXvYJaz2Nhvo^T7v`Qc4^#ax3_YJ0xnu#n5EOLDO>-LoTkzXIYymFpXn~@ zwAxQ-<&V$Jh{iOVt+pr|d`e(rMy32$g;1-xJkw*TF*$4xtYY&KK~k%Arlz#LS}l*V z7*Qu>Z(NTIt1jj9?AQnYL;mY7*)0EOJbcIYC<T_N?VVCFv-+;*mp*>ZG5OG&vG1?B zB@OijHQiO8IrsOGj2C`tj@VJ}V0SQoEB|9h{g${_ltzAHZ}xARW7sz%^R+v@Tcgz| zbNuPH+PV@|-leBJr|e;?A;<J(=ZN?Gs1<wv3=vdcOY0(b;v<Lrbxc!}zd6-jDXubR zdg`Ro+*HPjo_pw6tYR&kS}f;CwE#NeYzC>Z^sB_6u>X>^vM~M>ZpCG!WK!WIwM;H) zTB&846fJ|z9B}<2uqTz3z@RS2e&V8jWitb$S`F+qrA;3#^g?9{_z!8i2Pu19Cdgt0 zbEGE2;XUCq4aB`2Qk|)7RZ~d~`pQUAul_t+amViFV<X#j)<AGTvRRF0y~NM${N3p@ zzkOt8J|vA`s@M!f@vQbBV?5tH$+#}q&RT`AeLqucEs@`<*v)+Zhk_WM37MF;mp=Bk zH;GmwwV6sj*{Av@IN;jRf8+)K4NCtJRitaf`tZ77fR+fs$>{Jkx@xM?tt(5PqE*#Y z*VJnBa&qz-9NNr`jLb6Lh(KPQWLK@`j1Bc%G+U?2bUJFe8#2<jSO`;`RP!{!LN|70 zRA~@|YWC%Imw3EdaG|WVKiBff(J#JUI}-%Pu^KS$K#?j)8B7PLSMXFxF*a$W*j!Gf zQVyj-l(336Yb~KYTk%2c`cVAYE>$_`E+_~B&+)3ffX617g)BEJQ}t$yu7GkgozBvI zdLmN0F5RMY?~Mvp3uvc69bgKh+|?-7cGXt+gp|Fr_9rc~ZCYs}GqV?kH>-FZQmvc3 zEwRiJUu>{19zET6ydx5gbjtRg@J9c_g^+E7wPq3gW@p_)$Hbm!gvr>x&@<T*+qr2_ z6eRq9NIt4td{$k>7^3W#K3bfej!7Bp%}X^sXQ)=a{E?<By$$`}{?)%v$*YKahc<Tl zn_XzLmW{fG6oCP|?(Mft-g*QHmzxhL<>lQVkJ=pB5cD`2>cm2@)CioWm@Con`VPL) z&v*G6xvn){uI*?XS~ga0(^QVMwbnA#Onb|^Dm4niRw&p+eI?z$G0V`bN#%N-d|GmH zuX*@yck~U{OT2&}msV^+nIbTj^j8&VR3@86)i2eu@S93%Sc+so^#hBrIrJ-V3dpp9 z9EwgpKr|Fmqf|0L8fY0MWCMDcE?ni*P_cCXrno$1byI|Uj)wi%*1j+=p#0EwRGSjt zHKbk-C~jZ0FKnor_J#p*?5NG$$EmAK;=sh2_Cb%wtQNswi@jR(lo@O$PpGfywf4@S zMKb!k0Ym`dlVF5=Sw*8LS;|aOJb!<EOIxqbPzQ+vm>CE?)I6#I$6L7A8E8^Hb7?)7 zsbP+Ghvc6z9#5#sm1(=FMgFaPZY07kT>2hkL&YVH>w~;E>|nb4jIrpjJ>v5sP5U<< zFTN3=EGz23WL?ixG~5|^ZKg9aePJdt7x(owR2A4fPH>An5P6k#%erkHhqp_<;g(2r zw<CD^(Ds%E&rTXyoVk2fZ3QkgOumGe)cW=Q4VleNYdn@hLwlP`vWsZ9X#z{6RvjjM zK?@4lICn)k$JJDG8fGo;uC1!%c$O>UR6#ZRNrK!GeOXP*jyNsXQfeL)ouT*y%dYsf zUicMbFsU9)Wc^Czygs3vl^Mj$(=1A|5EkVLAoQos7tO;{_$CAZ5Ex2l2Tlt`h-lKD zDrzVe6geD0O)5qXOCB}b_DO43_vzXp`462It#)rpTT!9iV8u*{AYg=|5WK)~OS;Os ztSo<7(6iGxBBUYx#y_>Y<C#F{<Heo`!l)B1_xsx0t!K~brGmOT=9Ss!mvpO4(ShCe zNMP=<rpb=oulFrX2M5A7B<Yx4@}G*>xuvg2UiN28es&=GUd*>h=OT3Zos?&^Z;`u+ z?7yA4=N|ub*{w(R@7rZ7HRkCs2M7?}HFf9F`0a;BY5ixvLM{RDE=Y?vqTSTmpvUd1 zC$+#<m+^HRr^@9F5?4|Th)*47HgF~f5QpZC8f*oEA^Q-hImf|&)WK|6&s0@1sB8f} zTn>wd3x}`FU$S0bsk~04))m#DB+g)gQFrgUmi;wqf&Thusv$YihsixFC;A>b(b!(G zs3|7S=>j4gRRhXS3*QeR{=~ij+BmxWp#-4)Dej!&ziYq}qo!pmMbH>D%hs&MD>ML{ zkcmu{J|R0eGgT>9hyd_m`o6LY+Lm2y6_E#ObOXOQIU*dNYo9$d8g8%OP}_z`3Kn-) zuPG=+J@E<8pl1{WTu60dzur4I6O@EBhe;O+XvN^!SL9dp*5HguK<Joq16uXg`0#=a zsZj`>x5=UteG9RPNN0OpWgyh9pn-L|0`>c`2}xD4R15YC`R6{n2e6^Df;$FG-GNIz z<;=TF9~}Kk`-R!)rsJ`ex7o3!1c!>zKE)JGNHeE{qk(}sqZD}N^mKGVnmg_BS>akr zX3KaeHUhG)s8<TLA3qc`r=b_Oycie^G|fE0vP;uZN>-=SIhl*{(~jxzfH-WQ8t{(L zXw2nz_*w0%qzEzVpZf=unDxdj8=Db`p)^Eb<EqHc0!Ei1eY<W9g9pIngrRIT8MU0z zq-_m_TG9H&15l8kuc_r~)^j;20w=;->)Ke5&$X=Mxq<!;P1klN%4}w0o4S}<mbr0R z`jWMtin&j>qr{e!khxFW92r-e<Xn-wKa)4*m88(!c)e&hgb85*s$wVt00x9AJE2f; zPbsq~I|RhC9zyA)dWFV%G&HA!N9rz6mI%lvKA5ey!E}U#sVMUngck;hL-i5}0y~W~ zPYaFS=}*<xYuqrJ>84?{g_m4Lojt6xx?Eyge!kOLT?&v<MW$Xl9iFfl+x%WF*q^Z- zV1qH&Rmi6%-m;A8X6H|L_KBWIEr;i|I<Cv4>p49?+%qs4@A=w7CK_K<RQh(e#1=+l z^AiEb^J0r=vefyQGxAXFj{MRR)vikqv)Z(c0aHw$HNRMael6Pu`hp--KfN&CvU@L6 zFV`|UX5N1km#s7Hj96;BXC~%PcJ@%a6QoBPURZ>51j!TFJ!q`X?r#z+O0sk;(}?Ca zsJg7FuC77JpAQ_iDcY1&ZE9KqCRWJ@gM5i?6<2My@LrU!5>2ti>0p?~<oqWnf)gck zn0snxUa!D6IrmqmJ2}OT*9+y9LqAaUKxv8;<3Nq7Hh_GylrF_e%^Y}U0Pp~nH2P7( z{!qQxGY}5My@D>oGB&WgbCvP#u<72iYLhXD(CVq+fINZf*I8z9qRwaxrlke@Lh(~4 z7G9Shdn{(v*Hu(Lx9d3fwA$<$dNS5|=i=e{PMv{`E&WW~4!4~tYG*P7URB}JY%cSY z@>01m5@McTda?7}`Nh%rlrJ0=O$%R{n>)lDQ$4u!^5YnD>652<F=Y;8zMuTmKg5iT z_(z*!Ten2oupn#8%d&KtEVFOVVE^u(E$eHnMkG^nz?PQ+YEZvFkeip{Z*KOl-=OX9 zAGqnJejQ(I=WV%Mb5q9#t~f1~Qwbcl7FBVV2ADrp_v#zB6JYCmt}MwKYWXLr@UWFD zah}A?tfUD0KgIARr>cjHtlR=dl)WBPMY-%?wxMMLwd2$^Jk}u0I_&0{9K51{a}+}# zEX$c(4REGK41gDyw(LCoM&UTH2-VaoL_Hg=`S?x8<Y2o=O(SvEz~G*Yr?Yd8*$^og z%#x@JUAh3|yvJL-X<)Y_GHQYH3_A8U*G|`q{S{j!=tyyHae6keGZ1WDr4>po4m-=Y z&AN9UtE~;f`*p;uYJ--ZU7aRy<vPI!@cUq3z`HOIv$Gj8%YR`e3OwCFR17+PD|W=g zB7!)th`~;e>N}To9-G%B`oP`dGPR>W;#lX2S@6l6czq#Y(s>=~ftN$F$-DhO<pn>_ zc176k5ra44xDc6c*?#d5(>*tLs?SDOWzQ!@{^681NXQuZE|8oD4)_nQ-#^^DH40XN zvSNMao}uj^m58iG)tKA9y0QR`?T5L+aKn0j+ZI0LE9M6coYTYwLAmJSoZGmTrgZ{0 z*rw@Vh)|j?^wn-s%3GPC6;h!DewBm^bseaXD4{_5url6$MLS<(4<rR)h#Xic2nQ5F zD4|GZR)MtxHm{-z75FOb^`JXs(ZUKX2bAp_b^^*O^bi?%@Ch3qC9QO!=jk-y`_w3a z8%i;yN6;ogbO;&>YCb4#g6a#wa8E1-5&}~oT40(gc6UbVT41@eJf{bR)Y5Oltr{l1 zuo%x;b)qFWX#ChFR!_mON25=0i$F75n!JqlxP1QfVfP4sgw{G|Wx=Vu&=-wQE$H>0 z^jix{JGeHjv9ssBsmGcYBL>#D^jK<Ic(ErqTG+p_C^*w(xoBculGpIYI*Ua_v{<K_ z{p16`=omaGFHN^B3{MAMM(c~|g~6D7oYkC>w^e8ap}cncnJQ`Vbms|Hu&vL8ves$? zGt9PM?HyHrbm=yyFJbF{q&^33b~m}jUki`J@2zU6v6U2C%=u}Ws+?>cXG-M}pLB7c ze`S!;&(LVg0W#pxr2gt$D;Y|xd}`BUc9ki;s(qJ(YpKMuaw<K_RO+!kVrMK#6rj@u z>7sPLm?Nc>oz4|)8?LzfN>&ro$et67(|VJ9Zg?Ro>I-_SJefKZDukm!ZLNFDn)XwY zG?AWu#C)nwD@I}&86nYQ#+W@QpZP_s?9NUT7Bn;Zrv2XeXzcCjMY9-tCEh$JI1D_v z`Cly(Jv(F7j4do$rRZroMx&SCQNIcsyp=qT8eWP)D{KLlvAkfFK2_jZx4o*eFk6dI z2^cM`)?$mrD%GXb)t8r7pi&@(_pjzHMQgdBnh!cOr6p@w5MeP)<?`qy+ihdD&;WU2 zL!(R;2{!vHfy))cc_ms|c|B;55~j|BQKHh+aM;(>RQF}U%LQK|Rex}U6zDR#a?mj@ zFRcMHJr#EsE1Y$!zZG-03O*2L`{I)WAnBQSbt2+wC=hg+frV#Ahx~`m^$Do25#7h7 zGfqpeWv_l*UWkig3q0C!XTi4AG=5CS)K-+dXEU+lQmg!4Q1lLjI|b83EFO*c<{psW zsqKniIGX8^tTEBIINrmE^7+G2>Fb~UVsviG+#YO+432=d<kDVLYf#2LtNL>(I(Vax z`dbxmG&|hh3f@a#uS)f4scLqeuQ7jBHmTwp(s;(v0G>pxz%dri<t*YnO=e92x5mq= zP|mK&;AyM#b;+Tp)&$}jP)vwk(b%z~nUe91q+0sau;aO;R$6yGSG3%L5rrFpLVFq> zbkgQ$kZg)1r@Iys4)kT^X+*SY=|+Tr70f^?^OzVmo2D1)nV0mrIZs6`c@^86(l@46 zrout%+ld`22VLOJx!L{s#+pJmSM=aVhsK+<LYg3;Kx=nY0)e!o&z<FG>IPET|5_S4 zG-Wq2ng6bDkb3iU(%@-NG&VXjP_1YFZRw+oT3yz`_A$qJ{LtiaY2kGc+yxNRm7+|= z@6B}72QI(F$Ave@Ao&?;Wrl|Qdp7lSq1jDSW0?&l#TjYaTfE4kXt&>((!F(SH@ZZ$ zwYIjE*tE8?0oW1i!>yrp+*)3>iI<8Bjhw2if*(Y~FO-YI$mi4&*R})c>>6%Edt0TZ z+uz4*yV|)Ep;{Wyr>wflsz{jm2~!`>EH{K)$wj_w`!6q-Yo;wZYg#h2QUMJmj0(7U zpcG230cDCXSw*n<uxaRNmM9U1YKBn=^e%RpgnFV@KaC43&L_MBn$hPo6~ls-4^VPL zmZ`x~F|{D<>+uV>Y0v|$w}G{pP#B5U;)21TDcr>jn+l^|qo7LzF|<zHZr66Cr%vSt zdMFhNs_C4u);znt>{XxF67(VbU=;hDixVTetvcpwlLNt1%n|!(tJEp5Sxax=sz;Wd zrp{;-WCiz+49cL=&D_ZR&|NE!WINkK;m8xQ_V;Ng9n``gzrS=(XM59B907~dixU8i zo|4^?*|Z7K=73HL`m9n6tn<N<XbchovL8OIJqq;Kv;GbR{YC3E3(X)h)lg!3rcOe$ zFHkiba#F;K3Q?b>t$+$d^{GCq(d%tom9M32;aZ-s9NI1C=kvu*rU2!`%ZgAz;9eU% z{!5d5ZTuiP%j7z6v3xcU^F@gWpa>B>$Y(K~z;Pp1k0*I$=0FFIf+*wwYnW)zINjcK zCfuU-=tUhEvb_~?IL;V+tt5`t)*eq0gH~NgFlM+{!|bPBU#vC|P6S5#bmq=U3oo%h zUmDV~($YU@ZC=R{5j*9F?vEis{|4iHXdv3x84IZ@Fa3;pPqr8jhg+mzytB_b*%zA@ zLr4?H97yiOUz0zM^-RTmu-`ED+OCx2geOPIMO4imJLbRhhCPw44v_y!H7LZ^Wda^~ zD>?(*fCbg+b<|5@u^~&#t1QK7JHe||Xf7;D*}re!et)w+kg_w@yKP%<aBa$sH|{`l z7elroM;pK6j<|iC*}ZZZCOeB>!=IOIm$n?*zjo=Zu;;F^=#*EkEX89hm*TO+QpCDL zSs}H}vFp?QpFWXWq;|pU#@b_R)UXU_p(I_BF4~iYmfJM*)bxXUPE%+~>LpXa)~AJf zMTsO5H1O2FU=;<U)b#O(5$s)kgKzAN2*!v}v^peU?46syqlBhsb-th|={*;k_q^2R zR{u+;ajp-qMjR%O)uuC9P@#=Lu1DGxYI9r01hL5@E!y-EqY0H}F^6P|>cSxXuk(S( zi%z*M+#WT>>{fw$1v(&T+-rmHAh7Q*rE;twdZ%M8TfaIGm4Z*n=f$XRa+t|_C}1^9 z5kaT!{N$;;F6OASMxMzy;^?~&^@#FoA*NIQsNEI|oA(ZG8VuNCa6mINL1r>k;|WRD zs2mMMXZsv=fpbx9$ME9djL;eOO?G<1K2-J$w=Be>^Rd~!cu3h(1^$Az7vB1_K-E*G z&(s|^Y}rgX<?2xS2%wvW@7>nj*|EN5UC_0<)S8=}iVA<N+vRdcHfuKnq1fm{+uG`N zEUZFZCQ~V9FcrwRtzO<*X_%M(P=pPYkd^CrSxH}&lxx)W)qQsL^@1{*B6YT&hVy{( zEJxu5>~~tK!J^25`gV#;ARdG7PH_QOsBry5nM0LRZ@wAqidgxG(?Ch{8g*E&_r;o| z?k_|oQ93S+Akr@Q%M5xCBHd!}l+C2K8I4U+*brHebds^VtEuq5##WQQA}HF7BK*FN ziuhRfd4&7LilVa2GE<p*R5Arkr@Ia}ZqRvV2g1f#)d!*Arkx`(wsxs&MvC}Mz>Qd* zAG*~SHrZo7t^F5~jykav1^cw$gI!{b@32Q@!M4yo><FVvUjzz0X5THTa+lC7ge6PA z5JhiGS#7o}0^4cv@n~e)CZqt<xIfiXCpx6g*D%NNPwv%Zq>Nz)|2pg@x`TUn_3qg2 zL3`Ocz&1gcpB3BYt*r(K5n5bVDOOgc&~76get*YJ{Z|g_xrR1wkgVED7+rF5X~s`6 zRlzX4{Ig81dFA(Oa(;g{!%01$yUv!3LcxqgkY3r1Q7VrT3fcgqnZs(Pc_GC)!!FHd zrcl+bO76T4U{I-_-^{5ptPa6gXEzGssLAMQ3YbiO%|oD|&l_0NR_BY_cw^h3Q4-C% zh!wpITa1n~lIBRJekh|L7>|J09Z^zWFfJ6kYYTNEQqmT)Fd?3Eh<WvqV$ts&62W&V z^z`365fhuhAay<(4A{JZ5c8*{-)1+c8!nCQ5t>fDwrhUza1dQ)n`6<*=(IQzJR3CI z*n5^fm!fa=m}1WbLT|^M?Sl)yi}&8LI}o(>HC6^%v9<>VdxU*!>2BsA<34>Ry0>X> z6f-({`8V9xfWVHBZ}=n3=FR>s>q7zG8b@tau@zyOh|g77m}x81c5d9TVPiAj-j>E& zINoE)=hy21Qq<^KMw44@*R-r_%U{Kq(6u#}F)(IiXpo>Oyt;BJ?>o?vm}KhAQG+WH zaihVVL}qtoLyk|)Y;sl$$>x>XeKXbWw!Heh#H=ESPgieAdBPphAjk?2J|C6uh|S}9 zluc1Hik4YX7#38zmHIPu#cF82hMn+47CPI~8ZxqMYkA6>VUNsNLJKE5<B?7ekctzl z+zZi1?2;rJd>&~uOoJj4a=z#g;A!)x#B`wcDvCtMjCZQ-?g!<;Sd;afsMRvP@*@RP z%xC1;V6@%YF6go2!)MkB5#Kphhp1--lDDBgZxpyo+Oygl>oA$_m>9RBB6mm#2EO+# z*;v72frge|bxFZ(zg{{r-qfLZke4)^2|Q5i$X36FX=(9?3@#_==`zxqOANXU#HcvX zba_<u>Z=fWtTHSzMMo|VadLD^NXyF6ZBh146kme~Hai!0^$Hy!4A)$w$cYlzPyx*3 zXrP^YU1iyz%b~s>iq+Q8-ITtODty3&Uz*m{TGX1=_H-|bpg*7a#a%4B$Fn4-Ib)R> zPQ6-fgSX*xj(zcQfjc4WuWHv@$}Av-)tVbN-;|<#U%vefd1~T+$s-S4I{zZauxI}1 z@uiOo8|vJfnfX5*KVI`ECcW{*ptXT1+%aTyoM!Sb{hrxU!LZNB<}!{cmVcg}VmD@s z#l8S~doiw0^4L+-fv89m>Oj<LKZivCS`ZbXbTbKgRq8;fq+Ts_P_G;uwK6z*tDYT| z&!@Wn<1L*9C)tnr$isZJkPg3z35EQvrReVIsH@FL^Os^mxCSF*NPa<0a=Tidgk=}d zKte0OD5QK5%73#kjyfB`~tR}3rl`v~#_PFFVY3UGTc73iK#%bGAj*(!=XL>F?r zQz@R$WxjKrX>itimYDzg|2q#=7611Wf${3r4yne{Ea+dq$6wAA75Ob$1^HPSER&U@ zRdakQdPL^t=9vo-S>`p`Ja9Uwm-mXAEA8nMA&pPR=93bwCPgd9vPc<A4RitJ#Xy9p z87y=(_ybMBu&eT{-7XMN+%RvoV;j_O(}|L8n-g>oLCKgR?Wz#`2jU)y$-PX<BvEgT zr0u<DSaO`1GlYXC5r56}|I^ADy8e~hKmVgOcV}kf?}<u>CkT0FvYTCgy!^o@d0?k# z!|(8qlusz1$!Pl|kC2S{%O6noisbY3Ly3O_w6uW!Q$3itsdWsiHj%jI6%yyI<U}es zGE*cH2bazQcZ`hUwx4^648RMUQ<alZ)o(}-eH30JQT`$sP|uS&ews}4ACe}Gi}dh| zB#Lw0z|WBZO&iYZBD+;><Sx|^nbW*TMl~PdxfjU@_Zu>h`Vxty){wZihD@a5y{JtZ z&}NXh@G+UgD(+45khuCB8Pt@K@zf(^LW}p{Z#tFwO){OHM`rNe(X<(Srijc47fDq6 zb25+?#Cbj-$1~<}&Mq>IbB^M5dY*3BuXFTK^${6OExP;x#$cLzoSeip9_9sHS2H=p z>&OJxOHT10ld$GNGOF$&Ginbh(fl08(_|*KmxS=z1YR4!-zsU!Ne|aWW;hpK{}9h3 zqs3!v5Pyo|yc3!)U|dCI97k2(WL$JS@%`PZdzJB@UY-kOQWAGZ@v!2?Jb{4x7$NF+ z2ob8$sq-yD(7%vm@PuSG5~ABjh#u`;vI}whCqfK(e~zD!Ts)um5h12JLRP&`NP$d9 zk(Ut5|0JY%fsj%QA!QJ(@;?w#@hl-CK3Dl1AyvO1Wc7JMs!?kp9VeurlMola*HcVL zV+J8juM!eiN66YA5)%5DkhZT86260w4v;l%L`pC6uY}w%OGtMbA+Z|?x$&!n>=X#u z6((f&SwaR-zCYw9WEj`C|3`$3ex8s6?-Me9Cm}cEJ8!}FAL=D!0-u>UOvvFM5OV7` z37N#>?H>{n$9ax55HdAK$ldtdbQvMX@pz(-ko)mCbCi$=A0^~u79pR*`%ZNdGIx-W zhd&_XivxuG70&tSe-ZK}{0(2OAmj=B4Nv0l{>poVEa17PZYJbuT%&TsxIBIJMwiYY zd7W^0q*)Sy_(=+mzQN%9%EB@-xSHg@T7tls@{b_~pz0F;Sk&Lqchi3;5F`tUL!!p< zeaT}Em9jri9`huNF(i*Q#DMcB7BErHo;YT36&=avS)w7s$zv6se>8cl#_`eQF-J<s z3&~@ifPgT0oH)OVFlsHnkzRk|IC1@n<HYqRjuY3PI8I!D;y7{riQ~leCytf#xAu?p zAKZ0w|4o*@BbLzU$jzgJ2X~DP^&hk}R7)^b_mJIWi0r~3-9#)ffU0r77GU9h_}N27 z$T$YaLL}nBk9+M<|E@7hXwSiZyl05?<8xzpHH3E_B>j>8!CUt2I*60@W8QAT32@rK z{E@%>YR9hK2S@k!-?V4fpIy1dQ3FTV<5sQ}-;FP$SAP&+If0`F-0ZkHNDZ#N7Wd0n zf6c`wFa1-0&K7b6e^x&v?l1ov#LEocrGhkZ*cUXAP%Y*?m86k$$XzBXWc4JAWJA_+ zP_LQ?e7}jTBKfGNGGnhU!UbAMF{Gmu{msirIjJBbsU%exayurX1{W@oI@AO-;16-4 zHqDJc!wV+wMxbq*NHf+$0D1hi_`_Q;39Y0Jc+xOgj}BBFq?2qUU1SqxV>8)8Za|D` zE9oZNNQ`U;i^mSqgPupd7_KY-{H9FcO4HNR(9|de4Jy@YfOcWY;g9^xB6IofmZ5e3 a+yCF-xe%%PhM>XyGaQHaKcms${{I6J08oYi literal 0 HcmV?d00001 diff --git a/examples/runtime/font/five_minutes.otf b/examples/runtime/font/five_minutes.otf new file mode 100644 index 0000000000000000000000000000000000000000..dee9aa7dbb61d3ea7be72fd4799f70b56f235e22 GIT binary patch literal 27156 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 literal 0 HcmV?d00001 diff --git a/examples/runtime/font/mias_scribblings.ttf b/examples/runtime/font/mias_scribblings.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c61802cc0221978acbbef35ba5a07bec532967ab GIT binary patch literal 102032 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 literal 0 HcmV?d00001 diff --git a/examples/runtime/font/ruritania.ttf b/examples/runtime/font/ruritania.ttf new file mode 100644 index 0000000000000000000000000000000000000000..32b494ef7b02ca57045ff44d9fdc92047ff883b9 GIT binary patch literal 126500 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 literal 0 HcmV?d00001 diff --git a/examples/runtime/font/signika-regular.ttf b/examples/runtime/font/signika-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5845c93d2978a87ae054777e90d5f6ef6059e2aa GIT binary patch literal 141132 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 Z$RnS}1)zDX| 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 =+_cjI#5}fnX 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 Pn#XP$9-KQDy!rnDQ9+AO literal 0 HcmV?d00001 diff --git a/examples/runtime/font/visitor1.ttf b/examples/runtime/font/visitor1.ttf new file mode 100644 index 0000000000000000000000000000000000000000..04ce123d4bbfbe14c4e60982181804b847a96025 GIT binary patch literal 27552 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 Ps8Xvx0u{mUV6OhZx}kpw literal 0 HcmV?d00001 From 043a0623469612f3604462913506d7f68121a12f Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:53:21 +0200 Subject: [PATCH 27/38] fix bug of bleeding styled text --- examples/common/font/font_manager.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 7e5adf85..12972c13 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -465,23 +465,16 @@ void FontManager::init() m_cachedFonts = new CachedFont[MAX_OPENED_FONT]; m_buffer = new uint8_t[MAX_FONT_BUFFER_SIZE]; + const uint32_t W = 3; // Create filler rectangle - uint8_t buffer[4*4*4]; - memset( buffer, 255, 4 * 4 * 4); + uint8_t buffer[W*W*4]; + memset( buffer, 255, W * W * 4); - m_blackGlyph.m_width=3; - m_blackGlyph.m_height=3; - bool addResult = addBitmap(m_blackGlyph, buffer); - BX_UNUSED(addResult); - BX_CHECK( addResult , "unable to add white glyph" ); - //make sure the black glyph doesn't bleed - - /*int16_t texUnit = 65535 / m_textureWidth; - m_blackGlyph.texture_x0 += texUnit; - m_blackGlyph.texture_y0 += texUnit; - m_blackGlyph.texture_x1 -= texUnit; - m_blackGlyph.texture_y1 -= texUnit;*/ - + m_blackGlyph.m_width = W; + m_blackGlyph.m_height = W; + + ///make sure the black glyph doesn't bleed by using a one pixel inner outline + m_blackGlyph.m_regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1 ); } FontManager::~FontManager() From 4ca2b3f4afc1ae4418a4f4348c725ecc6305d297 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:53:47 +0200 Subject: [PATCH 28/38] move shaders to embedded shader system --- examples/common/font/makefile | 17 +-- examples/common/font/text_buffer_manager.cpp | 134 +++++++++++-------- examples/common/font/text_buffer_manager.h | 5 - 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/examples/common/font/makefile b/examples/common/font/makefile index c9953f66..61c359c4 100644 --- a/examples/common/font/makefile +++ b/examples/common/font/makefile @@ -1,20 +1,9 @@ # -# Copyright 2013 Roy Jeremie. All rights reserved. +# Copyright 2011-2013 Branimir Karadzic. All rights reserved. # License: http://www.opensource.org/licenses/BSD-2-Clause # -BGFX_DIR=../../.. -RUNTIME_DIR=$(BGFX_DIR)/examples/runtime -BUILD_DIR=../../../.build - -# include $(BGFX_DIR)/premake/shader-embeded.mk -include $(BGFX_DIR)/premake/shader.mk +include ../../../premake/shader-embeded.mk rebuild: -# @make -s --no-print-directory clean all - @make -s --no-print-directory TARGET=0 clean all - @make -s --no-print-directory TARGET=1 clean all - @make -s --no-print-directory TARGET=2 clean all - @make -s --no-print-directory TARGET=3 clean all - @make -s --no-print-directory TARGET=4 clean all - + @make -s --no-print-directory clean all diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 2e391f31..711ed0bd 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -10,6 +10,14 @@ #include <math.h> #include <stddef.h> /* offsetof */ +#include "vs_font_basic.bin.h" +#include "fs_font_basic.bin.h" +#include "vs_font_distance_field.bin.h" +#include "fs_font_distance_field.bin.h" +#include "vs_font_distance_field_subpixel.bin.h" +#include "fs_font_distance_field_subpixel.bin.h" + + #define MAX_TEXT_BUFFER_COUNT 64 #define MAX_BUFFERED_CHARACTERS 8192 @@ -479,6 +487,73 @@ void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) { m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT]; + + const bgfx::Memory* vs_font_basic; + const bgfx::Memory* fs_font_basic; + const bgfx::Memory* vs_font_distance_field; + const bgfx::Memory* fs_font_distance_field; + const bgfx::Memory* vs_font_distance_field_subpixel; + const bgfx::Memory* fs_font_distance_field_subpixel; + + switch (bgfx::getRendererType() ) + { + case bgfx::RendererType::Direct3D9: + vs_font_basic = bgfx::makeRef(vs_font_basic_dx9, sizeof(vs_font_basic_dx9) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_dx9, sizeof(fs_font_basic_dx9) ); + vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx9, sizeof(vs_font_distance_field_dx9) ); + fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx9, sizeof(fs_font_distance_field_dx9) ); + vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx9, sizeof(vs_font_distance_field_subpixel_dx9) ); + fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx9, sizeof(fs_font_distance_field_subpixel_dx9) ); + break; + + case bgfx::RendererType::Direct3D11: + vs_font_basic = bgfx::makeRef(vs_font_basic_dx11, sizeof(vs_font_basic_dx11) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_dx11, sizeof(fs_font_basic_dx11) ); + vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx11, sizeof(vs_font_distance_field_dx11) ); + fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx11, sizeof(fs_font_distance_field_dx11) ); + vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx11, sizeof(vs_font_distance_field_subpixel_dx11) ); + fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx11, sizeof(fs_font_distance_field_subpixel_dx11) ); + break; + + default: + vs_font_basic = bgfx::makeRef(vs_font_basic_glsl, sizeof(vs_font_basic_glsl) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_glsl, sizeof(fs_font_basic_glsl) ); + vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_glsl, sizeof(vs_font_distance_field_glsl) ); + fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_glsl, sizeof(fs_font_distance_field_glsl) ); + vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_glsl, sizeof(vs_font_distance_field_subpixel_glsl) ); + fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_glsl, sizeof(fs_font_distance_field_subpixel_glsl) ); + break; + } + + bgfx::VertexShaderHandle vsh; + bgfx::FragmentShaderHandle fsh; + + vsh = bgfx::createVertexShader(vs_font_basic); + fsh = bgfx::createFragmentShader(fs_font_basic); + m_basicProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + vsh = bgfx::createVertexShader(vs_font_distance_field); + fsh = bgfx::createFragmentShader(fs_font_distance_field); + m_distanceProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + vsh = bgfx::createVertexShader(vs_font_distance_field_subpixel); + fsh = bgfx::createFragmentShader(fs_font_distance_field_subpixel); + m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); + bgfx::destroyVertexShader(vsh); + bgfx::destroyFragmentShader(fsh); + + m_vertexDecl.begin(); + m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); + m_vertexDecl.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true); + m_vertexDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); + m_vertexDecl.end(); + + u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); + u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); } TextBufferManager::~TextBufferManager() @@ -489,64 +564,11 @@ TextBufferManager::~TextBufferManager() bgfx::destroyUniform(u_texColor); bgfx::destroyUniform(u_inverse_gamma); - //bgfx::destroyProgram(m_basicProgram); - //bgfx::destroyProgram(m_distanceProgram); - //bgfx::destroyProgram(m_distanceSubpixelProgram); + bgfx::destroyProgram(m_basicProgram); + bgfx::destroyProgram(m_distanceProgram); + bgfx::destroyProgram(m_distanceSubpixelProgram); } -void TextBufferManager::init(bgfx::ProgramHandle _basicProgram, bgfx::ProgramHandle _distanceProgram, bgfx::ProgramHandle _distanceSubpixelProgram) -{ - m_basicProgram = _basicProgram; - m_distanceProgram = _distanceProgram; - m_distanceSubpixelProgram = _distanceSubpixelProgram; - - m_vertexDecl.begin(); - m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); - m_vertexDecl.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true); - m_vertexDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); - m_vertexDecl.end(); - - u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); - u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); -} -/* -void TextBufferManager::init(const char* _shaderPath) -{ - m_vertexDecl.begin(); - m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); - m_vertexDecl.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true); - m_vertexDecl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true); - m_vertexDecl.end(); - - u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv); - u_inverse_gamma = bgfx::createUniform("u_inverse_gamma", bgfx::UniformType::Uniform1f); - - const bgfx::Memory* mem; - mem = loadShader(_shaderPath, "vs_font_basic"); - bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); - mem = loadShader(_shaderPath, "fs_font_basic"); - bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); - m_basicProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - - mem = loadShader(_shaderPath, "vs_font_distance_field"); - vsh = bgfx::createVertexShader(mem); - mem = loadShader(_shaderPath, "fs_font_distance_field"); - fsh = bgfx::createFragmentShader(mem); - m_distanceProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - - mem = loadShader(_shaderPath, "vs_font_distance_field_subpixel"); - vsh = bgfx::createVertexShader(mem); - mem = loadShader(_shaderPath, "fs_font_distance_field_subpixel"); - fsh = bgfx::createFragmentShader(mem); - m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); -}*/ - TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType _bufferType) { uint16_t textIdx = m_textBufferHandles.alloc(); diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 662974e2..57dc818f 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -31,11 +31,6 @@ public: TextBufferManager(FontManager* _fontManager = NULL); ~TextBufferManager(); - //shaders program - - void init(bgfx::ProgramHandle _basicProgram, bgfx::ProgramHandle _distanceProgram, bgfx::ProgramHandle _distanceSubpixelProgram); - //void init(const char* _shaderPath); - TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); void destroyTextBuffer(TextBufferHandle _handle); void submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth = 0); From d1a128d62acea02ef62fec447ba6816bb9959385 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:54:33 +0200 Subject: [PATCH 29/38] remove compiled shaders in favor of embedded one --- examples/runtime/shaders/dx11/fs_font_basic.bin | Bin 898 -> 0 bytes .../shaders/dx11/fs_font_distance_field.bin | Bin 1366 -> 0 bytes .../dx11/fs_font_distance_field_subpixel.bin | Bin 1622 -> 0 bytes examples/runtime/shaders/dx9/fs_font_basic.bin | Bin 445 -> 0 bytes .../shaders/dx9/fs_font_distance_field.bin | Bin 737 -> 0 bytes .../dx9/fs_font_distance_field_subpixel.bin | Bin 885 -> 0 bytes examples/runtime/shaders/gles/fs_font_basic.bin | Bin 389 -> 0 bytes .../shaders/gles/fs_font_distance_field.bin | Bin 773 -> 0 bytes .../gles/fs_font_distance_field_subpixel.bin | Bin 1119 -> 0 bytes examples/runtime/shaders/glsl/fs_font_basic.bin | Bin 350 -> 0 bytes .../shaders/glsl/fs_font_distance_field.bin | Bin 734 -> 0 bytes .../glsl/fs_font_distance_field_subpixel.bin | Bin 1080 -> 0 bytes 12 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/runtime/shaders/dx11/fs_font_basic.bin delete mode 100644 examples/runtime/shaders/dx11/fs_font_distance_field.bin delete mode 100644 examples/runtime/shaders/dx11/fs_font_distance_field_subpixel.bin delete mode 100644 examples/runtime/shaders/dx9/fs_font_basic.bin delete mode 100644 examples/runtime/shaders/dx9/fs_font_distance_field.bin delete mode 100644 examples/runtime/shaders/dx9/fs_font_distance_field_subpixel.bin delete mode 100644 examples/runtime/shaders/gles/fs_font_basic.bin delete mode 100644 examples/runtime/shaders/gles/fs_font_distance_field.bin delete mode 100644 examples/runtime/shaders/gles/fs_font_distance_field_subpixel.bin delete mode 100644 examples/runtime/shaders/glsl/fs_font_basic.bin delete mode 100644 examples/runtime/shaders/glsl/fs_font_distance_field.bin delete mode 100644 examples/runtime/shaders/glsl/fs_font_distance_field_subpixel.bin diff --git a/examples/runtime/shaders/dx11/fs_font_basic.bin b/examples/runtime/shaders/dx11/fs_font_basic.bin deleted file mode 100644 index 9c8e68466f98f818055d4bf2b6dfcb212b547ba3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 898 zcma)3Jxjw-6uq^TR#B`4LC_(if)ranunxAGenM?DFG>-?uSQyEO^Fqpr05^e&B@WF zt2p>?#KleN;9Ad3@<36+3n%yH+<WdjFUg9$&v(^*CZe7PBqu8Vba_ops=-ijbN7C{ z@bWSC_VnmOui_`_N1g}X`5ojf@Y+YDr!(0Ha56yAB)<fDJ-Q)kqud3s;z#gq#tFbW zK4SprA&{KjF!I@6%RE=Dx@C)lMze0(Ul_wYZ=KmDt=Eoh>(n}KDO38ik}ry)BB}=! z(^gcg(X2tFB%<*|G_eqm&c$Le>U25<kt@})pS^{E4S<6^Nxvhg*}n|txj%x&p(K%+ z=Q}Vjw)ZwPQ7{TxiBzqq>11Tes;22_>S#D~26McF&r|>zU(du2V^z;(3>X#pw4R3` zg+U!y7$=H2qIS|r-yZ+xcG&iQ*in~fDL_rP-rB<5!sPFU!;Vi`^ZiU{x{5nj#g&<h z<F`e~<(8pg&X>Z2+9@|vast0s&J2398R)vG`CDWot}c7w?vcJm@tLIVc*vW*yC%6~ yi70sK`H>uZ;GK&&)AoA2pScxS6UM61LLCIyYXFe{52X`4`&azdlbp<dY3UOy*<*wN diff --git a/examples/runtime/shaders/dx11/fs_font_distance_field.bin b/examples/runtime/shaders/dx11/fs_font_distance_field.bin deleted file mode 100644 index c1cd8756db8eae8ff11750f4b48968f05362148e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1366 zcma)6O>Yum5FS2@wc3@7Up;I*sWC)Q40y0h7bryRHoIFxj7hC_n>L|BwlwL<5PS5Z z7h|IF4{-6|(SrvQul|L4^Q7Sq;4{1LP;98_gxPs{=9$lTq3YBkk^R8|5e=2X1X4(p zn+xWLPY3S%{bXV1+mBbj%D?jw_zDRkeCRgx4|E;iJLs1<kzKA-KLZnq;xNZw;=>`m zA?o4y7#f2f70%829LjNA;}moVfeCzPV0Tx$-k#ZRwS8x8yVLUgF~s%uy1Twd54N89 z?Va{USHEgs(`yZ<p*x#v>z=Qh?d{GMg7ji0SIiXixy-F>HcS0}zwRt9wUD2COF@^R zEZmdyJBu^-FTyzcXW@7%AS~lN1LMxa)n&`6yLD@cOsiqp<W`!dW!YuwTc~*hJkG&2 zb*RXAP2_M(_F~0FqfV`C&%tSc_#K+RK$H%Gdh>z#=W%lE5x4zB3!<AhDNdd6yt0DX zG>Q#0E$CCuJfDY{fgbWUF*0L!h>|{qST(KnO28PO!Ih5iXz0gtDlJ@vRh2yr{!isg zUetmd%)g?rw^LybvG>8xNiJnkc9efwVV9K6;q{VS;)@uFASx+456-mo2Tm{x6OQr# zrN(lNcv9;u@`yibfK7ZahblboX+iaO7yIVDg|&Ky^mG|>3g^1wRuDJ9ncpMqJcz5l z2=^m*dJa8G+{TRJetb=m1EHx&vx>i<AMR56#ZC}L^q*aR4f{5X!i2k!_(?vg!M>Mz ySV#E08=e*KTEbU8o}00ISefIN+%C@Np}a%<HBk)8zh4pN9w(E0f{8sYmi_{p%zTLe diff --git a/examples/runtime/shaders/dx11/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/dx11/fs_font_distance_field_subpixel.bin deleted file mode 100644 index 8f9fa68bc575f61bc28b9b677443eb0945e63483..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1622 zcma)6O-~bH5T0(K1uV4Iiys&_oRpZxR?*@Cw)BHGB1^hkLW~KbEP(_pSxZ7<Vw#$G z){F7v#hbly^q_x%f1npVnjXB?XZC%kZ3q}Ana;cO@ys*xZnxx=L!sB5??lwq3KK{+ zQdnEa*M3bUKixYXY1LkiH|Xb42(fI0Xc+bm^fz=9&JWNpa8?V&(h+<j1`d<_Fx2hR zJEA6zkD+1cNnvc(=TNTW9;47M1SW`$!yc?Ryu*Bbx9&R|d;7bdKj3k_!^VN{(Zii* ze*Hy#t6^TR-Z0Bc&XVbDZ)|$LnXm8d@1V$>O=V_Nvoo30?Q}X#?RLB3EH3W?pSg`d zSD-A+N%+QbX8t1V=Xe|iPsIt#ex4zY0%vu7#da!g#a^boy<}I(Ew1HlyIP>Ojh;7= z#~9qxgo+II1csZdE*4!7b;^b6<PedC#3%}9E)pe!qUOBR_U-@s9x?4FiJ)}t77fw9 zI@fBLEkWT{A`$T9a|dUh&qGbeRC(JNnK@^0ZAntT`#LXVF>KRPmgcYEdL?H}=bnS_ zhdxIxDSTj!`|$C8-bWM79K%2ii|E_u={ZrjsFYMSMfC6Jnv$VvORp3kneRN-&HWj7 zE2eWkz9r#;zA^60GomlUlVP3R6B*Gd<g-Y=SmDE1%qOs?@L3q(6XXo=L1~ovvP|nd z=F0rDx;LMNzwG%gQRG<HVW+|V7(0et_xuwImuHY3Z^Fta_5t!U8mFW!V0!t|_p*** ze`B%_#CrFpdF6!P;JYFiCv(szxGPu!eh*9XIWF(b>To|E8SU?<WvY3YAMc6ZOSTi> zDKi@u9K`>ZzDkd*Nl{<V7SUGj7c;~;#&~?cEQW<2qOSu=hJ`1x@GGkBPH?4GEZ^&C vG42z@Ow~*B|6EfX=I}Xj+??A$-c@KAiqA!0FTjd0&RN3m$XW8Qx}fGSWDb|D diff --git a/examples/runtime/shaders/dx9/fs_font_basic.bin b/examples/runtime/shaders/dx9/fs_font_basic.bin deleted file mode 100644 index 911d8c15a305afeda1f98113aeac47e334a954dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmXv~y-EW?5dJnf@wD&?TfxIhn~)zY0zzUAB*j_i8L$hY5d)D6Nd(IkTZ=0#w~mc( zU@G53xF_%dT))}Xy&Y!u`<b1+ldP}Q^Y<6<u28l1$L=AyIPUEL$QXhtCOP8?NSW%4 zDnp@yBW76-!^P+^$tU>?ZvnQ*$>-N}K5Px^I2~Wl@_Bx{i1*JA;(nT?advlgGn&Oo zem@;gShQ=+cCCHbthE}A2F`#rATogNvQx)*(;dN;!=cH25MKe^)h<xkBtTCgHO-nj zS5xzfFfswat%%!#m;nZ6n_6!Apf4RCupaQWO9NO#lF#+L;9jGsk-J2*)L!$C4gSuN y(<qe2d*occNKf(g*q8Hhma;%tnhkf4%=Rfd&H1YcL)U|zg8#FEa9y~<S^&S)I#c!l diff --git a/examples/runtime/shaders/dx9/fs_font_distance_field.bin b/examples/runtime/shaders/dx9/fs_font_distance_field.bin deleted file mode 100644 index 786420d654b31178e77f4dfef71f518675c82a86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 737 zcmY*WO=}ZT6g_V;Hd7Y~(yd@{)ow!5;36P2A0S!8g-r(v3PEg&fyjg;g3BjvT}*df zKDY5ln3cc4KOoF6aF<PA&wV#hJ2RJi-?`_WxpU^luy4$lKfi%r5lY_Q`lslfce;-O z3>ktMCOP9XFkm`nlo$pPo-@n!akLzN>Sfbxj_)xl?8&XyY%yw%j`4ExZk{c&t7Yx* z?5Nfs3<tI0`?r_ld99aym`$cETJ@7wz4h#*-fT1)cm+HFst&MiDxIpDJr&#p9G1Nw z#MeN3EqJ7OhnVmMZ$AN|ha^%fmztuM^Pwi^21(V$03So#=foV4x&w0ga1Qn&^kdd3 zU06B5J2q*9_61jtAxGXNoRwA14okP^YTy_YPG{s?d=*WZ>r$8dahD=TQn>x_9@*`u z@R((<3Uhw_W?KuM{M~0m-o}<gPxedg-hcIL)&}LEuQRdKA#^6@%xXKMwSI?cNl*Qf zUihYO5&cq3Ipouylp!9KM324|_x9j_VDC}T06qIR5Bjv?tar-U`3HOdoa#AAs3D&F OJb06oSr@tYMDGA$3xIwA diff --git a/examples/runtime/shaders/dx9/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/dx9/fs_font_distance_field_subpixel.bin deleted file mode 100644 index 38798a5516bcd0991c1f6f8862b765928ee3e47f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 885 zcmYjOu}&L75Pf^+;3EYtQqV-gN|mIrFertkC>Sh76s92Nq)3TmAwmQa(IEp8<)X9{ zM@PA|&PRka`46P~0=hKWytm5*-`(hD-n@A;JNtgLY0UTgJK!Ki>iu8;0)w6PjpqPH zG+~B6#kc^5{4LW`nn8lM{OdUzpYERzilbtJ9}O%pr#C*wC*#%eGPVx)CdEnd^|bx+ z!>jh@a5QX>4tBrnPuhdx+wtKMonB|9*Xg}k>8y6UU2FqSfR+PnpGs>{&8`VI0f%Mo zC-GaLe=9tRxZ*zX@CZ+d|C+vjM_`>6w3dM6DFuM6l+R|Cy1^&s8d=LV0DgwJFNrxI zchAV>$2!=LA>W{%b30Q9c*i8y6Z66&$B?65;!JJi)L8xyw*tqYa<N8nbtz5NeWIvA zle1K%=1QV(+3ZHx2K(~-)T%79%FTz^F#atatD5w&#;GPFhc_k7V9n4&G3?xoFKzCS zy=Ju=jH7nKy!MpDvsvzvv;5xydx4ZN`_<<MUo)w{>g3CsAs6?e{xJvY);!%2!daMR z4Qz`1Cgpx~zM4<W345&5{nR=OtjjMFlwnR}8TE5wzMSo;GXRUkLHlE+ul;LI>QXy* UkrOfDv$1v>;;hd5(tE1?1K?|#NB{r; diff --git a/examples/runtime/shaders/gles/fs_font_basic.bin b/examples/runtime/shaders/gles/fs_font_basic.bin deleted file mode 100644 index 02a1f107dccfa0db8b977f24f4b12bab716cc993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389 zcmZXQO-{ow5QXX1rx>Xlryw^}WfgT*QCP6+5+TbZb~;jGN3Qc%#EO%01x|n+QZ*Gj zkKfEU@6B%iJez&}e9uv3Qo+*;f83MG$`p@iG#oHLRG<nYTtenjXQ*Jg9NS2(Q5jpp zQIu67?Y4fGP;)1{ttpI6NF!{II)_H4YiNRy8e_BgpOS|D@NF=IQlJJJkq-iZ+JP%8 z590TUug`DT1c_2Qp|Tbhux4=tw-B?3C<+6^>Tzl{A*@)}pFE}Ef4f6@CAVJm^id6H qZ{O8c4k_s+=G`<|z(nlSckS!h>f7KWFZj-id^n6JUmSfBa`OxGhJb(o diff --git a/examples/runtime/shaders/gles/fs_font_distance_field.bin b/examples/runtime/shaders/gles/fs_font_distance_field.bin deleted file mode 100644 index cfb5c3ceaf37b93867226852c49da5e342265c74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 773 zcmZuv!ES;;5Up3fViGS)MMOYtVtO*QJ@nRN(-0~PZUQV_LD8nCerbQ9U(gu@U1Pbh zyEE^-o%eS6^3>~n|Nitv9Pt<)pM!@NqfmS$HbUmG7RkDRIF(^JH~Kt}L=2-*+h$a` zh^5M46J|xq)uMXmPz5Eg7c!M<Zfrxf7kL6(zVcy9g_V>la;_>X>ZfBVBFI9K12c_J z13=^@lv#m9!FZ1QZVmTTVvK35_6}~rw;dA(;Mfz>Bmhc#9m>@hTx5urQGG#B?+;fX zPXl>J(EeXgV^SyOYbYO4?9O)Zc5L&ZN*2iySUZVpbr9F2i(fT(rv}f&k9dztJW99| zOz5Cpk`4|I!;aF|+RI?t+$or1TNc*9GP0R5Or@+8Z^C2e^ejCvo1C!^`+E1<CGdta zt*!|pBqHU(Sy?Na7K||#3sZ4AfBmj=ra3hu9lYK)I6es4UX*t<;;Bk`Gn`BNd1&(x dnA^CGC9<rMOwwSf!lZeaNYYM$;$Mbw^9N|+?ymp< diff --git a/examples/runtime/shaders/gles/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/gles/fs_font_distance_field_subpixel.bin deleted file mode 100644 index bc7057e81cdcaf0f780d88b8bf5991918c35ae4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1119 zcmb7D%Wm5+5NxjciUo2Z8;91@mSE%*#Oa~89E(CwElMF^NiHqhl7pW5rTv9`L3j1A z>H1Ja7gF4v8FF@a`SRuF=J)%bTa~3UgXgdD(~Gsya;3JaD&bY-uN%nLRZ=gkTUn+m zgXwfgvv#G*DqX-fDK=}VA9p__?BZHBkJY-;3u~X~R+TyI<;sUW1y)t1Q~N5iqI^28 zR0>6+N?_c2vj9|CLtSi;D0UY3KkngyLX0tkRUF_m_`>FJ2et?}Cjd%&Bg!=xTx3X> zX>&o)w8txuXMnsO)czOb8z3J+%offJzd7D;c!Jw0b<U1Qfq@DTg?`mLEjwG;+1CmD zs}J`hh0nP-w$0(&Xw-M&yil1LDzgu%+<ic0Zm7(A2LgON8}1cgjfU;4FVw{yLjxTW zIutgcw?B2w(yBi3xRa5_<y7~p1n-pKar}taY>CJaibO+p^xbCGA`<O6U_LAo$8(_b zwSR?7b7{v8HZ;Jvr&nNCo=X)Pmx-OeyK%+5B58mXGz4t)D?;4J#9@jN;yQU4ax=~+ z;NTcca0={BBwxo%o#fqA3T$$^3#&<tDl)7dT6_=8?VP4V@(UC8aX+2naLsifrol1l L?Tg%Bmi6f`3JqHa diff --git a/examples/runtime/shaders/glsl/fs_font_basic.bin b/examples/runtime/shaders/glsl/fs_font_basic.bin deleted file mode 100644 index acd2c4b09ea2bd65a668eecfd5d8ea3fb7e40f01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 350 zcmZXQu?~VT5QcT_Q(WTGs%e1eM4U*7yQ47#v63dxk^%)ZPClux;1k#)MvPmpU+=sB z8t%5!>HYbbX{Jgp1-PDrP%ZdbsvOEVFEXZr`pBS;D%J)vlgdXrRvi~9XqK!%TaZYp zPR<`m?0b7H`3drv3%~?j5daqzRC!@Uk?WiKbB2vY7~_$ZHZX@3bqFlLp=&~HLqB@x z@<s-aw%x^8bo8EW%OBhrXzT;EY7@Vz73;Ue-!+%x&8&vdOV>90Pt-%7Bh8{v#cBUB L#{5lmLum2>Vl8vO diff --git a/examples/runtime/shaders/glsl/fs_font_distance_field.bin b/examples/runtime/shaders/glsl/fs_font_distance_field.bin deleted file mode 100644 index b1db0c0e27a8fe4cf5e817404a69bd25f2a95544..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 734 zcmZuv!ES;;5Up3fVv=5VD^dj1CZ;D7(|eCiLr_*i0<2vZ1e>1vrTv9|L1z$fjpf3^ z%zJO<y<NY)j7HzTKlhbThg23Y^<2v;i*zSd4u>e;XF{#Yjes)LqF%{Ns-;y$s!59k zDzOcqqQX{66}vZ;E%noHnZ}SuX#tE|pB6w`Xwdl{iNfg;zxy*hQ;9KVusTP0fWUD% zjKOtgoD%@0{T}5R3?4GX>$tumsGHLb$TvX#8Pxm>+GR2th7Al<fGGClxHug<d??Lg zseyHyc=j+Ir@?O;{Gq|;_z>?|NyLe8!x{bPj--Q&!=$GSjCLK)+nK^Sw&hU`EGL^8 z!&G#sL>nHvq-UFfIpmCUYU<-#pTIlHbh;cKk%*MX7iFW&ZJ1&#Hm2hC{sw*L!f<Lq zIyhbxo-YJ_UX_ou;!vf$8SZ7ge6)E2%xm4o5?R(tCRw;vQPN&aB<Z$5@h{7|`vbJy B;qCwc diff --git a/examples/runtime/shaders/glsl/fs_font_distance_field_subpixel.bin b/examples/runtime/shaders/glsl/fs_font_distance_field_subpixel.bin deleted file mode 100644 index d66589e293bce85f83c08736ca64baacdf07189a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmb7DO>crg5Up2!#U#D#R^9Tc5Ytl=(|eCiL#Uu35!SAVVAE57Y5zihL1*~TwH_L| zurTx9+j%oHe|{PazJ9)M%S3HcnS*7UhOx`jrBoSgqinNI)Z^|gfn8W6)uUWXH8aXc z)oH$hGFiA#QeYvaip`72g7WFNOk>ERGzZ3w4+9|03n;P;5{1?bzxy*hP>3<6v5Gz1 zfh$Z7LokKMIRQ}G=~1@EU?W33kE=6+sy<wR91Y~Op!#2stAShuF;iF*e5QEAt^~VL zTCQbutkBa?9-`2%VyBYER(A4r1b_8m+_Sozi$h)QUwWfniStZlqNz--QW;*MGSyV3 ztpgqw&$@eg*rV<^X&ZHRM_)txg!Y9==<T~ISS*Vpk3H&XY)*Z@NN|n`4#$Uh^^piP zp+Hn*M>}nLF9K1Y0(xPAIGh5FuWc1cyh_Z_!hr_p&r}6Y<*8M^cA3y>ryJjxmqit@ zjFy1)eg%l@nK;~Igt(3#`dp9m5m>keBisVB5m~Lnxr$cJRtg+)x(h2vj5^Z29kh51 g%x;{fpX3)NlwrG_Vt>iCC#KFZn(edPPs6zR1sE?*MgRZ+ From b2e506d7aa04fc3eb6a335a16e2a21eca306ad83 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 19:55:20 +0200 Subject: [PATCH 30/38] better font sample --- examples/10-font/font.cpp | 175 ++++++++++++-------------------------- 1 file changed, 55 insertions(+), 120 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 802ef7af..cfbf84e9 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -12,39 +12,6 @@ #include <stdio.h> #include <string.h> -static const char* s_shaderPath = NULL; -long int fsize(FILE* _file) -{ - long int pos = ftell(_file); - fseek(_file, 0L, SEEK_END); - long int size = ftell(_file); - fseek(_file, pos, SEEK_SET); - return size; -} - -static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shaderName) -{ - char out[512]; - strcpy(out, _shaderPath); - strcat(out, _shaderName); - strcat(out, ".bin"); - - FILE* file = fopen(out, "rb"); - if (NULL != file) - { - uint32_t size = (uint32_t)fsize(file); - const bgfx::Memory* mem = bgfx::alloc(size+1); - /*size_t ignore =*/ fread(mem->data, 1, size, file); - /*BX_UNUSED(ignore);*/ - fclose(file); - mem->data[mem->size-1] = '\0'; - return mem; - } - - return NULL; -} - - int _main_(int /*_argc*/, char** /*_argv*/) { uint32_t width = 1280; @@ -66,121 +33,89 @@ int _main_(int /*_argc*/, char** /*_argv*/) , 1.0f , 0 ); - - // Setup root path for binary shaders. Shader binaries are different - // for each renderer. - switch (bgfx::getRendererType() ) - { - default: - case bgfx::RendererType::Direct3D9: - s_shaderPath = "shaders/dx9/"; - break; - - case bgfx::RendererType::Direct3D11: - s_shaderPath = "shaders/dx11/"; - break; - - case bgfx::RendererType::OpenGL: - s_shaderPath = "shaders/glsl/"; - break; - - case bgfx::RendererType::OpenGLES2: - case bgfx::RendererType::OpenGLES3: - s_shaderPath = "shaders/gles/"; - break; - } - - const bgfx::Memory* mem; - mem = loadShader(s_shaderPath, "vs_font_basic"); - bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); - mem = loadShader(s_shaderPath, "fs_font_basic"); - bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); - bgfx::ProgramHandle _basicProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - - mem = loadShader(s_shaderPath, "vs_font_distance_field"); - vsh = bgfx::createVertexShader(mem); - mem = loadShader(s_shaderPath, "fs_font_distance_field"); - fsh = bgfx::createFragmentShader(mem); - bgfx::ProgramHandle _distanceProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - - mem = loadShader(s_shaderPath, "vs_font_distance_field_subpixel"); - vsh = bgfx::createVertexShader(mem); - mem = loadShader(s_shaderPath, "fs_font_distance_field_subpixel"); - fsh = bgfx::createFragmentShader(mem); - bgfx::ProgramHandle _distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - - + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); - textBufferManager->init(_basicProgram, _distanceProgram, _distanceSubpixelProgram); //load some truetype files - TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); - TrueTypeHandle consola_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/consola.ttf"); + const char* fontNames[7] = { + "font/droidsans.ttf", + "font/chp-fire.ttf", + "font/bleeding_cowboys.ttf", + "font/mias_scribblings.ttf", + "font/ruritania.ttf", + "font/signika-regular.ttf", + "font/five_minutes.otf" + }; - //create some usable font with of a specific size - FontHandle times_24 = fontManager->createFontByPixelSize(times_tt, 0, 24); + const uint32_t fontCount = sizeof(fontNames)/sizeof(const char*); - //preload glyphs and blit them to atlas - fontManager->preloadGlyph(times_24, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); - - //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph - fontManager->unloadTrueType(times_tt); + TrueTypeHandle fontFiles[fontCount]; + FontHandle fonts[fontCount]; + for(int32_t ii = 0; ii<fontCount ; ++ii) + { + //instantiate a usable font + fontFiles[ii] = fontManager->loadTrueTypeFromFile(fontNames[ii]); + fonts[ii] = fontManager->createFontByPixelSize(fontFiles[ii], 0, 32); + //preload glyphs and blit them to atlas + fontManager->preloadGlyph(fonts[ii], L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); + //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph + fontManager->unloadTrueType(fontFiles[ii]); + } + + TrueTypeHandle console_tt = fontManager->loadTrueTypeFromFile("font/visitor1.ttf"); //this font doesn't have any preloaded glyph's but the truetype file is loaded //so glyph will be generated as needed - FontHandle consola_16 = fontManager->createFontByPixelSize(consola_tt, 0, 16); + FontHandle consola_16 = fontManager->createFontByPixelSize(console_tt, 0, 10); //create a static text buffer compatible with alpha font //a static text buffer content cannot be modified after its first submit. TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, STATIC); //the pen position represent the top left of the box of the first line of text - textBufferManager->setPenPosition(staticText, 20.0f, 100.0f); - - //add some text to the buffer - textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); - //the position of the pen is adjusted when there is an endline - + textBufferManager->setPenPosition(staticText, 24.0f, 100.0f); + + for(int32_t ii = 0; ii<fontCount ; ++ii) + { + //add some text to the buffer + textBufferManager->appendText(staticText, fonts[ii], L"The quick brown fox jumps over the lazy dog\n"); + //the position of the pen is adjusted when there is an endline + } + + // Now write some styled text + //setup style colors textBufferManager->setBackgroundColor(staticText, 0x551111FF); textBufferManager->setUnderlineColor(staticText, 0xFF2222FF); textBufferManager->setOverlineColor(staticText, 0x2222FFFF); - textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); - + textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); //text + bkg textBufferManager->setStyle(staticText, STYLE_BACKGROUND); - textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); - + textBufferManager->appendText(staticText, fonts[0], L"The quick "); + //text + strike-through textBufferManager->setStyle(staticText, STYLE_STRIKE_THROUGH); - textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); - + textBufferManager->appendText(staticText, fonts[0], L"brown fox "); + //text + overline textBufferManager->setStyle(staticText, STYLE_OVERLINE); - textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); - + textBufferManager->appendText(staticText, fonts[0], L"jumps over "); + //text + underline textBufferManager->setStyle(staticText, STYLE_UNDERLINE); - textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); - + textBufferManager->appendText(staticText, fonts[0], L"the lazy "); //text + bkg + strike-through textBufferManager->setStyle(staticText, STYLE_BACKGROUND|STYLE_STRIKE_THROUGH); - textBufferManager->appendText(staticText, times_24, L"The quick brown fox jumps over the lazy dog\n"); - + textBufferManager->appendText(staticText, fonts[0], L"dog\n"); + + //create a transient buffer for realtime data TextBufferHandle transientText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, TRANSIENT); - uint32_t w = 0,h = 0; while (!processEvents(width, height, debug, reset) ) { @@ -247,17 +182,17 @@ int _main_(int /*_argc*/, char** /*_argv*/) } - fontManager->unloadTrueType(consola_tt); - fontManager->destroyFont(consola_16); - fontManager->destroyFont(times_24); + fontManager->unloadTrueType(console_tt); + //destroy the fonts + fontManager->destroyFont(consola_16); + for(int32_t ii = 0; ii<fontCount ; ++ii) + { + fontManager->destroyFont(fonts[ii]); + } textBufferManager->destroyTextBuffer(staticText); textBufferManager->destroyTextBuffer(transientText); - bgfx::destroyProgram(_basicProgram); - bgfx::destroyProgram(_distanceProgram); - bgfx::destroyProgram(_distanceSubpixelProgram); - delete textBufferManager; delete fontManager; From 2f89ab16baafe7176378e8b53ffb4c50dc8cf67f Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 8 May 2013 23:55:54 +0200 Subject: [PATCH 31/38] rework the samples --- examples/10-font/font.cpp | 2 +- examples/11-fontsdf/fontsdf.cpp | 183 +++++++------------ examples/common/font/text_buffer_manager.cpp | 31 +++- examples/common/font/text_buffer_manager.h | 10 + 4 files changed, 104 insertions(+), 122 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index cfbf84e9..7cd2006a 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -162,7 +162,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) float view[16]; float proj[16]; - mtxLookAt(view, eye, at); + mtxLookAt(view, eye, at); //setup a top-left ortho matrix for screen space drawing float centering = 0.5f; mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index 7df4aedd..cefab1bc 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -12,39 +12,24 @@ #include <stdio.h> #include <string.h> -static const char* s_shaderPath = NULL; -long int fsize(FILE* _file) +inline void mtxTranslate(float* _result, float x, float y, float z) { - long int pos = ftell(_file); - fseek(_file, 0L, SEEK_END); - long int size = ftell(_file); - fseek(_file, pos, SEEK_SET); - return size; + memset(_result, 0, sizeof(float)*16); + _result[0] = _result[5] = _result[10] = _result[15] = 1.0f; + _result[12] = x; + _result[13] = y; + _result[14] = z; } -static const bgfx::Memory* loadShader(const char* _shaderPath, const char* _shaderName) +inline void mtxScale(float* _result, float x, float y, float z) { - char out[512]; - strcpy(out, _shaderPath); - strcat(out, _shaderName); - strcat(out, ".bin"); - - FILE* file = fopen(out, "rb"); - if (NULL != file) - { - uint32_t size = (uint32_t)fsize(file); - const bgfx::Memory* mem = bgfx::alloc(size+1); - /*size_t ignore =*/ fread(mem->data, 1, size, file); - /*BX_UNUSED(ignore);*/ - fclose(file); - mem->data[mem->size-1] = '\0'; - return mem; - } - - return NULL; + memset(_result, 0, sizeof(float)*16); + _result[0] = x; + _result[5] = y; + _result[10] = z; + _result[15] = 1.0f; } - int _main_(int /*_argc*/, char** /*_argv*/) { uint32_t width = 1280; @@ -68,92 +53,44 @@ int _main_(int /*_argc*/, char** /*_argv*/) , 1.0f , 0 ); - - // Setup root path for binary shaders. Shader binaries are different - // for each renderer. - switch (bgfx::getRendererType() ) - { - default: - case bgfx::RendererType::Direct3D9: - s_shaderPath = "shaders/dx9/"; - break; - - case bgfx::RendererType::Direct3D11: - s_shaderPath = "shaders/dx11/"; - break; - - case bgfx::RendererType::OpenGL: - s_shaderPath = "shaders/glsl/"; - break; - - case bgfx::RendererType::OpenGLES2: - case bgfx::RendererType::OpenGLES3: - s_shaderPath = "shaders/gles/"; - break; - } - - const bgfx::Memory* mem; - mem = loadShader(s_shaderPath, "vs_font_basic"); - bgfx::VertexShaderHandle vsh = bgfx::createVertexShader(mem); - mem = loadShader(s_shaderPath, "fs_font_basic"); - bgfx::FragmentShaderHandle fsh = bgfx::createFragmentShader(mem); - bgfx::ProgramHandle _basicProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - - mem = loadShader(s_shaderPath, "vs_font_distance_field"); - vsh = bgfx::createVertexShader(mem); - mem = loadShader(s_shaderPath, "fs_font_distance_field"); - fsh = bgfx::createFragmentShader(mem); - bgfx::ProgramHandle _distanceProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - mem = loadShader(s_shaderPath, "vs_font_distance_field_subpixel"); - vsh = bgfx::createVertexShader(mem); - mem = loadShader(s_shaderPath, "fs_font_distance_field_subpixel"); - fsh = bgfx::createFragmentShader(mem); - bgfx::ProgramHandle _distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); - bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); - //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); - textBufferManager->init(_basicProgram, _distanceProgram, _distanceSubpixelProgram); //load a truetype files - TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("c:/windows/fonts/times.ttf"); + /* + "font/droidsans.ttf", + "font/chp-fire.ttf", + "font/bleeding_cowboys.ttf", + "font/mias_scribblings.ttf", + "font/ruritania.ttf", + "font/signika-regular.ttf", + "font/five_minutes.otf" + */ + TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("font/bleeding_cowboys.ttf"); + + //create a distance field font FontHandle distance_font = fontManager->createFontByPixelSize(times_tt, 0, 48, FONT_TYPE_DISTANCE); + //create a scalled down version of the same font (without adding anything to the atlas) + FontHandle smaller_font = fontManager->createScaledFontToPixelSize(distance_font, 32); + //preload glyph and generate (generate bitmap's) - fontManager->preloadGlyph(distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ. \n"); + fontManager->preloadGlyph(distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,\" \n"); - uint32_t fontsCount = 0; - FontHandle fonts[64]; - fonts[fontsCount++] = distance_font; - //generate various sub distance field fonts at various size - int32_t step=4; - for(int32_t ii = 64; ii>1 ; ii-=step) - { - if(ii<32) step = 2; - //instantiate a usable font - FontHandle font = fontManager->createScaledFontToPixelSize(distance_font, ii); - fonts[fontsCount++] = font; - } //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph fontManager->unloadTrueType(times_tt); - TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); - - textBufferManager->setPenPosition(staticText, 10.0f, 70.0f); - textBufferManager->setTextColor(staticText, 0xFFFFFFFF); - //textBufferManager->setTextColor(staticText, 0x000000FF); - for(uint32_t ii = 0; ii< fontsCount; ++ii) - { - textBufferManager->appendText(staticText, fonts[ii], L"The quick brown fox jumps over the lazy dog\n"); - //textBufferManager->appendText(staticText, fonts[i], L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); - } - + TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); + textBufferManager->setTextColor(staticText, 0xDD0000FF); + + //textBufferManager->appendText(staticText, distance_font, L"The quick brown fox jumps over the lazy dog\n"); + //textBufferManager->appendText(staticText, distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); + textBufferManager->appendText(staticText, distance_font, L"BGFX "); + textBufferManager->appendText(staticText, smaller_font, L"bgfx"); + + + int64_t timeOffset = bx::getHPCounter(); while (!processEvents(width, height, debug, reset) ) { // Set view 0 default viewport. @@ -169,6 +106,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) last = now; const double freq = double(bx::getHPFrequency() ); const double toMs = 1000.0/freq; + float time = (float)( (now - timeOffset)/double(bx::getHPFrequency() ) ); // Use debug font to print information about this example. bgfx::dbgTextClear(); @@ -178,17 +116,36 @@ int _main_(int /*_argc*/, char** /*_argv*/) float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; - + float view[16]; float proj[16]; - mtxLookAt(view, eye, at); + mtxLookAt(view, eye, at); float centering = 0.5f; //setup a top-left ortho matrix for screen space drawing - mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); - + mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + // Set view and projection matrix for view 0. - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, proj); + TextRectangle rect = textBufferManager->getRectangle(staticText); + + float mtxA[16]; + float mtxB[16]; + float mtxC[16]; + mtxRotateZ(mtxA, time*0.37f); + mtxTranslate(mtxB, -(rect.width*0.5f), -(rect.height*0.5f), 0); + mtxMul(mtxC, mtxB, mtxA); + + float scale=4.1f+4.0f*sinf(time); + mtxScale(mtxA, scale, scale, 1.0f); + mtxMul(mtxB, mtxC, mtxA); + + mtxTranslate(mtxC, ((width)*0.5f), ((height)*0.5f), 0); + mtxMul(mtxA, mtxB, mtxC); + + // Set model matrix for rendering. + bgfx::setTransform(mtxA); + //draw your text textBufferManager->submitTextBuffer(staticText, 0); @@ -197,17 +154,11 @@ int _main_(int /*_argc*/, char** /*_argv*/) bgfx::frame(); } - //destroy the fonts - for(uint32_t ii=0; ii<fontsCount;++ii) - { - fontManager->destroyFont(fonts[ii]); - } + //destroy the fonts + fontManager->destroyFont(distance_font); + fontManager->destroyFont(smaller_font); - textBufferManager->destroyTextBuffer(staticText); - - bgfx::destroyProgram(_basicProgram); - bgfx::destroyProgram(_distanceProgram); - bgfx::destroyProgram(_distanceSubpixelProgram); + textBufferManager->destroyTextBuffer(staticText); delete textBufferManager; delete fontManager; diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 711ed0bd..736628d1 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -115,6 +115,9 @@ public: uint32_t getIndexSize(){ return sizeof(uint16_t); } uint32_t getTextColor(){ return toABGR(m_textColor); } + + TextRectangle getRectangle() const { return m_rectangle; } + private: void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); @@ -147,6 +150,8 @@ private: float m_lineDescender; float m_lineGap; + TextRectangle m_rectangle; + /// FontManager* m_fontManager; @@ -195,7 +200,8 @@ TextBuffer::TextBuffer(FontManager* _fontManager) m_lineDescender = 0; m_lineGap = 0; m_fontManager = _fontManager; - + m_rectangle.width = 0; + m_rectangle.height = 0; m_vertexBuffer = new TextVertex[MAX_BUFFERED_CHARACTERS * 4]; m_indexBuffer = new uint16_t[MAX_BUFFERED_CHARACTERS * 6]; @@ -224,8 +230,10 @@ void TextBuffer::appendText(FontHandle _fontHandle, const char * _string) m_originY = m_penY; m_lineDescender = 0;// font.m_descender; m_lineAscender = 0;//font.m_ascender; + + } - + uint32_t codepoint; uint32_t state = 0; @@ -294,6 +302,8 @@ void TextBuffer::clearTextBuffer() m_lineStartIndex = 0; m_lineAscender = 0; m_lineDescender = 0; + m_rectangle.width = 0; + m_rectangle.height = 0; } void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo) @@ -307,9 +317,10 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons m_lineDescender = 0; m_lineAscender = 0; m_lineStartIndex = m_vertexCount; + return; } - + if( _font.m_ascender > m_lineAscender || (_font.m_descender < m_lineDescender) ) { if( _font.m_descender < m_lineDescender ) @@ -458,9 +469,12 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; m_vertexCount += 4; m_indexCount += 6; - - //TODO see what to do when doing subpixel rendering + m_penX += _glyphInfo.m_advance_x; + if(m_penX > m_rectangle.width) m_rectangle.width = m_penX; + if( (m_penY - m_lineDescender) > m_rectangle.height) m_rectangle.height = (m_penY - m_lineDescender); + //if(x1 > m_rectangle.width) m_rectangle.width = x1; + //if(y1 > m_rectangle.height) m_rectangle.height = y1; } void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) @@ -803,3 +817,10 @@ void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) BufferCache& bc = m_textBuffers[_handle.idx]; bc.m_textBuffer->clearTextBuffer(); } + +TextRectangle TextBufferManager::getRectangle(TextBufferHandle _handle) const +{ + BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + return bc.m_textBuffer->getRectangle(); +} diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 57dc818f..91c41d0f 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -24,6 +24,11 @@ enum TextStyleFlags STYLE_BACKGROUND = 1<<3, }; +struct TextRectangle +{ + float width, height; +}; + class TextBuffer; class TextBufferManager { @@ -54,6 +59,8 @@ public: /// Clear the text buffer and reset its state (pen/color) void clearTextBuffer(TextBufferHandle _handle); + + TextRectangle getRectangle(TextBufferHandle _handle) const; /// return the size of the text //Rectangle measureText(FontHandle fontHandle, const char * _string); @@ -80,4 +87,7 @@ private: bgfx::ProgramHandle m_basicProgram; bgfx::ProgramHandle m_distanceProgram; bgfx::ProgramHandle m_distanceSubpixelProgram; + + float m_height; + float m_width; }; From 925e0eb371189053e456edbd000fd2d11598f073 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Thu, 9 May 2013 00:05:45 +0200 Subject: [PATCH 32/38] remove blank space --- examples/11-fontsdf/fontsdf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index cefab1bc..230b7969 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -86,7 +86,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) //textBufferManager->appendText(staticText, distance_font, L"The quick brown fox jumps over the lazy dog\n"); //textBufferManager->appendText(staticText, distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); - textBufferManager->appendText(staticText, distance_font, L"BGFX "); + textBufferManager->appendText(staticText, distance_font, L"BGFX "); textBufferManager->appendText(staticText, smaller_font, L"bgfx"); From cf895eb5ba91f4663a55b390bb97446bc386a438 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Thu, 9 May 2013 00:49:01 +0200 Subject: [PATCH 33/38] remove m_ from POD struct + clean 3rdparty include --- examples/common/font/font_manager.cpp | 238 +++++++++---------- examples/common/font/font_manager.h | 34 +-- examples/common/font/text_buffer_manager.cpp | 164 ++++++------- examples/common/font/text_buffer_manager.h | 10 +- 4 files changed, 223 insertions(+), 223 deletions(-) diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 12972c13..b870d53e 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -10,15 +10,15 @@ # pragma warning(disable: 4146) // DISABLE warning C4146: unary minus operator applied to unsigned type, result still unsigned # pragma warning(disable: 4700) // DISABLE warning C4700: uninitialized local variable 'temp' used # pragma warning(disable: 4701) // DISABLE warning C4701: potentially uninitialized local variable '' used -# include "../../../3rdparty/freetype/freetype.h" +# include <freetype/freetype.h> # pragma warning(pop) #else -# include "../../../3rdparty/freetype/freetype.h" +# include <freetype/freetype.h> #endif // BX_COMPILER_MSVC -#include "../../../3rdparty/edtaa3/edtaa3func.h" -#include "../../../3rdparty/edtaa3/edtaa3func.cpp" +#include <edtaa3/edtaa3func.h> +#include <edtaa3/edtaa3func.cpp> #include <math.h> #include <bx/bx.h> @@ -80,8 +80,8 @@ private: struct FTHolder { - FT_Library m_library; - FT_Face m_face; + FT_Library library; + FT_Face face; }; FontManager::TrueTypeFont::TrueTypeFont(): m_font(NULL) { @@ -92,8 +92,8 @@ FontManager::TrueTypeFont::~TrueTypeFont() if(m_font!=NULL) { FTHolder* holder = (FTHolder*) m_font; - FT_Done_Face( holder->m_face ); - FT_Done_FreeType( holder->m_library ); + FT_Done_Face( holder->face ); + FT_Done_FreeType( holder->library ); delete m_font; m_font = NULL; } @@ -109,19 +109,19 @@ bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSiz FTHolder* holder = new FTHolder(); // Initialize Freetype library - FT_Error error = FT_Init_FreeType( &holder->m_library ); + FT_Error error = FT_Init_FreeType( &holder->library ); if( error) { delete holder; return false; } - error = FT_New_Memory_Face( holder->m_library, _buffer, _bufferSize, _fontIndex, &holder->m_face ); + error = FT_New_Memory_Face( holder->library, _buffer, _bufferSize, _fontIndex, &holder->face ); if ( error == FT_Err_Unknown_File_Format ) { // the font file could be opened and read, but it appears //that its font format is unsupported - FT_Done_FreeType( holder->m_library ); + FT_Done_FreeType( holder->library ); delete holder; return false; } @@ -129,25 +129,25 @@ bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSiz { // another error code means that the font file could not // be opened or read, or simply that it is broken... - FT_Done_FreeType( holder->m_library ); + FT_Done_FreeType( holder->library ); delete holder; return false; } // Select unicode charmap - error = FT_Select_Charmap( holder->m_face, FT_ENCODING_UNICODE ); + error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE ); if( error ) { - FT_Done_Face( holder->m_face ); - FT_Done_FreeType( holder->m_library ); + FT_Done_Face( holder->face ); + FT_Done_FreeType( holder->library ); return false; } //set size in pixels - error = FT_Set_Pixel_Sizes( holder->m_face, 0, _pixelHeight ); + error = FT_Set_Pixel_Sizes( holder->face, 0, _pixelHeight ); if( error ) { - FT_Done_Face( holder->m_face ); - FT_Done_FreeType( holder->m_library ); + FT_Done_Face( holder->face ); + FT_Done_FreeType( holder->library ); return false; } @@ -161,19 +161,19 @@ FontInfo FontManager::TrueTypeFont::getFontInfo() FTHolder* holder = (FTHolder*) m_font; //todo manage unscalable font - BX_CHECK(FT_IS_SCALABLE (holder->m_face), "Font is unscalable"); + BX_CHECK(FT_IS_SCALABLE (holder->face), "Font is unscalable"); - FT_Size_Metrics metrics = holder->m_face->size->metrics; + FT_Size_Metrics metrics = holder->face->size->metrics; FontInfo outFontInfo; - outFontInfo.m_scale = 1.0f; - outFontInfo.m_ascender = metrics.ascender /64.0f; - outFontInfo.m_descender = metrics.descender /64.0f; - outFontInfo.m_lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; + outFontInfo.scale = 1.0f; + outFontInfo.ascender = metrics.ascender /64.0f; + outFontInfo.descender = metrics.descender /64.0f; + outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; - outFontInfo.m_underline_position = FT_MulFix(holder->m_face->underline_position, metrics.y_scale) /64.0f; - outFontInfo.m_underline_thickness= FT_MulFix(holder->m_face->underline_thickness,metrics.y_scale) /64.0f; + outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f; + outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f; return outFontInfo; } @@ -182,10 +182,10 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); + _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - FT_GlyphSlot slot = holder->m_face->glyph; - FT_Error error = FT_Load_Glyph( holder->m_face, _glyphInfo.m_glyphIndex, FT_LOAD_DEFAULT ); + FT_GlyphSlot slot = holder->face->glyph; + FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); if(error) { return false; } FT_Glyph glyph; @@ -202,12 +202,12 @@ bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; - _glyphInfo.m_offset_x = (float) x; - _glyphInfo.m_offset_y = (float) y; - _glyphInfo.m_width = (float) w; - _glyphInfo.m_height = (float) h; - _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_x = (float) x; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x /64.0f; + _glyphInfo.advance_y = (float)slot->advance.y /64.0f; int32_t charsize = 1; int32_t depth=1; @@ -226,10 +226,10 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); + _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - FT_GlyphSlot slot = holder->m_face->glyph; - FT_Error error = FT_Load_Glyph( holder->m_face, _glyphInfo.m_glyphIndex, FT_LOAD_DEFAULT ); + FT_GlyphSlot slot = holder->face->glyph; + FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); if(error) { return false; } FT_Glyph glyph; @@ -245,12 +245,12 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; - _glyphInfo.m_offset_x = (float) x; - _glyphInfo.m_offset_y = (float) y; - _glyphInfo.m_width = (float) w; - _glyphInfo.m_height = (float) h; - _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_x = (float) x; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x /64.0f; + _glyphInfo.advance_y = (float)slot->advance.y /64.0f; int32_t charsize = 1; int32_t depth=3; int32_t stride = bitmap->bitmap.pitch; @@ -346,13 +346,13 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); FTHolder* holder = (FTHolder*) m_font; - _glyphInfo.m_glyphIndex = FT_Get_Char_Index( holder->m_face, _codePoint ); + _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING; FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL; - FT_GlyphSlot slot = holder->m_face->glyph; - FT_Error error = FT_Load_Glyph( holder->m_face, _glyphInfo.m_glyphIndex, loadMode ); + FT_GlyphSlot slot = holder->face->glyph; + FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, loadMode ); if(error) { return false; } FT_Glyph glyph; @@ -369,12 +369,12 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; - _glyphInfo.m_offset_x = (float) x; - _glyphInfo.m_offset_y = (float) y; - _glyphInfo.m_width = (float) w; - _glyphInfo.m_height = (float) h; - _glyphInfo.m_advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.m_advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_x = (float) x; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x /64.0f; + _glyphInfo.advance_y = (float)slot->advance.y /64.0f; int32_t charsize = 1; int32_t depth=1; @@ -412,10 +412,10 @@ bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphI make_distance_map(alphaImg, _outBuffer, nw, nh); free(alphaImg); - _glyphInfo.m_offset_x -= (float) dw; - _glyphInfo.m_offset_y -= (float) dh; - _glyphInfo.m_width = (float) nw ; - _glyphInfo.m_height = (float) nh; + _glyphInfo.offset_x -= (float) dw; + _glyphInfo.offset_y -= (float) dh; + _glyphInfo.width = (float) nw ; + _glyphInfo.height = (float) nh; } return true; @@ -429,13 +429,13 @@ typedef stl::unordered_map<CodePoint_t, GlyphInfo> GlyphHash_t; // cache font data struct FontManager::CachedFont { - CachedFont(){ m_trueTypeFont = NULL; m_masterFontHandle.idx = -1; } - FontInfo m_fontInfo; - GlyphHash_t m_cachedGlyphs; - FontManager::TrueTypeFont* m_trueTypeFont; + CachedFont(){ trueTypeFont = NULL; masterFontHandle.idx = -1; } + FontInfo fontInfo; + GlyphHash_t cachedGlyphs; + FontManager::TrueTypeFont* trueTypeFont; // an handle to a master font in case of sub distance field font - FontHandle m_masterFontHandle; - int16_t m_padding; + FontHandle masterFontHandle; + int16_t padding; }; @@ -470,11 +470,11 @@ void FontManager::init() uint8_t buffer[W*W*4]; memset( buffer, 255, W * W * 4); - m_blackGlyph.m_width = W; - m_blackGlyph.m_height = W; + m_blackGlyph.width = W; + m_blackGlyph.height = W; ///make sure the black glyph doesn't bleed by using a one pixel inner outline - m_blackGlyph.m_regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1 ); + m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1 ); } FontManager::~FontManager() @@ -582,12 +582,12 @@ FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_ uint16_t fontIdx = m_fontHandles.alloc(); BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); - m_cachedFonts[fontIdx].m_trueTypeFont = ttf; - m_cachedFonts[fontIdx].m_fontInfo = ttf->getFontInfo(); - m_cachedFonts[fontIdx].m_fontInfo.m_fontType = _fontType; - m_cachedFonts[fontIdx].m_fontInfo.m_pixelSize = _pixelSize; - m_cachedFonts[fontIdx].m_cachedGlyphs.clear(); - m_cachedFonts[fontIdx].m_masterFontHandle.idx = -1; + m_cachedFonts[fontIdx].trueTypeFont = ttf; + m_cachedFonts[fontIdx].fontInfo = ttf->getFontInfo(); + m_cachedFonts[fontIdx].fontInfo.fontType = _fontType; + m_cachedFonts[fontIdx].fontInfo.pixelSize = _pixelSize; + m_cachedFonts[fontIdx].cachedGlyphs.clear(); + m_cachedFonts[fontIdx].masterFontHandle.idx = -1; FontHandle ret = {fontIdx}; return ret; } @@ -596,24 +596,24 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, { BX_CHECK(bgfx::invalidHandle != _baseFontHandle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_baseFontHandle.idx]; - FontInfo& fontInfo = font.m_fontInfo; + FontInfo& fontInfo = font.fontInfo; FontInfo newFontInfo = fontInfo; - newFontInfo.m_pixelSize = _pixelSize; - newFontInfo.m_scale = (float)_pixelSize / (float) fontInfo.m_pixelSize; - newFontInfo.m_ascender = (newFontInfo.m_ascender * newFontInfo.m_scale); - newFontInfo.m_descender = (newFontInfo.m_descender * newFontInfo.m_scale); - newFontInfo.m_lineGap = (newFontInfo.m_lineGap * newFontInfo.m_scale); - newFontInfo.m_underline_thickness = (newFontInfo.m_underline_thickness * newFontInfo.m_scale); - newFontInfo.m_underline_position = (newFontInfo.m_underline_position * newFontInfo.m_scale); + newFontInfo.pixelSize = _pixelSize; + newFontInfo.scale = (float)_pixelSize / (float) fontInfo.pixelSize; + newFontInfo.ascender = (newFontInfo.ascender * newFontInfo.scale); + newFontInfo.descender = (newFontInfo.descender * newFontInfo.scale); + newFontInfo.lineGap = (newFontInfo.lineGap * newFontInfo.scale); + newFontInfo.underline_thickness = (newFontInfo.underline_thickness * newFontInfo.scale); + newFontInfo.underline_position = (newFontInfo.underline_position * newFontInfo.scale); uint16_t fontIdx = m_fontHandles.alloc(); BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); - m_cachedFonts[fontIdx].m_cachedGlyphs.clear(); - m_cachedFonts[fontIdx].m_fontInfo = newFontInfo; - m_cachedFonts[fontIdx].m_trueTypeFont = NULL; - m_cachedFonts[fontIdx].m_masterFontHandle = _baseFontHandle; + m_cachedFonts[fontIdx].cachedGlyphs.clear(); + m_cachedFonts[fontIdx].fontInfo = newFontInfo; + m_cachedFonts[fontIdx].trueTypeFont = NULL; + m_cachedFonts[fontIdx].masterFontHandle = _baseFontHandle; FontHandle ret = {fontIdx}; return ret; } @@ -636,12 +636,12 @@ void FontManager::destroyFont(FontHandle _handle) { BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - if(m_cachedFonts[_handle.idx].m_trueTypeFont != NULL) + if(m_cachedFonts[_handle.idx].trueTypeFont != NULL) { - delete m_cachedFonts[_handle.idx].m_trueTypeFont; - m_cachedFonts[_handle.idx].m_trueTypeFont = NULL; + delete m_cachedFonts[_handle.idx].trueTypeFont; + m_cachedFonts[_handle.idx].trueTypeFont = NULL; } - m_cachedFonts[_handle.idx].m_cachedGlyphs.clear(); + m_cachedFonts[_handle.idx].cachedGlyphs.clear(); m_fontHandles.free(_handle.idx); } @@ -651,7 +651,7 @@ bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) CachedFont& font = m_cachedFonts[_handle.idx]; //if truetype present - if(font.m_trueTypeFont != NULL) + if(font.trueTypeFont != NULL) { //parse string for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) @@ -673,33 +673,33 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) { BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_handle.idx]; - FontInfo& fontInfo = font.m_fontInfo; + FontInfo& fontInfo = font.fontInfo; //check if glyph not already present - GlyphHash_t::iterator iter = font.m_cachedGlyphs.find(_codePoint); - if(iter != font.m_cachedGlyphs.end()) + GlyphHash_t::iterator iter = font.cachedGlyphs.find(_codePoint); + if(iter != font.cachedGlyphs.end()) { return true; } //if truetype present - if(font.m_trueTypeFont != NULL) + if(font.trueTypeFont != NULL) { GlyphInfo glyphInfo; //bake glyph as bitmap to buffer - switch(font.m_fontInfo.m_fontType) + switch(font.fontInfo.fontType) { case FONT_TYPE_ALPHA: - font.m_trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer); + font.trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer); break; //case FONT_TYPE_LCD: //font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); //break; case FONT_TYPE_DISTANCE: - font.m_trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); + font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; case FONT_TYPE_DISTANCE_SUBPIXEL: - font.m_trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); + font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; default: BX_CHECK(false, "TextureType not supported yet"); @@ -711,35 +711,35 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) return false; } - glyphInfo.m_advance_x = (glyphInfo.m_advance_x * fontInfo.m_scale); - glyphInfo.m_advance_y = (glyphInfo.m_advance_y * fontInfo.m_scale); - glyphInfo.m_offset_x = (glyphInfo.m_offset_x * fontInfo.m_scale); - glyphInfo.m_offset_y = (glyphInfo.m_offset_y * fontInfo.m_scale); - glyphInfo.m_height = (glyphInfo.m_height * fontInfo.m_scale); - glyphInfo.m_width = (glyphInfo.m_width * fontInfo.m_scale); + glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale); + glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale); + glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); + glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); + glyphInfo.height = (glyphInfo.height * fontInfo.scale); + glyphInfo.width = (glyphInfo.width * fontInfo.scale); // store cached glyph - font.m_cachedGlyphs[_codePoint] = glyphInfo; + font.cachedGlyphs[_codePoint] = glyphInfo; return true; }else { //retrieve glyph from parent font if any - if(font.m_masterFontHandle.idx != bgfx::invalidHandle) + if(font.masterFontHandle.idx != bgfx::invalidHandle) { - if(preloadGlyph(font.m_masterFontHandle, _codePoint)) + if(preloadGlyph(font.masterFontHandle, _codePoint)) { GlyphInfo glyphInfo; - getGlyphInfo(font.m_masterFontHandle, _codePoint, glyphInfo); + getGlyphInfo(font.masterFontHandle, _codePoint, glyphInfo); - glyphInfo.m_advance_x = (glyphInfo.m_advance_x * fontInfo.m_scale); - glyphInfo.m_advance_y = (glyphInfo.m_advance_y * fontInfo.m_scale); - glyphInfo.m_offset_x = (glyphInfo.m_offset_x * fontInfo.m_scale); - glyphInfo.m_offset_y = (glyphInfo.m_offset_y * fontInfo.m_scale); - glyphInfo.m_height = (glyphInfo.m_height * fontInfo.m_scale); - glyphInfo.m_width = (glyphInfo.m_width * fontInfo.m_scale); + glyphInfo.advance_x = (glyphInfo.advance_x * fontInfo.scale); + glyphInfo.advance_y = (glyphInfo.advance_y * fontInfo.scale); + glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); + glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); + glyphInfo.height = (glyphInfo.height * fontInfo.scale); + glyphInfo.width = (glyphInfo.width * fontInfo.scale); // store cached glyph - font.m_cachedGlyphs[_codePoint] = glyphInfo; + font.cachedGlyphs[_codePoint] = glyphInfo; return true; } } @@ -751,17 +751,17 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) const FontInfo& FontManager::getFontInfo(FontHandle _handle) { BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - return m_cachedFonts[_handle.idx].m_fontInfo; + return m_cachedFonts[_handle.idx].fontInfo; } bool FontManager::getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo) { - GlyphHash_t::iterator iter = m_cachedFonts[_handle.idx].m_cachedGlyphs.find(_codePoint); - if(iter == m_cachedFonts[_handle.idx].m_cachedGlyphs.end()) + GlyphHash_t::iterator iter = m_cachedFonts[_handle.idx].cachedGlyphs.find(_codePoint); + if(iter == m_cachedFonts[_handle.idx].cachedGlyphs.end()) { if(preloadGlyph(_handle, _codePoint)) { - iter = m_cachedFonts[_handle.idx].m_cachedGlyphs.find(_codePoint); + iter = m_cachedFonts[_handle.idx].cachedGlyphs.find(_codePoint); }else { return false; @@ -776,6 +776,6 @@ bool FontManager::getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, Glyph bool FontManager::addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data) { - _glyphInfo.m_regionIndex = m_atlas->addRegion((uint16_t) ceil(_glyphInfo.m_width),(uint16_t) ceil(_glyphInfo.m_height), _data, AtlasRegion::TYPE_GRAY); + _glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(_glyphInfo.width),(uint16_t) ceil(_glyphInfo.height), _data, AtlasRegion::TYPE_GRAY); return true; } diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index 43d83ef7..bf36689b 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -18,23 +18,23 @@ enum FontType struct FontInfo { //the font height in pixel - uint16_t m_pixelSize; + uint16_t pixelSize; /// Rendering type used for the font - int16_t m_fontType; + int16_t fontType; /// The pixel extents above the baseline in pixels (typically positive) - float m_ascender; + float ascender; /// The extents below the baseline in pixels (typically negative) - float m_descender; + float descender; /// The spacing in pixels between one row's descent and the next row's ascent - float m_lineGap; + float lineGap; /// The thickness of the under/hover/striketrough line in pixels - float m_underline_thickness; + float underline_thickness; /// The position of the underline relatively to the baseline - float m_underline_position; + float underline_position; //scale to apply to glyph data - float m_scale; + float scale; }; // Glyph metrics: @@ -75,34 +75,34 @@ typedef int32_t CodePoint_t; struct GlyphInfo { /// Index for faster retrieval - int32_t m_glyphIndex; + int32_t glyphIndex; /// Glyph's width in pixels. - float m_width; + float width; /// Glyph's height in pixels. - float m_height; + float height; /// Glyph's left offset in pixels - float m_offset_x; + float offset_x; /// Glyph's top offset in pixels /// Remember that this is the distance from the baseline to the top-most /// glyph scan line, upwards y coordinates being positive. - float m_offset_y; + float offset_y; /// For horizontal text layouts, this is the unscaled horizontal distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. - float m_advance_x; + float advance_x; /// For vertical text layouts, this is the unscaled vertical distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. - float m_advance_y; + float advance_y; /// region index in the atlas storing textures - uint16_t m_regionIndex; + uint16_t regionIndex; ///32 bits alignment - int16_t m_padding; + int16_t padding; }; BGFX_HANDLE(TrueTypeHandle); diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 736628d1..00433723 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -321,17 +321,17 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons return; } - if( _font.m_ascender > m_lineAscender || (_font.m_descender < m_lineDescender) ) + if( _font.ascender > m_lineAscender || (_font.descender < m_lineDescender) ) { - if( _font.m_descender < m_lineDescender ) + if( _font.descender < m_lineDescender ) { - m_lineDescender = _font.m_descender; - m_lineGap = _font.m_lineGap; + m_lineDescender = _font.descender; + m_lineGap = _font.lineGap; } - float txtDecals = (_font.m_ascender - m_lineAscender); - m_lineAscender = _font.m_ascender; - m_lineGap = _font.m_lineGap; + float txtDecals = (_font.ascender - m_lineAscender); + m_lineAscender = _font.ascender; + m_lineGap = _font.lineGap; m_penY += txtDecals; verticalCenterLastLine((txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender+m_lineGap)); @@ -345,7 +345,7 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons kerning = texture_glyph_get_kerning( glyph, previous ); } */ - m_penX += kerning * _font.m_scale; + m_penX += kerning * _font.scale; GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph(); @@ -353,10 +353,10 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons { float x0 = ( m_penX - kerning ); float y0 = ( m_penY - m_lineAscender); - float x1 = ( (float)x0 + (_glyphInfo.m_advance_x)); + float x1 = ( (float)x0 + (_glyphInfo.advance_x)); float y1 = ( m_penY - m_lineDescender + m_lineGap ); - m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_backgroundColor,STYLE_BACKGROUND); setVertex(m_vertexCount+1, x0, y1, m_backgroundColor,STYLE_BACKGROUND); @@ -377,10 +377,10 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons { float x0 = ( m_penX - kerning ); float y0 = (m_penY - m_lineDescender/2 ); - float x1 = ( (float)x0 + (_glyphInfo.m_advance_x)); - float y1 = y0+_font.m_underline_thickness; + float x1 = ( (float)x0 + (_glyphInfo.advance_x)); + float y1 = y0+_font.underline_thickness; - m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_underlineColor,STYLE_UNDERLINE); setVertex(m_vertexCount+1, x0, y1, m_underlineColor,STYLE_UNDERLINE); @@ -400,11 +400,11 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons if( m_styleFlags & STYLE_OVERLINE && m_overlineColor & 0xFF000000) { float x0 = ( m_penX - kerning ); - float y0 = (m_penY - _font.m_ascender ); - float x1 = ( (float)x0 + (_glyphInfo.m_advance_x)); - float y1 = y0+_font.m_underline_thickness; + float y0 = (m_penY - _font.ascender ); + float x1 = ( (float)x0 + (_glyphInfo.advance_x)); + float y1 = y0+_font.underline_thickness; - m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_overlineColor,STYLE_OVERLINE); setVertex(m_vertexCount+1, x0, y1, m_overlineColor,STYLE_OVERLINE); @@ -425,11 +425,11 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons if( m_styleFlags & STYLE_STRIKE_THROUGH && m_strikeThroughColor & 0xFF000000) { float x0 = ( m_penX - kerning ); - float y0 = (m_penY - _font.m_ascender/3 ); - float x1 = ( (float)x0 + (_glyphInfo.m_advance_x) ); - float y1 = y0+_font.m_underline_thickness; + float y0 = (m_penY - _font.ascender/3 ); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0+_font.underline_thickness; - m_fontManager->getAtlas()->packUV(blackGlyph.m_regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); setVertex(m_vertexCount+1, x0, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); @@ -448,13 +448,13 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons //handle glyph - float x0_precise = m_penX + (_glyphInfo.m_offset_x); + float x0_precise = m_penX + (_glyphInfo.offset_x); float x0 = ( x0_precise); - float y0 = ( m_penY + (_glyphInfo.m_offset_y)); - float x1 = ( x0 + _glyphInfo.m_width ); - float y1 = ( y0 + _glyphInfo.m_height ); + float y0 = ( m_penY + (_glyphInfo.offset_y)); + float x1 = ( x0 + _glyphInfo.width ); + float y1 = ( y0 + _glyphInfo.height ); - m_fontManager->getAtlas()->packUV(_glyphInfo.m_regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + m_fontManager->getAtlas()->packUV(_glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); setVertex(m_vertexCount+0, x0, y0, m_textColor); setVertex(m_vertexCount+1, x0, y1, m_textColor); @@ -470,7 +470,7 @@ void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, cons m_vertexCount += 4; m_indexCount += 6; - m_penX += _glyphInfo.m_advance_x; + m_penX += _glyphInfo.advance_x; if(m_penX > m_rectangle.width) m_rectangle.width = m_penX; if( (m_penY - m_lineDescender) > m_rectangle.height) m_rectangle.height = (m_penY - m_lineDescender); //if(x1 > m_rectangle.width) m_rectangle.width = x1; @@ -588,11 +588,11 @@ TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType uint16_t textIdx = m_textBufferHandles.alloc(); BufferCache& bc = m_textBuffers[textIdx]; - bc.m_textBuffer = new TextBuffer(m_fontManager); - bc.m_fontType = _type; - bc.m_bufferType = _bufferType; - bc.m_indexBufferHandle = bgfx::invalidHandle; - bc.m_vertexBufferHandle = bgfx::invalidHandle; + bc.textBuffer = new TextBuffer(m_fontManager); + bc.fontType = _type; + bc.bufferType = _bufferType; + bc.indexBufferHandle = bgfx::invalidHandle; + bc.vertexBufferHandle = bgfx::invalidHandle; TextBufferHandle ret = {textIdx}; return ret; @@ -604,19 +604,19 @@ void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) BufferCache& bc = m_textBuffers[_handle.idx]; m_textBufferHandles.free(_handle.idx); - delete bc.m_textBuffer; - bc.m_textBuffer = NULL; + delete bc.textBuffer; + bc.textBuffer = NULL; - if(bc.m_vertexBufferHandle == bgfx::invalidHandle ) return; + if(bc.vertexBufferHandle == bgfx::invalidHandle ) return; - switch(bc.m_bufferType) + switch(bc.bufferType) { case STATIC: { bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; - ibh.idx = bc.m_indexBufferHandle; - vbh.idx = bc.m_vertexBufferHandle; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; bgfx::destroyIndexBuffer(ibh); bgfx::destroyVertexBuffer(vbh); } @@ -625,8 +625,8 @@ void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) case DYNAMIC: bgfx::DynamicIndexBufferHandle ibh; bgfx::DynamicVertexBufferHandle vbh; - ibh.idx = bc.m_indexBufferHandle; - vbh.idx = bc.m_vertexBufferHandle; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; bgfx::destroyDynamicIndexBuffer(ibh); bgfx::destroyDynamicVertexBuffer(vbh); @@ -641,15 +641,15 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - uint32_t indexSize = bc.m_textBuffer->getIndexCount() * bc.m_textBuffer->getIndexSize(); - uint32_t vertexSize = bc.m_textBuffer->getVertexCount() * bc.m_textBuffer->getVertexSize(); + uint32_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize(); + uint32_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize(); const bgfx::Memory* mem; bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle()); float inverse_gamme = 1.0f/2.2f; bgfx::setUniform(u_inverse_gamma, &inverse_gamme); - switch (bc.m_fontType) + switch (bc.fontType) { case FONT_TYPE_ALPHA: bgfx::setProgram(m_basicProgram); @@ -661,81 +661,81 @@ void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, break; case FONT_TYPE_DISTANCE_SUBPIXEL: bgfx::setProgram(m_distanceSubpixelProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.m_textBuffer->getTextColor()); + bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.textBuffer->getTextColor()); break; } - switch(bc.m_bufferType) + switch(bc.bufferType) { case STATIC: { bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; - if(bc.m_vertexBufferHandle == bgfx::invalidHandle) + if(bc.vertexBufferHandle == bgfx::invalidHandle) { mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); ibh = bgfx::createIndexBuffer(mem); mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); - bc.m_indexBufferHandle = ibh.idx ; - bc.m_vertexBufferHandle = vbh.idx; + bc.indexBufferHandle = ibh.idx ; + bc.vertexBufferHandle = vbh.idx; }else { - ibh.idx = bc.m_indexBufferHandle; - vbh.idx = bc.m_vertexBufferHandle; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; } - bgfx::setVertexBuffer(vbh, bc.m_textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.m_textBuffer->getIndexCount()); + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); }break; case DYNAMIC: { bgfx::DynamicIndexBufferHandle ibh; bgfx::DynamicVertexBufferHandle vbh; - if(bc.m_vertexBufferHandle == bgfx::invalidHandle) + if(bc.vertexBufferHandle == bgfx::invalidHandle) { mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); ibh = bgfx::createDynamicIndexBuffer(mem); mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); - bc.m_indexBufferHandle = ibh.idx ; - bc.m_vertexBufferHandle = vbh.idx; + bc.indexBufferHandle = ibh.idx ; + bc.vertexBufferHandle = vbh.idx; }else { - ibh.idx = bc.m_indexBufferHandle; - vbh.idx = bc.m_vertexBufferHandle; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.m_textBuffer->getIndexBuffer(), indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); bgfx::updateDynamicIndexBuffer(ibh, mem); mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.m_textBuffer->getVertexBuffer(), vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); bgfx::updateDynamicVertexBuffer(vbh, mem); } - bgfx::setVertexBuffer(vbh, bc.m_textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.m_textBuffer->getIndexCount()); + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); }break; case TRANSIENT: { bgfx::TransientIndexBuffer tib; bgfx::TransientVertexBuffer tvb; - bgfx::allocTransientIndexBuffer(&tib, bc.m_textBuffer->getIndexCount()); - bgfx::allocTransientVertexBuffer(&tvb, bc.m_textBuffer->getVertexCount(), m_vertexDecl); - memcpy(tib.data, bc.m_textBuffer->getIndexBuffer(), indexSize); - memcpy(tvb.data, bc.m_textBuffer->getVertexBuffer(), vertexSize); - bgfx::setVertexBuffer(&tvb, bc.m_textBuffer->getVertexCount()); - bgfx::setIndexBuffer(&tib, bc.m_textBuffer->getIndexCount()); + bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount()); + bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); + memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount()); + bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount()); }break; } @@ -752,75 +752,75 @@ void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags ) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setStyle(_flags); + bc.textBuffer->setStyle(_flags); } void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba ) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setTextColor(_rgba); + bc.textBuffer->setTextColor(_rgba); } void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba ) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setBackgroundColor(_rgba); + bc.textBuffer->setBackgroundColor(_rgba); } void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba ) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setOverlineColor(_rgba); + bc.textBuffer->setOverlineColor(_rgba); } void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba ) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setUnderlineColor(_rgba); + bc.textBuffer->setUnderlineColor(_rgba); } void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba ) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setStrikeThroughColor(_rgba); + bc.textBuffer->setStrikeThroughColor(_rgba); } void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->setPenPosition(_x,_y); + bc.textBuffer->setPenPosition(_x,_y); } void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->appendText(_fontHandle, _string); + bc.textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->appendText(_fontHandle, _string); + bc.textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.m_textBuffer->clearTextBuffer(); + bc.textBuffer->clearTextBuffer(); } TextRectangle TextBufferManager::getRectangle(TextBufferHandle _handle) const { BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - return bc.m_textBuffer->getRectangle(); + return bc.textBuffer->getRectangle(); } diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 91c41d0f..9220c0e8 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -70,11 +70,11 @@ private: struct BufferCache { - uint16_t m_indexBufferHandle; - uint16_t m_vertexBufferHandle; - TextBuffer* m_textBuffer; - BufferType m_bufferType; - FontType m_fontType; + uint16_t indexBufferHandle; + uint16_t vertexBufferHandle; + TextBuffer* textBuffer; + BufferType bufferType; + FontType fontType; }; BufferCache* m_textBuffers; From fe41a9f6b8584abad46c960ae7202d16cf6b656e Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 15 May 2013 15:01:38 +0200 Subject: [PATCH 34/38] convert pragma once to include guards --- examples/common/cube_atlas.cpp | 1 - examples/common/cube_atlas.h | 6 ++++-- examples/common/font/font_manager.h | 6 +++++- examples/common/font/text_buffer_manager.h | 6 +++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index f1ee2081..42d91b7a 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -1,7 +1,6 @@ /* Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause */ -#pragma once #include "cube_atlas.h" #include <bx/bx.h> #include <bgfx.h> diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 3f981227..7dceea24 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -1,7 +1,8 @@ /* Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause */ -#pragma once +#ifndef __CUBE_ATLAS_H__ +#define __CUBE_ATLAS_H__ /// Inspired from texture-atlas from freetype-gl (http://code.google.com/p/freetype-gl/) /// by Nicolas Rougier (Nicolas.Rougier@inria.fr) @@ -130,4 +131,5 @@ private: AtlasRegion* m_regions; uint8_t* m_textureBuffer; -}; \ No newline at end of file +}; +#endif // __CUBE_ATLAS_H__ diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index bf36689b..b0f98b5f 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -1,7 +1,9 @@ /* Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause */ -#pragma once +#ifndef __FONT_MANAGER_H__ +#define __FONT_MANAGER_H__ + #include <bgfx.h> #include <bx/handlealloc.h> @@ -200,3 +202,5 @@ private: //temporary buffer to raster glyph uint8_t* m_buffer; }; + +#endif // __FONT_MANAGER_H__ diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index 9220c0e8..e0225afa 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -1,7 +1,9 @@ /* Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause */ -#pragma once +#ifndef __TEXT_BUFFER_MANAGER_H__ +#define __TEXT_BUFFER_MANAGER_H__ + #include "font_manager.h" BGFX_HANDLE(TextBufferHandle); @@ -91,3 +93,5 @@ private: float m_height; float m_width; }; + +#endif // __TEXT_BUFFER_MANAGER_H__ From 1194e6f5565e1b174bc469cfce51cc34202bcc4e Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 15 May 2013 15:02:25 +0200 Subject: [PATCH 35/38] get rid of missleading NULL initializer --- examples/common/font/text_buffer_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index e0225afa..cdab8e43 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -35,7 +35,7 @@ class TextBuffer; class TextBufferManager { public: - TextBufferManager(FontManager* _fontManager = NULL); + TextBufferManager(FontManager* _fontManager); ~TextBufferManager(); TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); From a4006cf0abe7dd80a04af714c902969b210b244d Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 15 May 2013 15:07:04 +0200 Subject: [PATCH 36/38] harmonize license header text --- examples/10-font/font.cpp | 5 +++++ examples/11-fontsdf/fontsdf.cpp | 5 +++++ examples/common/cube_atlas.cpp | 6 ++++-- examples/common/cube_atlas.h | 6 ++++-- examples/common/font/font_manager.cpp | 6 ++++-- examples/common/font/font_manager.h | 6 ++++-- examples/common/font/text_buffer_manager.cpp | 6 ++++-- examples/common/font/text_buffer_manager.h | 6 ++++-- 8 files changed, 34 insertions(+), 12 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 7cd2006a..938cb144 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -1,3 +1,8 @@ +/* + * Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + #include <bgfx.h> #include <bx/bx.h> #include <bx/timer.h> diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index 230b7969..0a56fc59 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -1,3 +1,8 @@ +/* + * Copyright 2013 Jeremie Roy. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + #include <bgfx.h> #include <bx/bx.h> #include <bx/timer.h> diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index 42d91b7a..f68f93ba 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -1,6 +1,8 @@ -/* Copyright 2013 Jeremie Roy. All rights reserved. +/* + * Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause -*/ + */ + #include "cube_atlas.h" #include <bx/bx.h> #include <bgfx.h> diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 7dceea24..9ac55826 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -1,6 +1,8 @@ -/* Copyright 2013 Jeremie Roy. All rights reserved. +/* + * Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause -*/ + */ + #ifndef __CUBE_ATLAS_H__ #define __CUBE_ATLAS_H__ diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index b870d53e..17201a6d 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -1,6 +1,8 @@ -/* Copyright 2013 Jeremie Roy. All rights reserved. +/* + * Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause -*/ + */ + #include "font_manager.h" #include "../cube_atlas.h" diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index b0f98b5f..ce4be0c9 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -1,6 +1,8 @@ -/* Copyright 2013 Jeremie Roy. All rights reserved. +/* + * Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause -*/ + */ + #ifndef __FONT_MANAGER_H__ #define __FONT_MANAGER_H__ diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 00433723..3ed7c4a2 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -1,6 +1,8 @@ -/* Copyright 2013 Jeremie Roy. All rights reserved. +/* + * Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause -*/ + */ + #include "text_buffer_manager.h" #include "../cube_atlas.h" diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index cdab8e43..b9742aca 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -1,6 +1,8 @@ -/* Copyright 2013 Jeremie Roy. All rights reserved. +/* + * Copyright 2013 Jeremie Roy. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause -*/ + */ + #ifndef __TEXT_BUFFER_MANAGER_H__ #define __TEXT_BUFFER_MANAGER_H__ From 61305ed0e4374ef6602fb164a2a8d79d408e0320 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 15 May 2013 15:12:25 +0200 Subject: [PATCH 37/38] fix warning and remove useless includes --- examples/10-font/font.cpp | 5 +++-- examples/11-fontsdf/fontsdf.cpp | 3 --- examples/common/font/font_manager.cpp | 1 - examples/common/font/text_buffer_manager.cpp | 3 --- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 938cb144..0309defb 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -6,6 +6,7 @@ #include <bgfx.h> #include <bx/bx.h> #include <bx/timer.h> +#include <bx/countof.h> #include "../common/entry.h" #include "../common/dbg.h" #include "../common/math.h" @@ -15,7 +16,6 @@ #include "../common/font/text_buffer_manager.h" #include <stdio.h> -#include <string.h> int _main_(int /*_argc*/, char** /*_argv*/) { @@ -154,7 +154,8 @@ int _main_(int /*_argc*/, char** /*_argv*/) //Use transient text to display debug information //Code below is similar to commented code above wchar_t fpsText[64]; - swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); + //swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); + swprintf(fpsText, countof(fpsText), L"Frame: % 7.3f[ms]", double(frameTime)*toMs); textBufferManager->clearTextBuffer(transientText); textBufferManager->setPenPosition(transientText, 20.0, 4.0f); diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index 0a56fc59..c1f9d860 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -14,9 +14,6 @@ #include "../common/font/font_manager.h" #include "../common/font/text_buffer_manager.h" -#include <stdio.h> -#include <string.h> - inline void mtxTranslate(float* _result, float x, float y, float z) { memset(_result, 0, sizeof(float)*16); diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 17201a6d..782bd89c 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -21,7 +21,6 @@ #include <edtaa3/edtaa3func.h> #include <edtaa3/edtaa3func.cpp> -#include <math.h> #include <bx/bx.h> diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index 3ed7c4a2..c5047c3f 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -7,9 +7,6 @@ #include "../cube_atlas.h" #include <bx/bx.h> -#include <stdio.h> -#include <string.h> -#include <math.h> #include <stddef.h> /* offsetof */ #include "vs_font_basic.bin.h" From c4b4b15e373e167b15a90393f49eda60f476f4c5 Mon Sep 17 00:00:00 2001 From: Jeremie Roy <jeremie.roy@gmail.com> Date: Wed, 15 May 2013 15:21:23 +0200 Subject: [PATCH 38/38] uncrustify whole font code --- examples/10-font/font.cpp | 116 +-- examples/11-fontsdf/fontsdf.cpp | 81 +- examples/common/cube_atlas.cpp | 552 ++++++----- examples/common/cube_atlas.h | 202 ++-- examples/common/font/font_manager.cpp | 705 +++++++------ examples/common/font/font_manager.h | 198 ++-- examples/common/font/text_buffer_manager.cpp | 987 ++++++++++--------- examples/common/font/text_buffer_manager.h | 112 +-- 8 files changed, 1586 insertions(+), 1367 deletions(-) diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 0309defb..d8c1d7ea 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -6,7 +6,7 @@ #include <bgfx.h> #include <bx/bx.h> #include <bx/timer.h> -#include <bx/countof.h> +#include <bx/countof.h> #include "../common/entry.h" #include "../common/dbg.h" #include "../common/math.h" @@ -19,12 +19,12 @@ int _main_(int /*_argc*/, char** /*_argv*/) { - uint32_t width = 1280; + uint32_t width = 1280; uint32_t height = 720; uint32_t debug = BGFX_DEBUG_TEXT; uint32_t reset = 0; - bgfx::init(); + bgfx::init(); bgfx::reset(width, height); @@ -33,20 +33,21 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Set view 0 clear state. bgfx::setViewClear(0 - , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT - , 0x303030ff - , 1.0f - , 0 - ); - + , BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT + , 0x303030ff + , 1.0f + , 0 + ); + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); //load some truetype files - const char* fontNames[7] = { + const char* fontNames[7] = + { "font/droidsans.ttf", - "font/chp-fire.ttf", + "font/chp-fire.ttf", "font/bleeding_cowboys.ttf", "font/mias_scribblings.ttf", "font/ruritania.ttf", @@ -54,11 +55,11 @@ int _main_(int /*_argc*/, char** /*_argv*/) "font/five_minutes.otf" }; - const uint32_t fontCount = sizeof(fontNames)/sizeof(const char*); - + const uint32_t fontCount = sizeof(fontNames) / sizeof(const char*); + TrueTypeHandle fontFiles[fontCount]; FontHandle fonts[fontCount]; - for(int32_t ii = 0; ii<fontCount ; ++ii) + for (int32_t ii = 0; ii < fontCount; ++ii) { //instantiate a usable font fontFiles[ii] = fontManager->loadTrueTypeFromFile(fontNames[ii]); @@ -68,43 +69,43 @@ int _main_(int /*_argc*/, char** /*_argv*/) //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph fontManager->unloadTrueType(fontFiles[ii]); } - + TrueTypeHandle console_tt = fontManager->loadTrueTypeFromFile("font/visitor1.ttf"); //this font doesn't have any preloaded glyph's but the truetype file is loaded //so glyph will be generated as needed FontHandle consola_16 = fontManager->createFontByPixelSize(console_tt, 0, 10); - + //create a static text buffer compatible with alpha font //a static text buffer content cannot be modified after its first submit. TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, STATIC); - + //the pen position represent the top left of the box of the first line of text textBufferManager->setPenPosition(staticText, 24.0f, 100.0f); - for(int32_t ii = 0; ii<fontCount ; ++ii) + for (int32_t ii = 0; ii < fontCount; ++ii) { //add some text to the buffer textBufferManager->appendText(staticText, fonts[ii], L"The quick brown fox jumps over the lazy dog\n"); //the position of the pen is adjusted when there is an endline } - // Now write some styled text - - //setup style colors + // Now write some styled text + + //setup style colors textBufferManager->setBackgroundColor(staticText, 0x551111FF); textBufferManager->setUnderlineColor(staticText, 0xFF2222FF); textBufferManager->setOverlineColor(staticText, 0x2222FFFF); - textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); + textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); //text + bkg textBufferManager->setStyle(staticText, STYLE_BACKGROUND); textBufferManager->appendText(staticText, fonts[0], L"The quick "); - + //text + strike-through textBufferManager->setStyle(staticText, STYLE_STRIKE_THROUGH); textBufferManager->appendText(staticText, fonts[0], L"brown fox "); - + //text + overline textBufferManager->setStyle(staticText, STYLE_OVERLINE); textBufferManager->appendText(staticText, fonts[0], L"jumps over "); @@ -112,25 +113,25 @@ int _main_(int /*_argc*/, char** /*_argv*/) //text + underline textBufferManager->setStyle(staticText, STYLE_UNDERLINE); textBufferManager->appendText(staticText, fonts[0], L"the lazy "); - + //text + bkg + strike-through - textBufferManager->setStyle(staticText, STYLE_BACKGROUND|STYLE_STRIKE_THROUGH); + textBufferManager->setStyle(staticText, STYLE_BACKGROUND | STYLE_STRIKE_THROUGH); textBufferManager->appendText(staticText, fonts[0], L"dog\n"); - - - //create a transient buffer for realtime data - TextBufferHandle transientText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, TRANSIENT); - - uint32_t w = 0,h = 0; - while (!processEvents(width, height, debug, reset) ) + + //create a transient buffer for realtime data + TextBufferHandle transientText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, TRANSIENT); + + uint32_t w = 0, h = 0; + while (!processEvents(width, height, debug, reset) ) { - - if(w!=width|| h!=height) + if (w != width + || h != height) { - w=width; - h= height; - printf("ri: %d,%d\n",width,height); + w = width; + h = height; + printf("ri: %d,%d\n", width, height); } + // Set view 0 default viewport. bgfx::setViewRect(0, 0, 0, width, height); @@ -143,35 +144,35 @@ int _main_(int /*_argc*/, char** /*_argv*/) const int64_t frameTime = now - last; last = now; const double freq = double(bx::getHPFrequency() ); - const double toMs = 1000.0/freq; + const double toMs = 1000.0 / freq; // Use debug font to print information about this example. //bgfx::dbgTextClear(); //bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/10-font"); //bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use the font system to display text and styled text."); //bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); - + //Use transient text to display debug information //Code below is similar to commented code above wchar_t fpsText[64]; //swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); - swprintf(fpsText, countof(fpsText), L"Frame: % 7.3f[ms]", double(frameTime)*toMs); - + swprintf(fpsText, countof(fpsText), L"Frame: % 7.3f[ms]", double(frameTime) * toMs); + textBufferManager->clearTextBuffer(transientText); - textBufferManager->setPenPosition(transientText, 20.0, 4.0f); - textBufferManager->appendText(transientText, consola_16, L"bgfx/examples/10-font\n"); + textBufferManager->setPenPosition(transientText, 20.0, 4.0f); + textBufferManager->appendText(transientText, consola_16, L"bgfx/examples/10-font\n"); textBufferManager->appendText(transientText, consola_16, L"Description: Use the font system to display text and styled text.\n"); textBufferManager->appendText(transientText, consola_16, fpsText); float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; - + float view[16]; float proj[16]; mtxLookAt(view, eye, at); - //setup a top-left ortho matrix for screen space drawing + //setup a top-left ortho matrix for screen space drawing float centering = 0.5f; - mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + mtxOrtho(proj, centering, width + centering, height + centering, centering, -1.0f, 1.0f); // Set view and projection matrix for view 0. bgfx::setViewTransform(0, view, proj); @@ -180,30 +181,29 @@ int _main_(int /*_argc*/, char** /*_argv*/) textBufferManager->submitTextBuffer(transientText, 0); //submit the static text - textBufferManager->submitTextBuffer(staticText, 0); - - // Advance to next frame. Rendering thread will be kicked to + textBufferManager->submitTextBuffer(staticText, 0); + + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); } - - + fontManager->unloadTrueType(console_tt); //destroy the fonts - fontManager->destroyFont(consola_16); - for(int32_t ii = 0; ii<fontCount ; ++ii) + fontManager->destroyFont(consola_16); + for (int32_t ii = 0; ii < fontCount; ++ii) { fontManager->destroyFont(fonts[ii]); } textBufferManager->destroyTextBuffer(staticText); - textBufferManager->destroyTextBuffer(transientText); + textBufferManager->destroyTextBuffer(transientText); delete textBufferManager; - delete fontManager; - + delete fontManager; + // Shutdown bgfx. - bgfx::shutdown(); + bgfx::shutdown(); return 0; } diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index c1f9d860..8fd4daef 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -16,7 +16,7 @@ inline void mtxTranslate(float* _result, float x, float y, float z) { - memset(_result, 0, sizeof(float)*16); + memset(_result, 0, sizeof(float) * 16); _result[0] = _result[5] = _result[10] = _result[15] = 1.0f; _result[12] = x; _result[13] = y; @@ -25,7 +25,7 @@ inline void mtxTranslate(float* _result, float x, float y, float z) inline void mtxScale(float* _result, float x, float y, float z) { - memset(_result, 0, sizeof(float)*16); + memset(_result, 0, sizeof(float) * 16); _result[0] = x; _result[5] = y; _result[10] = z; @@ -34,7 +34,7 @@ inline void mtxScale(float* _result, float x, float y, float z) int _main_(int /*_argc*/, char** /*_argv*/) { - uint32_t width = 1280; + uint32_t width = 1280; uint32_t height = 720; uint32_t debug = BGFX_DEBUG_TEXT; uint32_t reset = 0; @@ -48,14 +48,14 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Set view 0 clear state. bgfx::setViewClear(0 - , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT - //, 0x303030ff - //, 0xffffffff - , 0x000000FF - , 1.0f - , 0 - ); - + , BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT + //, 0x303030ff + //, 0xffffffff + , 0x000000FF + , 1.0f + , 0 + ); + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); @@ -63,7 +63,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) //load a truetype files /* "font/droidsans.ttf", - "font/chp-fire.ttf", + "font/chp-fire.ttf", "font/bleeding_cowboys.ttf", "font/mias_scribblings.ttf", "font/ruritania.ttf", @@ -71,29 +71,28 @@ int _main_(int /*_argc*/, char** /*_argv*/) "font/five_minutes.otf" */ TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("font/bleeding_cowboys.ttf"); - + //create a distance field font FontHandle distance_font = fontManager->createFontByPixelSize(times_tt, 0, 48, FONT_TYPE_DISTANCE); //create a scalled down version of the same font (without adding anything to the atlas) FontHandle smaller_font = fontManager->createScaledFontToPixelSize(distance_font, 32); - + //preload glyph and generate (generate bitmap's) fontManager->preloadGlyph(distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,\" \n"); //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph fontManager->unloadTrueType(times_tt); - - TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); + + TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); textBufferManager->setTextColor(staticText, 0xDD0000FF); - - //textBufferManager->appendText(staticText, distance_font, L"The quick brown fox jumps over the lazy dog\n"); + + //textBufferManager->appendText(staticText, distance_font, L"The quick brown fox jumps over the lazy dog\n"); //textBufferManager->appendText(staticText, distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); textBufferManager->appendText(staticText, distance_font, L"BGFX "); textBufferManager->appendText(staticText, smaller_font, L"bgfx"); - int64_t timeOffset = bx::getHPCounter(); - while (!processEvents(width, height, debug, reset) ) + while (!processEvents(width, height, debug, reset) ) { // Set view 0 default viewport. bgfx::setViewRect(0, 0, 0, width, height); @@ -107,14 +106,14 @@ int _main_(int /*_argc*/, char** /*_argv*/) const int64_t frameTime = now - last; last = now; const double freq = double(bx::getHPFrequency() ); - const double toMs = 1000.0/freq; - float time = (float)( (now - timeOffset)/double(bx::getHPFrequency() ) ); + const double toMs = 1000.0 / freq; + float time = (float)( (now - timeOffset) / double(bx::getHPFrequency() ) ); // Use debug font to print information about this example. bgfx::dbgTextClear(); bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontsdf"); bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of various size."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime) * toMs); float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; @@ -124,48 +123,48 @@ int _main_(int /*_argc*/, char** /*_argv*/) mtxLookAt(view, eye, at); float centering = 0.5f; //setup a top-left ortho matrix for screen space drawing - mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + mtxOrtho(proj, centering, width + centering, height + centering, centering, -1.0f, 1.0f); // Set view and projection matrix for view 0. - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, proj); TextRectangle rect = textBufferManager->getRectangle(staticText); float mtxA[16]; float mtxB[16]; float mtxC[16]; - mtxRotateZ(mtxA, time*0.37f); - mtxTranslate(mtxB, -(rect.width*0.5f), -(rect.height*0.5f), 0); - + mtxRotateZ(mtxA, time * 0.37f); + mtxTranslate(mtxB, -(rect.width * 0.5f), -(rect.height * 0.5f), 0); + mtxMul(mtxC, mtxB, mtxA); - - float scale=4.1f+4.0f*sinf(time); + + float scale = 4.1f + 4.0f * sinf(time); mtxScale(mtxA, scale, scale, 1.0f); mtxMul(mtxB, mtxC, mtxA); - - mtxTranslate(mtxC, ((width)*0.5f), ((height)*0.5f), 0); + + mtxTranslate(mtxC, ( (width) * 0.5f), ( (height) * 0.5f), 0); mtxMul(mtxA, mtxB, mtxC); - + // Set model matrix for rendering. bgfx::setTransform(mtxA); //draw your text - textBufferManager->submitTextBuffer(staticText, 0); + textBufferManager->submitTextBuffer(staticText, 0); - // Advance to next frame. Rendering thread will be kicked to + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); } - //destroy the fonts + //destroy the fonts fontManager->destroyFont(distance_font); - fontManager->destroyFont(smaller_font); - - textBufferManager->destroyTextBuffer(staticText); + fontManager->destroyFont(smaller_font); + + textBufferManager->destroyTextBuffer(staticText); delete textBufferManager; - delete fontManager; + delete fontManager; // Shutdown bgfx. - bgfx::shutdown(); + bgfx::shutdown(); return 0; } diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index f68f93ba..4dd552f7 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -5,67 +5,74 @@ #include "cube_atlas.h" #include <bx/bx.h> -#include <bgfx.h> +#include <bgfx.h> #include <vector> - //********** Rectangle packer implementation ************ class RectanglePacker -{ +{ public: - RectanglePacker(); - RectanglePacker(uint32_t _width, uint32_t _height); - - /// non constructor initialization - void init(uint32_t _width, uint32_t _height); - /// find a suitable position for the given rectangle - /// @return true if the rectangle can be added, false otherwise - bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY ); - /// return the used surface in squared unit - uint32_t getUsedSurface() { return m_usedSpace; } - /// return the total available surface in squared unit - uint32_t getTotalSurface() { return m_width*m_height; } - /// return the usage ratio of the available surface [0:1] - float getUsageRatio(); - /// reset to initial state - void clear(); +RectanglePacker(); +RectanglePacker(uint32_t _width, uint32_t _height); + +/// non constructor initialization +void init(uint32_t _width, uint32_t _height); +/// find a suitable position for the given rectangle +/// @return true if the rectangle can be added, false otherwise +bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY); +/// return the used surface in squared unit +uint32_t getUsedSurface() +{ + return m_usedSpace; +} +/// return the total available surface in squared unit +uint32_t getTotalSurface() +{ + return m_width * m_height; +} +/// return the usage ratio of the available surface [0:1] +float getUsageRatio(); +/// reset to initial state +void clear(); private: - int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height); - /// Merges all skyline nodes that are at the same level. - void merge(); +int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height); +/// Merges all skyline nodes that are at the same level. +void merge(); - struct Node +struct Node +{ + Node(int16_t _x, int16_t _y, int16_t _width) : m_x(_x), m_y(_y), m_width(_width) { - Node(int16_t _x, int16_t _y, int16_t _width):m_x(_x), m_y(_y), m_width(_width) {} - - /// The starting x-coordinate (leftmost). - int16_t m_x; - /// The y-coordinate of the skyline level line. - int16_t m_y; - /// The line _width. The ending coordinate (inclusive) will be x+width-1. - int32_t m_width; //32bit to avoid padding - }; + } - /// width (in pixels) of the underlying texture - uint32_t m_width; - /// height (in pixels) of the underlying texture - uint32_t m_height; - /// Surface used in squared pixel - uint32_t m_usedSpace; - /// node of the skyline algorithm - std::vector<Node> m_skyline; + /// The starting x-coordinate (leftmost). + int16_t m_x; + /// The y-coordinate of the skyline level line. + int16_t m_y; + /// The line _width. The ending coordinate (inclusive) will be x+width-1. + int32_t m_width; //32bit to avoid padding }; -RectanglePacker::RectanglePacker(): m_width(0), m_height(0), m_usedSpace(0) -{ +/// width (in pixels) of the underlying texture +uint32_t m_width; +/// height (in pixels) of the underlying texture +uint32_t m_height; +/// Surface used in squared pixel +uint32_t m_usedSpace; +/// node of the skyline algorithm +std::vector<Node> m_skyline; +}; + +RectanglePacker::RectanglePacker() : m_width(0), m_height(0), m_usedSpace(0) +{ } -RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height):m_width(_width), m_height(_height), m_usedSpace(0) -{ - // We want a one pixel border around the whole atlas to avoid any artefact when - // sampling texture - m_skyline.push_back(Node(1,1, _width-2)); +RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height) : m_width(_width), m_height(_height), m_usedSpace(0) +{ + // We want a one pixel border around the whole atlas to avoid any artefact when + // sampling texture + m_skyline.push_back(Node(1, 1, _width - 2) ); } void RectanglePacker::init(uint32_t _width, uint32_t _height) @@ -78,32 +85,33 @@ void RectanglePacker::init(uint32_t _width, uint32_t _height) m_skyline.clear(); // We want a one pixel border around the whole atlas to avoid any artifact when - // sampling texture - m_skyline.push_back(Node(1,1, _width-2)); + // sampling texture + m_skyline.push_back(Node(1, 1, _width - 2) ); } bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY) { int y, best_height, best_index; - int32_t best_width; - Node* node; - Node* prev; - _outX = 0; + int32_t best_width; + Node* node; + Node* prev; + _outX = 0; _outY = 0; - + uint32_t ii; - best_height = INT_MAX; - best_index = -1; - best_width = INT_MAX; - for( ii = 0; ii < m_skyline.size(); ++ii ) + best_height = INT_MAX; + best_index = -1; + best_width = INT_MAX; + for (ii = 0; ii < m_skyline.size(); ++ii) { - y = fit( ii, _width, _height ); - if( y >= 0 ) + y = fit(ii, _width, _height); + if (y >= 0) { - node = &m_skyline[ii]; - if( ( (y + _height) < best_height ) || - ( ((y + _height) == best_height) && (node->m_width < best_width)) ) + node = &m_skyline[ii]; + if ( ( (y + _height) < best_height) + || ( ( (y + _height) == best_height) + && (node->m_width < best_width) ) ) { best_height = y + _height; best_index = ii; @@ -111,116 +119,124 @@ bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX = node->m_x; _outY = y; } - } - } + } + } - if( best_index == -1 ) - { + if (best_index == -1) + { return false; - } - - Node newNode(_outX, _outY + _height, _width); - m_skyline.insert(m_skyline.begin() + best_index, newNode); + } - for(ii = best_index+1; ii < m_skyline.size(); ++ii) - { - node = &m_skyline[ii]; - prev = &m_skyline[ii-1]; - if (node->m_x < (prev->m_x + prev->m_width) ) - { - int shrink = prev->m_x + prev->m_width - node->m_x; - node->m_x += shrink; - node->m_width -= shrink; - if (node->m_width <= 0) - { - m_skyline.erase(m_skyline.begin() + ii); - --ii; - } - else - { - break; - } - } - else - { - break; - } - } + Node newNode(_outX, _outY + _height, _width); + m_skyline.insert(m_skyline.begin() + best_index, newNode); - merge(); - m_usedSpace += _width * _height; - return true; + for (ii = best_index + 1; ii < m_skyline.size(); ++ii) + { + node = &m_skyline[ii]; + prev = &m_skyline[ii - 1]; + if (node->m_x < (prev->m_x + prev->m_width) ) + { + int shrink = prev->m_x + prev->m_width - node->m_x; + node->m_x += shrink; + node->m_width -= shrink; + if (node->m_width <= 0) + { + m_skyline.erase(m_skyline.begin() + ii); + --ii; + } + else + { + break; + } + } + else + { + break; + } + } + + merge(); + m_usedSpace += _width * _height; + return true; } - + float RectanglePacker::getUsageRatio() -{ - uint32_t total = m_width*m_height; - if(total > 0) +{ + uint32_t total = m_width * m_height; + if (total > 0) + { return (float) m_usedSpace / (float) total; + } else + { return 0.0f; + } } void RectanglePacker::clear() { m_skyline.clear(); - m_usedSpace = 0; - - // We want a one pixel border around the whole atlas to avoid any artefact when - // sampling texture - m_skyline.push_back(Node(1,1, m_width-2)); + m_usedSpace = 0; + + // We want a one pixel border around the whole atlas to avoid any artefact when + // sampling texture + m_skyline.push_back(Node(1, 1, m_width - 2) ); } int32_t RectanglePacker::fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height) { int32_t width = _width; - int32_t height = _height; - - const Node& baseNode = m_skyline[_skylineNodeIndex]; - - int32_t x = baseNode.m_x, y; + int32_t height = _height; + + const Node& baseNode = m_skyline[_skylineNodeIndex]; + + int32_t x = baseNode.m_x, y; int32_t _width_left = width; int32_t i = _skylineNodeIndex; - if ( (x + width) > (int32_t)(m_width-1) ) - { - return -1; - } - y = baseNode.m_y; - while( _width_left > 0 ) + if ( (x + width) > (int32_t)(m_width - 1) ) { - const Node& node = m_skyline[i]; - if( node.m_y > y ) - { - y = node.m_y; - } - if( (y + height) > (int32_t)(m_height-1) ) - { + return -1; + } + + y = baseNode.m_y; + while (_width_left > 0) + { + const Node& node = m_skyline[i]; + if (node.m_y > y) + { + y = node.m_y; + } + + if ( (y + height) > (int32_t)(m_height - 1) ) + { return -1; - } - _width_left -= node.m_width; + } + + _width_left -= node.m_width; ++i; } + return y; } - + void RectanglePacker::merge() { Node* node; - Node* next; - uint32_t ii; + Node* next; + uint32_t ii; - for( ii=0; ii < m_skyline.size()-1; ++ii ) - { - node = (Node *) &m_skyline[ii]; - next = (Node *) &m_skyline[ii+1]; - if( node->m_y == next->m_y ) + for (ii = 0; ii < m_skyline.size() - 1; ++ii) + { + node = (Node*) &m_skyline[ii]; + next = (Node*) &m_skyline[ii + 1]; + if (node->m_y == next->m_y) { node->m_width += next->m_width; - m_skyline.erase(m_skyline.begin() + ii + 1); + m_skyline.erase(m_skyline.begin() + ii + 1); --ii; } - } + } } //********** Cube Atlas implementation ************ @@ -231,15 +247,18 @@ struct Atlas::PackedLayer AtlasRegion faceRegion; }; -Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) +Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount) { - BX_CHECK(_textureSize >= 64 && _textureSize <= 4096, "suspicious texture size" ); - BX_CHECK(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000, "suspicious _regions count" ); + BX_CHECK(_textureSize >= 64 + && _textureSize <= 4096, "suspicious texture size"); + BX_CHECK(_maxRegionsCount >= 64 + && _maxRegionsCount <= 32000, "suspicious _regions count"); m_layers = new PackedLayer[24]; - for(int ii=0; ii<24;++ii) + for (int ii = 0; ii < 24; ++ii) { - m_layers[ii].packer.init(_textureSize, _textureSize); + m_layers[ii].packer.init(_textureSize, _textureSize); } + m_usedLayers = 0; m_usedFaces = 0; @@ -248,28 +267,29 @@ Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) m_maxRegionCount = _maxRegionsCount; m_regions = new AtlasRegion[_maxRegionsCount]; m_textureBuffer = new uint8_t[ _textureSize * _textureSize * 6 * 4 ]; - memset(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4); + memset(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4); //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP - uint32_t flags = 0;// BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; + uint32_t flags = 0; // BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; //Uncomment this to debug atlas //const bgfx::Memory* mem = bgfx::alloc(textureSize*textureSize * 6 * 4); - //memset(mem->data, 255, mem->size); - const bgfx::Memory* mem = NULL; + //memset(mem->data, 255, mem->size); + const bgfx::Memory* mem = NULL; m_textureHandle = bgfx::createTextureCube(6 - , _textureSize - , 1 - , bgfx::TextureFormat::BGRA8 - , flags - ,mem - ); + , _textureSize + , 1 + , bgfx::TextureFormat::BGRA8 + , flags + , mem + ); } -Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount) +Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount) { - BX_CHECK(_regionCount <= 64 && _maxRegionsCount <= 4096, "suspicious initialization"); + BX_CHECK(_regionCount <= 64 + && _maxRegionsCount <= 4096, "suspicious initialization"); //layers are frozen m_usedLayers = 24; m_usedFaces = 6; @@ -277,27 +297,32 @@ Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _re m_textureSize = _textureSize; m_regionCount = _regionCount; //regions are frozen - if(_regionCount < _maxRegionsCount) + if (_regionCount < _maxRegionsCount) + { m_maxRegionCount = _regionCount; + } else + { m_maxRegionCount = _maxRegionsCount; + } + m_regions = new AtlasRegion[_regionCount]; m_textureBuffer = new uint8_t[getTextureBufferSize()]; - + //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP - uint32_t flags = 0;//BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; - memcpy(m_regions, _regionBuffer, _regionCount * sizeof(AtlasRegion)); - memcpy(m_textureBuffer, _textureBuffer, getTextureBufferSize()); + uint32_t flags = 0; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; + memcpy(m_regions, _regionBuffer, _regionCount * sizeof(AtlasRegion) ); + memcpy(m_textureBuffer, _textureBuffer, getTextureBufferSize() ); m_textureHandle = bgfx::createTextureCube(6 - , _textureSize - , 1 - , bgfx::TextureFormat::BGRA8 - , flags - , bgfx::makeRef(m_textureBuffer, getTextureBufferSize()) - ); + , _textureSize + , 1 + , bgfx::TextureFormat::BGRA8 + , flags + , bgfx::makeRef(m_textureBuffer, getTextureBufferSize() ) + ); } Atlas::~Atlas() @@ -307,183 +332,198 @@ Atlas::~Atlas() delete[] m_textureBuffer; } -uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type, uint16_t outline) +uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type, uint16_t outline) { if (m_regionCount >= m_maxRegionCount) { return UINT16_MAX; } - - uint16_t x=0,y=0; + + uint16_t x = 0, y = 0; // We want each bitmap to be separated by at least one black pixel // TODO manage mipmaps uint32_t idx = 0; - while(idx<m_usedLayers) + while (idx < m_usedLayers) { - if(m_layers[idx].faceRegion.getType() == _type) + if (m_layers[idx].faceRegion.getType() == _type) { - if(m_layers[idx].packer.addRectangle(_width+1,_height+1,x,y)) break; + if (m_layers[idx].packer.addRectangle(_width + 1, _height + 1, x, y) ) + { + break; + } } + idx++; } - if(idx >= m_usedLayers) + if (idx >= m_usedLayers) { //do we have still room to add layers ? - if( (idx + _type) > 24 || m_usedFaces>=6) + if ( (idx + _type) > 24 + || m_usedFaces >= 6) { - return UINT16_MAX; - } - //create new layers - for(int ii=0; ii < _type; ++ii) - { - m_layers[idx+ii].faceRegion.setMask(_type, m_usedFaces, ii); + return UINT16_MAX; } + + //create new layers + for (int ii = 0; ii < _type; ++ii) + { + m_layers[idx + ii].faceRegion.setMask(_type, m_usedFaces, ii); + } + m_usedLayers += _type; m_usedFaces++; - //add it to the created layer - if(!m_layers[idx].packer.addRectangle(_width+1, _height+1, x, y)) + if (!m_layers[idx].packer.addRectangle(_width + 1, _height + 1, x, y) ) { return UINT16_MAX; } } - + AtlasRegion& region = m_regions[m_regionCount]; - region.m_x = x ; - region.m_y = y ; + region.m_x = x; + region.m_y = y; region.m_width = _width; region.m_height = _height; region.m_mask = m_layers[idx].faceRegion.m_mask; updateRegion(region, _bitmapBuffer); - + region.m_x += outline; region.m_y += outline; - region.m_width -= (outline*2); - region.m_height -= (outline*2); + region.m_width -= (outline * 2); + region.m_height -= (outline * 2); return m_regionCount++; } void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer) -{ +{ const bgfx::Memory* mem = bgfx::alloc(_region.m_width * _region.m_height * 4); //BAD! - memset(mem->data,0, mem->size); - if(_region.getType() == AtlasRegion::TYPE_BGRA8) - { + memset(mem->data, 0, mem->size); + if (_region.getType() == AtlasRegion::TYPE_BGRA8) + { const uint8_t* inLineBuffer = _bitmapBuffer; - uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4); + uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize * m_textureSize * 4) + ( ( (_region.m_y * m_textureSize) + _region.m_x) * 4); //update the cpu buffer - for(int yy = 0; yy < _region.m_height; ++yy) + for (int yy = 0; yy < _region.m_height; ++yy) { memcpy(outLineBuffer, inLineBuffer, _region.m_width * 4); - inLineBuffer += _region.m_width*4; - outLineBuffer += m_textureSize*4; + inLineBuffer += _region.m_width * 4; + outLineBuffer += m_textureSize * 4; } + //update the GPU buffer memcpy(mem->data, _bitmapBuffer, mem->size); - }else + } + else { uint32_t layer = _region.getComponentIndex(); //uint32_t face = _region.getFaceIndex(); const uint8_t* inLineBuffer = _bitmapBuffer; - uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4)); - + uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize * m_textureSize * 4) + ( ( (_region.m_y * m_textureSize) + _region.m_x) * 4) ); + //update the cpu buffer - for(int yy = 0; yy<_region.m_height; ++yy) + for (int yy = 0; yy < _region.m_height; ++yy) { - for(int xx = 0; xx<_region.m_width; ++xx) + for (int xx = 0; xx < _region.m_width; ++xx) { - outLineBuffer[(xx*4) + layer] = inLineBuffer[xx]; + outLineBuffer[(xx * 4) + layer] = inLineBuffer[xx]; } + //update the GPU buffer - memcpy(mem->data + yy*_region.m_width*4, outLineBuffer, _region.m_width*4); + memcpy(mem->data + yy * _region.m_width * 4, outLineBuffer, _region.m_width * 4); inLineBuffer += _region.m_width; - outLineBuffer += m_textureSize*4; + outLineBuffer += m_textureSize * 4; } } - bgfx::updateTextureCube(m_textureHandle, (uint8_t)_region.getFaceIndex(), 0, _region.m_x, _region.m_y, _region.m_width, _region.m_height, mem); + + bgfx::updateTextureCube(m_textureHandle, (uint8_t)_region.getFaceIndex(), 0, _region.m_x, _region.m_y, _region.m_width, _region.m_height, mem); } -void Atlas::packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) +void Atlas::packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) { packUV(m_layers[_idx].faceRegion, _vertexBuffer, _offset, _stride); } -void Atlas::packUV( uint16_t handle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) +void Atlas::packUV(uint16_t handle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) { const AtlasRegion& region = m_regions[handle]; packUV(region, _vertexBuffer, _offset, _stride); } -void Atlas::packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) +void Atlas::packUV(const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) { - float texMult = 65535.0f / ((float)(m_textureSize)); + float texMult = 65535.0f / ( (float)(m_textureSize) ); static const int16_t minVal = -32768; static const int16_t maxVal = 32767; - - int16_t x0 = (int16_t)(_region.m_x * texMult)-32768; - int16_t y0 = (int16_t)(_region.m_y * texMult)-32768; - int16_t x1 = (int16_t)((_region.m_x + _region.m_width)* texMult)-32768; - int16_t y1 = (int16_t)((_region.m_y + _region.m_height)* texMult)-32768; - int16_t w = (int16_t) ((32767.0f/4.0f) * _region.getComponentIndex()); - _vertexBuffer+=_offset; - switch(_region.getFaceIndex()) + int16_t x0 = (int16_t)(_region.m_x * texMult) - 32768; + int16_t y0 = (int16_t)(_region.m_y * texMult) - 32768; + int16_t x1 = (int16_t)( (_region.m_x + _region.m_width) * texMult) - 32768; + int16_t y1 = (int16_t)( (_region.m_y + _region.m_height) * texMult) - 32768; + int16_t w = (int16_t) ( (32767.0f / 4.0f) * _region.getComponentIndex() ); + + _vertexBuffer += _offset; + switch (_region.getFaceIndex() ) { case 0: // +X - x0= -x0; - x1= -x1; - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, maxVal, y0, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, maxVal, y1, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, maxVal, y1, x1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, maxVal, y0, x1, w); _vertexBuffer+=_stride; + x0 = -x0; + x1 = -x1; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, maxVal, y0, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, maxVal, y1, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, maxVal, y1, x1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, maxVal, y0, x1, w); _vertexBuffer += _stride; break; - case 1: // -X - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, minVal, y0, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, minVal, y1, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, minVal, y1, x1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, minVal, y0, x1, w); _vertexBuffer+=_stride; + + case 1: // -X + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, minVal, y0, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, minVal, y1, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, minVal, y1, x1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, minVal, y0, x1, w); _vertexBuffer += _stride; break; - case 2: // +Y - writeUV(_vertexBuffer, x0, maxVal, y0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, maxVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, maxVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, maxVal, y0, w); _vertexBuffer+=_stride; + + case 2: // +Y + writeUV(_vertexBuffer, x0, maxVal, y0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, maxVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, maxVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, maxVal, y0, w); _vertexBuffer += _stride; break; + case 3: // -Y - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, x0, minVal, y0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, minVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, minVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, minVal, y0, w); _vertexBuffer+=_stride; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, x0, minVal, y0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, minVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, minVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, minVal, y0, w); _vertexBuffer += _stride; break; + case 4: // +Z - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, x0, y0, maxVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, y1, maxVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y1, maxVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y0, maxVal, w); _vertexBuffer+=_stride; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, x0, y0, maxVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, y1, maxVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y1, maxVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y0, maxVal, w); _vertexBuffer += _stride; break; + case 5: // -Z - x0= -x0; - x1= -x1; - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, x0, y0, minVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, y1, minVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y1, minVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y0, minVal, w); _vertexBuffer+=_stride; + x0 = -x0; + x1 = -x1; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, x0, y0, minVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, y1, minVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y1, minVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y0, minVal, w); _vertexBuffer += _stride; break; } } diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 9ac55826..e44d022c 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -15,7 +15,7 @@ /// algorithm based on C++ sources provided by Jukka Jylänki at: /// http://clb.demon.fi/files/RectangleBinPack/ -#include <bgfx.h> +#include <bgfx.h> struct AtlasRegion { @@ -23,115 +23,147 @@ struct AtlasRegion { TYPE_GRAY = 1, // 1 component TYPE_BGRA8 = 4 // 4 components - }; + }; uint16_t m_x, m_y; uint16_t m_width, m_height; uint32_t m_mask; //encode the region type, the face index and the component index in case of a gray region - Type getType()const { return (Type) ((m_mask >> 0) & 0x0000000F); } - uint32_t getFaceIndex()const { return (m_mask >> 4) & 0x0000000F; } - uint32_t getComponentIndex()const { return (m_mask >> 8) & 0x0000000F; } - void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex) { m_mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type; } + Type getType() const + { + return (Type) ( (m_mask >> 0) & 0x0000000F); + } + uint32_t getFaceIndex() const + { + return (m_mask >> 4) & 0x0000000F; + } + uint32_t getComponentIndex() const + { + return (m_mask >> 8) & 0x0000000F; + } + void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex) + { + m_mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type; + } }; class Atlas { public: - /// create an empty dynamic atlas (region can be updated and added) - /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) - /// @param maxRegionCount maximum number of region allowed in the atlas - Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount = 4096); - - /// initialize a static atlas with serialized data (region can be updated but not added) - /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) - /// @param textureBuffer buffer of size 6*textureSize*textureSize*sizeof(uint32_t) (will be copied) - /// @param regionCount number of region in the Atlas - /// @param regionBuffer buffer containing the region (will be copied) - /// @param maxRegionCount maximum number of region allowed in the atlas - Atlas(uint16_t _textureSize, const uint8_t * _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount = 4096); - ~Atlas(); - - /// add a region to the atlas, and copy the content of mem to the underlying texture - uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8, uint16_t outline = 0); +/// create an empty dynamic atlas (region can be updated and added) +/// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) +/// @param maxRegionCount maximum number of region allowed in the atlas +Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount = 4096); - /// update a preallocated region - void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer); +/// initialize a static atlas with serialized data (region can be updated but not added) +/// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) +/// @param textureBuffer buffer of size 6*textureSize*textureSize*sizeof(uint32_t) (will be copied) +/// @param regionCount number of region in the Atlas +/// @param regionBuffer buffer containing the region (will be copied) +/// @param maxRegionCount maximum number of region allowed in the atlas +Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount = 4096); +~Atlas(); - /// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format. - /// v0 -- v3 - /// | | encoded in that order: v0,v1,v2,v3 - /// v1 -- v2 - /// @remark the UV are four signed short normalized components. - /// @remark the x,y,z components encode cube uv coordinates. The w component encode the color channel if any. - /// @param handle handle to the region we are interested in - /// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first. - /// @param offset byte offset to the first uv coordinate of the vertex in the buffer - /// @param stride stride between tho UV coordinates, usually size of a Vertex. - void packUV( uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); - void packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); - - /// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas - void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); +/// add a region to the atlas, and copy the content of mem to the underlying texture +uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8, uint16_t outline = 0); - /// Pack the vertex index of the region as 2 quad into an index buffer - void packIndex(uint16_t* _indexBuffer, uint32_t _startIndex, uint32_t _startVertex ) - { - _indexBuffer[_startIndex+0] = _startVertex+0; - _indexBuffer[_startIndex+1] = _startVertex+1; - _indexBuffer[_startIndex+2] = _startVertex+2; - _indexBuffer[_startIndex+3] = _startVertex+0; - _indexBuffer[_startIndex+4] = _startVertex+2; - _indexBuffer[_startIndex+5] = _startVertex+3; - } +/// update a preallocated region +void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer); - /// return the TextureHandle (cube) of the atlas - bgfx::TextureHandle getTextureHandle() const { return m_textureHandle; } +/// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format. +/// v0 -- v3 +/// | | encoded in that order: v0,v1,v2,v3 +/// v1 -- v2 +/// @remark the UV are four signed short normalized components. +/// @remark the x,y,z components encode cube uv coordinates. The w component encode the color channel if any. +/// @param handle handle to the region we are interested in +/// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first. +/// @param offset byte offset to the first uv coordinate of the vertex in the buffer +/// @param stride stride between tho UV coordinates, usually size of a Vertex. +void packUV(uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride); +void packUV(const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride); - //retrieve a region info - const AtlasRegion& getRegion(uint16_t _handle) const { return m_regions[_handle]; } - - /// retrieve the size of side of a texture in pixels - uint16_t getTextureSize(){ return m_textureSize; } +/// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas +void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride); - /// retrieve the usage ratio of the atlas - //float getUsageRatio() const { return 0.0f; } +/// Pack the vertex index of the region as 2 quad into an index buffer +void packIndex(uint16_t* _indexBuffer, uint32_t _startIndex, uint32_t _startVertex) +{ + _indexBuffer[_startIndex + 0] = _startVertex + 0; + _indexBuffer[_startIndex + 1] = _startVertex + 1; + _indexBuffer[_startIndex + 2] = _startVertex + 2; + _indexBuffer[_startIndex + 3] = _startVertex + 0; + _indexBuffer[_startIndex + 4] = _startVertex + 2; + _indexBuffer[_startIndex + 5] = _startVertex + 3; +} - /// retrieve the numbers of region in the atlas - uint16_t getRegionCount() const { return m_regionCount; } +/// return the TextureHandle (cube) of the atlas +bgfx::TextureHandle getTextureHandle() const +{ + return m_textureHandle; +} - /// retrieve a pointer to the region buffer (in order to serialize it) - const AtlasRegion* getRegionBuffer() const { return m_regions; } - - /// retrieve the byte size of the texture - uint32_t getTextureBufferSize() const { return 6*m_textureSize*m_textureSize*4; } +//retrieve a region info +const AtlasRegion& getRegion(uint16_t _handle) const +{ + return m_regions[_handle]; +} - /// retrieve the mirrored texture buffer (to serialize it) - const uint8_t* getTextureBuffer() const { return m_textureBuffer; } +/// retrieve the size of side of a texture in pixels +uint16_t getTextureSize() +{ + return m_textureSize; +} + +/// retrieve the usage ratio of the atlas +//float getUsageRatio() const { return 0.0f; } + +/// retrieve the numbers of region in the atlas +uint16_t getRegionCount() const +{ + return m_regionCount; +} + +/// retrieve a pointer to the region buffer (in order to serialize it) +const AtlasRegion* getRegionBuffer() const +{ + return m_regions; +} + +/// retrieve the byte size of the texture +uint32_t getTextureBufferSize() const +{ + return 6 * m_textureSize * m_textureSize * 4; +} + +/// retrieve the mirrored texture buffer (to serialize it) +const uint8_t* getTextureBuffer() const +{ + return m_textureBuffer; +} private: - void writeUV( uint8_t* _vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w) - { - ((uint16_t*) _vertexBuffer)[0] = _x; - ((uint16_t*) _vertexBuffer)[1] = _y; - ((uint16_t*) _vertexBuffer)[2] = _z; - ((uint16_t*) _vertexBuffer)[3] = _w; - } - struct PackedLayer; - PackedLayer* m_layers; +void writeUV(uint8_t* _vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w) +{ + ( (uint16_t*) _vertexBuffer)[0] = _x; + ( (uint16_t*) _vertexBuffer)[1] = _y; + ( (uint16_t*) _vertexBuffer)[2] = _z; + ( (uint16_t*) _vertexBuffer)[3] = _w; +} +struct PackedLayer; +PackedLayer* m_layers; - uint32_t m_usedLayers; - uint32_t m_usedFaces; +uint32_t m_usedLayers; +uint32_t m_usedFaces; - bgfx::TextureHandle m_textureHandle; - uint16_t m_textureSize; +bgfx::TextureHandle m_textureHandle; +uint16_t m_textureSize; - uint16_t m_regionCount; - uint16_t m_maxRegionCount; - - AtlasRegion* m_regions; - uint8_t* m_textureBuffer; +uint16_t m_regionCount; +uint16_t m_maxRegionCount; +AtlasRegion* m_regions; +uint8_t* m_textureBuffer; }; #endif // __CUBE_ATLAS_H__ diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 782bd89c..582356d1 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -7,40 +7,42 @@ #include "../cube_atlas.h" #if BX_COMPILER_MSVC -# pragma warning(push) -# pragma warning(disable: 4100) // DISABLE warning C4100: '' : unreferenced formal parameter -# pragma warning(disable: 4146) // DISABLE warning C4146: unary minus operator applied to unsigned type, result still unsigned -# pragma warning(disable: 4700) // DISABLE warning C4700: uninitialized local variable 'temp' used -# pragma warning(disable: 4701) // DISABLE warning C4701: potentially uninitialized local variable '' used -# include <freetype/freetype.h> -# pragma warning(pop) +# pragma warning(push) +# pragma warning(disable: 4100) // DISABLE warning C4100: '' : unreferenced formal parameter +# pragma warning(disable: 4146) // DISABLE warning C4146: unary minus operator applied to unsigned type, result still unsigned +# pragma warning(disable: 4700) // DISABLE warning C4700: uninitialized local variable 'temp' used +# pragma warning(disable: 4701) // DISABLE warning C4701: potentially uninitialized local variable '' used +# include <freetype/freetype.h> +# pragma warning(pop) #else -# include <freetype/freetype.h> +# include <freetype/freetype.h> #endif // BX_COMPILER_MSVC - #include <edtaa3/edtaa3func.h> #include <edtaa3/edtaa3func.cpp> #include <bx/bx.h> - #if BGFX_CONFIG_USE_TINYSTL namespace tinystl { //struct bgfx_allocator //{ - //static void* static_allocate(size_t _bytes); - //static void static_deallocate(void* _ptr, size_t /*_bytes*/); + //static void* static_allocate(size_t _bytes); + //static void static_deallocate(void* _ptr, size_t /*_bytes*/); //}; } // namespace tinystl //# define TINYSTL_ALLOCATOR tinystl::bgfx_allocator -# include <TINYSTL/unordered_map.h> +# include <TINYSTL/unordered_map.h> //# include <TINYSTL/unordered_set.h> namespace stl = tinystl; #else -# include <unordered_map> -namespace std { namespace tr1 {} } -namespace stl { +# include <unordered_map> +namespace std +{ namespace tr1 + {} +} +namespace stl +{ using namespace std; using namespace std::tr1; } @@ -48,53 +50,52 @@ namespace stl { class FontManager::TrueTypeFont { -public: - TrueTypeFont(); - ~TrueTypeFont(); +public: +TrueTypeFont(); +~TrueTypeFont(); - /// Initialize from an external buffer - /// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime - /// @return true if the initialization succeed - bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight ); - - /// return the font descriptor of the current font - FontInfo getFontInfo(); - - /// raster a glyph as 8bit alpha to a memory buffer - /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) - bool bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); +/// Initialize from an external buffer +/// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime +/// @return true if the initialization succeed +bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight); - /// raster a glyph as 32bit subpixel rgba to a memory buffer - /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t) - bool bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); +/// return the font descriptor of the current font +FontInfo getFontInfo(); - /// raster a glyph as 8bit signed distance to a memory buffer - /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) - bool bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); +/// raster a glyph as 8bit alpha to a memory buffer +/// update the GlyphInfo according to the raster strategy +/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) +bool bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); + +/// raster a glyph as 32bit subpixel rgba to a memory buffer +/// update the GlyphInfo according to the raster strategy +/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t) +bool bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); + +/// raster a glyph as 8bit signed distance to a memory buffer +/// update the GlyphInfo according to the raster strategy +/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) +bool bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); private: - void* m_font; +void* m_font; }; - struct FTHolder { FT_Library library; FT_Face face; }; -FontManager::TrueTypeFont::TrueTypeFont(): m_font(NULL) -{ +FontManager::TrueTypeFont::TrueTypeFont() : m_font(NULL) +{ } FontManager::TrueTypeFont::~TrueTypeFont() { - if(m_font!=NULL) + if (m_font != NULL) { FTHolder* holder = (FTHolder*) m_font; - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); + FT_Done_Face(holder->face); + FT_Done_FreeType(holder->library); delete m_font; m_font = NULL; } @@ -102,55 +103,58 @@ FontManager::TrueTypeFont::~TrueTypeFont() bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight) { - BX_CHECK((_bufferSize > 256 && _bufferSize < 100000000), "TrueType buffer size is suspicious"); - BX_CHECK((_pixelHeight > 4 && _pixelHeight < 128), "TrueType buffer size is suspicious"); - - BX_CHECK(m_font == NULL, "TrueTypeFont already initialized" ); - - FTHolder* holder = new FTHolder(); + BX_CHECK( (_bufferSize > 256 + && _bufferSize < 100000000), "TrueType buffer size is suspicious"); + BX_CHECK( (_pixelHeight > 4 + && _pixelHeight < 128), "TrueType buffer size is suspicious"); + + BX_CHECK(m_font == NULL, "TrueTypeFont already initialized"); + + FTHolder* holder = new FTHolder(); // Initialize Freetype library - FT_Error error = FT_Init_FreeType( &holder->library ); - if( error) + FT_Error error = FT_Init_FreeType(&holder->library); + if (error) { delete holder; return false; } - error = FT_New_Memory_Face( holder->library, _buffer, _bufferSize, _fontIndex, &holder->face ); - if ( error == FT_Err_Unknown_File_Format ) - { + error = FT_New_Memory_Face(holder->library, _buffer, _bufferSize, _fontIndex, &holder->face); + if (error == FT_Err_Unknown_File_Format) + { // the font file could be opened and read, but it appears //that its font format is unsupported - FT_Done_FreeType( holder->library ); + FT_Done_FreeType(holder->library); delete holder; return false; } - else if ( error ) + else if (error) { // another error code means that the font file could not // be opened or read, or simply that it is broken... - FT_Done_FreeType( holder->library ); + FT_Done_FreeType(holder->library); delete holder; return false; } - // Select unicode charmap - error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE ); - if( error ) - { - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); - return false; - } + // Select unicode charmap + error = FT_Select_Charmap(holder->face, FT_ENCODING_UNICODE); + if (error) + { + FT_Done_Face(holder->face); + FT_Done_FreeType(holder->library); + return false; + } + //set size in pixels - error = FT_Set_Pixel_Sizes( holder->face, 0, _pixelHeight ); - if( error ) - { - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); - return false; - } + error = FT_Set_Pixel_Sizes(holder->face, 0, _pixelHeight); + if (error) + { + FT_Done_Face(holder->face); + FT_Done_FreeType(holder->library); + return false; + } m_font = holder; return true; @@ -158,88 +162,106 @@ bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSiz FontInfo FontManager::TrueTypeFont::getFontInfo() { - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - + //todo manage unscalable font - BX_CHECK(FT_IS_SCALABLE (holder->face), "Font is unscalable"); + BX_CHECK(FT_IS_SCALABLE(holder->face), "Font is unscalable"); FT_Size_Metrics metrics = holder->face->size->metrics; - FontInfo outFontInfo; outFontInfo.scale = 1.0f; - outFontInfo.ascender = metrics.ascender /64.0f; - outFontInfo.descender = metrics.descender /64.0f; - outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; - - outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f; - outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f; + outFontInfo.ascender = metrics.ascender / 64.0f; + outFontInfo.descender = metrics.descender / 64.0f; + outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) / 64.0f; + + outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) / 64.0f; + outFontInfo.underline_thickness = FT_MulFix(holder->face->underline_thickness, metrics.y_scale) / 64.0f; return outFontInfo; } bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) -{ - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); +{ + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - - _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - + + _glyphInfo.glyphIndex = FT_Get_Char_Index(holder->face, _codePoint); + FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); - if(error) { return false; } - + FT_Error error = FT_Load_Glyph(holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT); + if (error) + { + return false; + } + FT_Glyph glyph; - error = FT_Get_Glyph( slot, &glyph ); - if ( error ) { return false; } - - error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 ); - if(error){ return false; } - + error = FT_Get_Glyph(slot, &glyph); + if (error) + { + return false; + } + + error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); + if (error) + { + return false; + } + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - + int32_t x = bitmap->left; int32_t y = -bitmap->top; int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; _glyphInfo.offset_x = (float) x; - _glyphInfo.offset_y = (float) y; - _glyphInfo.width = (float) w; - _glyphInfo.height = (float) h; - _glyphInfo.advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x / 64.0f; + _glyphInfo.advance_y = (float)slot->advance.y / 64.0f; int32_t charsize = 1; - int32_t depth=1; + int32_t depth = 1; int32_t stride = bitmap->bitmap.pitch; - for( int32_t ii=0; ii<h; ++ii ) - { - memcpy(_outBuffer+(ii*w) * charsize * depth, - bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); - } + for (int32_t ii = 0; ii < h; ++ii) + { + memcpy(_outBuffer + (ii * w) * charsize * depth, + bitmap->bitmap.buffer + (ii * stride) * charsize, w * charsize * depth); + } + FT_Done_Glyph(glyph); return true; } bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - - _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - + + _glyphInfo.glyphIndex = FT_Get_Char_Index(holder->face, _codePoint); + FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); - if(error) { return false; } - + FT_Error error = FT_Load_Glyph(holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT); + if (error) + { + return false; + } + FT_Glyph glyph; - error = FT_Get_Glyph( slot, &glyph ); - if ( error ) { return false; } - - error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_LCD, 0, 1 ); - if(error){ return false; } - + error = FT_Get_Glyph(slot, &glyph); + if (error) + { + return false; + } + + error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_LCD, 0, 1); + if (error) + { + return false; + } + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; int32_t x = bitmap->left; int32_t y = -bitmap->top; @@ -247,216 +269,257 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI int32_t h = bitmap->bitmap.rows; _glyphInfo.offset_x = (float) x; - _glyphInfo.offset_y = (float) y; - _glyphInfo.width = (float) w; - _glyphInfo.height = (float) h; - _glyphInfo.advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x / 64.0f; + _glyphInfo.advance_y = (float)slot->advance.y / 64.0f; int32_t charsize = 1; - int32_t depth=3; + int32_t depth = 3; int32_t stride = bitmap->bitmap.pitch; - for( int32_t ii=0; ii<h; ++ii ) - { - memcpy(_outBuffer+(ii*w) * charsize * depth, - bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); - } + for (int32_t ii = 0; ii < h; ++ii) + { + memcpy(_outBuffer + (ii * w) * charsize * depth, + bitmap->bitmap.buffer + (ii * stride) * charsize, w * charsize * depth); + } + FT_Done_Glyph(glyph); return true; } //TODO optimize: remove dynamic allocation and convert double to float -void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int width, unsigned int height ) +void make_distance_map(unsigned char* img, unsigned char* outImg, unsigned int width, unsigned int height) { - short * xdist = (short *) malloc( width * height * sizeof(short) ); - short * ydist = (short *) malloc( width * height * sizeof(short) ); - double * gx = (double *) calloc( width * height, sizeof(double) ); - double * gy = (double *) calloc( width * height, sizeof(double) ); - double * data = (double *) calloc( width * height, sizeof(double) ); - double * outside = (double *) calloc( width * height, sizeof(double) ); - double * inside = (double *) calloc( width * height, sizeof(double) ); - uint32_t ii; + short* xdist = (short*) malloc(width * height * sizeof(short) ); + short* ydist = (short*) malloc(width * height * sizeof(short) ); + double* gx = (double*) calloc(width * height, sizeof(double) ); + double* gy = (double*) calloc(width * height, sizeof(double) ); + double* data = (double*) calloc(width * height, sizeof(double) ); + double* outside = (double*) calloc(width * height, sizeof(double) ); + double* inside = (double*) calloc(width * height, sizeof(double) ); + uint32_t ii; - // Convert img into double (data) - double img_min = 255, img_max = -255; - for( ii=0; ii<width*height; ++ii) - { - double v = img[ii]; - data[ii] = v; - if (v > img_max) img_max = v; - if (v < img_min) img_min = v; - } - // Rescale image levels between 0 and 1 - for( ii=0; ii<width*height; ++ii) - { - data[ii] = (img[ii]-img_min)/(img_max-img_min); - } + // Convert img into double (data) + double img_min = 255, img_max = -255; + for (ii = 0; ii < width * height; ++ii) + { + double v = img[ii]; + data[ii] = v; + if (v > img_max) + { + img_max = v; + } - // Compute outside = edtaa3(bitmap); % Transform background (0's) - computegradient( data, width, height, gx, gy); - edtaa3(data, gx, gy, width, height, xdist, ydist, outside); - for( ii=0; ii<width*height; ++ii) - if( outside[ii] < 0 ) - outside[ii] = 0.0; + if (v < img_min) + { + img_min = v; + } + } - // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) - memset(gx, 0, sizeof(double)*width*height ); - memset(gy, 0, sizeof(double)*width*height ); - for( ii=0; ii<width*height; ++ii) - data[ii] = 1.0 - data[ii]; - computegradient( data, width, height, gx, gy); - edtaa3(data, gx, gy, width, height, xdist, ydist, inside); - for( ii=0; ii<width*height; ++ii) - if( inside[ii] < 0 ) - inside[ii] = 0.0; + // Rescale image levels between 0 and 1 + for (ii = 0; ii < width * height; ++ii) + { + data[ii] = (img[ii] - img_min) / (img_max - img_min); + } - // distmap = outside - inside; % Bipolar distance field - unsigned char *out = outImg;//(unsigned char *) malloc( width * height * sizeof(unsigned char) ); - for( ii=0; ii<width*height; ++ii) - { + // Compute outside = edtaa3(bitmap); % Transform background (0's) + computegradient(data, width, height, gx, gy); + edtaa3(data, gx, gy, width, height, xdist, ydist, outside); + for (ii = 0; ii < width * height; ++ii) + { + if (outside[ii] < 0) + { + outside[ii] = 0.0; + } + } + + // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) + memset(gx, 0, sizeof(double) * width * height); + memset(gy, 0, sizeof(double) * width * height); + for (ii = 0; ii < width * height; ++ii) + { + data[ii] = 1.0 - data[ii]; + } + + computegradient(data, width, height, gx, gy); + edtaa3(data, gx, gy, width, height, xdist, ydist, inside); + for (ii = 0; ii < width * height; ++ii) + { + if (inside[ii] < 0) + { + inside[ii] = 0.0; + } + } + + // distmap = outside - inside; % Bipolar distance field + unsigned char* out = outImg; //(unsigned char *) malloc( width * height * sizeof(unsigned char) ); + for (ii = 0; ii < width * height; ++ii) + { //out[i] = 127 - outside[i]*8; //if(out[i]<0) out[i] = 0; //out[i] += inside[i]*16; //if(out[i]>255) out[i] = 255; outside[ii] -= inside[ii]; - outside[ii] = 128 + outside[ii]*16; + outside[ii] = 128 + outside[ii] * 16; //if(outside[i] > 8) outside[i] = 8; //if(inside[i] > 8) outside[i] = 8; //outside[i] = 128 - inside[i]*8 + outside[i]*8; - - if( outside[ii] < 0 ) outside[ii] = 0; - if( outside[ii] > 255 ) outside[ii] = 255; - out[ii] = 255 - (unsigned char) outside[ii]; - //out[i] = (unsigned char) outside[i]; - } - free( xdist ); - free( ydist ); - free( gx ); - free( gy ); - free( data ); - free( outside ); - free( inside ); + if (outside[ii] < 0) + { + outside[ii] = 0; + } + + if (outside[ii] > 255) + { + outside[ii] = 255; + } + + out[ii] = 255 - (unsigned char) outside[ii]; + //out[i] = (unsigned char) outside[i]; + } + + free(xdist); + free(ydist); + free(gx); + free(gy); + free(data); + free(outside); + free(inside); } - bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) -{ - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); +{ + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - - _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - - FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING; + + _glyphInfo.glyphIndex = FT_Get_Char_Index(holder->face, _codePoint); + + FT_Int32 loadMode = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL; FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, loadMode ); - if(error) { return false; } - + FT_Error error = FT_Load_Glyph(holder->face, _glyphInfo.glyphIndex, loadMode); + if (error) + { + return false; + } + FT_Glyph glyph; - error = FT_Get_Glyph( slot, &glyph ); - if ( error ) { return false; } - - error = FT_Glyph_To_Bitmap( &glyph, renderMode, 0, 1 ); - if(error){ return false; } - + error = FT_Get_Glyph(slot, &glyph); + if (error) + { + return false; + } + + error = FT_Glyph_To_Bitmap(&glyph, renderMode, 0, 1); + if (error) + { + return false; + } + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - + int32_t x = bitmap->left; int32_t y = -bitmap->top; int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; _glyphInfo.offset_x = (float) x; - _glyphInfo.offset_y = (float) y; - _glyphInfo.width = (float) w; - _glyphInfo.height = (float) h; - _glyphInfo.advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.advance_y = (float)slot->advance.y /64.0f; - - int32_t charsize = 1; - int32_t depth=1; - int32_t stride = bitmap->bitmap.pitch; - - for(int32_t ii=0; ii<h; ++ii ) - { + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x / 64.0f; + _glyphInfo.advance_y = (float)slot->advance.y / 64.0f; + + int32_t charsize = 1; + int32_t depth = 1; + int32_t stride = bitmap->bitmap.pitch; + + for (int32_t ii = 0; ii < h; ++ii) + { + memcpy(_outBuffer + (ii * w) * charsize * depth, + bitmap->bitmap.buffer + (ii * stride) * charsize, w * charsize * depth); + } - memcpy(_outBuffer+(ii*w) * charsize * depth, - bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); - } FT_Done_Glyph(glyph); - - if(w*h >0) + + if (w * h > 0) { uint32_t dw = 6; - uint32_t dh = 6; - if(dw<2) dw = 2; - if(dh<2) dh = 2; - - uint32_t nw = w + dw*2; - uint32_t nh = h + dh*2; - BX_CHECK(nw*nh < 128*128, "buffer overflow"); - uint32_t buffSize = nw*nh*sizeof(uint8_t); - - uint8_t * alphaImg = (uint8_t *) malloc( buffSize ); - memset(alphaImg, 0, nw*nh*sizeof(uint8_t)); + uint32_t dh = 6; + if (dw < 2) + { + dw = 2; + } + + if (dh < 2) + { + dh = 2; + } + + uint32_t nw = w + dw * 2; + uint32_t nh = h + dh * 2; + BX_CHECK(nw * nh < 128 * 128, "buffer overflow"); + uint32_t buffSize = nw * nh * sizeof(uint8_t); + + uint8_t* alphaImg = (uint8_t*) malloc(buffSize); + memset(alphaImg, 0, nw * nh * sizeof(uint8_t) ); //copy the original buffer to the temp one - for(uint32_t ii= dh; ii< nh-dh; ++ii) + for (uint32_t ii = dh; ii < nh - dh; ++ii) { - memcpy(alphaImg+ii*nw+dw, _outBuffer+(ii-dh)*w, w); + memcpy(alphaImg + ii * nw + dw, _outBuffer + (ii - dh) * w, w); } - + make_distance_map(alphaImg, _outBuffer, nw, nh); - free(alphaImg); - + free(alphaImg); + _glyphInfo.offset_x -= (float) dw; _glyphInfo.offset_y -= (float) dh; - _glyphInfo.width = (float) nw ; + _glyphInfo.width = (float) nw; _glyphInfo.height = (float) nh; } - - return true; + + return true; } - - //************************************************************* -typedef stl::unordered_map<CodePoint_t, GlyphInfo> GlyphHash_t; +typedef stl::unordered_map<CodePoint_t, GlyphInfo> GlyphHash_t; // cache font data struct FontManager::CachedFont { - CachedFont(){ trueTypeFont = NULL; masterFontHandle.idx = -1; } + CachedFont() + { + trueTypeFont = NULL; masterFontHandle.idx = -1; + } FontInfo fontInfo; GlyphHash_t cachedGlyphs; FontManager::TrueTypeFont* trueTypeFont; // an handle to a master font in case of sub distance field font - FontHandle masterFontHandle; + FontHandle masterFontHandle; int16_t padding; }; - - - const uint16_t MAX_OPENED_FILES = 64; const uint16_t MAX_OPENED_FONT = 64; -const uint32_t MAX_FONT_BUFFER_SIZE = 512*512*4; +const uint32_t MAX_FONT_BUFFER_SIZE = 512 * 512 * 4; -FontManager::FontManager(Atlas* _atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(Atlas* _atlas) : m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { m_atlas = _atlas; - m_ownAtlas = false; - init(); + m_ownAtlas = false; + init(); } -FontManager::FontManager(uint32_t _textureSideWidth):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(uint32_t _textureSideWidth) : m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { m_atlas = new Atlas(_textureSideWidth); - m_ownAtlas = true; + m_ownAtlas = true; init(); } @@ -465,73 +528,72 @@ void FontManager::init() m_cachedFiles = new CachedFile[MAX_OPENED_FILES]; m_cachedFonts = new CachedFont[MAX_OPENED_FONT]; m_buffer = new uint8_t[MAX_FONT_BUFFER_SIZE]; - + const uint32_t W = 3; // Create filler rectangle - uint8_t buffer[W*W*4]; - memset( buffer, 255, W * W * 4); + uint8_t buffer[W * W * 4]; + memset(buffer, 255, W * W * 4); m_blackGlyph.width = W; m_blackGlyph.height = W; ///make sure the black glyph doesn't bleed by using a one pixel inner outline - m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1 ); + m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1); } FontManager::~FontManager() { BX_CHECK(m_fontHandles.getNumHandles() == 0, "All the fonts must be destroyed before destroying the manager"); - delete [] m_cachedFonts; + delete[] m_cachedFonts; BX_CHECK(m_filesHandles.getNumHandles() == 0, "All the font files must be destroyed before destroying the manager"); - delete [] m_cachedFiles; - - delete [] m_buffer; - - if(m_ownAtlas) - { + delete[] m_cachedFiles; + + delete[] m_buffer; + + if (m_ownAtlas) + { delete m_atlas; } } - - TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) { - FILE * pFile; - pFile = fopen (_fontPath, "rb"); - if (pFile==NULL) + FILE* pFile; + pFile = fopen(_fontPath, "rb"); + if (pFile == NULL) { TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } - + // Go to the end of the file. if (fseek(pFile, 0L, SEEK_END) == 0) { // Get the size of the file. long bufsize = ftell(pFile); - if (bufsize == -1) + if (bufsize == -1) { fclose(pFile); TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } - + uint8_t* buffer = new uint8_t[bufsize]; // Go back to the start of the file. fseek(pFile, 0L, SEEK_SET); // Read the entire file into memory. - uint32_t newLen = fread((void*)buffer, sizeof(char), bufsize, pFile); - if (newLen == 0) + uint32_t newLen = fread( (void*)buffer, sizeof(char), bufsize, pFile); + if (newLen == 0) { fclose(pFile); - delete [] buffer; + delete[] buffer; TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } + fclose(pFile); uint16_t id = m_filesHandles.alloc(); @@ -541,20 +603,21 @@ TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) TrueTypeHandle ret = {id}; return ret; } + //TODO validate font TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size) -{ - uint16_t id = m_filesHandles.alloc(); +{ + uint16_t id = m_filesHandles.alloc(); BX_CHECK(id != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFiles[id].buffer = new uint8_t[_size]; m_cachedFiles[id].bufferSize = _size; memcpy(m_cachedFiles[id].buffer, _buffer, _size); - - //TODO validate font + + //TODO validate font TrueTypeHandle ret = {id}; return ret; } @@ -573,19 +636,19 @@ FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_ BX_CHECK(bgfx::invalidHandle != _tt_handle.idx, "Invalid handle used"); TrueTypeFont* ttf = new TrueTypeFont(); - if(!ttf->init( m_cachedFiles[_tt_handle.idx].buffer, m_cachedFiles[_tt_handle.idx].bufferSize, _typefaceIndex, _pixelSize)) + if (!ttf->init(m_cachedFiles[_tt_handle.idx].buffer, m_cachedFiles[_tt_handle.idx].bufferSize, _typefaceIndex, _pixelSize) ) { delete ttf; FontHandle invalid = BGFX_INVALID_HANDLE; return invalid; } - + uint16_t fontIdx = m_fontHandles.alloc(); - BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); - + BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); + m_cachedFonts[fontIdx].trueTypeFont = ttf; m_cachedFonts[fontIdx].fontInfo = ttf->getFontInfo(); - m_cachedFonts[fontIdx].fontInfo.fontType = _fontType; + m_cachedFonts[fontIdx].fontInfo.fontType = _fontType; m_cachedFonts[fontIdx].fontInfo.pixelSize = _pixelSize; m_cachedFonts[fontIdx].cachedGlyphs.clear(); m_cachedFonts[fontIdx].masterFontHandle.idx = -1; @@ -608,7 +671,6 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, newFontInfo.underline_thickness = (newFontInfo.underline_thickness * newFontInfo.scale); newFontInfo.underline_position = (newFontInfo.underline_position * newFontInfo.scale); - uint16_t fontIdx = m_fontHandles.alloc(); BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFonts[fontIdx].cachedGlyphs.clear(); @@ -619,7 +681,7 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, return ret; } -FontHandle FontManager::loadBakedFontFromFile(const char* /*fontPath*/, const char* /*descriptorPath*/) +FontHandle FontManager::loadBakedFontFromFile(const char* /*fontPath*/, const char* /*descriptorPath*/) { //assert(false); //TODO implement FontHandle invalid = BGFX_INVALID_HANDLE; @@ -637,33 +699,35 @@ void FontManager::destroyFont(FontHandle _handle) { BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - if(m_cachedFonts[_handle.idx].trueTypeFont != NULL) + if (m_cachedFonts[_handle.idx].trueTypeFont != NULL) { delete m_cachedFonts[_handle.idx].trueTypeFont; m_cachedFonts[_handle.idx].trueTypeFont = NULL; } - m_cachedFonts[_handle.idx].cachedGlyphs.clear(); + + m_cachedFonts[_handle.idx].cachedGlyphs.clear(); m_fontHandles.free(_handle.idx); } bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) -{ +{ BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_handle.idx]; //if truetype present - if(font.trueTypeFont != NULL) - { + if (font.trueTypeFont != NULL) + { //parse string - for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) + for (uint32_t ii = 0, end = wcslen(_string); ii < end; ++ii) { //if glyph cached, continue CodePoint_t codePoint = _string[ii]; - if(!preloadGlyph(_handle, codePoint)) + if (!preloadGlyph(_handle, codePoint) ) { return false; } } + return true; } @@ -677,37 +741,40 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) FontInfo& fontInfo = font.fontInfo; //check if glyph not already present GlyphHash_t::iterator iter = font.cachedGlyphs.find(_codePoint); - if(iter != font.cachedGlyphs.end()) + if (iter != font.cachedGlyphs.end() ) { return true; } //if truetype present - if(font.trueTypeFont != NULL) + if (font.trueTypeFont != NULL) { GlyphInfo glyphInfo; - + //bake glyph as bitmap to buffer - switch(font.fontInfo.fontType) + switch (font.fontInfo.fontType) { case FONT_TYPE_ALPHA: font.trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer); break; + //case FONT_TYPE_LCD: - //font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); - //break; + //font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); + //break; case FONT_TYPE_DISTANCE: font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; + case FONT_TYPE_DISTANCE_SUBPIXEL: font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; + default: BX_CHECK(false, "TextureType not supported yet"); - }; + } //copy bitmap to texture - if(!addBitmap(glyphInfo, m_buffer) ) + if (!addBitmap(glyphInfo, m_buffer) ) { return false; } @@ -717,17 +784,18 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); glyphInfo.height = (glyphInfo.height * fontInfo.scale); - glyphInfo.width = (glyphInfo.width * fontInfo.scale); + glyphInfo.width = (glyphInfo.width * fontInfo.scale); // store cached glyph font.cachedGlyphs[_codePoint] = glyphInfo; return true; - }else + } + else { //retrieve glyph from parent font if any - if(font.masterFontHandle.idx != bgfx::invalidHandle) + if (font.masterFontHandle.idx != bgfx::invalidHandle) { - if(preloadGlyph(font.masterFontHandle, _codePoint)) + if (preloadGlyph(font.masterFontHandle, _codePoint) ) { GlyphInfo glyphInfo; getGlyphInfo(font.masterFontHandle, _codePoint, glyphInfo); @@ -750,33 +818,34 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) } const FontInfo& FontManager::getFontInfo(FontHandle _handle) -{ +{ BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); return m_cachedFonts[_handle.idx].fontInfo; } bool FontManager::getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo) -{ +{ GlyphHash_t::iterator iter = m_cachedFonts[_handle.idx].cachedGlyphs.find(_codePoint); - if(iter == m_cachedFonts[_handle.idx].cachedGlyphs.end()) + if (iter == m_cachedFonts[_handle.idx].cachedGlyphs.end() ) { - if(preloadGlyph(_handle, _codePoint)) + if (preloadGlyph(_handle, _codePoint) ) { iter = m_cachedFonts[_handle.idx].cachedGlyphs.find(_codePoint); - }else + } + else { return false; } } + _outInfo = iter->second; return true; } // **************************************************************************** - bool FontManager::addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data) { - _glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(_glyphInfo.width),(uint16_t) ceil(_glyphInfo.height), _data, AtlasRegion::TYPE_GRAY); + _glyphInfo.regionIndex = m_atlas->addRegion( (uint16_t) ceil(_glyphInfo.width), (uint16_t) ceil(_glyphInfo.height), _data, AtlasRegion::TYPE_GRAY); return true; } diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index ce4be0c9..3b0d0745 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -12,7 +12,7 @@ class Atlas; enum FontType { - FONT_TYPE_ALPHA = 0x00000100 , // L8 + FONT_TYPE_ALPHA = 0x00000100, // L8 //FONT_TYPE_LCD = 0x00000200, // BGRA8 //FONT_TYPE_RGBA = 0x00000300, // BGRA8 FONT_TYPE_DISTANCE = 0x00000400, // L8 @@ -21,7 +21,7 @@ enum FontType struct FontInfo { - //the font height in pixel + //the font height in pixel uint16_t pixelSize; /// Rendering type used for the font int16_t fontType; @@ -36,7 +36,7 @@ struct FontInfo float underline_thickness; /// The position of the underline relatively to the baseline float underline_position; - + //scale to apply to glyph data float scale; }; @@ -47,26 +47,26 @@ struct FontInfo // xmin xmax // | | // |<-------- width -------->| -// | | +// | | // | +-------------------------+----------------- ymax // | | ggggggggg ggggg | ^ ^ -// | | g:::::::::ggg::::g | | | -// | | g:::::::::::::::::g | | | -// | | g::::::ggggg::::::gg | | | -// | | g:::::g g:::::g | | | -// offset_x -|-------->| g:::::g g:::::g | offset_y | -// | | g:::::g g:::::g | | | -// | | g::::::g g:::::g | | | -// | | g:::::::ggggg:::::g | | | +// | | g:::::::::ggg::::g | | | +// | | g:::::::::::::::::g | | | +// | | g::::::ggggg::::::gg | | | +// | | g:::::g g:::::g | | | +// offset_x -|-------->| g:::::g g:::::g | offset_y | +// | | g:::::g g:::::g | | | +// | | g::::::g g:::::g | | | +// | | g:::::::ggggg:::::g | | | // | | g::::::::::::::::g | | height -// | | gg::::::::::::::g | | | +// | | gg::::::::::::::g | | | // baseline ---*---------|---- gggggggg::::::g-----*-------- | -// / | | g:::::g | | -// origin | | gggggg g:::::g | | -// | | g:::::gg gg:::::g | | -// | | g::::::ggg:::::::g | | -// | | gg:::::::::::::g | | -// | | ggg::::::ggg | | +// / | | g:::::g | | +// origin | | gggggg g:::::g | | +// | | g:::::gg gg:::::g | | +// | | g::::::ggg:::::::g | | +// | | gg:::::::::::::g | | +// | | ggg::::::ggg | | // | | gggggg | v // | +-------------------------+----------------- ymin // | | @@ -75,18 +75,18 @@ struct FontInfo /// Unicode value of a character typedef int32_t CodePoint_t; -/// A structure that describe a glyph. +/// A structure that describe a glyph. struct GlyphInfo { /// Index for faster retrieval int32_t glyphIndex; - + /// Glyph's width in pixels. float width; /// Glyph's height in pixels. float height; - + /// Glyph's left offset in pixels float offset_x; @@ -98,15 +98,15 @@ struct GlyphInfo /// For horizontal text layouts, this is the unscaled horizontal distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. float advance_x; - + /// For vertical text layouts, this is the unscaled vertical distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. float advance_y; - + /// region index in the atlas storing textures uint16_t regionIndex; ///32 bits alignment - int16_t padding; + int16_t padding; }; BGFX_HANDLE(TrueTypeHandle); @@ -115,94 +115,100 @@ BGFX_HANDLE(FontHandle); class FontManager { public: - /// create the font manager using an external cube atlas (doesn't take ownership of the atlas) - FontManager(Atlas* _atlas); - /// create the font manager and create the texture cube as BGRA8 with linear filtering - FontManager(uint32_t _textureSideWidth = 512); +/// create the font manager using an external cube atlas (doesn't take ownership of the atlas) +FontManager(Atlas* _atlas); +/// create the font manager and create the texture cube as BGRA8 with linear filtering +FontManager(uint32_t _textureSideWidth = 512); - ~FontManager(); +~FontManager(); - /// retrieve the atlas used by the font manager (e.g. to add stuff to it) - Atlas* getAtlas() { return m_atlas; } - - /// load a TrueType font from a file path - /// @return invalid handle if the loading fail - TrueTypeHandle loadTrueTypeFromFile(const char* _fontPath); +/// retrieve the atlas used by the font manager (e.g. to add stuff to it) +Atlas* getAtlas() +{ + return m_atlas; +} - /// load a TrueType font from a given buffer. - /// the buffer is copied and thus can be freed or reused after this call - /// @return invalid handle if the loading fail - TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size); +/// load a TrueType font from a file path +/// @return invalid handle if the loading fail +TrueTypeHandle loadTrueTypeFromFile(const char* _fontPath); - /// unload a TrueType font (free font memory) but keep loaded glyphs - void unloadTrueType(TrueTypeHandle _handle); - - /// return a font whose height is a fixed pixel size - FontHandle createFontByPixelSize(TrueTypeHandle _handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType = FONT_TYPE_ALPHA); +/// load a TrueType font from a given buffer. +/// the buffer is copied and thus can be freed or reused after this call +/// @return invalid handle if the loading fail +TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size); - /// return a scaled child font whose height is a fixed pixel size - FontHandle createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize); +/// unload a TrueType font (free font memory) but keep loaded glyphs +void unloadTrueType(TrueTypeHandle _handle); - /// load a baked font (the set of glyph is fixed) - /// @return INVALID_HANDLE if the loading fail - FontHandle loadBakedFontFromFile(const char* _imagePath, const char* _descriptorPath); +/// return a font whose height is a fixed pixel size +FontHandle createFontByPixelSize(TrueTypeHandle _handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType = FONT_TYPE_ALPHA); - /// load a baked font (the set of glyph is fixed) - /// @return INVALID_HANDLE if the loading fail - FontHandle loadBakedFontFromMemory(const uint8_t* _imageBuffer, uint32_t _imageSize, const uint8_t* _descriptorBuffer, uint32_t _descriptorSize); +/// return a scaled child font whose height is a fixed pixel size +FontHandle createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize); - /// destroy a font (truetype or baked) - void destroyFont(FontHandle _handle); +/// load a baked font (the set of glyph is fixed) +/// @return INVALID_HANDLE if the loading fail +FontHandle loadBakedFontFromFile(const char* _imagePath, const char* _descriptorPath); - /// Preload a set of glyphs from a TrueType file - /// @return true if every glyph could be preloaded, false otherwise - /// if the Font is a baked font, this only do validation on the characters - bool preloadGlyph(FontHandle _handle, const wchar_t* _string); +/// load a baked font (the set of glyph is fixed) +/// @return INVALID_HANDLE if the loading fail +FontHandle loadBakedFontFromMemory(const uint8_t* _imageBuffer, uint32_t _imageSize, const uint8_t* _descriptorBuffer, uint32_t _descriptorSize); - /// Preload a single glyph, return true on success - bool preloadGlyph(FontHandle _handle, CodePoint_t _character); +/// destroy a font (truetype or baked) +void destroyFont(FontHandle _handle); - /// bake a font to disk (the set of preloaded glyph) - /// @return true if the baking succeed, false otherwise - bool saveBakedFont(FontHandle _handle, const char* _fontDirectory, const char* _fontName ); - - /// return the font descriptor of a font - /// @remark the handle is required to be valid - const FontInfo& getFontInfo(FontHandle _handle); - - /// Return the rendering informations about the glyph region - /// Load the glyph from a TrueType font if possible - /// @return true if the Glyph is available - bool getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo); +/// Preload a set of glyphs from a TrueType file +/// @return true if every glyph could be preloaded, false otherwise +/// if the Font is a baked font, this only do validation on the characters +bool preloadGlyph(FontHandle _handle, const wchar_t* _string); - GlyphInfo& getBlackGlyph(){ return m_blackGlyph; } +/// Preload a single glyph, return true on success +bool preloadGlyph(FontHandle _handle, CodePoint_t _character); - class TrueTypeFont; //public to shut off Intellisense warning +/// bake a font to disk (the set of preloaded glyph) +/// @return true if the baking succeed, false otherwise +bool saveBakedFont(FontHandle _handle, const char* _fontDirectory, const char* _fontName); + +/// return the font descriptor of a font +/// @remark the handle is required to be valid +const FontInfo& getFontInfo(FontHandle _handle); + +/// Return the rendering informations about the glyph region +/// Load the glyph from a TrueType font if possible +/// @return true if the Glyph is available +bool getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo); + +GlyphInfo& getBlackGlyph() +{ + return m_blackGlyph; +} + +class TrueTypeFont; //public to shut off Intellisense warning private: - - struct CachedFont; - struct CachedFile - { - uint8_t* buffer; - uint32_t bufferSize; - }; - void init(); - bool addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data); +struct CachedFont; +struct CachedFile +{ + uint8_t* buffer; + uint32_t bufferSize; +}; - bool m_ownAtlas; - Atlas* m_atlas; - - bx::HandleAlloc m_fontHandles; - CachedFont* m_cachedFonts; - - bx::HandleAlloc m_filesHandles; - CachedFile* m_cachedFiles; - - GlyphInfo m_blackGlyph; +void init(); +bool addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data); - //temporary buffer to raster glyph - uint8_t* m_buffer; +bool m_ownAtlas; +Atlas* m_atlas; + +bx::HandleAlloc m_fontHandles; +CachedFont* m_cachedFonts; + +bx::HandleAlloc m_filesHandles; +CachedFile* m_cachedFiles; + +GlyphInfo m_blackGlyph; + +//temporary buffer to raster glyph +uint8_t* m_buffer; }; #endif // __FONT_MANAGER_H__ diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index c5047c3f..ee851b79 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -16,173 +16,220 @@ #include "vs_font_distance_field_subpixel.bin.h" #include "fs_font_distance_field_subpixel.bin.h" - -#define MAX_TEXT_BUFFER_COUNT 64 +#define MAX_TEXT_BUFFER_COUNT 64 #define MAX_BUFFERED_CHARACTERS 8192 // Table from Flexible and Economical UTF-8 Decoder // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. -static const uint8_t utf8d[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 +static const uint8_t utf8d[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df + 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3,0x3, // e0..ef + 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,0x8, // f0..ff + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1,0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8 }; #define UTF8_ACCEPT 0 #define UTF8_REJECT 1 -inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) { - uint32_t type = utf8d[byte]; +inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) +{ + uint32_t type = utf8d[byte]; - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); - *state = utf8d[256 + *state*16 + type]; - return *state; + *state = utf8d[256 + *state * 16 + type]; + return *state; } -inline int utf8_strlen(uint8_t* s, size_t* count) { - uint32_t codepoint; - uint32_t state = 0; +inline int utf8_strlen(uint8_t* s, size_t* count) +{ + uint32_t codepoint; + uint32_t state = 0; - for (*count = 0; *s; ++s) - if (!utf8_decode(&state, &codepoint, *s)) - *count += 1; + for (*count = 0; *s; ++s) + { + if (!utf8_decode(&state, &codepoint, *s) ) + { + *count += 1; + } + } - return state != UTF8_ACCEPT; + return state != UTF8_ACCEPT; } - class TextBuffer { -public: - - /// TextBuffer is bound to a fontManager for glyph retrieval - /// @remark the ownership of the manager is not taken - TextBuffer(FontManager* _fontManager); - ~TextBuffer(); +public: - void setStyle(uint32_t _flags = STYLE_NORMAL) { m_styleFlags = _flags; } - void setTextColor(uint32_t _rgba = 0x000000FF) { m_textColor = toABGR(_rgba); } - void setBackgroundColor(uint32_t _rgba = 0x000000FF) { m_backgroundColor = toABGR(_rgba); } +/// TextBuffer is bound to a fontManager for glyph retrieval +/// @remark the ownership of the manager is not taken +TextBuffer(FontManager* _fontManager); +~TextBuffer(); - void setOverlineColor(uint32_t _rgba = 0x000000FF) { m_overlineColor = toABGR(_rgba); } - void setUnderlineColor(uint32_t _rgba = 0x000000FF) { m_underlineColor = toABGR(_rgba); } - void setStrikeThroughColor(uint32_t _rgba = 0x000000FF) { m_strikeThroughColor = toABGR(_rgba); } - - void setPenPosition(float _x, float _y) { m_penX = _x; m_penY = _y; } - - /// return the size of the text - //Rectangle measureText(FontHandle _fontHandle, const char * _string); - //Rectangle measureText(FontHandle _fontHandle, const wchar_t * _string); +void setStyle(uint32_t _flags = STYLE_NORMAL) +{ + m_styleFlags = _flags; +} +void setTextColor(uint32_t _rgba = 0x000000FF) +{ + m_textColor = toABGR(_rgba); +} +void setBackgroundColor(uint32_t _rgba = 0x000000FF) +{ + m_backgroundColor = toABGR(_rgba); +} - /// append an ASCII/utf-8 string to the buffer using current pen position and color - void appendText(FontHandle _fontHandle, const char * _string); +void setOverlineColor(uint32_t _rgba = 0x000000FF) +{ + m_overlineColor = toABGR(_rgba); +} +void setUnderlineColor(uint32_t _rgba = 0x000000FF) +{ + m_underlineColor = toABGR(_rgba); +} +void setStrikeThroughColor(uint32_t _rgba = 0x000000FF) +{ + m_strikeThroughColor = toABGR(_rgba); +} - /// append a wide char unicode string to the buffer using current pen position and color - void appendText(FontHandle _fontHandle, const wchar_t * _string); +void setPenPosition(float _x, float _y) +{ + m_penX = _x; m_penY = _y; +} - /// Clear the text buffer and reset its state (pen/color) - void clearTextBuffer(); - - /// get pointer to the vertex buffer to submit it to the graphic card - const uint8_t* getVertexBuffer(){ return (uint8_t*) m_vertexBuffer; } - /// number of vertex in the vertex buffer - uint32_t getVertexCount(){ return m_vertexCount; } - /// size in bytes of a vertex - uint32_t getVertexSize(){ return sizeof(TextVertex); } - - /// get a pointer to the index buffer to submit it to the graphic - const uint16_t* getIndexBuffer(){ return m_indexBuffer; } - /// number of index in the index buffer - uint32_t getIndexCount(){ return m_indexCount; } - /// size in bytes of an index - uint32_t getIndexSize(){ return sizeof(uint16_t); } +/// return the size of the text +//Rectangle measureText(FontHandle _fontHandle, const char * _string); +//Rectangle measureText(FontHandle _fontHandle, const wchar_t * _string); - uint32_t getTextColor(){ return toABGR(m_textColor); } +/// append an ASCII/utf-8 string to the buffer using current pen position and color +void appendText(FontHandle _fontHandle, const char* _string); - TextRectangle getRectangle() const { return m_rectangle; } +/// append a wide char unicode string to the buffer using current pen position and color +void appendText(FontHandle _fontHandle, const wchar_t* _string); + +/// Clear the text buffer and reset its state (pen/color) +void clearTextBuffer(); + +/// get pointer to the vertex buffer to submit it to the graphic card +const uint8_t* getVertexBuffer() +{ + return (uint8_t*) m_vertexBuffer; +} +/// number of vertex in the vertex buffer +uint32_t getVertexCount() +{ + return m_vertexCount; +} +/// size in bytes of a vertex +uint32_t getVertexSize() +{ + return sizeof(TextVertex); +} + +/// get a pointer to the index buffer to submit it to the graphic +const uint16_t* getIndexBuffer() +{ + return m_indexBuffer; +} +/// number of index in the index buffer +uint32_t getIndexCount() +{ + return m_indexCount; +} +/// size in bytes of an index +uint32_t getIndexSize() +{ + return sizeof(uint16_t); +} + +uint32_t getTextColor() +{ + return toABGR(m_textColor); +} + +TextRectangle getRectangle() const +{ + return m_rectangle; +} private: - void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); - void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); - uint32_t toABGR(uint32_t _rgba) - { - return (((_rgba >> 0) & 0xff) << 24) | - (((_rgba >> 8) & 0xff) << 16) | - (((_rgba >> 16) & 0xff) << 8) | - (((_rgba >> 24) & 0xff) << 0); - } - - uint32_t m_styleFlags; +void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); +void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); +uint32_t toABGR(uint32_t _rgba) +{ + return ( ( (_rgba >> 0) & 0xff) << 24) | + ( ( (_rgba >> 8) & 0xff) << 16) | + ( ( (_rgba >> 16) & 0xff) << 8) | + ( ( (_rgba >> 24) & 0xff) << 0); +} - // color states - uint32_t m_textColor; +uint32_t m_styleFlags; - uint32_t m_backgroundColor; - uint32_t m_overlineColor; - uint32_t m_underlineColor; - uint32_t m_strikeThroughColor; +// color states +uint32_t m_textColor; - //position states - float m_penX; - float m_penY; +uint32_t m_backgroundColor; +uint32_t m_overlineColor; +uint32_t m_underlineColor; +uint32_t m_strikeThroughColor; - float m_originX; - float m_originY; +//position states +float m_penX; +float m_penY; - float m_lineAscender; - float m_lineDescender; - float m_lineGap; - - TextRectangle m_rectangle; +float m_originX; +float m_originY; - /// - FontManager* m_fontManager; - - void setVertex(uint32_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) - { - m_vertexBuffer[_i].x = _x; - m_vertexBuffer[_i].y = _y; - m_vertexBuffer[_i].rgba = _rgba; - m_styleBuffer[_i] = _style; - } +float m_lineAscender; +float m_lineDescender; +float m_lineGap; - struct TextVertex - { - float x,y; - int16_t u,v,w,t; - uint32_t rgba; - }; +TextRectangle m_rectangle; - TextVertex* m_vertexBuffer; - uint16_t* m_indexBuffer; - uint8_t* m_styleBuffer; - - uint32_t m_vertexCount; - uint32_t m_indexCount; - uint32_t m_lineStartIndex; +/// +FontManager* m_fontManager; + +void setVertex(uint32_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) +{ + m_vertexBuffer[_i].x = _x; + m_vertexBuffer[_i].y = _y; + m_vertexBuffer[_i].rgba = _rgba; + m_styleBuffer[_i] = _style; +} + +struct TextVertex +{ + float x, y; + int16_t u, v, w, t; + uint32_t rgba; }; +TextVertex* m_vertexBuffer; +uint16_t* m_indexBuffer; +uint8_t* m_styleBuffer; - +uint32_t m_vertexCount; +uint32_t m_indexCount; +uint32_t m_lineStartIndex; +}; TextBuffer::TextBuffer(FontManager* _fontManager) -{ +{ m_styleFlags = STYLE_NORMAL; //0xAABBGGRR m_textColor = 0xFFFFFFFF; @@ -198,18 +245,16 @@ TextBuffer::TextBuffer(FontManager* _fontManager) m_lineAscender = 0; m_lineDescender = 0; m_lineGap = 0; - m_fontManager = _fontManager; + m_fontManager = _fontManager; m_rectangle.width = 0; m_rectangle.height = 0; - + m_vertexBuffer = new TextVertex[MAX_BUFFERED_CHARACTERS * 4]; m_indexBuffer = new uint16_t[MAX_BUFFERED_CHARACTERS * 6]; m_styleBuffer = new uint8_t[MAX_BUFFERED_CHARACTERS * 4]; m_vertexCount = 0; m_indexCount = 0; m_lineStartIndex = 0; - - } TextBuffer::~TextBuffer() @@ -218,67 +263,70 @@ TextBuffer::~TextBuffer() delete[] m_indexBuffer; } -void TextBuffer::appendText(FontHandle _fontHandle, const char * _string) -{ +void TextBuffer::appendText(FontHandle _fontHandle, const char* _string) +{ GlyphInfo glyph; - const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); - - if(m_vertexCount == 0) + const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); + + if (m_vertexCount == 0) { m_originX = m_penX; m_originY = m_penY; - m_lineDescender = 0;// font.m_descender; - m_lineAscender = 0;//font.m_ascender; - - + m_lineDescender = 0; // font.m_descender; + m_lineAscender = 0; //font.m_ascender; } - + uint32_t codepoint; uint32_t state = 0; for (; *_string; ++_string) - if (!utf8_decode(&state, &codepoint, *_string)) + { + if (!utf8_decode(&state, &codepoint, *_string) ) { - if(m_fontManager->getGlyphInfo(_fontHandle, (CodePoint_t)codepoint, glyph)) + if (m_fontManager->getGlyphInfo(_fontHandle, (CodePoint_t)codepoint, glyph) ) { - appendGlyph((CodePoint_t)codepoint, font, glyph); - }else + appendGlyph( (CodePoint_t)codepoint, font, glyph); + } + else { BX_CHECK(false, "Glyph not found"); } } - //printf("U+%04X\n", codepoint); + } + + //printf("U+%04X\n", codepoint); if (state != UTF8_ACCEPT) { - // assert(false && "The string is not well-formed"); + // assert(false && "The string is not well-formed"); return; //"The string is not well-formed\n" } } -void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) -{ +void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t* _string) +{ GlyphInfo glyph; - const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); - - if(m_vertexCount == 0) + const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); + + if (m_vertexCount == 0) { m_originX = m_penX; m_originY = m_penY; - m_lineDescender = 0;// font.m_descender; - m_lineAscender = 0;//font.m_ascender; + m_lineDescender = 0; // font.m_descender; + m_lineAscender = 0; //font.m_ascender; m_lineGap = 0; } //parse string - for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) + for (uint32_t ii = 0, end = wcslen(_string); ii < end; ++ii) { //if glyph cached, continue uint32_t _codePoint = _string[ii]; - if(m_fontManager->getGlyphInfo(_fontHandle, _codePoint, glyph)) + if (m_fontManager->getGlyphInfo(_fontHandle, _codePoint, glyph) ) { appendGlyph(_codePoint, font, glyph); - }else + } + else { BX_CHECK(false, "Glyph not found"); } @@ -286,7 +334,7 @@ void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) } /* TextBuffer::Rectangle TextBuffer::measureText(FontHandle _fontHandle, const char * _string) -{ +{ } TextBuffer::Rectangle TextBuffer::measureText(FontHandle _fontHandle, const wchar_t * _string) @@ -306,198 +354,211 @@ void TextBuffer::clearTextBuffer() } void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo) -{ +{ //handle newlines - if(_codePoint == L'\n' ) - { - m_penX = m_originX; - m_penY -= m_lineDescender; + if (_codePoint == L'\n') + { + m_penX = m_originX; + m_penY -= m_lineDescender; m_penY += m_lineGap; m_lineDescender = 0; m_lineAscender = 0; - m_lineStartIndex = m_vertexCount; - + m_lineStartIndex = m_vertexCount; + return; - } - - if( _font.ascender > m_lineAscender || (_font.descender < m_lineDescender) ) - { - if( _font.descender < m_lineDescender ) + } + + if (_font.ascender > m_lineAscender + || (_font.descender < m_lineDescender) ) + { + if (_font.descender < m_lineDescender) { m_lineDescender = _font.descender; m_lineGap = _font.lineGap; } - + float txtDecals = (_font.ascender - m_lineAscender); m_lineAscender = _font.ascender; - m_lineGap = _font.lineGap; - + m_lineGap = _font.lineGap; + m_penY += txtDecals; - verticalCenterLastLine((txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender+m_lineGap)); - } - + verticalCenterLastLine( (txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender + m_lineGap) ); + } + //handle kerning float kerning = 0; - /* - if( previous && markup->font->kerning ) - { - kerning = texture_glyph_get_kerning( glyph, previous ); - } + /* + if( previous && markup->font->kerning ) + { + kerning = texture_glyph_get_kerning( glyph, previous ); + } */ m_penX += kerning * _font.scale; GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph(); - - if( m_styleFlags & STYLE_BACKGROUND && m_backgroundColor & 0xFF000000) + + if (m_styleFlags & STYLE_BACKGROUND + && m_backgroundColor & 0xFF000000) { - float x0 = ( m_penX - kerning ); - float y0 = ( m_penY - m_lineAscender); - float x1 = ( (float)x0 + (_glyphInfo.advance_x)); - float y1 = ( m_penY - m_lineDescender + m_lineGap ); - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); - - setVertex(m_vertexCount+0, x0, y0, m_backgroundColor,STYLE_BACKGROUND); - setVertex(m_vertexCount+1, x0, y1, m_backgroundColor,STYLE_BACKGROUND); - setVertex(m_vertexCount+2, x1, y1, m_backgroundColor,STYLE_BACKGROUND); - setVertex(m_vertexCount+3, x1, y0, m_backgroundColor,STYLE_BACKGROUND); - - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; - m_vertexCount += 4; - m_indexCount += 6; - } - - if( m_styleFlags & STYLE_UNDERLINE && m_underlineColor & 0xFF000000) - { - float x0 = ( m_penX - kerning ); - float y0 = (m_penY - m_lineDescender/2 ); - float x1 = ( (float)x0 + (_glyphInfo.advance_x)); - float y1 = y0+_font.underline_thickness; - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); - - setVertex(m_vertexCount+0, x0, y0, m_underlineColor,STYLE_UNDERLINE); - setVertex(m_vertexCount+1, x0, y1, m_underlineColor,STYLE_UNDERLINE); - setVertex(m_vertexCount+2, x1, y1, m_underlineColor,STYLE_UNDERLINE); - setVertex(m_vertexCount+3, x1, y0, m_underlineColor,STYLE_UNDERLINE); - - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; - m_vertexCount += 4; - m_indexCount += 6; - } - - if( m_styleFlags & STYLE_OVERLINE && m_overlineColor & 0xFF000000) - { - float x0 = ( m_penX - kerning ); - float y0 = (m_penY - _font.ascender ); - float x1 = ( (float)x0 + (_glyphInfo.advance_x)); - float y1 = y0+_font.underline_thickness; - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); - - setVertex(m_vertexCount+0, x0, y0, m_overlineColor,STYLE_OVERLINE); - setVertex(m_vertexCount+1, x0, y1, m_overlineColor,STYLE_OVERLINE); - setVertex(m_vertexCount+2, x1, y1, m_overlineColor,STYLE_OVERLINE); - setVertex(m_vertexCount+3, x1, y0, m_overlineColor,STYLE_OVERLINE); - - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; - m_vertexCount += 4; - m_indexCount += 6; - } - - - if( m_styleFlags & STYLE_STRIKE_THROUGH && m_strikeThroughColor & 0xFF000000) - { - float x0 = ( m_penX - kerning ); - float y0 = (m_penY - _font.ascender/3 ); + float x0 = (m_penX - kerning); + float y0 = (m_penY - m_lineAscender); float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); - float y1 = y0+_font.underline_thickness; - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + float y1 = (m_penY - m_lineDescender + m_lineGap); - setVertex(m_vertexCount+0, x0, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); - setVertex(m_vertexCount+1, x0, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); - setVertex(m_vertexCount+2, x1, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); - setVertex(m_vertexCount+3, x1, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + setVertex(m_vertexCount + 0, x0, y0, m_backgroundColor, STYLE_BACKGROUND); + setVertex(m_vertexCount + 1, x0, y1, m_backgroundColor, STYLE_BACKGROUND); + setVertex(m_vertexCount + 2, x1, y1, m_backgroundColor, STYLE_BACKGROUND); + setVertex(m_vertexCount + 3, x1, y0, m_backgroundColor, STYLE_BACKGROUND); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if (m_styleFlags & STYLE_UNDERLINE + && m_underlineColor & 0xFF000000) + { + float x0 = (m_penX - kerning); + float y0 = (m_penY - m_lineDescender / 2); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0 + _font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); + + setVertex(m_vertexCount + 0, x0, y0, m_underlineColor, STYLE_UNDERLINE); + setVertex(m_vertexCount + 1, x0, y1, m_underlineColor, STYLE_UNDERLINE); + setVertex(m_vertexCount + 2, x1, y1, m_underlineColor, STYLE_UNDERLINE); + setVertex(m_vertexCount + 3, x1, y0, m_underlineColor, STYLE_UNDERLINE); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if (m_styleFlags & STYLE_OVERLINE + && m_overlineColor & 0xFF000000) + { + float x0 = (m_penX - kerning); + float y0 = (m_penY - _font.ascender); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0 + _font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); + + setVertex(m_vertexCount + 0, x0, y0, m_overlineColor, STYLE_OVERLINE); + setVertex(m_vertexCount + 1, x0, y1, m_overlineColor, STYLE_OVERLINE); + setVertex(m_vertexCount + 2, x1, y1, m_overlineColor, STYLE_OVERLINE); + setVertex(m_vertexCount + 3, x1, y0, m_overlineColor, STYLE_OVERLINE); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if (m_styleFlags & STYLE_STRIKE_THROUGH + && m_strikeThroughColor & 0xFF000000) + { + float x0 = (m_penX - kerning); + float y0 = (m_penY - _font.ascender / 3); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0 + _font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); + + setVertex(m_vertexCount + 0, x0, y0, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount + 1, x0, y1, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount + 2, x1, y1, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount + 3, x1, y0, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; m_vertexCount += 4; m_indexCount += 6; } - //handle glyph float x0_precise = m_penX + (_glyphInfo.offset_x); - float x0 = ( x0_precise); - float y0 = ( m_penY + (_glyphInfo.offset_y)); - float x1 = ( x0 + _glyphInfo.width ); - float y1 = ( y0 + _glyphInfo.height ); - - m_fontManager->getAtlas()->packUV(_glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + float x0 = (x0_precise); + float y0 = (m_penY + (_glyphInfo.offset_y) ); + float x1 = (x0 + _glyphInfo.width); + float y1 = (y0 + _glyphInfo.height); - setVertex(m_vertexCount+0, x0, y0, m_textColor); - setVertex(m_vertexCount+1, x0, y1, m_textColor); - setVertex(m_vertexCount+2, x1, y1, m_textColor); - setVertex(m_vertexCount+3, x1, y0, m_textColor); + m_fontManager->getAtlas()->packUV(_glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + setVertex(m_vertexCount + 0, x0, y0, m_textColor); + setVertex(m_vertexCount + 1, x0, y1, m_textColor); + setVertex(m_vertexCount + 2, x1, y1, m_textColor); + setVertex(m_vertexCount + 3, x1, y0, m_textColor); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; m_vertexCount += 4; m_indexCount += 6; - + m_penX += _glyphInfo.advance_x; - if(m_penX > m_rectangle.width) m_rectangle.width = m_penX; - if( (m_penY - m_lineDescender) > m_rectangle.height) m_rectangle.height = (m_penY - m_lineDescender); - //if(x1 > m_rectangle.width) m_rectangle.width = x1; + if (m_penX > m_rectangle.width) + { + m_rectangle.width = m_penX; + } + + if ( (m_penY - m_lineDescender) > m_rectangle.height) + { + m_rectangle.height = (m_penY - m_lineDescender); + } + + //if(x1 > m_rectangle.width) m_rectangle.width = x1; //if(y1 > m_rectangle.height) m_rectangle.height = y1; } void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) -{ - for( uint32_t ii=m_lineStartIndex; ii < m_vertexCount; ii+=4 ) - { - if( m_styleBuffer[ii] == STYLE_BACKGROUND) +{ + for (uint32_t ii = m_lineStartIndex; ii < m_vertexCount; ii += 4) + { + if (m_styleBuffer[ii] == STYLE_BACKGROUND) { - m_vertexBuffer[ii+0].y = _top; - m_vertexBuffer[ii+1].y = _bottom; - m_vertexBuffer[ii+2].y = _bottom; - m_vertexBuffer[ii+3].y = _top; - }else{ - m_vertexBuffer[ii+0].y += _dy; - m_vertexBuffer[ii+1].y += _dy; - m_vertexBuffer[ii+2].y += _dy; - m_vertexBuffer[ii+3].y += _dy; + m_vertexBuffer[ii + 0].y = _top; + m_vertexBuffer[ii + 1].y = _bottom; + m_vertexBuffer[ii + 2].y = _bottom; + m_vertexBuffer[ii + 3].y = _top; } - } + else + { + m_vertexBuffer[ii + 0].y += _dy; + m_vertexBuffer[ii + 1].y += _dy; + m_vertexBuffer[ii + 2].y += _dy; + m_vertexBuffer[ii + 3].y += _dy; + } + } } // **************************************************************** -TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) +TextBufferManager::TextBufferManager(FontManager* _fontManager) : m_fontManager(_fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) { m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT]; @@ -511,17 +572,17 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f switch (bgfx::getRendererType() ) { case bgfx::RendererType::Direct3D9: - vs_font_basic = bgfx::makeRef(vs_font_basic_dx9, sizeof(vs_font_basic_dx9) ); - fs_font_basic = bgfx::makeRef(fs_font_basic_dx9, sizeof(fs_font_basic_dx9) ); + vs_font_basic = bgfx::makeRef(vs_font_basic_dx9, sizeof(vs_font_basic_dx9) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_dx9, sizeof(fs_font_basic_dx9) ); vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx9, sizeof(vs_font_distance_field_dx9) ); fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx9, sizeof(fs_font_distance_field_dx9) ); vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx9, sizeof(vs_font_distance_field_subpixel_dx9) ); - fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx9, sizeof(fs_font_distance_field_subpixel_dx9) ); + fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx9, sizeof(fs_font_distance_field_subpixel_dx9) ); break; case bgfx::RendererType::Direct3D11: - vs_font_basic = bgfx::makeRef(vs_font_basic_dx11, sizeof(vs_font_basic_dx11) ); - fs_font_basic = bgfx::makeRef(fs_font_basic_dx11, sizeof(fs_font_basic_dx11) ); + vs_font_basic = bgfx::makeRef(vs_font_basic_dx11, sizeof(vs_font_basic_dx11) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_dx11, sizeof(fs_font_basic_dx11) ); vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx11, sizeof(vs_font_distance_field_dx11) ); fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx11, sizeof(fs_font_distance_field_dx11) ); vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx11, sizeof(vs_font_distance_field_subpixel_dx11) ); @@ -529,8 +590,8 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f break; default: - vs_font_basic = bgfx::makeRef(vs_font_basic_glsl, sizeof(vs_font_basic_glsl) ); - fs_font_basic = bgfx::makeRef(fs_font_basic_glsl, sizeof(fs_font_basic_glsl) ); + vs_font_basic = bgfx::makeRef(vs_font_basic_glsl, sizeof(vs_font_basic_glsl) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_glsl, sizeof(fs_font_basic_glsl) ); vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_glsl, sizeof(vs_font_distance_field_glsl) ); fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_glsl, sizeof(fs_font_distance_field_glsl) ); vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_glsl, sizeof(vs_font_distance_field_subpixel_glsl) ); @@ -540,24 +601,24 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f bgfx::VertexShaderHandle vsh; bgfx::FragmentShaderHandle fsh; - - vsh = bgfx::createVertexShader(vs_font_basic); + + vsh = bgfx::createVertexShader(vs_font_basic); fsh = bgfx::createFragmentShader(fs_font_basic); m_basicProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); + bgfx::destroyFragmentShader(fsh); - vsh = bgfx::createVertexShader(vs_font_distance_field); + vsh = bgfx::createVertexShader(vs_font_distance_field); fsh = bgfx::createFragmentShader(fs_font_distance_field); m_distanceProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); - vsh = bgfx::createVertexShader(vs_font_distance_field_subpixel); + vsh = bgfx::createVertexShader(vs_font_distance_field_subpixel); fsh = bgfx::createFragmentShader(fs_font_distance_field_subpixel); m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); + bgfx::destroyFragmentShader(fsh); m_vertexDecl.begin(); m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); @@ -577,50 +638,54 @@ TextBufferManager::~TextBufferManager() bgfx::destroyUniform(u_texColor); bgfx::destroyUniform(u_inverse_gamma); - bgfx::destroyProgram(m_basicProgram); - bgfx::destroyProgram(m_distanceProgram); - bgfx::destroyProgram(m_distanceSubpixelProgram); + bgfx::destroyProgram(m_basicProgram); + bgfx::destroyProgram(m_distanceProgram); + bgfx::destroyProgram(m_distanceSubpixelProgram); } TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType _bufferType) -{ +{ uint16_t textIdx = m_textBufferHandles.alloc(); BufferCache& bc = m_textBuffers[textIdx]; - - bc.textBuffer = new TextBuffer(m_fontManager); + + bc.textBuffer = new TextBuffer(m_fontManager); bc.fontType = _type; - bc.bufferType = _bufferType; + bc.bufferType = _bufferType; bc.indexBufferHandle = bgfx::invalidHandle; bc.vertexBufferHandle = bgfx::invalidHandle; TextBufferHandle ret = {textIdx}; - return ret; + return ret; } void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; m_textBufferHandles.free(_handle.idx); delete bc.textBuffer; bc.textBuffer = NULL; - if(bc.vertexBufferHandle == bgfx::invalidHandle ) return; - - switch(bc.bufferType) + if (bc.vertexBufferHandle == bgfx::invalidHandle) + { + return; + } + + switch (bc.bufferType) { case STATIC: - { + { bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; ibh.idx = bc.indexBufferHandle; vbh.idx = bc.vertexBufferHandle; bgfx::destroyIndexBuffer(ibh); bgfx::destroyVertexBuffer(vbh); - } + } + + break; - break; case DYNAMIC: bgfx::DynamicIndexBufferHandle ibh; bgfx::DynamicVertexBufferHandle vbh; @@ -628,114 +693,122 @@ void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) vbh.idx = bc.vertexBufferHandle; bgfx::destroyDynamicIndexBuffer(ibh); bgfx::destroyDynamicVertexBuffer(vbh); - + break; + case TRANSIENT: //naturally destroyed - break; - } + break; + } } void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - + uint32_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize(); uint32_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize(); const bgfx::Memory* mem; - bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle()); - float inverse_gamme = 1.0f/2.2f; + bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle() ); + float inverse_gamme = 1.0f / 2.2f; bgfx::setUniform(u_inverse_gamma, &inverse_gamme); - + switch (bc.fontType) { case FONT_TYPE_ALPHA: bgfx::setProgram(m_basicProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); + bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); break; + case FONT_TYPE_DISTANCE: bgfx::setProgram(m_distanceProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); + bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); break; + case FONT_TYPE_DISTANCE_SUBPIXEL: bgfx::setProgram(m_distanceSubpixelProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.textBuffer->getTextColor()); - break; - } + bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR), bc.textBuffer->getTextColor() ); + break; + } - switch(bc.bufferType) + switch (bc.bufferType) { - case STATIC: + case STATIC: + { + bgfx::IndexBufferHandle ibh; + bgfx::VertexBufferHandle vbh; + + if (bc.vertexBufferHandle == bgfx::invalidHandle) { - bgfx::IndexBufferHandle ibh; - bgfx::VertexBufferHandle vbh; + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + ibh = bgfx::createIndexBuffer(mem); - if(bc.vertexBufferHandle == bgfx::invalidHandle) - { - mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); - ibh = bgfx::createIndexBuffer(mem); + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); - mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); - vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); - - bc.indexBufferHandle = ibh.idx ; - bc.vertexBufferHandle = vbh.idx; - }else - { - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; - } - bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); - }break; - case DYNAMIC: + bc.indexBufferHandle = ibh.idx; + bc.vertexBufferHandle = vbh.idx; + } + else { - bgfx::DynamicIndexBufferHandle ibh; - bgfx::DynamicVertexBufferHandle vbh; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + } - if(bc.vertexBufferHandle == bgfx::invalidHandle) - { - mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); - ibh = bgfx::createDynamicIndexBuffer(mem); + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount() ); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount() ); + } break; - mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); - vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); + case DYNAMIC: + { + bgfx::DynamicIndexBufferHandle ibh; + bgfx::DynamicVertexBufferHandle vbh; - bc.indexBufferHandle = ibh.idx ; - bc.vertexBufferHandle = vbh.idx; - }else - { - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; - - mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); - bgfx::updateDynamicIndexBuffer(ibh, mem); - - mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); - bgfx::updateDynamicVertexBuffer(vbh, mem); - } - bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); - - }break; - case TRANSIENT: + if (bc.vertexBufferHandle == bgfx::invalidHandle) { - bgfx::TransientIndexBuffer tib; - bgfx::TransientVertexBuffer tvb; - bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount()); - bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); - memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); - memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); - bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount()); - }break; + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + ibh = bgfx::createDynamicIndexBuffer(mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); + + bc.indexBufferHandle = ibh.idx; + bc.vertexBufferHandle = vbh.idx; + } + else + { + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + bgfx::updateDynamicIndexBuffer(ibh, mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::updateDynamicVertexBuffer(vbh, mem); + } + + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount() ); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount() ); + } break; + + case TRANSIENT: + { + bgfx::TransientIndexBuffer tib; + bgfx::TransientVertexBuffer tvb; + bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount() ); + bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); + memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount() ); + bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount() ); + } break; } bgfx::submit(_id, _depth); @@ -747,79 +820,79 @@ void TextBufferManager::submitTextBufferMask(TextBufferHandle /*_handle*/, uint3 BX_CHECK(false, "TODO TODO"); } -void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setStyle(_flags); -} - -void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setTextColor(_rgba); -} - -void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setBackgroundColor(_rgba); -} - -void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setOverlineColor(_rgba); -} - -void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba ) +void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setUnderlineColor(_rgba); + bc.textBuffer->setStyle(_flags); } -void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setStrikeThroughColor(_rgba); -} - -void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) +void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setPenPosition(_x,_y); + bc.textBuffer->setTextColor(_rgba); } -void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string) +void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setBackgroundColor(_rgba); +} + +void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setOverlineColor(_rgba); +} + +void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setUnderlineColor(_rgba); +} + +void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setStrikeThroughColor(_rgba); +} + +void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setPenPosition(_x, _y); +} + +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char* _string) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->appendText(_fontHandle, _string); } -void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string) +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t* _string) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->clearTextBuffer(); } TextRectangle TextBufferManager::getRectangle(TextBufferHandle _handle) const { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; return bc.textBuffer->getRectangle(); } diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index b9742aca..8e2af8db 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -9,27 +9,27 @@ #include "font_manager.h" BGFX_HANDLE(TextBufferHandle); - + /// type of vertex and index buffer to use with a TextBuffer enum BufferType { STATIC, - DYNAMIC , + DYNAMIC, TRANSIENT }; /// special style effect (can be combined) enum TextStyleFlags { - STYLE_NORMAL = 0, - STYLE_OVERLINE = 1, - STYLE_UNDERLINE = 1<<1, - STYLE_STRIKE_THROUGH = 1<<2, - STYLE_BACKGROUND = 1<<3, + STYLE_NORMAL = 0, + STYLE_OVERLINE = 1, + STYLE_UNDERLINE = 1 << 1, + STYLE_STRIKE_THROUGH = 1 << 2, + STYLE_BACKGROUND = 1 << 3, }; struct TextRectangle -{ +{ float width, height; }; @@ -37,63 +37,63 @@ class TextBuffer; class TextBufferManager { public: - TextBufferManager(FontManager* _fontManager); - ~TextBufferManager(); - - TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); - void destroyTextBuffer(TextBufferHandle _handle); - void submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth = 0); - void submitTextBufferMask(TextBufferHandle _handle, uint32_t _viewMask, int32_t _depth = 0); - - void setStyle(TextBufferHandle _handle, uint32_t _flags = STYLE_NORMAL); - void setTextColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +TextBufferManager(FontManager* _fontManager); +~TextBufferManager(); - void setOverlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - - void setPenPosition(TextBufferHandle _handle, float _x, float _y); +TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); +void destroyTextBuffer(TextBufferHandle _handle); +void submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth = 0); +void submitTextBufferMask(TextBufferHandle _handle, uint32_t _viewMask, int32_t _depth = 0); - /// append an ASCII/utf-8 string to the buffer using current pen position and color - void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string); +void setStyle(TextBufferHandle _handle, uint32_t _flags = STYLE_NORMAL); +void setTextColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +void setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - /// append a wide char unicode string to the buffer using current pen position and color - void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string); +void setOverlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +void setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +void setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - /// Clear the text buffer and reset its state (pen/color) - void clearTextBuffer(TextBufferHandle _handle); +void setPenPosition(TextBufferHandle _handle, float _x, float _y); - TextRectangle getRectangle(TextBufferHandle _handle) const; - - /// return the size of the text - //Rectangle measureText(FontHandle fontHandle, const char * _string); - //Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); +/// append an ASCII/utf-8 string to the buffer using current pen position and color +void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char* _string); + +/// append a wide char unicode string to the buffer using current pen position and color +void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t* _string); + +/// Clear the text buffer and reset its state (pen/color) +void clearTextBuffer(TextBufferHandle _handle); + +TextRectangle getRectangle(TextBufferHandle _handle) const; + +/// return the size of the text +//Rectangle measureText(FontHandle fontHandle, const char * _string); +//Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); private: - - struct BufferCache - { - uint16_t indexBufferHandle; - uint16_t vertexBufferHandle; - TextBuffer* textBuffer; - BufferType bufferType; - FontType fontType; - }; - BufferCache* m_textBuffers; - bx::HandleAlloc m_textBufferHandles; - FontManager* m_fontManager; - bgfx::VertexDecl m_vertexDecl; - bgfx::UniformHandle u_texColor; - bgfx::UniformHandle u_inverse_gamma; - //shaders program - bgfx::ProgramHandle m_basicProgram; - bgfx::ProgramHandle m_distanceProgram; - bgfx::ProgramHandle m_distanceSubpixelProgram; +struct BufferCache +{ + uint16_t indexBufferHandle; + uint16_t vertexBufferHandle; + TextBuffer* textBuffer; + BufferType bufferType; + FontType fontType; +}; - float m_height; - float m_width; +BufferCache* m_textBuffers; +bx::HandleAlloc m_textBufferHandles; +FontManager* m_fontManager; +bgfx::VertexDecl m_vertexDecl; +bgfx::UniformHandle u_texColor; +bgfx::UniformHandle u_inverse_gamma; +//shaders program +bgfx::ProgramHandle m_basicProgram; +bgfx::ProgramHandle m_distanceProgram; +bgfx::ProgramHandle m_distanceSubpixelProgram; + +float m_height; +float m_width; }; #endif // __TEXT_BUFFER_MANAGER_H__