| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091 |
- /****************************************************************************
- * truetype.c
- *
- * This module implements rendering of TrueType fonts.
- * This file was written by Alexander Enzmann. He wrote the code for
- * rendering glyphs and generously provided us these enhancements.
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996,1999 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file.
- * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by email to team-coord@povray.org or visit us on the web at
- * http://www.povray.org. The latest version of POV-Ray may be found at this site.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- * Alexander Ennzmann - original code...
- * Eduard Schwan - Mac compatibility...
- * Steve Demlow - Various bug fixes, data size independence...
- * Andreas Dilger - Kerning, multiple component glyphs...
- *
- * Changed I/O macros to functions for machine independence, Jan 1996 [AED]
- * Changed I/O functions for data size independence, Jan 1996 [AED], [SCD]
- * Major re-organization to make code more understandable, Jan 1996 [AED]
- * Added proper letter spacing, full kerning support, Jan 1996 [AED]
- * Changed to find own x/y min/max for each glyph (fonts bad?), Jan 1996 [AED]
- * Added special case for space character, Jan 1996 [AED]
- * Added support for multiple glyph characters, Feb 1996 [AED]
- * Changed functions to only use promoted types (no USHORTs), Mar 1996 [AED]
- * Cache Format 4 glyph table index to speed up parsing, Mar 1996 [AED]
- * Fixed TTF rendering bug that leaves horizontal streaks, Nov. 1996 Kochin Chang (KochinC@aol.com)
- * Allowed Macintosh-charmap TTF files to be processed, Nov. 1996 Bob Spence/Eduard Schwan
- *
- * Modifications by Hans-Detlev Fink, January 1999, used with permission
- * Modifications by Thomas Willhalm, March 1999, used with permission
- *
- *****************************************************************************/
- #include "frame.h"
- #include "povray.h"
- #include "vector.h"
- #include "povproto.h"
- #include "bbox.h"
- #include "matrices.h"
- #include "objects.h"
- #include "truetype.h"
- #include "csg.h" /* [ARE 11/94] */
- #include "povray.h"
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
- /* uncomment this to debug ttf. DEBUG1 gives less output than DEBUG2
- #define TTF_DEBUG2 1
- #define TTF_DEBUG 1
- */
- #undef EPSILON
- #define EPSILON 1.0e-10
- #ifndef TTF_Tolerance
- #define TTF_Tolerance 1.0e-6 /* -4 worked, -8 failed */
- #endif
- #ifndef SEEK_SET
- #define SEEK_SET 0 /* seek from start of file */
- #define SEEK_CUR 1 /* relative to current position */
- #define SEEK_END 2 /* relative to end of file */
- #endif
- #define MAX_ITERATIONS 50
- #define COEFF_LIMIT 1.0e-20
- /* For decoding glyph coordinate bit flags */
- #define ONCURVE 0x01
- #define XSHORT 0x02
- #define YSHORT 0x04
- #define REPEAT_FLAGS 0x08 /* repeat flag n times */
- #define SHORT_X_IS_POS 0x10 /* the short vector is positive */
- #define NEXT_X_IS_ZERO 0x10 /* the relative x coordinate is zero */
- #define SHORT_Y_IS_POS 0x20 /* the short vector is positive */
- #define NEXT_Y_IS_ZERO 0x20 /* the relative y coordinate is zero */
- /* For decoding multi-component glyph bit flags */
- #define ARG_1_AND_2_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_X_AND_Y_SCALE 0x0040
- #define WE_HAVE_A_TWO_BY_TWO 0x0080
- #define WE_HAVE_INSTRUCTIONS 0x0100
- #define USE_MY_METRICS 0x0200
- /* For decoding kern coverage bit flags */
- #define KERN_HORIZONTAL 0x01
- #define KERN_MINIMUM 0x02
- #define KERN_CROSS_STREAM 0x04
- #define KERN_OVERRIDE 0x08
- /* Some marcos to make error detection easier, as well as clarify code */
- #define READSHORT(fp) readSHORT(fp, __LINE__, __FILE__)
- #define READLONG(fp) readLONG(fp, __LINE__, __FILE__)
- #define READUSHORT(fp) readUSHORT(fp, __LINE__, __FILE__)
- #define READULONG(fp) readULONG(fp, __LINE__, __FILE__)
- #define READFIXED(fp) readLONG(fp, __LINE__, __FILE__)
- #define READFWORD(fp) readSHORT(fp, __LINE__, __FILE__)
- #define READUFWORD(fp) readUSHORT(fp, __LINE__, __FILE__)
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
- /* Type definitions to match the TTF spec, makes code clearer */
- typedef char CHAR;
- typedef unsigned char BYTE;
- typedef short SHORT;
- typedef unsigned short USHORT;
- typedef long LONG;
- typedef unsigned long ULONG;
- typedef short FWord;
- typedef unsigned short uFWord;
- #if !defined(MACOS)
- typedef long Fixed;
- #endif
- typedef struct
- {
- Fixed version; /* 0x10000 (1.0) */
- USHORT numTables; /* number of tables */
- USHORT searchRange; /* (max2 <= numTables)*16 */
- USHORT entrySelector; /* log2 (max2 <= numTables) */
- USHORT rangeShift; /* numTables*16-searchRange */
- } sfnt_OffsetTable;
- typedef struct
- {
- BYTE tag[4];
- ULONG checkSum;
- ULONG offset;
- ULONG length;
- } sfnt_TableDirectory;
- typedef sfnt_TableDirectory *sfnt_TableDirectoryPtr;
- typedef struct
- {
- ULONG bc;
- ULONG ad;
- } longDateTime;
- typedef struct
- {
- Fixed version; /* for this table, set to 1.0 */
- Fixed fontRevision; /* For Font Manufacturer */
- ULONG checkSumAdjustment;
- ULONG magicNumber; /* signature, must be 0x5F0F3CF5 == MAGIC */
- USHORT flags;
- USHORT unitsPerEm; /* How many in Font Units per EM */
- longDateTime created;
- longDateTime modified;
- FWord xMin; /* Font wide bounding box in ideal space */
- FWord yMin; /* Baselines and metrics are NOT worked */
- FWord xMax; /* into these numbers) */
- FWord yMax;
- USHORT macStyle; /* macintosh style word */
- USHORT lowestRecPPEM; /* lowest recommended pixels per Em */
- SHORT fontDirectionHint;
- SHORT indexToLocFormat; /* 0 - short offsets, 1 - long offsets */
- SHORT glyphDataFormat;
- } sfnt_FontHeader;
- typedef struct
- {
- USHORT platformID;
- USHORT specificID;
- ULONG offset;
- } sfnt_platformEntry;
- typedef sfnt_platformEntry *sfnt_platformEntryPtr;
- typedef struct
- {
- USHORT format;
- USHORT length;
- USHORT version;
- } sfnt_mappingTable;
- typedef struct
- {
- Fixed version;
- FWord Ascender;
- FWord Descender;
- FWord LineGap;
- uFWord advanceWidthMax;
- FWord minLeftSideBearing;
- FWord minRightSideBearing;
- FWord xMaxExtent;
- SHORT caretSlopeRise;
- SHORT caretSlopeRun;
- SHORT reserved1;
- SHORT reserved2;
- SHORT reserved3;
- SHORT reserved4;
- SHORT reserved5;
- SHORT metricDataFormat;
- USHORT numberOfHMetrics; /* number of hMetrics in the hmtx table */
- } sfnt_HorizHeader;
- typedef struct
- {
- SHORT numContours;
- SHORT xMin;
- SHORT yMin;
- SHORT xMax;
- SHORT yMax;
- } GlyphHeader;
- typedef struct
- {
- GlyphHeader header;
- USHORT numPoints;
- USHORT *endPoints;
- BYTE *flags;
- DBL *x, *y;
- USHORT myMetrics;
- } GlyphOutline;
- typedef struct
- {
- BYTE inside_flag; /* 1 if this an inside contour, 0 if outside */
- USHORT count; /* Number of points in the contour */
- BYTE *flags; /* On/off curve flags */
- DBL *x, *y; /* Coordinates of control vertices */
- } Contour;
- typedef struct GlyphStruct *GlyphPtr;
- /* Contour information for a single glyph */
- typedef struct GlyphStruct
- {
- GlyphHeader header; /* Count and sizing information about this
- * glyph */
- USHORT glyph_index; /* Internal glyph index for this character */
- Contour *contours; /* Array of outline contours */
- USHORT unitsPerEm; /* Max units character */
- GlyphPtr next; /* Next cached glyph */
- USHORT c; /* Character code */
- USHORT myMetrics; /* Which glyph index this is for metrics */
- } Glyph;
- typedef struct KernData_struct
- {
- USHORT left, right; /* Glyph index of left/right to kern */
- FWord value; /* Delta in FUnits to apply in between */
- } KernData;
- /*
- * [esp] There's already a "KernTable" on the Mac... renamed to TTKernTable for
- * now in memorium to its author.
- */
- typedef struct KernStruct
- {
- USHORT coverage; /* Coverage bit field of this subtable */
- USHORT nPairs; /* # of kerning pairs in this table */
- KernData *kern_pairs; /* Array of kerning values */
- } TTKernTable;
- typedef struct KernTableStruct
- {
- USHORT nTables; /* # of subtables in the kerning table */
- TTKernTable *tables;
- } KernTables;
- typedef struct longHorMertric
- {
- uFWord advanceWidth; /* Total width of a glyph in FUnits */
- FWord lsb; /* FUnits to the left of the glyph */
- } longHorMetric;
- /* Useful general data about this font */
- typedef struct FontFileInfoStruct
- {
- char *filename;
- FILE *fp;
- USHORT platformID; /* Which character encoding to use */
- USHORT specificID;
- ULONG cmap_table_offset; /* File locations for these tables */
- ULONG glyf_table_offset;
- USHORT numGlyphs; /* How many symbols in this file */
- USHORT unitsPerEm; /* The "resoultion" of this font */
- SHORT indexToLocFormat; /* 0 - short format, 1 - long format */
- ULONG *loca_table; /* Mapping from characters to glyphs */
- GlyphPtr glyphs; /* Cached info for this font */
- KernTables kerning_tables; /* Kerning info for this font */
- USHORT numberOfHMetrics; /* The number of explicit spacings */
- longHorMetric *hmtx_table; /* Horizontal spacing info */
- ULONG glyphIDoffset; /* Offset for Type 4 encoding tables */
- USHORT segCount, searchRange, /* Counts for Type 4 encoding tables */
- entrySelector, rangeShift;
- USHORT *startCount, *endCount, /* Type 4 (MS) encoding tables */
- *idDelta, *idRangeOffset;
- struct FontFileInfoStruct *next; /* Next font */
- } FontFileInfo;
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
- static BYTE tag_CharToIndexMap[] = "cmap"; /* 0x636d6170; */
- static BYTE tag_FontHeader[] = "head"; /* 0x68656164; */
- static BYTE tag_GlyphData[] = "glyf"; /* 0x676c7966; */
- static BYTE tag_IndexToLoc[] = "loca"; /* 0x6c6f6361; */
- static BYTE tag_Kerning[] = "kern"; /* 0x6b65726e; */
- static BYTE tag_MaxProfile[] = "maxp"; /* 0x6d617870; */
- static BYTE tag_HorizHeader[] = "hhea"; /* 0x68686561; */
- static BYTE tag_HorizMetric[] = "hmtx"; /* 0x686d7478; */
- static FontFileInfo *TTFonts = NULL;
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
- /* Byte order independent I/O routines (probably already in other routines) */
- static SHORT readSHORT (FILE *infile, int line, char *file);
- static USHORT readUSHORT (FILE *infile, int line, char *file);
- static LONG readLONG (FILE *infile, int line, char *file);
- static ULONG readULONG (FILE *infile, int line, char *file);
- static int compare_tag4 (BYTE *ttf_tag, BYTE *known_tag);
- /* Internal TTF input routines */
- static FontFileInfo *ProcessFontFile (char *fontfilename);
- static FontFileInfo *OpenFontFile (char *filename);
- static void ProcessHeadTable (FontFileInfo *ffile, long head_table_offset);
- static void ProcessLocaTable (FontFileInfo *ffile, long loca_table_offset);
- static void ProcessMaxpTable (FontFileInfo *ffile, long maxp_table_offset);
- static void ProcessKernTable (FontFileInfo *ffile, long kern_table_offset);
- static void ProcessHheaTable (FontFileInfo *ffile, long hhea_table_offset);
- static void ProcessHmtxTable (FontFileInfo *ffile, long hmtx_table_offset);
- static GlyphPtr ProcessCharacter (FontFileInfo *ffile, unsigned int search_char, unsigned int *glyph_index);
- static USHORT ProcessCharMap (FontFileInfo *ffile, unsigned int search_char);
- static USHORT ProcessFormat0Glyph (FontFileInfo *ffile, unsigned int search_char);
- static USHORT ProcessFormat4Glyph (FontFileInfo *ffile, unsigned int search_char);
- static USHORT ProcessFormat6Glyph (FontFileInfo *ffile, unsigned int search_char);
- static GlyphPtr ExtractGlyphInfo (FontFileInfo *ffile, unsigned int *glyph_index, unsigned int c);
- static GlyphOutline *ExtractGlyphOutline (FontFileInfo *ffile, unsigned int *glyph_index, unsigned int c);
- static GlyphPtr ConvertOutlineToGlyph (FontFileInfo *ffile, GlyphOutline *ttglyph);
- /* Glyph surface intersection routines */
- static int Inside_Glyph (double x, double y, GlyphPtr glyph);
- static int solve_quad (double *x, double *y, double mindist, DBL maxdist);
- static void GetZeroOneHits (GlyphPtr glyph, VECTOR P, VECTOR D, DBL glyph_depth, double *t0, double *t1);
- static int GlyphIntersect (OBJECT *Object, VECTOR P, VECTOR D, GlyphPtr glyph, DBL glyph_depth, RAY *Ray, ISTACK *Depth_Stack); /* tw */
- /* POV-Ray object intersection/creation routines */
- static TTF *Create_TTF (void);
- static int All_TTF_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
- static int Inside_TTF (VECTOR IPoint, OBJECT *Object);
- static void TTF_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
- static TTF *Copy_TTF (OBJECT *Object);
- static void Translate_TTF (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
- static void Rotate_TTF (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
- static void Scale_TTF (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
- static void Transform_TTF (OBJECT *Object, TRANSFORM *Trans);
- static void Invert_TTF (OBJECT *Object);
- static void Destroy_TTF (OBJECT *Object);
- METHODS TTF_Methods =
- {All_TTF_Intersections,
- Inside_TTF, TTF_Normal,
- (COPY_METHOD)Copy_TTF, Translate_TTF, Rotate_TTF, Scale_TTF, Transform_TTF,
- Invert_TTF, Destroy_TTF};
- /*
- * The following work as macros if sizeof(short) == 16 bits and
- * sizeof(long) == 32 bits, but tend to break otherwise. Making these
- * into error functions also allows file error checking. Do not attempt to
- * "optimize" these functions - some architectures require them the way
- * that they are written.
- */
- static SHORT readSHORT(FILE *infile, int line, char *file)
- {
- int i0, i1 = 0; /* To quiet warnings */
- if ((i0 = fgetc(infile)) == EOF || (i1 = fgetc(infile)) == EOF)
- {
- Error("Error reading TrueType font file at line %d, %s\n", line, file);
- }
- if (i0 & 0x80) /* Subtract 1 after value is negated to avoid overflow [AED] */
- return -(((255 - i0) << 8) | (255 - i1)) - 1;
- else
- return (i0 << 8) | i1;
- }
- static USHORT readUSHORT(FILE *infile, int line, char *file)
- {
- int i0, i1 = 0; /* To quiet warnings */
- if ((i0 = fgetc(infile)) == EOF || (i1 = fgetc(infile)) == EOF)
- {
- Error("Error reading TrueType font file at line %d, %s\n", line, file);
- }
- return (USHORT)((((USHORT)i0) << 8) | ((USHORT)i1));
- }
- static LONG readLONG(FILE *infile, int line, char *file)
- {
- LONG i0, i1 = 0, i2 = 0, i3 = 0; /* To quiet warnings */
- if ((i0 = fgetc(infile)) == EOF || (i1 = fgetc(infile)) == EOF ||
- (i2 = fgetc(infile)) == EOF || (i3 = fgetc(infile)) == EOF)
- {
- Error("Error reading TrueType font file at line %d, %s\n", line, file);
- }
- if (i0 & 0x80) /* Subtract 1 after value is negated to avoid overflow [AED] */
- return -(((255 - i0) << 24) | ((255 - i1) << 16) |
- ((255 - i2) << 8) | (255 - i3)) - 1;
- else
- return (i0 << 24) | (i1 << 16) | (i2 << 8) | i3;
- }
- static ULONG readULONG(FILE *infile, int line, char *file)
- {
- int i0, i1 = 0, i2 = 0, i3 = 0; /* To quiet warnings */
- if ((i0 = fgetc(infile)) == EOF || (i1 = fgetc(infile)) == EOF ||
- (i2 = fgetc(infile)) == EOF || (i3 = fgetc(infile)) == EOF)
- {
- Error("Error reading TrueType font file at line %d, %s\n", line, file);
- }
- return (ULONG) ((((ULONG) i0) << 24) | (((ULONG) i1) << 16) |
- (((ULONG) i2) << 8) | ((ULONG) i3));
- }
- static int compare_tag4(BYTE *ttf_tag, BYTE *known_tag)
- {
- return (ttf_tag[0] == known_tag[0] && ttf_tag[1] == known_tag[1] &&
- ttf_tag[2] == known_tag[2] && ttf_tag[3] == known_tag[3]);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessNewTTF
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Ennzmann
- *
- * DESCRIPTION
- *
- * Takes an input string and a font filename, and creates a POV-Ray CSG
- * object for each letter in the string.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void ProcessNewTTF(OBJECT *object, char *filename, char *text_string, DBL depth, VECTOR offset)
- {
- FontFileInfo *ffile;
- int slen;
- VECTOR local_offset, total_offset;
- CSG *Object = (CSG *) object;
- TTF *ttf;
- OBJECT *Local;
- GlyphPtr glyph;
- DBL funit_size;
- TTKernTable *table;
- USHORT coverage;
- unsigned int search_char;
- unsigned int glyph_index, last_index = 0;
- FWord kern_value_x, kern_value_min_x;
- FWord kern_value_y, kern_value_min_y;
- int i, j, k;
- TRANSFORM Trans;
- /* Get general font info */
- ffile = ProcessFontFile(filename);
- /* Get info about each character in the string */
- slen = strlen(text_string);
- Make_Vector(total_offset, 0.0, 0.0, 0.0);
- Object->Children = NULL;
- for (i = 0; i < slen; i++)
- {
- /*
- * We need to make sure (for now) that this is only the lower 8 bits,
- * so we don't have all the high bits set if converted from a signed
- * char to an unsigned short.
- */
- search_char = ((unsigned int)text_string[i]) & 0xFF;
- #ifdef TTF_DEBUG
- Debug_Info("\nChar: '%c' (0x%X), Offset[%d]: <%g,%g,%g>\n", text_string[i],
- search_char, i, total_offset[X], total_offset[Y], total_offset[Z]);
- #endif
- /* Make a new child for each character */
- ttf = Create_TTF();
- Local = (OBJECT *) ttf;
- /* Set the depth information for the character */
- ttf->depth = depth;
- /*
- * Get pointers to the contour information for each character
- * in the text string.
- */
- glyph = ProcessCharacter(ffile, search_char, &glyph_index);
- ttf->glyph = (void *)glyph;
- funit_size = 1.0 / (DBL)(ffile->unitsPerEm);
- /*
- * Spacing based on the horizontal metric table, the kerning table,
- * and (possibly) the previous glyph.
- */
- if (i == 0) /* Ignore spacing on the left for the first character only */
- {
- /* Shift the glyph to start at the origin */
- total_offset[X] = -glyph->header.xMin * funit_size;
- Compute_Translation_Transform(&Trans, total_offset);
- Translate_TTF(Local, total_offset, &Trans);
- /* Shift next glyph by the width of this one excluding the left offset*/
- total_offset[X] = (ffile->hmtx_table[glyph->myMetrics].advanceWidth -
- ffile->hmtx_table[glyph->myMetrics].lsb) * funit_size;
- #ifdef TTF_DEBUG
- Debug_Info("aw(%d): %g\n", i,
- (ffile->hmtx_table[glyph->myMetrics].advanceWidth -
- ffile->hmtx_table[glyph->myMetrics].lsb)*funit_size);
- #endif
- }
- else /* Kern all of the other characters */
- {
- kern_value_x = kern_value_y = 0;
- kern_value_min_x = kern_value_min_y = -ffile->unitsPerEm;
- Make_Vector(local_offset, 0.0, 0.0, 0.0);
- for (j = 0; j < ffile->kerning_tables.nTables; j++)
- {
- table = ffile->kerning_tables.tables;
- coverage = table->coverage;
- /*
- * Don't use vertical kerning until such a time when we support
- * characters moving in the vertical direction...
- */
- if (!(coverage & KERN_HORIZONTAL))
- continue;
- /*
- * If we were keen, we could do a binary search for this
- * character combination, since the pairs are sorted in
- * order as if the left and right index values were a 32 bit
- * unsigned int (mostly - at least they are sorted on the
- * left glyph). Something to do when everything else works...
- */
- for (k = 0; k < table[j].nPairs; k++)
- {
- if (table[j].kern_pairs[k].left == last_index &&
- table[j].kern_pairs[k].right == glyph->myMetrics)
- {
- #ifdef TTF_DEBUG2
- Debug_Info("Found a kerning for <%d, %d> = %d",
- last_index, glyph_index, table[j].kern_pairs[k].value);
- #endif
- /*
- * By default, Windows & OS/2 assume at most a single table with
- * !KERN_MINIMUM, !KERN_CROSS_STREAM, KERN_OVERRIDE.
- */
- if (coverage & KERN_MINIMUM)
- {
- #ifdef TTF_DEBUG2
- Debug_Info(" KERN_MINIMUM\n");
- #endif
- if (coverage & KERN_CROSS_STREAM)
- kern_value_min_y = table[j].kern_pairs[k].value;
- else
- kern_value_min_x = table[j].kern_pairs[k].value;
- }
- else
- {
- if (coverage & KERN_CROSS_STREAM)
- {
- #ifdef TTF_DEBUG2
- Debug_Info(" KERN_CROSS_STREAM\n");
- #endif
- if (table[j].kern_pairs[k].value == (FWord)0x8000)
- {
- kern_value_y = 0;
- }
- else
- {
- if (coverage & KERN_OVERRIDE)
- kern_value_y = table[j].kern_pairs[k].value;
- else
- kern_value_y += table[j].kern_pairs[k].value;
- }
- }
- else
- {
- #ifdef TTF_DEBUG2
- Debug_Info(" KERN_VALUE\n");
- #endif
- if (coverage & KERN_OVERRIDE)
- kern_value_x = table[j].kern_pairs[k].value;
- else
- kern_value_x += table[j].kern_pairs[k].value;
- }
- }
- break;
- }
- /* Abort now if we have passed all potential matches */
- else if (table[j].kern_pairs[k].left > last_index)
- {
- break;
- }
- }
- }
- kern_value_x = (kern_value_x > kern_value_min_x ?
- kern_value_x : kern_value_min_x);
- kern_value_y = (kern_value_y > kern_value_min_y ?
- kern_value_y : kern_value_min_y);
- /*
- * Offset this character so that the left edge of the glyph is at
- * the previous offset + the lsb + any kerning amount.
- */
- local_offset[X] = total_offset[X] +
- (DBL)(ffile->hmtx_table[glyph->myMetrics].lsb -
- glyph->header.xMin + kern_value_x) * funit_size;
- local_offset[Y] = total_offset[Y] + (DBL)kern_value_y * funit_size;
- /* Translate this glyph to its final position in the string */
- Compute_Translation_Transform(&Trans, local_offset);
- Translate_TTF(Local, local_offset, &Trans);
- /* Shift next glyph by the width of this one */
- total_offset[X] += ffile->hmtx_table[glyph->myMetrics].advanceWidth *
- funit_size;
- #ifdef TTF_DEBUG
- Debug_Info("kern(%d): <%d, %d> (%g,%g)\n", i, last_index, glyph_index,
- (DBL)kern_value_x*funit_size, (DBL)kern_value_y * funit_size);
- Debug_Info("lsb(%d): %g\n", i,
- (DBL)ffile->hmtx_table[glyph->myMetrics].lsb * funit_size);
- Debug_Info("aw(%d): %g\n", i,
- (DBL)ffile->hmtx_table[glyph->myMetrics].advanceWidth *
- funit_size);
- #endif
- }
- /*
- * Add to the offset of the next character the minimum spacing specified.
- */
- VAddEq(total_offset, offset);
- /* Link this glyph with the others in the union */
- Object->Type |= (Local->Type & CHILDREN_FLAGS);
- Local->Type |= IS_CHILD_OBJECT;
- Local->Sibling = Object->Children;
- Object->Children = Local;
- last_index = glyph_index;
- }
- #ifdef TTF_DEBUG
- Debug_Info("TTF parsing of \"%s\" from %s complete\n", text_string, filename);
- #endif
- /* Close the font file descriptor */
- if (ffile->fp != NULL) /* just to be sure it exists -hdf99- */
- {
- fclose(ffile->fp);
- ffile->fp = NULL;
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessFontFile
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Ennzmann
- *
- * DESCRIPTION
- *
- * Read the header information about the specific font. Parse the tables
- * as we come across them.
- *
- * CHANGES
- *
- * Added tests for reading manditory tables/validity checks - Jan 1996 [AED]
- * Reordered table parsing to avoid lots of file seeking - Jan 1996 [AED]
- *
- ******************************************************************************/
- static FontFileInfo *ProcessFontFile(char *fontfilename)
- {
- unsigned i;
- long head_table_offset = 0;
- long loca_table_offset = 0;
- long maxp_table_offset = 0;
- long kern_table_offset = 0;
- long hhea_table_offset = 0;
- long hmtx_table_offset = 0;
- sfnt_OffsetTable OffsetTable;
- sfnt_TableDirectory Table;
- FontFileInfo *ffile;
- /* Open the font file */
-
- ffile = OpenFontFile(fontfilename);
- /* We have already read all the header info, no need to do it again */
- if (ffile->cmap_table_offset != 0)
- {
- return (ffile);
- }
- /*
- * Read the initial directory header on the TTF. The numTables variable
- * tells us how many tables are present in this file.
- */
-
- OffsetTable.version = READFIXED(ffile->fp);
- OffsetTable.numTables = READUSHORT(ffile->fp);
- OffsetTable.searchRange = READUSHORT(ffile->fp);
- OffsetTable.entrySelector = READUSHORT(ffile->fp);
- OffsetTable.rangeShift = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("OffsetTable:\n");
- Debug_Info("version=%d\n", OffsetTable.version);
- Debug_Info("numTables=%u\n", OffsetTable.numTables);
- Debug_Info("searchRange=%u\n", OffsetTable.searchRange);
- Debug_Info("entrySelector=%u\n", OffsetTable.entrySelector);
- Debug_Info("rangeShift=%u\n", OffsetTable.rangeShift);
- #endif
- /*
- * I don't know why we limit this to 40 tables, since the spec says there
- * can be any number, but that's how it was when I got it. Added a warning
- * just in case it ever happens in real life. [AED]
- */
- if (OffsetTable.numTables > 40)
- {
- Warning(0.0, "More than 40 (%d) TTF Tables in %s - some info may be lost!",
- OffsetTable.numTables, ffile->filename);
- }
- /* Process general font information and save it. */
-
- for (i = 0; i < OffsetTable.numTables && i < 40; i++)
- {
- if (fread(&Table.tag, sizeof(BYTE), 4, ffile->fp) != 4)
- {
- Error("Error reading TrueType font file table tag\n");
- }
- Table.checkSum = READULONG(ffile->fp);
- Table.offset = READULONG(ffile->fp);
- Table.length = READULONG(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("\nTable %d:\n",i);
- Debug_Info("tag=%c%c%c%c\n", Table.tag[0], Table.tag[1],
- Table.tag[2], Table.tag[3]);
- Debug_Info("checkSum=%u\n", Table.checkSum);
- Debug_Info("offset=%u\n", Table.offset);
- Debug_Info("length=%u\n", Table.length);
- #endif
- if (compare_tag4(Table.tag, tag_CharToIndexMap))
- ffile->cmap_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_GlyphData))
- ffile->glyf_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_FontHeader))
- head_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_IndexToLoc))
- loca_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_MaxProfile))
- maxp_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_Kerning))
- kern_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_HorizHeader))
- hhea_table_offset = Table.offset;
- else if (compare_tag4(Table.tag, tag_HorizMetric))
- hmtx_table_offset = Table.offset;
- }
- if (ffile->cmap_table_offset == 0 || ffile->glyf_table_offset == 0 ||
- head_table_offset == 0 || loca_table_offset == 0 ||
- hhea_table_offset == 0 || hmtx_table_offset == 0 ||
- maxp_table_offset == 0)
- {
- Error("Invalid TrueType font headers in %s\n", ffile->filename);
- }
- ProcessHeadTable(ffile, head_table_offset); /* Need indexToLocFormat */
- if ((ffile->indexToLocFormat != 0 && ffile->indexToLocFormat != 1) ||
- (ffile->unitsPerEm < 16 || ffile->unitsPerEm > 16384))
- Error("Invalid TrueType font data in %s\n", ffile->filename);
- ProcessMaxpTable(ffile, maxp_table_offset); /* Need numGlyphs */
- if (ffile->numGlyphs <= 0)
- Error("Invalid TrueType font data in %s\n", ffile->filename);
- ProcessLocaTable(ffile, loca_table_offset); /* Now we can do loca_table */
- ProcessHheaTable(ffile, hhea_table_offset); /* Need numberOfHMetrics */
- if (ffile->numberOfHMetrics <= 0)
- Error("Invalid TrueType font data in %s\n", ffile->filename);
- ProcessHmtxTable(ffile, hmtx_table_offset); /* Now we can read HMetrics */
- if (kern_table_offset != 0)
- ProcessKernTable(ffile, kern_table_offset);
- /* Return the information about this font */
-
- return ffile;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * OpenFontFile
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Ennzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static FontFileInfo *OpenFontFile(char *filename)
- {
- /* int i; */ /* tw, mtg */
- FontFileInfo *fontlist;
- char b[FILE_NAME_LENGTH];
- /* First look to see if we have already opened this font */
-
- for (fontlist = TTFonts; fontlist != NULL; fontlist = fontlist->next)
- if (!strcmp(filename, fontlist->filename))
- break;
- if (fontlist != NULL)
- {
- /* We have a match, use the previous information */
- if ((fontlist->fp == NULL) &&
- (fontlist->fp = Locate_File(fontlist->filename, READ_BINFILE_STRING,
- ".ttf", ".TTF",NULL,TRUE)) == NULL)
- Error("Can't open font file.\n");
- #ifdef TTF_DEBUG
- else
- Debug_Info("Using cached font info for %s\n", fontlist->filename);
- #endif
- }
- else
- {
- /*
- * We haven't looked at this font before, let's allocate a holder for the
- * information and set some defaults
- */
- fontlist = (FontFileInfo *)POV_CALLOC(1, sizeof(FontFileInfo), "FontFileInfo");
-
- if ((fontlist->fp = Locate_File(filename, READ_BINFILE_STRING,
- ".ttf", ".TTF",b,TRUE)) == NULL)
- {
- Error("Can't open font file.\n");
- }
-
- fontlist->filename = POV_STRDUP(b);
-
- /*
- * We try to choose ISO 8859-1 (Latin-1) as default for now.
- * For Microsoft encodings 3, 1 is for Unicode/Latin-1,
- * 3, 0 is for Non-unicode (ie symbols),
- * For Macintosh encodings 1, 0 is for Roman character set.
- */
- fontlist->platformID = 3;
- fontlist->specificID = 1;
- fontlist->next = TTFonts;
- TTFonts = fontlist;
- }
- return fontlist;
- }
- void FreeFontInfo()
- {
- int i;
- FontFileInfo *oldfont, *tempfont;
- GlyphPtr glyphs, tempglyph;
- for (oldfont = TTFonts; oldfont != NULL;)
- {
- if (oldfont->fp != NULL)
- fclose(oldfont->fp);
-
- if (oldfont->filename != NULL)
- POV_FREE(oldfont->filename);
-
- if (oldfont->loca_table != NULL)
- POV_FREE(oldfont->loca_table);
-
- if (oldfont->hmtx_table != NULL)
- POV_FREE(oldfont->hmtx_table);
- if (oldfont->kerning_tables.nTables != 0)
- {
- for (i = 0; i < oldfont->kerning_tables.nTables; i++)
- {
- if (oldfont->kerning_tables.tables[i].kern_pairs)
- POV_FREE(oldfont->kerning_tables.tables[i].kern_pairs);
- }
-
- POV_FREE(oldfont->kerning_tables.tables);
- }
-
- for (glyphs = oldfont->glyphs; glyphs != NULL;)
- {
- for (i = 0; i < glyphs->header.numContours; i++)
- {
- POV_FREE(glyphs->contours[i].flags);
- POV_FREE(glyphs->contours[i].x);
- POV_FREE(glyphs->contours[i].y);
- }
-
- if (glyphs->contours != NULL)
- POV_FREE(glyphs->contours);
- tempglyph = glyphs;
- glyphs = glyphs->next;
- POV_FREE(tempglyph);
- }
-
- if (oldfont->segCount != 0)
- {
- POV_FREE(oldfont->endCount);
- POV_FREE(oldfont->startCount);
- POV_FREE(oldfont->idDelta);
- POV_FREE(oldfont->idRangeOffset);
- }
- tempfont = oldfont;
- oldfont = oldfont->next;
- POV_FREE(tempfont);
- }
- TTFonts = NULL;
- }
- /* Process the font header table */
- static void ProcessHeadTable(FontFileInfo *ffile, long head_table_offset)
- {
- sfnt_FontHeader fontHeader;
- /* Read head table */
- fseek(ffile->fp, head_table_offset, SEEK_SET);
- fontHeader.version = READFIXED(ffile->fp);
- fontHeader.fontRevision = READFIXED(ffile->fp);
- fontHeader.checkSumAdjustment = READULONG(ffile->fp);
- fontHeader.magicNumber = READULONG(ffile->fp); /* should be 0x5F0F3CF5 */
- fontHeader.flags = READUSHORT(ffile->fp);
- fontHeader.unitsPerEm = READUSHORT(ffile->fp);
- fontHeader.created.bc = READULONG(ffile->fp);
- fontHeader.created.ad = READULONG(ffile->fp);
- fontHeader.modified.bc = READULONG(ffile->fp);
- fontHeader.modified.ad = READULONG(ffile->fp);
- fontHeader.xMin = READFWORD(ffile->fp);
- fontHeader.yMin = READFWORD(ffile->fp);
- fontHeader.xMax = READFWORD(ffile->fp);
- fontHeader.yMax = READFWORD(ffile->fp);
- fontHeader.macStyle = READUSHORT(ffile->fp);
- fontHeader.lowestRecPPEM = READUSHORT(ffile->fp);
- fontHeader.fontDirectionHint = READSHORT(ffile->fp);
- fontHeader.indexToLocFormat = READSHORT(ffile->fp);
- fontHeader.glyphDataFormat = READSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("\nfontHeader:\n");
- Debug_Info("version: %d\n",fontHeader.version);
- Debug_Info("fontRevision: %d\n",fontHeader.fontRevision);
- Debug_Info("checkSumAdjustment: %u\n",fontHeader.checkSumAdjustment);
- Debug_Info("magicNumber: 0x%8X\n",fontHeader.magicNumber);
- Debug_Info("flags: %u\n",fontHeader.flags);
- Debug_Info("unitsPerEm: %u\n",fontHeader.unitsPerEm);
- Debug_Info("created.bc: %u\n",fontHeader.created.bc);
- Debug_Info("created.ad: %u\n",fontHeader.created.ad);
- Debug_Info("modified.bc: %u\n",fontHeader.modified.bc);
- Debug_Info("modified.ad: %u\n",fontHeader.modified.ad);
- Debug_Info("xMin: %d\n",fontHeader.xMin);
- Debug_Info("yMin: %d\n",fontHeader.yMin);
- Debug_Info("xMax: %d\n",fontHeader.xMax);
- Debug_Info("yMax: %d\n",fontHeader.yMax);
- Debug_Info("macStyle: %u\n",fontHeader.macStyle);
- Debug_Info("lowestRecPPEM: %u\n",fontHeader.lowestRecPPEM);
- Debug_Info("fontDirectionHint: %d\n",fontHeader.fontDirectionHint);
- Debug_Info("indexToLocFormat: %d\n",fontHeader.indexToLocFormat);
- Debug_Info("glyphDataFormat: %d\n",fontHeader.glyphDataFormat);
- #endif
-
- if (fontHeader.magicNumber != 0x5F0F3CF5)
- {
- Error("Error reading TrueType font %s. Bad magic number (0x%8X)\n",
- ffile->filename, fontHeader.magicNumber);
- }
- ffile->indexToLocFormat = fontHeader.indexToLocFormat;
- ffile->unitsPerEm = fontHeader.unitsPerEm;
- }
- /* Determine the relative offsets of glyphs */
- static void ProcessLocaTable(FontFileInfo *ffile, long loca_table_offset)
- {
- int i;
- /* Move to location of table in file */
- fseek(ffile->fp, loca_table_offset, SEEK_SET);
- ffile->loca_table = (ULONG *)POV_MALLOC((ffile->numGlyphs+1) * sizeof(ULONG), "ttf");
- #ifdef TTF_DEBUG
- Debug_Info("\nlocation table:\n");
- Debug_Info("version: %s\n",(ffile->indexToLocFormat?"long":"short"));
- #endif
- /* Now read and save the location table */
-
- if (ffile->indexToLocFormat == 0) /* short version */
- {
- for (i = 0; i < ffile->numGlyphs; i++)
- {
- ffile->loca_table[i] = ((ULONG)READUSHORT(ffile->fp)) << 1;
- #ifdef TTF_DEBUG2
- Debug_Info("loca_table[%d] @ %u\n", i, ffile->loca_table[i]);
- #endif
- }
- }
- else /* long version */
- {
- for (i = 0; i < ffile->numGlyphs; i++)
- {
- ffile->loca_table[i] = READULONG(ffile->fp);
- #ifdef TTF_DEBUG2
- Debug_Info("loca_table[%d] @ %u\n", i, ffile->loca_table[i]);
- #endif
- }
- }
- }
- /*
- * This routine determines the total number of glyphs in a TrueType file.
- * Necessary so that we can allocate the proper amount of storage for the glyph
- * location table.
- */
- static void ProcessMaxpTable(FontFileInfo *ffile, long maxp_table_offset)
- {
- /* Seek to the maxp table, skipping the 4 byte version number */
- fseek(ffile->fp, maxp_table_offset + 4, SEEK_SET);
-
- ffile->numGlyphs = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("\nmaximum profile table:\n");
- Debug_Info("numGlyphs: %u\n", ffile->numGlyphs);
- #endif
- }
- /* Read the kerning information for a glyph */
- static void ProcessKernTable(FontFileInfo *ffile, long kern_table_offset)
- {
- int i, j;
- USHORT temp16;
- USHORT length;
- KernTables *kern_table;
- kern_table = &ffile->kerning_tables;
- /* Move to the beginning of the kerning table, skipping the 2 byte version */
- fseek(ffile->fp, kern_table_offset + 2, SEEK_SET);
- /* Read in the number of kerning tables */
- kern_table->nTables = READUSHORT(ffile->fp);
- kern_table->tables = NULL; /*<==[esp] added (in case nTables is zero)*/
-
- #ifdef TTF_DEBUG
- Debug_Info("\nKerning table:\n", kern_table_offset);
- Debug_Info("Offset: %ld\n", kern_table_offset);
- Debug_Info("Number of tables: %u\n",kern_table->nTables);
- #endif
- /* Don't do any more work if there isn't kerning info */
-
- if (kern_table->nTables == 0)
- return;
- kern_table->tables = (TTKernTable *)POV_MALLOC(kern_table->nTables * sizeof(TTKernTable),
- "ProcessKernTable");
-
- for (i = 0; i < kern_table->nTables; i++)
- {
- /* Read in a subtable */
-
- temp16 = READUSHORT(ffile->fp); /* Subtable version */
- length = READUSHORT(ffile->fp); /* Subtable length */
- kern_table->tables[i].coverage = READUSHORT(ffile->fp); /* Coverage bits */
-
- #ifdef TTF_DEBUG
- Debug_Info("Coverage table[%d] (0x%X):", i, kern_table->tables[i].coverage);
- Debug_Info(" type %u", (kern_table->tables[i].coverage >> 8));
- Debug_Info(" %s", (kern_table->tables[i].coverage & KERN_HORIZONTAL ?
- "Horizontal" : "Vertical" ));
- Debug_Info(" %s values", (kern_table->tables[i].coverage & KERN_MINIMUM ?
- "Minimum" : "Kerning" ));
- Debug_Info("%s", (kern_table->tables[i].coverage & KERN_CROSS_STREAM ?
- " Cross-stream" : "" ));
- Debug_Info("%s\n", (kern_table->tables[i].coverage & KERN_OVERRIDE ?
- " Override" : "" ));
- #endif
- kern_table->tables[i].kern_pairs = NULL; /*<==[esp] added*/
- kern_table->tables[i].nPairs = 0; /*<==[esp] added*/
- if ((kern_table->tables[i].coverage >> 8) == 0)
- {
- /* Can only handle format 0 kerning subtables */
- kern_table->tables[i].nPairs = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("entries in table[%d]: %d\n", i, kern_table->tables[i].nPairs);
- #endif
- temp16 = READUSHORT(ffile->fp); /* searchRange */
- temp16 = READUSHORT(ffile->fp); /* entrySelector */
- temp16 = READUSHORT(ffile->fp); /* rangeShift */
-
- kern_table->tables[i].kern_pairs =
- (KernData *)POV_MALLOC(kern_table->tables[i].nPairs * sizeof(KernData), "Kern Pairs");
- for (j = 0; j < kern_table->tables[i].nPairs; j++)
- {
- /* Read in a kerning pair */
- kern_table->tables[i].kern_pairs[j].left = READUSHORT(ffile->fp);
- kern_table->tables[i].kern_pairs[j].right = READUSHORT(ffile->fp);
- kern_table->tables[i].kern_pairs[j].value = READFWORD(ffile->fp);
- #ifdef TTF_DEBUG2
- Debug_Info("Kern pair: <%d,%d> = %d\n",
- (int)kern_table->tables[i].kern_pairs[j].left,
- (int)kern_table->tables[i].kern_pairs[j].right,
- (int)kern_table->tables[i].kern_pairs[j].value);
- #endif
- }
- }
- else
- {
- #ifdef TTF_DEBUG2
- Warning(0.0, "Cannot handle format %u kerning data\n",
- (kern_table->tables[i].coverage >> 8));
- #endif
- /*
- * Seek to the end of this table, excluding the length of the version,
- * length, and coverage USHORTs, which we have already read.
- */
- fseek(ffile->fp, (long)(length - 6), SEEK_CUR);
- kern_table->tables[i].nPairs = 0;
- }
- }
- }
- /*
- * This routine determines the total number of horizontal metrics.
- */
- static void ProcessHheaTable(FontFileInfo *ffile, long hhea_table_offset)
- {
- #ifdef TTF_DEBUG
- sfnt_HorizHeader horizHeader;
- /* Seek to the hhea table */
- fseek(ffile->fp, hhea_table_offset, SEEK_SET);
-
- horizHeader.version = READFIXED(ffile->fp);
- horizHeader.Ascender = READFWORD(ffile->fp);
- horizHeader.Descender = READFWORD(ffile->fp);
- horizHeader.LineGap = READFWORD(ffile->fp);
- horizHeader.advanceWidthMax = READUFWORD(ffile->fp);
- horizHeader.minLeftSideBearing = READFWORD(ffile->fp);
- horizHeader.minRightSideBearing = READFWORD(ffile->fp);
- horizHeader.xMaxExtent = READFWORD(ffile->fp);
- horizHeader.caretSlopeRise = READSHORT(ffile->fp);
- horizHeader.caretSlopeRun = READSHORT(ffile->fp);
- horizHeader.reserved1 = READSHORT(ffile->fp);
- horizHeader.reserved2 = READSHORT(ffile->fp);
- horizHeader.reserved3 = READSHORT(ffile->fp);
- horizHeader.reserved4 = READSHORT(ffile->fp);
- horizHeader.reserved5 = READSHORT(ffile->fp);
- horizHeader.metricDataFormat = READSHORT(ffile->fp);
- #else
- /* Seek to the hhea table, skipping all that stuff we don't need */
- fseek(ffile->fp, hhea_table_offset + 34, SEEK_SET);
-
- #endif
- ffile->numberOfHMetrics = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("\nhorizontal header table:\n");
- Debug_Info("Ascender: %d\n",horizHeader.Ascender);
- Debug_Info("Descender: %d\n",horizHeader.Descender);
- Debug_Info("LineGap: %d\n",horizHeader.LineGap);
- Debug_Info("advanceWidthMax: %d\n",horizHeader.advanceWidthMax);
- Debug_Info("minLeftSideBearing: %d\n",horizHeader.minLeftSideBearing);
- Debug_Info("minRightSideBearing: %d\n",horizHeader.minRightSideBearing);
- Debug_Info("xMaxExtent: %d\n",horizHeader.xMaxExtent);
- Debug_Info("caretSlopeRise: %d\n",horizHeader.caretSlopeRise);
- Debug_Info("caretSlopeRun: %d\n",horizHeader.caretSlopeRun);
- Debug_Info("metricDataFormat: %d\n",horizHeader.metricDataFormat);
- Debug_Info("numberOfHMetrics: %d\n",ffile->numberOfHMetrics);
- #endif
- }
- static void ProcessHmtxTable (FontFileInfo *ffile, long hmtx_table_offset)
- {
- int i;
- longHorMetric *metric;
- uFWord lastAW = 0; /* Just to quiet warnings. */
- fseek(ffile->fp, hmtx_table_offset, SEEK_SET);
- ffile->hmtx_table = (longHorMetric *)POV_MALLOC(ffile->numGlyphs*sizeof(longHorMetric), "ttf");
- /*
- * Read in the total glyph width, and the left side offset. There is
- * guaranteed to be at least one longHorMetric entry in this table to
- * set the advanceWidth for the subsequent lsb entries.
- */
- for (i=0, metric=ffile->hmtx_table; i < ffile->numberOfHMetrics; i++,metric++)
- {
- lastAW = metric->advanceWidth = READUFWORD(ffile->fp);
- metric->lsb = READFWORD(ffile->fp);
- }
- /* Read in the remaining left offsets */
- for (; i < ffile->numGlyphs; i++, metric++)
- {
- metric->advanceWidth = lastAW;
- metric->lsb = READFWORD(ffile->fp);
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessCharacter
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Finds the glyph description for the current character.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static GlyphPtr ProcessCharacter(FontFileInfo *ffile, unsigned int search_char, unsigned int *glyph_index)
- {
- GlyphPtr glyph;
- /* See if we have already processed this glyph */
- for (glyph = ffile->glyphs; glyph != NULL; glyph = glyph->next)
- {
- if (glyph->c == search_char)
- {
- /* Found it, no need to do any more work */
- #ifdef TTF_DEBUG
- Debug_Info("Cached glyph: %c/%u\n",(char)search_char,glyph->glyph_index);
- #endif
- *glyph_index = glyph->glyph_index;
- return glyph;
- }
- }
- *glyph_index = ProcessCharMap(ffile, search_char);
- if (*glyph_index == 0)
- Warning(0.0, "Character %d (0x%X) not found in %s\n", (BYTE)search_char,
- search_char, ffile->filename);
- /* See if we have already processed this glyph (using the glyph index) */
- for (glyph = ffile->glyphs; glyph != NULL; glyph = glyph->next)
- {
- if (glyph->glyph_index == *glyph_index)
- {
- /* Found it, no need to do any more work */
- #ifdef TTF_DEBUG
- Debug_Info("Cached glyph: %c/%u\n",(char)search_char,glyph->glyph_index);
- #endif
- *glyph_index = glyph->glyph_index;
- return glyph;
- }
- }
- glyph = ExtractGlyphInfo(ffile, glyph_index, search_char);
- /* Add this glyph to the ones we already know about */
-
- glyph->next = ffile->glyphs;
- ffile->glyphs = glyph;
- /* Glyph is all built */
-
- return glyph;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessCharMap
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Find the character mapping for 'search_char'. We should really know
- * which character set we are using (ie ISO 8859-1, Mac, Unicode, etc).
- * Search char should really be a USHORT to handle double byte systems.
- *
- * CHANGES
- *
- * 961120 esp Added check to allow Macintosh encodings to pass
- *
- ******************************************************************************/
- static USHORT ProcessCharMap(FontFileInfo *ffile, unsigned int search_char)
- {
- long old_table_offset;
- long entry_offset;
- sfnt_platformEntry cmapEntry;
- sfnt_mappingTable encodingTable;
- int i, table_count;
- /* Move to the start of the character map, skipping the 2 byte version */
- fseek(ffile->fp, ffile->cmap_table_offset + 2, SEEK_SET);
-
- table_count = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("table_count=%d\n", table_count);
- #endif
-
- /*
- * Search the tables until we find the glyph index for the search character.
- * Just return the first one we find...
- */
- for (i = 0; i < table_count; i++)
- {
- cmapEntry.platformID = READUSHORT(ffile->fp);
- cmapEntry.specificID = READUSHORT(ffile->fp);
- cmapEntry.offset = READULONG(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("cmapEntry: platformID=%d\n", cmapEntry.platformID);
- Debug_Info("cmapEntry: specificID=%d\n", cmapEntry.specificID);
- Debug_Info("cmapEntry: offset=%d\n", cmapEntry.offset);
- #endif
- /*
- * Check if this is the encoding table we want to use. We can't
- * be very picky, since we don't know what the user really wants.
- * It would be nice to know what we are really looking for.
- * Allow Type 1 platform as well (Macintosh) [esp]
- */
- if ((ffile->platformID != cmapEntry.platformID) && (1 != cmapEntry.platformID))
- {
- continue;
- }
- entry_offset = cmapEntry.offset;
- old_table_offset = ftell(ffile->fp); /* Save the current position */
- fseek(ffile->fp, ffile->cmap_table_offset + entry_offset, SEEK_SET);
-
- encodingTable.format = READUSHORT(ffile->fp);
- encodingTable.length = READUSHORT(ffile->fp);
- encodingTable.version = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("Encoding table, format: %u, length: %u, version: %u\n",
- encodingTable.format, encodingTable.length, encodingTable.version);
- #endif
- if (encodingTable.format == 0)
- {
- /*
- * Translation is simple - add 'entry_char' to the start of the
- * table and grab what's there.
- */
- #ifdef TTF_DEBUG
- Debug_Info("Apple standard index mapping\n");
- #endif
- return(ProcessFormat0Glyph(ffile, search_char));
- }
- #if 0 /* Want to get the rest of these working first */
- else if (encodingTable.format == 2)
- {
- /* Used for multi-byte character encoding (Chinese, Japanese, etc) */
- #ifdef TTF_DEBUG
- Debug_Info("High-byte index mapping\n");
- #endif
- return(ProcessFormat2Glyph(ffile, search_char));
- }
- #endif
- else if (encodingTable.format == 4)
- {
- /* Microsoft UGL encoding */
- #ifdef TTF_DEBUG
- Debug_Info("Microsoft standard index mapping\n");
- #endif
- return(ProcessFormat4Glyph(ffile, search_char));
- }
- else if (encodingTable.format == 6)
- {
- #ifdef TTF_DEBUG
- Debug_Info("Trimmed table mapping\n");
- #endif
- return(ProcessFormat6Glyph(ffile, search_char));
- }
- #ifdef TTF_DEBUG
- else
- Debug_Info("Unsupported index mapping format: %u\n",
- encodingTable.format);
- #endif
- /* Go to the next table entry if we didn't find a match */
- fseek(ffile->fp, old_table_offset, SEEK_SET);
- }
- /*
- * No character mapping was found - very odd, we should really have had the
- * character in at least one table. Perhaps getting here means we didn't
- * have any character mapping tables. '0' means no mapping.
- */
-
- return 0;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessFormat0Glyph
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * This handles the Apple standard index mapping for glyphs.
- * The file pointer must be pointing immediately after the version entry in the
- * encoding table for the next two functions to work.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static USHORT ProcessFormat0Glyph(FontFileInfo *ffile, unsigned int search_char)
- {
- BYTE temp_index;
- fseek(ffile->fp, (long)search_char, SEEK_CUR);
-
- if (fread(&temp_index, 1, 1, ffile->fp) != 1) /* Each index is 1 byte */
- {
- Error("Error reading TrueType font file at line %d, %s\n",
- __LINE__, __FILE__);
- }
-
- return (USHORT)(temp_index);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessFormat4Glyph
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * This handles the Microsoft standard index mapping for glyph tables
- *
- * CHANGES
- *
- * Mar 26, 1996: Cache segment info rather than read each time. [AED]
- *
- ******************************************************************************/
- static USHORT ProcessFormat4Glyph(FontFileInfo *ffile, unsigned int search_char)
- {
- int i;
- unsigned int glyph_index = 0; /* Set the glyph index to "not present" */
- /*
- * If this is the first time we are here, read all of the segment headers,
- * and save them for later calls to this function, rather than seeking and
- * mallocing for each character
- */
- if (ffile->segCount == 0)
- {
- USHORT temp16;
- ffile->segCount = READUSHORT(ffile->fp) >> 1;
- ffile->searchRange = READUSHORT(ffile->fp);
- ffile->entrySelector = READUSHORT(ffile->fp);
- ffile->rangeShift = READUSHORT(ffile->fp);
- /* Now allocate and read in the segment arrays */
-
- ffile->endCount = (USHORT *)POV_MALLOC(ffile->segCount * sizeof(USHORT), "ttf");
- ffile->startCount = (USHORT *)POV_MALLOC(ffile->segCount * sizeof(USHORT), "ttf");
- ffile->idDelta = (USHORT *)POV_MALLOC(ffile->segCount * sizeof(USHORT), "ttf");
- ffile->idRangeOffset = (USHORT *)POV_MALLOC(ffile->segCount * sizeof(USHORT), "ttf");
- for (i = 0; i < ffile->segCount; i++)
- {
- ffile->endCount[i] = READUSHORT(ffile->fp);
- }
-
- temp16 = READUSHORT(ffile->fp); /* Skip over 'reservedPad' */
-
- for (i = 0; i < ffile->segCount; i++)
- {
- ffile->startCount[i] = READUSHORT(ffile->fp);
- }
-
- for (i = 0; i < ffile->segCount; i++)
- {
- ffile->idDelta[i] = READUSHORT(ffile->fp);
- }
- /* location of start of idRangeOffset */
- ffile->glyphIDoffset = ftell(ffile->fp);
- for (i = 0; i < ffile->segCount; i++)
- {
- ffile->idRangeOffset[i] = READUSHORT(ffile->fp);
- }
- }
-
- /* Search the segments for our character */
-
- glyph_search:
- for (i = 0; i < ffile->segCount; i++)
- {
- if (search_char <= ffile->endCount[i])
- {
- if (search_char >= ffile->startCount[i])
- {
- /* Found correct range for this character */
-
- if (ffile->idRangeOffset[i] == 0)
- {
- glyph_index = search_char + ffile->idDelta[i];
- }
- else
- {
- /*
- * Alternate encoding of glyph indices, relies on a quite unusual way
- * of storing the offsets. We need the *2s because we are talking
- * about addresses of shorts and not bytes.
- *
- * (glyphIDoffset + i*2 + idRangeOffset[i]) == &idRangeOffset[i]
- */
- fseek(ffile->fp, ffile->glyphIDoffset + 2*i + ffile->idRangeOffset[i]+
- 2*(search_char - ffile->startCount[i]), SEEK_SET);
-
- glyph_index = READUSHORT(ffile->fp);
-
- if (glyph_index != 0)
- glyph_index = glyph_index + ffile->idDelta[i];
- }
- }
- break;
- }
- }
- /*
- * If we haven't found the character yet, and this is the first time to
- * search the tables, try looking in the Unicode user space, since this
- * is the location Microsoft recommends for symbol characters like those
- * in wingdings and dingbats.
- */
- if (glyph_index == 0 && search_char < 0x100)
- {
- search_char += 0xF000;
- #ifdef TTF_DEBUG
- Debug_Info("Looking for glyph in Unicode user space (0x%X)\n", search_char);
- #endif
- goto glyph_search;
- }
- /* Deallocate the memory we used for the segment arrays */
-
- return glyph_index;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ProcessFormat6Glyph
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * This handles the trimmed table mapping for glyphs.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static USHORT ProcessFormat6Glyph(FontFileInfo *ffile, unsigned int search_char)
- {
- USHORT firstCode, entryCount;
- BYTE glyph_index;
- firstCode = READUSHORT(ffile->fp);
- entryCount = READUSHORT(ffile->fp);
-
- if (search_char >= firstCode && search_char < firstCode + entryCount)
- {
- fseek(ffile->fp, (long)(search_char - firstCode), SEEK_CUR);
- glyph_index = READUSHORT(ffile->fp);
- }
- else
- glyph_index = 0;
-
- return glyph_index;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ExtractGlyphInfo
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Change TTF outline information for the glyph(s) into a useful format
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static GlyphPtr ExtractGlyphInfo(FontFileInfo *ffile, unsigned int *glyph_index, unsigned int c)
- {
- GlyphOutline *ttglyph;
- GlyphPtr glyph;
- ttglyph = ExtractGlyphOutline(ffile, glyph_index, c);
- /*
- * Convert the glyph outline information from TrueType layout into a more
- * easily processed format
- */
- glyph = ConvertOutlineToGlyph(ffile, ttglyph);
- glyph->c = c;
- glyph->glyph_index = *glyph_index;
- glyph->myMetrics = ttglyph->myMetrics;
- /* Free up outline information */
-
- if (ttglyph)
- {
- if (ttglyph->y) POV_FREE(ttglyph->y);
- if (ttglyph->x) POV_FREE(ttglyph->x);
- if (ttglyph->endPoints) POV_FREE(ttglyph->endPoints);
- if (ttglyph->flags) POV_FREE(ttglyph->flags);
- POV_FREE(ttglyph);
- }
-
- return glyph;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ExtractGlyphOutline
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Read the contour information for a specific glyph. This has to be a
- * separate routine from ExtractGlyphInfo because we call it recurisvely
- * for multiple component glyphs.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static GlyphOutline *ExtractGlyphOutline(FontFileInfo *ffile, unsigned int *glyph_index, unsigned int c)
- {
- int i;
- USHORT n;
- SHORT nc;
- GlyphOutline *ttglyph;
- ttglyph = (GlyphOutline *)POV_CALLOC(1, sizeof(GlyphOutline), "ttf");
- ttglyph->myMetrics = *glyph_index;
- /* Have to treat space characters differently */
- if (c != ' ')
- {
- fseek(ffile->fp, ffile->glyf_table_offset+ffile->loca_table[*glyph_index],
- SEEK_SET);
- ttglyph->header.numContours = READSHORT(ffile->fp);
- ttglyph->header.xMin = READFWORD(ffile->fp); /* These may be */
- ttglyph->header.yMin = READFWORD(ffile->fp); /* unreliable in */
- ttglyph->header.xMax = READFWORD(ffile->fp); /* some fonts. */
- ttglyph->header.yMax = READFWORD(ffile->fp);
- }
-
- #ifdef TTF_DEBUG
- Debug_Info("ttglyph->header:\n");
- Debug_Info("glyph_index=%d\n", *glyph_index);
- Debug_Info("loca_table[%d]=%d\n",*glyph_index,ffile->loca_table[*glyph_index]);
- Debug_Info("numContours=%d\n", ttglyph->header.numContours);
- #endif
- nc = ttglyph->header.numContours;
-
- /*
- * A positive number of contours means a regular glyph, with possibly
- * several separate line segments making up the outline.
- */
- if (nc > 0)
- {
- FWord coord;
- BYTE flag, repeat_count;
- USHORT temp16;
- /* Grab the contour endpoints */
-
- ttglyph->endPoints = (USHORT *)POV_MALLOC(nc * sizeof(USHORT), "ttf");
-
- for (i = 0; i < nc; i++)
- {
- ttglyph->endPoints[i] = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("endPoints[%d]=%d\n", i, ttglyph->endPoints[i]);
- #endif
- }
- /* Skip over the instructions */
- temp16 = READUSHORT(ffile->fp);
- fseek(ffile->fp, temp16, SEEK_CUR);
- /* Determine the number of points making up this glyph */
-
- n = ttglyph->numPoints = ttglyph->endPoints[nc - 1] + 1;
- #ifdef TTF_DEBUG
- Debug_Info("numPoints=%d\n", ttglyph->numPoints);
- #endif
- /* Read the flags */
-
- ttglyph->flags = (BYTE *)POV_MALLOC(n * sizeof(BYTE), "ttf");
-
- for (i = 0; i < ttglyph->numPoints; i++)
- {
- if (fread(&ttglyph->flags[i], sizeof(BYTE), 1, ffile->fp) != 1)
- {
- Error("Error reading TrueType font file at line %d, %s\n",
- __LINE__, __FILE__);
- }
-
- if (ttglyph->flags[i] & REPEAT_FLAGS)
- {
- if (fread(&repeat_count, sizeof(BYTE), 1, ffile->fp) != 1)
- {
- Error("Error reading TrueType font file at line %d, %s\n",
- __LINE__, __FILE__);
- }
-
- for (; repeat_count > 0; repeat_count--, i++)
- {
- ttglyph->flags[i + 1] = ttglyph->flags[i];
- }
- }
- }
- /* Read the coordinate vectors */
-
- ttglyph->x = (DBL *)POV_MALLOC(n * sizeof(DBL), "ttf");
- ttglyph->y = (DBL *)POV_MALLOC(n * sizeof(DBL), "ttf");
- coord = 0;
-
- for (i = 0; i < ttglyph->numPoints; i++)
- {
- /* Read each x coordinate */
-
- flag = ttglyph->flags[i];
-
- if (flag & XSHORT)
- {
- BYTE temp8;
- if (fread(&temp8, 1, 1, ffile->fp) != 1)
- {
- Error("Error reading TrueType font file at line %d, %s\n",
- __LINE__, __FILE__);
- }
-
- if (flag & SHORT_X_IS_POS)
- coord += temp8;
- else
- coord -= temp8;
- }
- else if (!(flag & NEXT_X_IS_ZERO))
- {
- coord += READSHORT(ffile->fp);
- }
-
- /* Find our own maximum and minimum x coordinates */
- if (coord > ttglyph->header.xMax)
- ttglyph->header.xMax = coord;
- if (coord < ttglyph->header.xMin)
- ttglyph->header.xMin = coord;
- ttglyph->x[i] = (DBL)coord / (DBL)ffile->unitsPerEm;
- }
- coord = 0;
-
- for (i = 0; i < ttglyph->numPoints; i++)
- {
- /* Read each y coordinate */
-
- flag = ttglyph->flags[i];
-
- if (flag & YSHORT)
- {
- BYTE temp8;
- if (fread(&temp8, 1, 1, ffile->fp) != 1)
- {
- Error("Error reading TrueType font file at line %d, %s\n",
- __LINE__, __FILE__);
- }
-
- if (flag & SHORT_Y_IS_POS)
- coord += temp8;
- else
- coord -= temp8;
- }
- else if (!(flag & NEXT_Y_IS_ZERO))
- {
- coord += READSHORT(ffile->fp);
- }
-
- /* Find out our own maximum and minimum y coordinates */
- if (coord > ttglyph->header.yMax)
- ttglyph->header.yMax = coord;
- if (coord < ttglyph->header.yMin)
- ttglyph->header.yMin = coord;
- ttglyph->y[i] = (DBL)coord / (DBL)ffile->unitsPerEm;
- }
- }
- /*
- * A negative number for numContours means that this glyph is
- * made up of several separate glyphs.
- */
- else if (nc < 0)
- {
- USHORT flags;
- ttglyph->header.numContours = 0;
- ttglyph->numPoints = 0;
- do
- {
- GlyphOutline *sub_ttglyph;
- unsigned int sub_glyph_index;
- long current_pos;
- SHORT arg1, arg2;
- DBL xoff = 0, yoff = 0;
- DBL xscale = 1, yscale = 1;
- DBL scale01 = 0, scale10 = 0;
- USHORT n2;
- SHORT nc2;
- flags = READUSHORT(ffile->fp);
- sub_glyph_index = READUSHORT(ffile->fp);
- #ifdef TTF_DEBUG
- Debug_Info("sub_glyph %d: ", sub_glyph_index);
- #endif
-
- if (flags & ARG_1_AND_2_ARE_WORDS)
- {
- #ifdef TTF_DEBUG
- Debug_Info("ARG_1_AND_2_ARE_WORDS ");
- #endif
- arg1 = READSHORT(ffile->fp);
- arg2 = READSHORT(ffile->fp);
- }
- else
- {
- arg1 = READUSHORT(ffile->fp);
- arg2 = arg1 & 0xFF;
- arg1 = (arg1 >> 8) & 0xFF;
- }
- #ifdef TTF_DEBUG
- if (flags & ROUND_XY_TO_GRID)
- {
- Debug_Info("ROUND_XY_TO_GRID ");
- }
- if (flags & MORE_COMPONENTS)
- {
- Debug_Info("MORE_COMPONENTS ");
- }
- #endif
- if (flags & WE_HAVE_A_SCALE)
- {
- xscale = yscale = (DBL)READSHORT(ffile->fp)/0x4000;
- #ifdef TTF_DEBUG
- Debug_Info("WE_HAVE_A_SCALE ");
- Debug_Info("xscale = %lf\t", xscale);
- Debug_Info("scale01 = %lf\n", scale01);
- Debug_Info("scale10 = %lf\t", scale10);
- Debug_Info("yscale = %lf\n", yscale);
- #endif
- }
- else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
- {
- xscale = (DBL)READSHORT(ffile->fp)/0x4000;
- yscale = (DBL)READSHORT(ffile->fp)/0x4000;
- #ifdef TTF_DEBUG
- Debug_Info("WE_HAVE_AN_X_AND_Y_SCALE ");
- Debug_Info("xscale = %lf\t", xscale);
- Debug_Info("scale01 = %lf\n", scale01);
- Debug_Info("scale10 = %lf\t", scale10);
- Debug_Info("yscale = %lf\n", yscale);
- #endif
- }
- else if (flags & WE_HAVE_A_TWO_BY_TWO)
- {
- xscale = (DBL)READSHORT(ffile->fp)/0x4000;
- scale01 = (DBL)READSHORT(ffile->fp)/0x4000;
- scale10 = (DBL)READSHORT(ffile->fp)/0x4000;
- yscale = (DBL)READSHORT(ffile->fp)/0x4000;
- #ifdef TTF_DEBUG
- Debug_Info("WE_HAVE_A_TWO_BY_TWO ");
- Debug_Info("xscale = %lf\t", xscale);
- Debug_Info("scale01 = %lf\n", scale01);
- Debug_Info("scale10 = %lf\t", scale10);
- Debug_Info("yscale = %lf\n", yscale);
- #endif
- }
- if (flags & ARGS_ARE_XY_VALUES)
- {
- xoff = (DBL)arg1 / ffile->unitsPerEm;
- yoff = (DBL)arg2 / ffile->unitsPerEm;
- #ifdef TTF_DEBUG
- Debug_Info("ARGS_ARE_XY_VALUES ");
- Debug_Info("\narg1 = %d xoff = %lf\t", arg1, xoff);
- Debug_Info("arg2 = %d yoff = %lf\n", arg2, yoff);
- #endif
- }
- else /* until I understand how this method works... */
- {
- Warning(0.0, "Can't handle part of glyph %d (0x%X).\n", c, c);
- continue;
- }
- if (flags & USE_MY_METRICS)
- {
- #ifdef TTF_DEBUG
- Debug_Info("USE_MY_METRICS ");
- #endif
- ttglyph->myMetrics = sub_glyph_index;
- }
- current_pos = ftell(ffile->fp);
- sub_ttglyph = ExtractGlyphOutline(ffile, &sub_glyph_index, c);
- fseek(ffile->fp, current_pos, SEEK_SET);
- if ((nc2 = sub_ttglyph->header.numContours) == 0)
- continue;
- nc = ttglyph->header.numContours;
- n = ttglyph->numPoints;
- n2 = sub_ttglyph->numPoints;
- ttglyph->endPoints = (USHORT *)POV_REALLOC(ttglyph->endPoints,
- (nc + nc2) * sizeof(USHORT), "ttf");
- ttglyph->flags = (BYTE *)POV_REALLOC(ttglyph->flags, (n+n2)*sizeof(BYTE), "ttf");
- ttglyph->x = (DBL *)POV_REALLOC(ttglyph->x, (n + n2) * sizeof(DBL), "ttf");
- ttglyph->y = (DBL *)POV_REALLOC(ttglyph->y, (n + n2) * sizeof(DBL), "ttf");
- /* Add the sub glyph info to the end of the current glyph */
- ttglyph->header.numContours += nc2;
- ttglyph->numPoints += n2;
- for (i = 0; i < nc2; i++)
- {
- ttglyph->endPoints[i + nc] = sub_ttglyph->endPoints[i] + n;
- #ifdef TTF_DEBUG
- Debug_Info("endPoints[%d]=%d\n", i + nc, ttglyph->endPoints[i + nc]);
- #endif
- }
- for (i = 0; i < n2; i++)
- {
- #ifdef TTF_DEBUG
- Debug_Info("x[%d]=%lf\t", i, sub_ttglyph->x[i]);
- Debug_Info("y[%d]=%lf\n", i, sub_ttglyph->y[i]);
- #endif
- ttglyph->flags[i + n] = sub_ttglyph->flags[i];
- ttglyph->x[i + n] = xscale * sub_ttglyph->x[i] +
- scale01 * sub_ttglyph->y[i] + xoff;
- ttglyph->y[i + n] = scale10 * sub_ttglyph->x[i] +
- yscale * sub_ttglyph->y[i] + yoff;
- #ifdef TTF_DEBUG
- Debug_Info("x[%d]=%lf\t", i+n, ttglyph->x[i+n]);
- Debug_Info("y[%d]=%lf\n", i+n, ttglyph->y[i+n]);
- #endif
- if (ttglyph->x[i + n] < ttglyph->header.xMin)
- ttglyph->header.xMin = ttglyph->x[i + n];
- if (ttglyph->x[i + n] > ttglyph->header.xMax)
- ttglyph->header.xMax = ttglyph->x[i + n];
- if (ttglyph->y[i + n] < ttglyph->header.yMin)
- ttglyph->header.yMin = ttglyph->y[i + n];
- if (ttglyph->y[i + n] > ttglyph->header.yMax)
- ttglyph->header.yMax = ttglyph->y[i + n];
- }
- /* Free up the sub glyph outline information */
-
- if (sub_ttglyph->y) POV_FREE(sub_ttglyph->y);
- if (sub_ttglyph->x) POV_FREE(sub_ttglyph->x);
- if (sub_ttglyph->endPoints) POV_FREE(sub_ttglyph->endPoints);
- if (sub_ttglyph->flags) POV_FREE(sub_ttglyph->flags);
- POV_FREE(sub_ttglyph);
- } while (flags & MORE_COMPONENTS);
- }
- #ifdef TTF_DEBUG
- Debug_Info("xMin=%d\n",ttglyph->header.xMin);
- Debug_Info("yMin=%d\n",ttglyph->header.yMin);
- Debug_Info("xMax=%d\n",ttglyph->header.xMax);
- Debug_Info("yMax=%d\n",ttglyph->header.yMax);
- #endif
- return ttglyph;
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ConvertOutlineToGlyph
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Transform a glyph from TrueType storage format to something a little easier
- * to manage.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static GlyphPtr ConvertOutlineToGlyph(FontFileInfo *ffile, GlyphOutline *ttglyph)
- {
- GlyphPtr glyph;
- DBL *temp_x, *temp_y;
- BYTE *temp_f;
- USHORT i, j, last_j;
- /* Create storage for this glyph */
- glyph = (Glyph *)POV_MALLOC(sizeof(Glyph), "ttf");
- if (ttglyph->header.numContours > 0)
- {
- glyph->contours = (Contour *)POV_MALLOC(ttglyph->header.numContours * sizeof(Contour), "ttf");
- }
- else
- {
- glyph->contours = NULL;
- }
- /* Copy sizing information about this glyph */
-
- memcpy(&glyph->header, &ttglyph->header, sizeof(GlyphHeader));
- /* Keep track of the size for this glyph */
-
- glyph->unitsPerEm = ffile->unitsPerEm;
- /* Now copy the vertex information into the contours */
-
- for (i = 0, last_j = 0; i < (USHORT) ttglyph->header.numContours; i++)
- {
- /* Figure out number of points in contour */
-
- j = ttglyph->endPoints[i] - last_j + 1;
- /* Copy the coordinate information into the glyph */
-
- temp_x = (DBL *)POV_MALLOC((j + 1) * sizeof(DBL), "ttf");
- temp_y = (DBL *)POV_MALLOC((j + 1) * sizeof(DBL), "ttf");
- temp_f = (BYTE *)POV_MALLOC((j + 1) * sizeof(BYTE), "ttf");
- memcpy(temp_x, &ttglyph->x[last_j], j * sizeof(DBL));
- memcpy(temp_y, &ttglyph->y[last_j], j * sizeof(DBL));
- memcpy(temp_f, &ttglyph->flags[last_j], j * sizeof(BYTE));
- temp_x[j] = ttglyph->x[last_j];
- temp_y[j] = ttglyph->y[last_j];
- temp_f[j] = ttglyph->flags[last_j];
- /* Figure out if this is an inside or outside contour */
-
- glyph->contours[i].inside_flag = 0;
- /* Plug in the reset of the contour components into the glyph */
-
- glyph->contours[i].count = j;
- glyph->contours[i].x = temp_x;
- glyph->contours[i].y = temp_y;
- glyph->contours[i].flags = temp_f;
- /*
- * Set last_j to point to the beginning of the next contour's coordinate
- * information
- */
-
- last_j = ttglyph->endPoints[i] + 1;
- }
- /* Show statistics about this glyph */
- #ifdef TTF_DEBUG
- Debug_Info("Number of contours: %u\n", glyph->header.numContours);
- Debug_Info("X extent: [%f, %f]\n",
- (DBL)glyph->header.xMin / (DBL)ffile->unitsPerEm,
- (DBL)glyph->header.xMax / (DBL)ffile->unitsPerEm);
- Debug_Info("Y extent: [%f, %f]\n",
- (DBL)glyph->header.yMin / (DBL)ffile->unitsPerEm,
- (DBL)glyph->header.yMax / (DBL)ffile->unitsPerEm);
- Debug_Info("Converted coord list(%d):\n", (int)glyph->header.numContours);
- for (i=0;i<(USHORT)glyph->header.numContours;i++)
- {
- for (j=0;j<=glyph->contours[i].count;j++)
- Debug_Info(" %c[%f, %f]\n",
- (glyph->contours[i].flags[j] & ONCURVE ? '*' : ' '),
- glyph->contours[i].x[j], glyph->contours[i].y[j]);
- Debug_Info("\n");
- }
- #endif
- return glyph;
- }
- /* Test to see if "point" is inside the splined polygon "points". */
- static int Inside_Glyph(double x, double y, GlyphPtr glyph)
- {
- int i, j, k, n, n1, crossings;
- int qi, ri, qj, rj;
- Contour *contour;
- double xt[3], yt[3], roots[2];
- DBL *xv, *yv;
- double x0, x1, x2, t;
- double y0, y1, y2;
- double m, b, xc;
- BYTE *fv;
- crossings = 0;
-
- n = glyph->header.numContours;
-
- contour = glyph->contours;
-
- for (i = 0; i < n; i++)
- {
- xv = contour[i].x;
- yv = contour[i].y;
- fv = contour[i].flags;
- x0 = xv[0];
- y0 = yv[0];
- n1 = contour[i].count;
-
- for (j = 1; j <= n1; j++)
- {
- x1 = xv[j];
- y1 = yv[j];
-
- if (fv[j] & ONCURVE)
- {
- /* Straight line - first set up for the next */
- /* Now do the crossing test */
-
- qi = ri = qj = rj = 0;
-
- if (y0 == y1)
- goto end_line_test;
-
- /* if (fabs((y - y0) / (y1 - y0)) < EPSILON) goto end_line_test; */
-
- if (y0 < y)
- qi = 1;
-
- if (y1 < y)
- qj = 1;
-
- if (qi == qj)
- goto end_line_test;
-
- if (x0 > x)
- ri = 1;
-
- if (x1 > x)
- rj = 1;
-
- if (ri & rj)
- {
- crossings++;
- goto end_line_test;
- }
-
- if ((ri | rj) == 0)
- goto end_line_test;
-
- m = (y1 - y0) / (x1 - x0);
- b = (y1 - y) - m * (x1 - x);
-
- if ((b / m) < EPSILON)
- {
- crossings++;
- }
-
- end_line_test:
- x0 = x1;
- y0 = y1;
- }
- else
- {
- if (j == n1)
- {
- x2 = xv[0];
- y2 = yv[0];
- }
- else
- {
- x2 = xv[j + 1];
- y2 = yv[j + 1];
-
- if (!(fv[j + 1] & ONCURVE))
- {
- /*
- * Parabola with far end floating - readjust the far end so that it
- * is on the curve.
- */
-
- x2 = 0.5 * (x1 + x2);
- y2 = 0.5 * (y1 + y2);
- }
- }
- /* only test crossing when y is in the range */
- /* this should also help saving some computations */
- if (((y0 < y) && (y1 < y) && (y2 < y)) ||
- ((y0 > y) && (y1 > y) && (y2 > y)))
- goto end_curve_test;
- yt[0] = y0 - 2.0 * y1 + y2;
- yt[1] = 2.0 * (y1 - y0);
- yt[2] = y0 - y;
-
- k = solve_quad(yt, roots, 0.0, 1.0);
- for (ri = 0; ri < k;) {
- if (roots[ri] <= EPSILON) {
- /* if y actually is not in range, discard the root */
- if (((y <= y0) && (y < y1)) || ((y >= y0) && (y > y1))) {
- k--;
- if (k > ri)
- roots[ri] = roots[ri+1];
- continue;
- }
- }
- else if (roots[ri] >= (1.0 - EPSILON)) {
- /* if y actually is not in range, discard the root */
- if (((y < y2) && (y < y1)) || ((y > y2) && (y > y1))) {
- k--;
- if (k > ri)
- roots[ri] = roots[ri+1];
- continue;
- }
- }
- ri++;
- }
-
- if (k > 0)
- {
- xt[0] = x0 - 2.0 * x1 + x2;
- xt[1] = 2.0 * (x1 - x0);
- xt[2] = x0;
-
- t = roots[0];
-
- xc = (xt[0] * t + xt[1]) * t + xt[2];
-
- if (xc > x)
- crossings++;
-
- if (k > 1)
- {
- t = roots[1];
- xc = (xt[0] * t + xt[1]) * t + xt[2];
-
- if (xc > x)
- crossings++;
- }
- }
- end_curve_test:
-
- x0 = x2;
-
- y0 = y2;
- }
- }
- }
-
- return (crossings & 1);
- }
- static int solve_quad(double *x, double *y, double mindist, DBL maxdist)
- {
- double d, t, a, b, c, q;
- a = x[0];
- b = -x[1];
- c = x[2];
-
- if (fabs(a) < COEFF_LIMIT)
- {
- if (fabs(b) < COEFF_LIMIT)
- return 0;
-
- q = c / b;
-
- if (q >= mindist && q <= maxdist)
- {
- y[0] = q;
- return 1;
- }
- else
- return 0;
- }
-
- d = b * b - 4.0 * a * c;
- if (d < EPSILON)
- return 0;
- d = sqrt(d);
- t = 2.0 * a;
- q = (b + d) / t;
-
- if (q >= mindist && q <= maxdist)
- {
- y[0] = q;
- q = (b - d) / t;
-
- if (q >= mindist && q <= maxdist)
- {
- y[1] = q;
- return 2;
- }
-
- return 1;
- }
-
- q = (b - d) / t;
-
- if (q >= mindist && q <= maxdist)
- {
- y[0] = q;
- return 1;
- }
-
- return 0;
- }
- /*
- * Returns the distance to z = 0 in t0, and the distance to z = 1 in t1.
- * These distances are to the the bottom and top surfaces of the glyph.
- * The distances are set to -1 if there is no hit.
- */
- static void GetZeroOneHits(GlyphPtr glyph, VECTOR P, VECTOR D, DBL glyph_depth, double *t0, double *t1)
- {
- double x0, y0, t;
- *t0 = -1.0;
- *t1 = -1.0;
- /* Are we parallel to the x-y plane? */
-
- if (fabs(D[Z]) < EPSILON)
- return;
- /* Solve: P[Y] + t * D[Y] = 0 */
-
- t = -P[Z] / D[Z];
-
- x0 = P[X] + t * D[X];
- y0 = P[Y] + t * D[Y];
-
- if (Inside_Glyph(x0, y0, glyph))
- *t0 = t;
- /* Solve: P[Y] + t * D[Y] = glyph_depth */
-
- t += (glyph_depth / D[Z]);
-
- x0 = P[X] + t * D[X];
- y0 = P[Y] + t * D[Y];
-
- if (Inside_Glyph(x0, y0, glyph))
- *t1 = t;
- }
- /*
- * Solving for a linear sweep of a non-linear curve can be performed by
- * projecting the ray onto the x-y plane, giving a parametric equation for the
- * ray as:
- *
- * x = x0 + x1 t, y = y0 + y1 t
- *
- * Eliminating t from the above gives the implicit equation:
- *
- * y1 x - x1 y - (x0 y1 - y0 x1) = 0.
- *
- * Substituting a parametric equation for x and y gives:
- *
- * y1 x(s) - x1 y(s) - (x0 y1 - y0 x1) = 0.
- *
- * which can be written as
- *
- * a x(s) + b y(s) + c = 0,
- *
- * where a = y1, b = -x1, c = (y0 x1 - x0 y1).
- *
- * For piecewise quadratics, the parametric equations will have the forms:
- *
- * x(s) = (1-s)^2 P0(x) + 2 s (1 - s) P1(x) + s^2 P2(x) y(s) = (1-s)^2 P0(y) + 2 s
- * (1 - s) P1(y) + s^2 P2(y)
- *
- * where P0 is the first defining vertex of the spline, P1 is the second, P2 is
- * the third. Using the substitutions:
- *
- * xt2 = x0 - 2 x1 + x2, xt1 = 2 * (x1 - x0), xt0 = x0; yt2 = y0 - 2 y1 + y2, yt1
- * = 2 * (y1 - y0), yt0 = y0;
- *
- * the equations can be written as:
- *
- * x(s) = xt2 s^2 + xt1 s + xt0, y(s) = yt2 s^2 + yt1 s + yt0.
- *
- * Substituting and multiplying out gives the following equation in s:
- *
- * s^2 * (a*xt2 + b*yt2) + s * (a*xt1 + b*yt1) + c + a*xt0 + b*yt0
- *
- * This is then solved using the quadratic formula. Any solutions of s that are
- * between 0 and 1 (inclusive) are valid solutions.
- */
- static int GlyphIntersect(OBJECT *Object, VECTOR P, VECTOR D, GlyphPtr glyph, DBL glyph_depth,
- RAY *Ray, ISTACK *Depth_Stack) /* tw */
- {
- Contour *contour;
- int i, j, k, l, n, m, Flag = 0;
- VECTOR N, IPoint;
- DBL Depth;
- double x0, x1, y0, y1, x2, y2, t, t0, t1, z;
- double xt0, xt1, xt2, yt0, yt1, yt2;
- double a, b, c, d0, d1, C[3], S[2];
- DBL *xv, *yv;
- BYTE *fv;
- TTF *ttf = (TTF *) Object;
- int dirflag = 0;
- /*
- * First thing to do is to get any hits at z = 0 and z = 1 (which are the
- * bottom and top surfaces of the glyph.
- */
-
- GetZeroOneHits(glyph, P, D, glyph_depth, &t0, &t1);
- if (t0 > 0.0)
- {
- Depth = t0 /* / len */;
- VScale(IPoint, Ray->Direction, Depth);
- VAddEq(IPoint, Ray->Initial);
-
- if (Depth > TTF_Tolerance &&
- Point_In_Clip(IPoint, Object->Clip))
- {
- Make_Vector(N, 0.0, 0.0, -1.0);
- MTransNormal(N, N, ttf->Trans);
- VNormalize(N, N);
- push_normal_entry(Depth, IPoint, N, Object, Depth_Stack);
- Flag = TRUE;
- }
- }
- if (t1 > 0.0)
- {
- Depth = t1 /* / len */;
- VScale(IPoint, Ray->Direction, Depth);
- VAddEq(IPoint, Ray->Initial);
-
- if (Depth > TTF_Tolerance &&
- Point_In_Clip(IPoint, Object->Clip))
- {
- Make_Vector(N, 0.0, 0.0, 1.0);
- MTransNormal(N, N, ttf->Trans);
- VNormalize(N, N);
- push_normal_entry(Depth, IPoint, N, Object, Depth_Stack);
- Flag = TRUE;
- }
- }
- /* Simple test to see if we can just toss this ray */
-
- if (fabs(D[X]) < EPSILON)
- {
- if (fabs(D[Y]) < EPSILON)
- {
- /*
- * This means the ray is moving parallel to the walls of the sweep
- * surface
- */
- return Flag;
- }
- else
- {
- dirflag = 0;
- }
- }
- else
- {
- dirflag = 1;
- }
- /*
- * Now walk through the glyph, looking for places where the ray hits the
- * walls
- */
-
- a = D[Y];
- b = -D[X];
- c = (P[Y] * D[X] - P[X] * D[Y]);
- n = glyph->header.numContours;
-
- for (i = 0, contour = glyph->contours; i < n; i++, contour++)
- {
- xv = contour->x;
- yv = contour->y;
- fv = contour->flags;
- x0 = xv[0];
- y0 = yv[0];
- m = contour->count;
-
- for (j = 1; j <= m; j++)
- {
- x1 = xv[j];
- y1 = yv[j];
-
- if (fv[j] & ONCURVE)
- {
- /* Straight line */
- d0 = (x1 - x0);
- d1 = (y1 - y0);
- t0 = d1 * D[X] - d0 * D[Y];
-
- if (fabs(t0) < EPSILON)
- /* No possible intersection */
- goto end_line_test;
-
- t = (D[X] * (P[Y] - y0) - D[Y] * (P[X] - x0)) / t0;
-
- if (t < 0.0 || t > 1.0)
- goto end_line_test;
-
- if (dirflag)
- t = ((x0 + t * d0) - P[X]) / D[X];
- else
- t = ((y0 + t * d1) - P[Y]) / D[Y];
-
- z = P[Z] + t * D[Z];
-
- Depth = t /* / len */;
- if (z >= 0 && z <= glyph_depth && Depth > TTF_Tolerance)
- {
- VScale(IPoint, Ray->Direction, Depth);
- VAddEq(IPoint, Ray->Initial);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- Make_Vector(N, d1, -d0, 0.0);
- MTransNormal(N, N, ttf->Trans);
- VNormalize(N, N);
- push_normal_entry(Depth, IPoint, N, Object, Depth_Stack);
- Flag = TRUE;
- }
- }
- end_line_test:
- x0 = x1;
- y0 = y1;
- }
- else
- {
- if (j == m)
- {
- x2 = xv[0];
- y2 = yv[0];
- }
- else
- {
- x2 = xv[j + 1];
- y2 = yv[j + 1];
-
- if (!(fv[j + 1] & ONCURVE))
- {
- /*
- * Parabola with far end DBLing - readjust the far end so that it
- * is on the curve. (In the correct place too.)
- */
-
- x2 = 0.5 * (x1 + x2);
- y2 = 0.5 * (y1 + y2);
- }
- }
- /* Make the interpolating quadrics */
-
- xt2 = x0 - 2.0 * x1 + x2;
- xt1 = 2.0 * (x1 - x0);
- xt0 = x0;
- yt2 = y0 - 2.0 * y1 + y2;
- yt1 = 2.0 * (y1 - y0);
- yt0 = y0;
- C[0] = a * xt2 + b * yt2;
- C[1] = a * xt1 + b * yt1;
- C[2] = a * xt0 + b * yt0 + c;
- k = solve_quad(C, S, 0.0, 1.0);
- for (l = 0; l < k; l++)
- {
- if (dirflag)
- t = ((S[l] * S[l] * xt2 + S[l] * xt1 + xt0) - P[X]) / D[X];
- else
- t = ((S[l] * S[l] * yt2 + S[l] * yt1 + yt0) - P[Y]) / D[Y];
- /*
- * If the intersection with this wall is between 0 and glyph_depth
- * along the z-axis, then it is a valid hit.
- */
- z = P[Z] + t * D[Z];
-
- Depth = t /* / len */;
-
- if (z >= 0 && z <= glyph_depth && Depth > TTF_Tolerance)
- {
- VScale(IPoint, Ray->Direction, Depth);
- VAddEq(IPoint, Ray->Initial);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- Make_Vector(N, 2.0 * yt2 * S[l] + yt1, -2.0 * xt2 * S[l] - xt1, 0.0);
- MTransNormal(N, N, ttf->Trans);
- VNormalize(N, N);
- push_normal_entry(Depth, IPoint, N, Object, Depth_Stack);
- Flag = TRUE;
- }
- }
- }
-
- x0 = x2;
- y0 = y2;
- }
- }
- }
-
- return Flag;
- }
- static int All_TTF_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
- {
- TTF *ttf = (TTF *) Object;
- /* DBL len; */ /* tw, mtg */
- VECTOR P, D;
- GlyphPtr glyph;
- Increase_Counter(stats[Ray_TTF_Tests]);
- /* Transform the point into the glyph's space */
-
- MInvTransPoint(P, Ray->Initial, ttf->Trans);
- MInvTransDirection(D, Ray->Direction, ttf->Trans);
- /* Tweak the ray to try to avoid pathalogical intersections */
- /*
- D[0] *= 1.0000013147;
- D[1] *= 1.0000022741;
- D[2] *= 1.0000017011;
- VLength(len, D);
- VInverseScaleEq(D, len);
- */
- glyph = (GlyphPtr)ttf->glyph;
- if (GlyphIntersect(Object, P, D, glyph,ttf->depth,Ray,Depth_Stack)) /* tw */
- {
- Increase_Counter(stats[Ray_TTF_Tests_Succeeded]);
- return TRUE;
- }
- return FALSE;
- }
- static int Inside_TTF(VECTOR IPoint, OBJECT *Object)
- {
- VECTOR New_Point;
- TTF *ttf = (TTF *) Object;
- GlyphPtr glyph;
- /* Transform the point into font space */
-
- MInvTransPoint(New_Point, IPoint, ttf->Trans);
- glyph = (GlyphPtr)ttf->glyph;
- if (New_Point[Z] >= 0.0 && New_Point[Z] <= ttf->depth &&
- Inside_Glyph(New_Point[X], New_Point[Y], glyph))
- return (!Test_Flag(ttf, INVERTED_FLAG));
- else
- return (Test_Flag(ttf, INVERTED_FLAG));
- }
- static void TTF_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
- {
- /* Use precomputed normal. [ARE 11/94] */
- Assign_Vector(Result, Inter->INormal);
- }
- static TTF *Copy_TTF(OBJECT *Object)
- {
- TTF *New, *Old = (TTF *) Object;
- New = Create_TTF();
- Destroy_Transform(New->Trans);
- *New = *Old;
- New->Trans = Copy_Transform(((TTF *) Object)->Trans);
-
- New->glyph = Old->glyph;
- return (New);
- }
- static void Translate_TTF(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
- {
- Transform_TTF(Object, Trans);
- }
- static void Rotate_TTF(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
- {
- Transform_TTF(Object, Trans);
- }
- static void Scale_TTF(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
- {
- Transform_TTF(Object, Trans);
- }
- static void Invert_TTF(OBJECT *Object)
- {
- Invert_Flag(Object, INVERTED_FLAG);
- }
- static void Transform_TTF(OBJECT *Object, TRANSFORM *Trans)
- {
- TTF *ttf = (TTF *) Object;
- Compose_Transforms(ttf->Trans, Trans);
- /* Calculate the bounds */
- Compute_TTF_BBox(ttf);
- }
- static TTF *Create_TTF()
- {
- TTF *New;
- New = (TTF *) POV_MALLOC(sizeof(TTF), "ttf");
- INIT_OBJECT_FIELDS(New, TTF_OBJECT, &TTF_Methods)
- /* Initialize TTF specific information */
- New->Trans = Create_Transform();
-
- New->glyph = NULL;
- New->depth = 1.0;
- /* Default bounds */
- Make_BBox(New->BBox, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
- return New;
- }
- static void Destroy_TTF(OBJECT *Object)
- {
- TTF *ttf = (TTF *) Object;
- Destroy_Transform(ttf->Trans);
- POV_FREE(Object);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_TTF_BBox
- *
- * INPUT
- *
- * ttf - ttf
- *
- * OUTPUT
- *
- * ttf
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer, August 1994
- *
- * DESCRIPTION
- *
- * Calculate the bounding box of a true type font.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void Compute_TTF_BBox(TTF *ttf)
- {
- DBL funit_size, xMin, yMin, zMin, xMax, yMax, zMax;
- GlyphPtr glyph;
- glyph = (GlyphPtr)ttf->glyph;
- funit_size = 1.0 / (DBL)(glyph->unitsPerEm);
- xMin = (DBL)glyph->header.xMin * funit_size;
- yMin = (DBL)glyph->header.yMin * funit_size;
- zMin = -TTF_Tolerance;
- xMax = (DBL)glyph->header.xMax * funit_size;
- yMax = (DBL)glyph->header.yMax * funit_size;
- zMax = ttf->depth + TTF_Tolerance;
- Make_BBox(ttf->BBox, xMin, yMin, zMin, xMax - xMin, yMax - yMin, zMax - zMin);
- #ifdef TTF_DEBUG
- Debug_Info("Bounds: <%g,%g,%g> -> <%g,%g,%g>\n",
- ttf->BBox.Lower_Left[0],
- ttf->BBox.Lower_Left[1],
- ttf->BBox.Lower_Left[2],
- ttf->BBox.Lengths[0],
- ttf->BBox.Lengths[1],
- ttf->BBox.Lengths[2]);
- #endif
- /* Apply the transformation to the bounding box */
- Recompute_BBox(&ttf->BBox, ttf->Trans);
- }
|