sfn.c 134 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827
  1. /*
  2. * libsfn/sfn.c
  3. *
  4. * Copyright (C) 2020 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief File functions: import, modify and save
  27. *
  28. */
  29. #include <stdint.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include "potracelib/potracelib.h"
  34. #include "zlib.h"
  35. #include "stb_png.h"
  36. #define SSFN_IMPLEMENTATION
  37. #include <ssfn.h>
  38. #include "libsfn.h"
  39. #include "vector.h"
  40. #include "bitmap.h"
  41. /* potrace bitmap stuff */
  42. #define BM_WORDSIZE ((int)sizeof(potrace_word))
  43. #define BM_WORDBITS (8*BM_WORDSIZE)
  44. #define BM_HIBIT (((potrace_word)1)<<(BM_WORDBITS-1))
  45. #define BM_ALLBITS (~(potrace_word)0)
  46. #define bm_scanline(bm, y) ((bm).map + (ptrdiff_t)(y)*(ptrdiff_t)(bm).dy)
  47. #define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS])
  48. #define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1)))
  49. #define BM_USET(bm, x, y) (*bm_index(bm, x, y) |= bm_mask(x))
  50. int rs = 0, re = 0x10FFFF, replace = 0, skipundef = 0, skipcode = 0, skipcleared = 0, hinting = 0, adv = 0, relul = 0;
  51. int px = 0, py = 0, rasterize = 0, origwh = 0, lastuni = -1, *fidx, dorounderr = 0, monosize = 0, advrecalc = 0, propo = 0;
  52. sfnctx_t ctx;
  53. sfnprogressbar_t pbar = NULL;
  54. void *my_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
  55. {
  56. size_t i;
  57. for(i = 0; i < haystacklen - needlelen && memcmp((uint8_t*)haystack + i, needle, needlelen); i++);
  58. return (i < haystacklen - needlelen) ? (void*)((uint8_t*)haystack + i) : NULL;
  59. }
  60. /**
  61. * Sort layers by type and scanline
  62. */
  63. int lyrsrt(const void *a, const void *b)
  64. {
  65. /* pixmap, bitmap first, then contours bigger area first */
  66. return ((sfnlayer_t*)a)->type != ((sfnlayer_t*)b)->type ?
  67. ((sfnlayer_t*)b)->type - ((sfnlayer_t*)a)->type :
  68. (((sfnlayer_t*)a)->miny != ((sfnlayer_t*)b)->miny ?
  69. ((sfnlayer_t*)a)->miny - ((sfnlayer_t*)b)->miny :
  70. ((sfnlayer_t*)a)->minx - ((sfnlayer_t*)b)->minx);
  71. }
  72. /**
  73. * Sort kerning pairs by next character's code point
  74. */
  75. int krnsrt(const void *a, const void *b)
  76. {
  77. return ((sfnkern_t*)a)->n - ((sfnkern_t*)b)->n;
  78. }
  79. /**
  80. * Sort kerning positions by list size
  81. */
  82. int possrt(const void *a, const void *b)
  83. {
  84. return ((sfnkpos_t*)b)->len - ((sfnkpos_t*)a)->len;
  85. }
  86. /**
  87. * Sort fragments by number of reference and type
  88. */
  89. int frgsrt(const void *a, const void *b)
  90. {
  91. return ((sfnfrag_t*)a)->cnt != ((sfnfrag_t*)b)->cnt ?
  92. ((sfnfrag_t*)b)->cnt - ((sfnfrag_t*)a)->cnt :
  93. (((sfnfrag_t*)a)->type != ((sfnfrag_t*)b)->type ?
  94. ((sfnfrag_t*)a)->type - ((sfnfrag_t*)b)->type :
  95. ((sfnfrag_t*)a)->w - ((sfnfrag_t*)b)->w);
  96. }
  97. /**
  98. * Sort fragment descriptors by type and scanline
  99. */
  100. int frdsrt(const void *a, const void *b)
  101. {
  102. return ctx.frags[fidx[((int*)a)[0]]].type != ctx.frags[fidx[((int*)b)[0]]].type ?
  103. ctx.frags[fidx[((int*)b)[0]]].type - ctx.frags[fidx[((int*)a)[0]]].type : (((int*)a)[1] == 255 || ((int*)b)[1] == 255 ? 0 :
  104. (((int*)a)[2] != ((int*)b)[2] ? ((int*)a)[2] - ((int*)b)[2] : ((int*)a)[1] - ((int*)b)[1]));
  105. }
  106. /**
  107. * Compare two normalized contour fragments, allowing rounding errors in coordinates
  108. */
  109. int frgcmp(sfncont_t *a, sfncont_t *b, int l)
  110. {
  111. int i;
  112. if(l<1) return 0;
  113. for(; l; l--, a++, b++) {
  114. if(a->type != b->type) return a->type - b->type;
  115. i = a->px - b->px; if((i < 0 ? -i : i) > 1) return i;
  116. i = a->c1x - b->c1x; if((i < 0 ? -i : i) > 1) return i;
  117. i = a->c2x - b->c2x; if((i < 0 ? -i : i) > 1) return i;
  118. }
  119. return 0;
  120. }
  121. /**
  122. * Parse compressed SSFN font format (binary)
  123. *
  124. * @param ptr pointer to buffer
  125. * @param size size of the buffer
  126. */
  127. void sfn(unsigned char *ptr, int size)
  128. {
  129. ssfn_font_t *font = (ssfn_font_t*)ptr;
  130. sfnlayer_t *currlayer;
  131. unsigned char *ptr2, color, *frg, *cmd, *bitmap = NULL;
  132. int f, i, j, k, l, m, n, o, u, x, y, w, h, unicode = 0;
  133. /* sanity checks */
  134. if((unsigned int)size != font->size || memcmp((unsigned char*)font + font->size - 4, SSFN_ENDMAGIC, 4))
  135. { if(!quiet) { fprintf(stderr, "libsfn: missing end magic or incorrect font size\n"); } return; }
  136. if(!font->fragments_offs) { if(!quiet) { fprintf(stderr, "libsfn: missing fragments table\n"); } return; }
  137. if(!font->characters_offs) { if(!quiet) { fprintf(stderr, "libsfn: missing characters table\n"); } return; }
  138. if(font->characters_offs <= font->fragments_offs) {
  139. if(!quiet) { fprintf(stderr, "libsfn: incorrect characters table offset\n"); } return; }
  140. if(font->kerning_offs && (font->kerning_offs <= font->characters_offs || (font->ligature_offs &&
  141. font->kerning_offs <= font->ligature_offs)))
  142. { if(!quiet) { fprintf(stderr, "libsfn: incorrect kerning table offset\n"); } return; }
  143. if(font->ligature_offs && font->ligature_offs <= font->characters_offs)
  144. { if(!quiet) { fprintf(stderr, "libsfn: incorrect ligature table offset\n"); } return; }
  145. if(font->cmap_offs && ((font->size - font->cmap_offs) & 3))
  146. { if(!quiet) { fprintf(stderr, "libsfn: incorrect cmap table offset\n"); } return; }
  147. /* header */
  148. ctx.family = SSFN_TYPE_FAMILY(font->type);
  149. ctx.style = SSFN_TYPE_STYLE(font->type);
  150. ctx.width = font->width;
  151. ctx.height = font->height;
  152. ctx.baseline = font->baseline;
  153. ctx.underline = font->underline;
  154. /* string table */
  155. ptr = (unsigned char *)font + sizeof(ssfn_font_t);
  156. for(i = -6; ptr < (unsigned char *)font + font->fragments_offs; i++) {
  157. switch(i) {
  158. case -6: sfn_setstr(&ctx.name, (char*)ptr, 0); break;
  159. case -5: sfn_setstr(&ctx.familyname, (char*)ptr, 0); break;
  160. case -4: sfn_setstr(&ctx.subname, (char*)ptr, 0); break;
  161. case -3: sfn_setstr(&ctx.revision, (char*)ptr, 0); break;
  162. case -2: sfn_setstr(&ctx.manufacturer, (char*)ptr, 0); break;
  163. case -1: sfn_setstr(&ctx.license, (char*)ptr, 0); break;
  164. default: sfn_setstr(&ctx.ligatures[i], (char*)ptr, 0); break;
  165. }
  166. ptr += strlen((char*)ptr) + 1;
  167. }
  168. /* character mappings */
  169. ptr = (unsigned char *)font + font->characters_offs;
  170. ptr2 = (unsigned char *)font + (font->ligature_offs ? font->ligature_offs : (font->kerning_offs ?
  171. font->kerning_offs : (font->cmap_offs ? font->cmap_offs : font->size - 4)));
  172. for(unicode = 0; ptr < ptr2;) {
  173. if(ptr[0] == 0xFF) { unicode += 65536; ptr++; }
  174. else if((ptr[0] & 0xC0) == 0xC0) { k = (((ptr[0] & 0x3F) << 8) | ptr[1]) + 1; unicode += k; ptr += 2; }
  175. else if((ptr[0] & 0xC0) == 0x80) { k = (ptr[0] & 0x3F) + 1; unicode += k; ptr++; }
  176. else {
  177. if(pbar) (*pbar)(0, 0, unicode, 0x10FFFF, PBAR_RDFILE);
  178. n = ptr[1]; k = ptr[0]; w = ptr[2];
  179. u = unicode >= rs && unicode <= re ? sfn_charadd(unicode, ptr[2], ptr[3], ptr[4], ptr[5], ptr[0] & 0x3F) : 0;
  180. ptr += 6; color = 0xFE;
  181. for(f = 0; f < n; f++) {
  182. if(ptr[0] == 255 && ptr[1] == 255) {
  183. color = ptr[2]; ptr += k & 0x40 ? 6 : 5;
  184. } else {
  185. x = ptr[0]; y = ptr[1];
  186. if(k & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; }
  187. else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; }
  188. if(u) {
  189. if(m < font->fragments_offs || (unsigned int)m >= font->characters_offs) {
  190. if(!quiet) fprintf(stderr,"libsfn: incorrect fragment offset %x\n",m);
  191. return;
  192. }
  193. frg = (unsigned char*)font + m;
  194. if(!(frg[0] & 0x80)) {
  195. /* contour */
  196. currlayer = sfn_layeradd(unicode, SSFN_FRAG_CONTOUR, 0, 0, 0, 0, color, NULL);
  197. if(!currlayer) return;
  198. j = (frg[0] & 0x3F);
  199. if(frg[0] & 0x40) { j <<= 8; j |= frg[1]; frg++; }
  200. j++; frg++;
  201. cmd = frg; frg += (j+3)/4;
  202. for(i = 0; i < j; i++) {
  203. switch((cmd[i / 4] >> ((i & 3) * 2)) & 3) {
  204. case SSFN_CONTOUR_MOVE:
  205. sfn_contadd(currlayer, SSFN_CONTOUR_MOVE, frg[0]+x, frg[1]+y, 0,0, 0,0);
  206. frg += 2;
  207. break;
  208. case SSFN_CONTOUR_LINE:
  209. sfn_contadd(currlayer, SSFN_CONTOUR_LINE, frg[0]+x, frg[1]+y, 0,0, 0,0);
  210. frg += 2;
  211. break;
  212. case SSFN_CONTOUR_QUAD:
  213. sfn_contadd(currlayer, SSFN_CONTOUR_QUAD, frg[0]+x, frg[1]+y, frg[2]+x, frg[3]+y, 0,0);
  214. frg += 4;
  215. break;
  216. case SSFN_CONTOUR_CUBIC:
  217. sfn_contadd(currlayer, SSFN_CONTOUR_CUBIC, frg[0]+x, frg[1]+y, frg[2]+x, frg[3]+y,
  218. frg[4]+x, frg[5]+y);
  219. frg += 6;
  220. break;
  221. }
  222. }
  223. } else if((frg[0] & 0x60) == 0x00) {
  224. /* bitmap */
  225. m = ((frg[0] & 0x1F) + 1);
  226. bitmap = (unsigned char*)malloc(w * (frg[1] + 1));
  227. if(!bitmap) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  228. memset(bitmap, 0xFF, w * (frg[1] + 1));
  229. cmd = frg + 2;
  230. for(h = l = 0; h < frg[1] + 1; h++)
  231. for(i = h*m, j = 1, o = 0; o < w; o++, j <<= 1) {
  232. if(j >= 0x100) { j = 1; i++; }
  233. bitmap[l++] = (cmd[i] & j) ? 0xFE : 0xFF;
  234. }
  235. sfn_layeradd(unicode, SSFN_FRAG_BITMAP, x, y, w, frg[1] + 1, color, bitmap);
  236. free(bitmap);
  237. } else if((frg[0] & 0x60) == 0x20) {
  238. /* pixel map */
  239. j = (frg[2] + 1) * (frg[3] + 1);
  240. bitmap = rle_dec(frg + 4, (((frg[0] & 0x1F) << 8) | frg[1]) + 1, &j);
  241. if(!bitmap) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  242. sfn_layeradd(unicode, SSFN_FRAG_PIXMAP, x, y, frg[2] + 1, frg[3] + 1, 0xFE, bitmap);
  243. free(bitmap);
  244. } else if((frg[0] & 0x60) == 0x40) {
  245. /* kerning relation */
  246. j = (((frg[0] & 0x3) << 8) | frg[1]) + 1;
  247. for(i = 0, frg += 2; i < j; i++, frg += 8) {
  248. y = ((frg[2] & 0xF) << 16) | (frg[1] << 8) | frg[0];
  249. m = ((frg[5] & 0xF) << 16) | (frg[4] << 8) | frg[3];
  250. cmd = (unsigned char*)font + font->kerning_offs + ((((frg[2] >> 4) & 0xF) << 24) |
  251. (((frg[5] >> 4) & 0xF) << 16) | (frg[7] << 8) | frg[6]);
  252. while(y <= m) {
  253. l = ((*cmd++) & 0x7F) + 1;
  254. if(cmd[-1] & 0x80) {
  255. if(cmd[0])
  256. while(l-- && y <= m)
  257. sfn_kernadd(unicode, y++, x ? (char)cmd[0] : 0, x ? 0 : (char)cmd[0]);
  258. else
  259. y += l;
  260. cmd++;
  261. } else while(l-- && y <= m) {
  262. if(cmd[0])
  263. sfn_kernadd(unicode, y, x ? (char)cmd[0] : 0, x ? 0 : (char)cmd[0]);
  264. y++;
  265. cmd++;
  266. }
  267. }
  268. }
  269. } else {
  270. /* hinting grid */
  271. j = frg[0] & 31; frg++;
  272. memset(ctx.glyphs[unicode].hintv, 0, 33);
  273. memset(ctx.glyphs[unicode].hinth, 0, 33);
  274. if(x > 0) {
  275. ctx.glyphs[unicode].hintv[0] = j + 1;
  276. ctx.glyphs[unicode].hintv[1] = x - 1;
  277. for(l = 2; j && l < 33; l++, frg++, j--)
  278. ctx.glyphs[unicode].hintv[l] = ctx.glyphs[unicode].hintv[l - 1] + frg[0];
  279. } else
  280. if(y > 0) {
  281. ctx.glyphs[unicode].hinth[0] = j + 1;
  282. ctx.glyphs[unicode].hinth[1] = y - 1;
  283. for(l = 2; j && l < 33; l++, frg++, j--)
  284. ctx.glyphs[unicode].hinth[l] = ctx.glyphs[unicode].hinth[l - 1] + frg[0];
  285. }
  286. }
  287. color = 0xFE;
  288. }
  289. }
  290. }
  291. unicode++;
  292. }
  293. }
  294. /* color map */
  295. if(font->cmap_offs) {
  296. memcpy(ctx.cpal, (uint8_t*)font + font->cmap_offs, font->size - font->cmap_offs - 4);
  297. ctx.numcpal = (font->size - font->cmap_offs - 4) / 4;
  298. }
  299. }
  300. /**
  301. * Parse SSFN ASCII font format (text)
  302. *
  303. * @param ptr pointer to zero terminated UTF-8 string
  304. * @param size size of the buffer
  305. */
  306. void asc(char *ptr, int size)
  307. {
  308. int x, y, w = 0, h = 0, o, i, par[6], unicode = -1, nc = 0, numchars, len = 0, line = 1;
  309. char *end = ptr + size-4, *e;
  310. unsigned char *bitmap = NULL, color = 0xFE;
  311. sfnlayer_t *currlayer = NULL;
  312. for(numchars = 0,e=ptr++;e < end && *e;e++)
  313. if(e[0]=='\n' && e[1]=='=' && e[2]=='=' && e[3]=='=') numchars++;
  314. while(ptr < end && *ptr) {
  315. /* end marker */
  316. if(ptr[-1] == '\n' && ptr[0] == '#' && ptr[1] == ' ' && ptr[2] == 'E') break;
  317. /* properties */
  318. if(ptr[-1] == '\n' && ptr[0] == '$' && ptr[1] >= 'a' && ptr[1] <= 'z') {
  319. for(e = ptr; e < end && *e && *e != ' ' && *e != '\r' && *e != '\n'; e++);
  320. while(*e == ' ') e++;
  321. switch(ptr[1]) {
  322. case 't': sfn_setfamilytype(atoi(e)); break;
  323. case 's':
  324. if(ptr[2]=='u' && *e == '\"') { e++; sfn_setstr(&ctx.subname, e, 0); } else
  325. if(ptr[2]=='t') {
  326. for(; *e && *e != '\r' && *e != '\n'; e++)
  327. if(e[-1] == ' ') {
  328. if(*e == 'b') ctx.style |= SSFN_STYLE_BOLD;
  329. if(*e == 'i') ctx.style |= SSFN_STYLE_ITALIC;
  330. if(*e == '1') ctx.style |= SSFN_STYLE_USRDEF1;
  331. if(*e == '2') ctx.style |= SSFN_STYLE_USRDEF2;
  332. }
  333. }
  334. break;
  335. case 'b': ctx.baseline = atoi(e); break;
  336. case 'u': ctx.underline = atoi(e); break;
  337. case 'n': if(*e == '\"') { e++; sfn_setstr(&ctx.name, e, 0); } break;
  338. case 'f': if(*e == '\"') { e++; sfn_setstr(&ctx.familyname, e, 0); } break;
  339. case 'r': if(*e == '\"') { e++; sfn_setstr(&ctx.revision, e, 0); } break;
  340. case 'm': if(*e == '\"') { e++; sfn_setstr(&ctx.manufacturer, e, 0); } break;
  341. case 'l': if(*e == '\"') { e++; sfn_setstr(&ctx.license, e, 0); } break;
  342. case 'g': break;
  343. default: fprintf(stderr,"libsfn: line %d: unknown property\n",line); break;
  344. }
  345. }
  346. if(unicode != -1) {
  347. /* foreground color command */
  348. if(*ptr == 'f') {
  349. for(ptr++; *ptr == ' '; ptr++);
  350. color = *ptr=='-' ? 0xFE : sfn_cpaladd(
  351. gethex((char*)ptr+2, 2), gethex((char*)ptr+4, 2),
  352. gethex((char*)ptr+6, 2), gethex((char*)ptr, 2));
  353. } else
  354. /* bitmap layer */
  355. if(*ptr == '.' || *ptr == 'X' || *ptr == 'x') {
  356. bitmap = realloc(bitmap, len);
  357. if(!bitmap) { fprintf(stderr,"libsfn: line %d: memory allocation error\n",line); return; }
  358. for(i = 0; i < len && ptr < end && *ptr && (*ptr == '.' || *ptr == 'X' || *ptr == 'x' ||
  359. *ptr == '\r' || *ptr == '\n'); ptr++) {
  360. switch(*ptr) {
  361. case '\n': line++; break;
  362. case 'x':
  363. case 'X': bitmap[i++] = 0xFE; break;
  364. case '.': bitmap[i++] = 0XFF; break;
  365. }
  366. }
  367. ptr--;
  368. sfn_layeradd(unicode, SSFN_FRAG_BITMAP, 0, 0, w, h, color, bitmap);
  369. currlayer = NULL;
  370. } else
  371. /* pixmap layer */
  372. if((*ptr == '-' || (*ptr >= '0' && *ptr <= '9') || (*ptr >= 'A' && *ptr <= 'F') || (*ptr >= 'a' && *ptr <= 'f')) &&
  373. ptr[1] != ' ') {
  374. bitmap = realloc(bitmap, len);
  375. if(!bitmap) { fprintf(stderr,"libsfn: line %d: memory allocation error\n",line); return; }
  376. for(i = 0; i < len && ptr < end && *ptr && (*ptr == ' ' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9') ||
  377. (*ptr >= 'A' && *ptr <= 'F') || (*ptr >= 'a' && *ptr <= 'f') || *ptr == '\r' || *ptr == '\n'); ptr++) {
  378. if(*ptr == '\n') line++; else
  379. if(*ptr == '-') { bitmap[i++] = 0xFF; while(*ptr == '-') ptr++; } else
  380. if((*ptr >= '0' && *ptr <= '9') || (*ptr >= 'A' && *ptr <= 'F') || (*ptr >= 'a' && *ptr <= 'f')) {
  381. bitmap[i++] = sfn_cpaladd(gethex(ptr+2, 2), gethex(ptr+4, 2), gethex(ptr+6,2), gethex(ptr,2));
  382. ptr += 8;
  383. }
  384. }
  385. ptr--;
  386. sfn_layeradd(unicode, SSFN_FRAG_PIXMAP, 0, 0, w, h, color, bitmap);
  387. currlayer = NULL;
  388. } else
  389. /* horizontal hinting grid */
  390. if(*ptr == 'H') {
  391. for(i = 0, ptr += 2; i < 32 && ptr < end && *ptr && *ptr != '\r' && *ptr != '\n';) {
  392. while(*ptr && (*ptr < '0' || *ptr > '9')) ptr++;
  393. ctx.glyphs[unicode].hinth[1+i++] = atoi(ptr);
  394. while(*ptr >= '0' && *ptr <= '9') ptr++;
  395. }
  396. ctx.glyphs[unicode].hinth[0] = i;
  397. currlayer = NULL;
  398. } else
  399. /* vertical hinting grid */
  400. if(*ptr == 'V') {
  401. for(i = 0, ptr += 2; i < 32 && ptr < end && *ptr && *ptr != '\r' && *ptr != '\n';) {
  402. while(*ptr && (*ptr < '0' || *ptr > '9')) ptr++;
  403. ctx.glyphs[unicode].hintv[1+i++] = atoi(ptr);
  404. while(*ptr >= '0' && *ptr <= '9') ptr++;
  405. }
  406. ctx.glyphs[unicode].hintv[0] = i;
  407. currlayer = NULL;
  408. } else
  409. /* kerning info */
  410. if(*ptr == 'k') {
  411. for(ptr+=2, i=0; ptr < end && *ptr && ptr[1] != '\r' && ptr[1] != '\n'; i++) {
  412. par[1] = par[2] = 0;
  413. if((ptr[0] == 'U' || ptr[0] == 'u') && ptr[1] == '+') {
  414. ptr += 2;
  415. par[0] = gethex(ptr, 6);
  416. while((*ptr >= '0' && *ptr <= '9') || (*ptr >= 'A' && *ptr <= 'F') || (*ptr >= 'a' && *ptr <= 'f'))
  417. ptr++;
  418. } else
  419. par[0] = ssfn_utf8(&ptr);
  420. while(*ptr == ' ') ptr++;
  421. par[1] = atoi(ptr);
  422. while(*ptr == '-' || (*ptr >= '0' && *ptr <= '9')) ptr++;
  423. if(*ptr == ' ') {
  424. while(*ptr == ' ') ptr++;
  425. par[2] = atoi(ptr);
  426. while(*ptr == '-' || (*ptr >= '0' && *ptr <= '9')) ptr++;
  427. }
  428. if(*ptr == ',') ptr++;
  429. while(*ptr == ' ') ptr++;
  430. if(i >= ctx.glyphs[unicode].numkern || ctx.glyphs[unicode].kern) {
  431. ctx.glyphs[unicode].numkern += 512;
  432. ctx.glyphs[unicode].kern = (sfnkern_t*)realloc(ctx.glyphs[unicode].kern,
  433. ctx.glyphs[unicode].numkern * sizeof(sfnkern_t));
  434. if(!ctx.glyphs[unicode].kern) { fprintf(stderr,"libsfn: line %d: memory allocation error\n",line); return; }
  435. }
  436. ctx.glyphs[unicode].kern[i].n = par[0];
  437. ctx.glyphs[unicode].kern[i].x = par[1];
  438. ctx.glyphs[unicode].kern[i].y = par[2];
  439. }
  440. if(!i && ctx.glyphs[unicode].kern) {
  441. free(ctx.glyphs[unicode].kern);
  442. ctx.glyphs[unicode].kern = NULL;
  443. }
  444. ctx.glyphs[unicode].numkern = i;
  445. currlayer = NULL;
  446. } else
  447. /* contour */
  448. if(*ptr == 'm' || *ptr == 'l' || *ptr == 'q' || *ptr == 'c') {
  449. e = ptr; par[0]=par[1]=par[2]=par[3]=par[4]=par[5]=0;
  450. for(ptr+=2, i=0; ptr < end && *ptr && *ptr != '\r' && *ptr != '\n' && i < 6; ptr++) {
  451. par[i++] = atoi(ptr);
  452. while(ptr < end && *ptr!=' ' && *ptr!=',' && ptr[1] && ptr[1] != '\r' && ptr[1] != '\n') ptr++;
  453. }
  454. ptr--;
  455. if(*e == 'm') {
  456. if(i<2) {fprintf(stderr,"libsfn: line %d: too few move arguments in U+%06X\n",line,unicode);exit(0);}
  457. currlayer = sfn_layeradd(unicode, SSFN_FRAG_CONTOUR, 0, 0, 0, 0, color, NULL);
  458. sfn_contadd(currlayer, SSFN_CONTOUR_MOVE, par[0], par[1], 0,0, 0,0);
  459. } else if(currlayer) {
  460. switch(*e) {
  461. case 'l':
  462. if(i<2) fprintf(stderr,"libsfn: line %d: too few line arguments in U+%06X\n",line,unicode);
  463. else sfn_contadd(currlayer, SSFN_CONTOUR_LINE, par[0], par[1], 0,0, 0,0);
  464. break;
  465. case 'q':
  466. if(i<4) fprintf(stderr,"libsfn: line %d: too few quadratic curve arguments in U+%06X\n",line,unicode);
  467. else sfn_contadd(currlayer, SSFN_CONTOUR_QUAD, par[0], par[1], par[2], par[3], 0,0);
  468. break;
  469. case 'c':
  470. if(i<6) fprintf(stderr,"libsfn: line %d: too few bezier curve arguments in U+%06X\n",line,unicode);
  471. else sfn_contadd(currlayer, SSFN_CONTOUR_CUBIC, par[0], par[1], par[2], par[3], par[4], par[5]);
  472. break;
  473. }
  474. } else {
  475. fprintf(stderr,"libsfn: line %d: contour path does not start with a 'move to' command in U+%06X\n",line,
  476. unicode);
  477. break;
  478. }
  479. }
  480. }
  481. /* characters */
  482. if(ptr[-1] == '\n' && ptr[0] == '=' && ptr[1] == '=' && ptr[2] == '=') {
  483. if(pbar) (*pbar)(0, 0, ++nc, numchars, PBAR_RDFILE);
  484. ptr += 5; unicode = gethex(ptr, 6);
  485. ptr += 10; w = atoi(ptr); while(*ptr && *ptr != '\r' && *ptr != '\n' && *ptr != '=') ptr++;
  486. ptr += 2; h = atoi(ptr); while(*ptr && *ptr != '\r' && *ptr != '\n' && *ptr != '=') ptr++;
  487. ptr += 2; x = atoi(ptr); while(*ptr && *ptr != '\r' && *ptr != '\n' && *ptr != '=') ptr++;
  488. ptr += 2; y = atoi(ptr); while(*ptr && *ptr != '\r' && *ptr != '\n' && *ptr != '=') ptr++;
  489. ptr += 2; o = atoi(ptr); while(*ptr && *ptr != '\r' && *ptr != '\n' && *ptr != '\"') ptr++;
  490. if(unicode >= SSFN_LIG_FIRST && unicode <= SSFN_LIG_LAST && *ptr == '\"')
  491. sfn_setstr(&ctx.ligatures[unicode-SSFN_LIG_FIRST], ptr + 1, 0);
  492. if(w > 255) { w = 255; } if(w < 0) w = 0;
  493. if(h > 255) { h = 255; } if(h < 0) h = 0;
  494. if(x > 254) { x = 254; } if(x < 0) x = 0;
  495. if(y > 254) { y = 254; } if(y < 0) y = 0;
  496. if(o > 63) { o = 63; } if(o < 0) o = 0;
  497. len = (w + 1) * (h + 1);
  498. if(unicode < rs || unicode > re || unicode < 0 || unicode > 0x10FFFF || !sfn_charadd(unicode, w, h, x, y, o))
  499. unicode = -1;
  500. color = 0xFE;
  501. }
  502. /* go to next line */
  503. while(ptr < end && *ptr && *ptr != '\r' && *ptr != '\n') ptr++;
  504. while(*ptr == '\r' || *ptr == '\n') {
  505. if(*ptr == '\n') line++;
  506. ptr++;
  507. }
  508. }
  509. if(bitmap) free(bitmap);
  510. }
  511. /**
  512. * Initialize SSFN context
  513. *
  514. * @param pb progressbar callback
  515. */
  516. void sfn_init(sfnprogressbar_t pb)
  517. {
  518. memset(&ctx, 0, sizeof(ctx));
  519. skipcleared = 0;
  520. pbar = pb;
  521. }
  522. /**
  523. * Free SSFN context
  524. */
  525. void sfn_free()
  526. {
  527. int i;
  528. if(ctx.name) free(ctx.name);
  529. if(ctx.familyname) free(ctx.familyname);
  530. if(ctx.subname) free(ctx.subname);
  531. if(ctx.revision) free(ctx.revision);
  532. if(ctx.manufacturer) free(ctx.manufacturer);
  533. if(ctx.license) free(ctx.license);
  534. for(i = 0; i < 0x110000; i++)
  535. sfn_chardel(i);
  536. memset(&ctx, 0, sizeof(ctx));
  537. }
  538. /**
  539. * Remove a character by deleting all of its layers
  540. *
  541. * @param unicode character to delete
  542. */
  543. void sfn_chardel(int unicode)
  544. {
  545. int i;
  546. if(unicode < 0 || unicode>0x10FFFF) return;
  547. if(ctx.glyphs[unicode].layers) {
  548. for(i = 0; i < ctx.glyphs[unicode].numlayer; i++)
  549. if(ctx.glyphs[unicode].layers[i].data)
  550. free(ctx.glyphs[unicode].layers[i].data);
  551. free(ctx.glyphs[unicode].layers);
  552. }
  553. if(ctx.glyphs[unicode].kern)
  554. free(ctx.glyphs[unicode].kern);
  555. memset(&ctx.glyphs[unicode], 0, sizeof(sfnglyph_t));
  556. }
  557. /**
  558. * Add a character to font
  559. *
  560. * @param unicode character to add
  561. * @param w width
  562. * @param h height
  563. * @param ax advance x
  564. * @param ay advance y
  565. * @param ox overlap x
  566. * @return true on success
  567. */
  568. int sfn_charadd(int unicode, int w, int h, int ax, int ay, int ox)
  569. {
  570. if(unicode < rs || unicode > re || unicode < 0 || unicode > 0x10FFFF || (ctx.glyphs[unicode].layers && !replace) ||
  571. (skipundef && uniname(unicode) == UNICODE_NUMNAMES) || (ctx.skip[unicode >> 3] & (1 << (unicode & 7)))) return 0;
  572. if(ctx.glyphs[unicode].layers && replace) sfn_chardel(unicode);
  573. else memset(&ctx.glyphs[unicode], 0, sizeof(sfnglyph_t));
  574. if(ax) ay = 0;
  575. ctx.glyphs[unicode].width = w;
  576. ctx.glyphs[unicode].height = h;
  577. ctx.glyphs[unicode].adv_x = ax + (ax ? adv : 0);
  578. ctx.glyphs[unicode].adv_y = ay + (!ax ? adv: 0);
  579. ctx.glyphs[unicode].ovl_x = ox;
  580. ctx.glyphs[unicode].rtl = uninames[uniname(unicode)].rtl;
  581. return 1;
  582. }
  583. /**
  584. * Add a layer to character
  585. *
  586. * @param unicode character to add layer to
  587. * @param t type of the layer (SSFN_FRAG_x)
  588. * @param x offset x
  589. * @param y offset y
  590. * @param w width
  591. * @param h height
  592. * @param c color index, 254 foreground
  593. * @param data pointer to data buffer
  594. * @return pointer to a layer struct or NULL on error
  595. */
  596. sfnlayer_t *sfn_layeradd(int unicode, int t, int x, int y, int w, int h, int c, unsigned char *data)
  597. {
  598. sfnlayer_t *lyr = NULL;
  599. unsigned char *data2;
  600. int i, j, l;
  601. if(unicode < rs || unicode > re || unicode < 0 || unicode > 0x10FFFF) return NULL;
  602. if(t != SSFN_FRAG_CONTOUR && !iswhitespace(unicode) && (!data || isempty(w * h, data))) return NULL;
  603. if(ctx.glyphs[unicode].numlayer >= 255) {
  604. if(!quiet) fprintf(stderr, "libsfn: too many layers in U+%06x character's glyph.\n", unicode);
  605. return NULL;
  606. }
  607. if(t != SSFN_FRAG_CONTOUR)
  608. for(i = 0; i < ctx.glyphs[unicode].numlayer; i++)
  609. if(ctx.glyphs[unicode].layers[i].type == t && (t != SSFN_FRAG_BITMAP || ctx.glyphs[unicode].layers[i].color == c))
  610. { lyr = &ctx.glyphs[unicode].layers[i]; break; }
  611. if(x < 0) {
  612. if(!quiet) fprintf(stderr, "libsfn: negative x position in U+%06x character's glyph.\n", unicode);
  613. x = 0;
  614. }
  615. if(x + w > ctx.glyphs[unicode].width) {
  616. if(t != SSFN_FRAG_CONTOUR && lyr && lyr->data) {
  617. l = (x + w) * ctx.glyphs[unicode].height;
  618. data2 = (unsigned char*)malloc(l + 1);
  619. if(!data2) { fprintf(stderr,"libsfn: memory allocation error\n"); return NULL; }
  620. memset(data2, 0xFF, l + 1);
  621. for(j = 0; j < ctx.glyphs[unicode].height; j++)
  622. for(i = 0; i < ctx.glyphs[unicode].width; i++)
  623. data2[j * (x + w) + i] = lyr->data[ctx.glyphs[unicode].width * j + i];
  624. free(lyr->data);
  625. lyr->data = data2;
  626. }
  627. ctx.glyphs[unicode].width = x + w;
  628. }
  629. if(y < 0) {
  630. if(!quiet) fprintf(stderr, "libsfn: negative y position in U+%06x character's glyph.\n", unicode);
  631. y = 0;
  632. }
  633. if(y + h > ctx.glyphs[unicode].height) {
  634. if(t != SSFN_FRAG_CONTOUR && lyr && lyr->data) {
  635. l = ctx.glyphs[unicode].width * (y + h);
  636. lyr->data = (unsigned char*)realloc(lyr->data, l + 1);
  637. if(!lyr->data) { fprintf(stderr,"libsfn: memory allocation error\n"); return NULL; }
  638. memset(lyr->data + ctx.glyphs[unicode].width * ctx.glyphs[unicode].height, 0,
  639. ctx.glyphs[unicode].width * (y + h - ctx.glyphs[unicode].height));
  640. }
  641. ctx.glyphs[unicode].height = y + h;
  642. }
  643. if(!lyr) {
  644. ctx.glyphs[unicode].layers = (sfnlayer_t*)realloc(ctx.glyphs[unicode].layers,
  645. (ctx.glyphs[unicode].numlayer + 1) * sizeof(sfnlayer_t));
  646. if(!ctx.glyphs[unicode].layers) { fprintf(stderr,"libsfn: memory allocation error\n"); return NULL; }
  647. lyr = &ctx.glyphs[unicode].layers[ctx.glyphs[unicode].numlayer++];
  648. memset(lyr, 0, sizeof(sfnlayer_t));
  649. lyr->type = t;
  650. lyr->color = c;
  651. if(t != SSFN_FRAG_CONTOUR) {
  652. l = ctx.glyphs[unicode].width * ctx.glyphs[unicode].height;
  653. lyr->data = (unsigned char*)malloc(l + 1);
  654. if(!lyr->data) { fprintf(stderr,"libsfn: memory allocation error\n"); return NULL; }
  655. memset(lyr->data, 0xFF, l + 1);
  656. }
  657. }
  658. if(t != SSFN_FRAG_CONTOUR && data) {
  659. for(j = 0; j < h; j++)
  660. for(i = 0; i < w; i++)
  661. lyr->data[(y + j) * ctx.glyphs[unicode].width + (x + i)] = data[j * w + i];
  662. if(!ctx.glyphs[unicode].adv_x && !ctx.glyphs[unicode].adv_y) {
  663. if(ctx.family == SSFN_FAMILY_MONOSPACE)
  664. ctx.glyphs[unicode].adv_x = ctx.glyphs[unicode].width + 1 + adv;
  665. else {
  666. for(y = l = 0; y < ctx.glyphs[unicode].height; y++)
  667. for(j = ctx.glyphs[unicode].width; (unsigned int)j > (unsigned int)l; j--)
  668. if(lyr->data[y * ctx.glyphs[unicode].width + j]) l = j;
  669. ctx.glyphs[unicode].adv_x = (iswhitespace(unicode) ? ctx.glyphs[unicode].width : l) + 1 + adv;
  670. }
  671. }
  672. }
  673. ctx.lx = ctx.ly = 0;
  674. return lyr;
  675. }
  676. /**
  677. * Delete a layer from character
  678. *
  679. * @param unicode character to remove layer from
  680. * @param idx layer
  681. */
  682. void sfn_layerdel(int unicode, int idx)
  683. {
  684. if(unicode < 0 || unicode > 0x10FFFF || ctx.glyphs[unicode].numlayer < 1 || idx >= ctx.glyphs[unicode].numlayer) return;
  685. if(ctx.glyphs[unicode].layers[idx].data) free(ctx.glyphs[unicode].layers[idx].data);
  686. ctx.glyphs[unicode].layers[idx].data = NULL;
  687. ctx.glyphs[unicode].numlayer--;
  688. memcpy(&ctx.glyphs[unicode].layers[idx], &ctx.glyphs[unicode].layers[idx+1],
  689. (ctx.glyphs[unicode].numlayer - idx) * sizeof(sfnlayer_t));
  690. }
  691. /**
  692. * Add a contour command to a layer
  693. *
  694. * @param lyr pointer to layer
  695. * @param t type (SSFN_CONT_x)
  696. * @param px next point x
  697. * @param py next point y
  698. * @param c1x control point #1 x
  699. * @param c1y control point #1 y
  700. * @param c2x control point #2 x
  701. * @param c2y control point #2 y
  702. * @return true on success
  703. */
  704. int sfn_contadd(sfnlayer_t *lyr, int t, int px, int py, int c1x, int c1y, int c2x, int c2y)
  705. {
  706. sfncont_t *cont;
  707. int cx, cy;
  708. if(!lyr || lyr->type != SSFN_FRAG_CONTOUR) return 0;
  709. if(lyr->len >= 32767) {
  710. if(!quiet) fprintf(stderr, "libsfn: too many points in contour in U+%06x character's glyph.\n", unicode);
  711. return 0;
  712. }
  713. lyr->data = (unsigned char*)realloc(lyr->data, (lyr->len + 1) * sizeof(sfncont_t));
  714. if(!lyr->data) { lyr->len = 0; return 0; }
  715. /* clamp coordinates to prevent overflow */
  716. if(px<0 || px>254 || py<0 || py>254 || c1x<0 || c1x>254 || c1y<0 || c1y>254 || c2x<0 || c2x>254 || c2y<0 || c2y>254) {
  717. /* should never happen */
  718. if(!quiet && lastuni != unicode)
  719. fprintf(stderr,"\rlibsfn: scaling error U+%06x px %d py %d c1x %d c1y %d c2x %d c2y %d\n", unicode, px, py, c1x, c1y,
  720. c2x, c2y);
  721. lastuni = unicode;
  722. if(px<0) { px = 0; } if(px>254) px = 254;
  723. if(py<0) { py = 0; } if(py>254) py = 254;
  724. if(c1x<0) { c1x = 0; } if(c1x>254) c1x = 254;
  725. if(c1y<0) { c1y = 0; } if(c1y>254) c1y = 254;
  726. if(c2x<0) { c2x = 0; } if(c2x>254) c2x = 254;
  727. if(c2y<0) { c2y = 0; } if(c2y>254) c2y = 254;
  728. }
  729. /* convert trivial cubic curves to quadratic ones, requires less storage space in fonts */
  730. if(t == SSFN_CONTOUR_CUBIC) {
  731. if((c1x >> 1) == (c2x >> 1) && (c1y >> 1) == (c2y >> 1)) { t = SSFN_CONTOUR_QUAD; c2x = c2y = 0; } else
  732. if(ctx.lx > 0 && ctx.ly > 0) {
  733. cx = ((c1x - ctx.lx) / 2) + ctx.lx;
  734. cy = ((c1y - ctx.ly) / 2) + ctx.ly;
  735. if(((((c2x - cx) / 2) + cx) >> 1) == (px >> 1) && ((((c2y - cy) / 2) + cy) >> 1) == (py >> 1)) {
  736. t = SSFN_CONTOUR_QUAD; c1x = cx; c1y = cy; c2x = c2y = 0;
  737. }
  738. }
  739. }
  740. cont = &((sfncont_t *)(lyr->data))[lyr->len++];
  741. cont->type = t & 0xFF;
  742. cont->px = px; if(px + 1 > ctx.glyphs[unicode].width) ctx.glyphs[unicode].width = px + 1;
  743. cont->py = py; if(py + 1 > ctx.glyphs[unicode].height) ctx.glyphs[unicode].height = py + 1;
  744. cont->c1x = c1x; if(c1x + 1 > ctx.glyphs[unicode].width) ctx.glyphs[unicode].width = c1x + 1;
  745. cont->c1y = c1y; if(c1y + 1 > ctx.glyphs[unicode].height) ctx.glyphs[unicode].height = c1y + 1;
  746. cont->c2x = c2x; if(c2x + 1 > ctx.glyphs[unicode].width) ctx.glyphs[unicode].width = c2x + 1;
  747. cont->c2y = c2y; if(c2y + 1 > ctx.glyphs[unicode].height) ctx.glyphs[unicode].height = c2y + 1;
  748. ctx.lx = px; ctx.ly = py;
  749. return 1;
  750. }
  751. /**
  752. * Add a kerning relation
  753. *
  754. * @param unicode previous code point in relation
  755. * @param next next unicode in relation
  756. * @param x kerning offset x
  757. * @param y kerning offset y
  758. * @return true on success
  759. */
  760. int sfn_kernadd(int unicode, int next, int x, int y)
  761. {
  762. int i;
  763. if(unicode < rs || unicode > re || unicode < 33 || unicode > 0x10FFFF || next < rs || next > re ||
  764. next < 33 || next > 0x10FFFFF) return 0;
  765. if(x < -128) x = -128;
  766. if(x > 127) x = 127;
  767. if(y < -128) y = -128;
  768. if(y > 127) y = 127;
  769. for(i = 0; i < ctx.glyphs[unicode].numkern; i++)
  770. if(ctx.glyphs[unicode].kern[i].n == next) {
  771. if(!x && !y) {
  772. memcpy(&ctx.glyphs[unicode].kern[i], &ctx.glyphs[unicode].kern[i+1], (ctx.glyphs[unicode].numkern - i) *
  773. sizeof(sfnkern_t));
  774. ctx.glyphs[unicode].numkern--;
  775. } else {
  776. ctx.glyphs[unicode].kern[i].x = x;
  777. ctx.glyphs[unicode].kern[i].y = y;
  778. }
  779. return 1;
  780. }
  781. if(!x && !y) return 0;
  782. if(ctx.glyphs[unicode].numkern >= 32767) {
  783. if(!quiet) fprintf(stderr,"libsfn: too many kerning pairs for U+%06x, truncated to 32767\n", unicode);
  784. return 1;
  785. }
  786. i = ctx.glyphs[unicode].numkern++;
  787. ctx.glyphs[unicode].kern = (sfnkern_t*)realloc(ctx.glyphs[unicode].kern, ctx.glyphs[unicode].numkern * sizeof(sfnkern_t));
  788. if(!ctx.glyphs[unicode].kern) { ctx.glyphs[unicode].numkern = 0; return 0; }
  789. while(i > 0 && ctx.glyphs[unicode].kern[i-1].n > next) {
  790. ctx.glyphs[unicode].kern[i].n = ctx.glyphs[unicode].kern[i-1].n;
  791. ctx.glyphs[unicode].kern[i].x = ctx.glyphs[unicode].kern[i-1].x;
  792. ctx.glyphs[unicode].kern[i].y = ctx.glyphs[unicode].kern[i-1].y;
  793. i--;
  794. }
  795. ctx.glyphs[unicode].kern[i].n = next;
  796. ctx.glyphs[unicode].kern[i].x = x;
  797. ctx.glyphs[unicode].kern[i].y = y;
  798. return 1;
  799. }
  800. /**
  801. * Calculate hinting grid
  802. *
  803. * @param unicode character to calculate hints to
  804. */
  805. void sfn_hintgen(int unicode)
  806. {
  807. int i, j, x, y, h[256], v[256], mx = 0, my = 0, limit = 3;
  808. sfncont_t *cont;
  809. if(unicode < 0 || unicode > 0x10FFFF) return;
  810. memset(ctx.glyphs[unicode].hintv, 0, 33);
  811. memset(ctx.glyphs[unicode].hinth, 0, 33);
  812. if(!ctx.glyphs[unicode].layers) return;
  813. /* look for vertical or horizontal lines in contour paths */
  814. memset(h, 0, sizeof(h)); memset(v, 0, sizeof(v));
  815. for(i = 0; i < ctx.glyphs[unicode].numlayer; i++)
  816. if(ctx.glyphs[unicode].layers[i].type == SSFN_FRAG_CONTOUR) {
  817. cont = (sfncont_t*)ctx.glyphs[unicode].layers[i].data;
  818. x = cont->px; y = cont->py;
  819. for(j = 0; j < ctx.glyphs[unicode].layers[i].len; j++, cont++) {
  820. if(cont->type == SSFN_CONTOUR_LINE) {
  821. if(x != cont->px && y == cont->py) v[y] += x > cont->px ? x - cont->px : cont->px - x;
  822. if(x == cont->px && y != cont->py) h[x] += y > cont->py ? y - cont->py : cont->py - y;
  823. }
  824. x = cont->px; y = cont->py;
  825. if(x > mx) mx = x;
  826. if(y > my) my = y;
  827. }
  828. }
  829. /* now lets see which coordinates have more points than the limit, those will be the grid lines */
  830. mx /= limit; my /= limit;
  831. for(i = 0; i < 256; i++) {
  832. if(h[i] > my && ctx.glyphs[unicode].hintv[0] < 32)
  833. ctx.glyphs[unicode].hintv[1 + ctx.glyphs[unicode].hintv[0]++] = i;
  834. if(v[i] > mx && ctx.glyphs[unicode].hinth[0] < 32)
  835. ctx.glyphs[unicode].hinth[1 + ctx.glyphs[unicode].hinth[0]++] = i;
  836. }
  837. }
  838. /**
  839. * Add a kerning position list
  840. *
  841. * @param data pointer to buffer
  842. * @param len length of buffer
  843. * @return kpos index or -1 on error
  844. */
  845. int sfn_kposadd(char *data, int len)
  846. {
  847. unsigned char *comp;
  848. int i;
  849. if(!data || len < 1) return -1;
  850. comp = rle_enc((unsigned char*)data, len, &len);
  851. for(i = 0; i < ctx.numkpos; i++)
  852. if(len == ctx.kpos[i].len && !memcmp(comp, ctx.kpos[i].data, len)) {
  853. free(comp);
  854. return i;
  855. }
  856. i = ctx.numkpos++;
  857. ctx.kpos = (sfnkpos_t*)realloc(ctx.kpos, ctx.numkpos * sizeof(sfnkpos_t));
  858. ctx.kpos[i].idx = i;
  859. ctx.kpos[i].len = len;
  860. ctx.kpos[i].data = comp;
  861. return i;
  862. }
  863. /**
  864. * Add a fragment to the global list
  865. *
  866. * @param type type of the fragment (SSFN_FRAG_x)
  867. * @param w width
  868. * @param h height
  869. * @param data pointer to buffer
  870. * @return fragment index or -1 on error
  871. */
  872. int sfn_fragadd(int type, int w, int h, void *data)
  873. {
  874. int i, l = w * h;
  875. unsigned char *data2;
  876. if(w < 1 || h < 0 || !data)
  877. return -1;
  878. if(type == SSFN_FRAG_CONTOUR) { l = w * sizeof(sfncont_t); h = 0; } else
  879. if(type == SSFN_FRAG_KERNING) { l = w * sizeof(sfnkgrp_t); h = 0; } else
  880. if(type == SSFN_FRAG_HINTING) { l = w; h = 0; }
  881. for(i = 0; i < ctx.numfrags; i++)
  882. if(ctx.frags[i].type == type && ctx.frags[i].w == w && ctx.frags[i].h == h && ctx.frags[i].len == l &&
  883. (type == SSFN_FRAG_CONTOUR && dorounderr ? !frgcmp((sfncont_t*)ctx.frags[i].data, (sfncont_t*)data, w) :
  884. !memcmp(ctx.frags[i].data, data, l))) {
  885. ctx.frags[i].cnt++;
  886. return i;
  887. }
  888. if(type != SSFN_FRAG_HINTING || l > 0) {
  889. data2 = (unsigned char*)malloc(l);
  890. if(!data2) { fprintf(stderr,"libsfn: memory allocation error\n"); return -1; }
  891. memcpy(data2, data, l);
  892. } else
  893. data2 = NULL;
  894. i = ctx.numfrags++;
  895. ctx.frags = (sfnfrag_t*)realloc(ctx.frags, ctx.numfrags * sizeof(sfnfrag_t));
  896. if(!ctx.frags) { fprintf(stderr,"libsfn: memory allocation error\n"); return -1; }
  897. ctx.frags[i].idx = i;
  898. ctx.frags[i].pos = 0;
  899. ctx.frags[i].cnt = 1;
  900. ctx.frags[i].type = type;
  901. ctx.frags[i].w = w;
  902. ctx.frags[i].h = h;
  903. ctx.frags[i].len = l;
  904. ctx.frags[i].data = data2;
  905. return i;
  906. }
  907. /**
  908. * Add a fragment to a character
  909. *
  910. * @param unicode character to add to
  911. * @param type type of the fragment (SSFN_FRAG_x)
  912. * @param w width
  913. * @param h height
  914. * @param x offset x
  915. * @param y offset y
  916. * @param data pointer to buffer
  917. * @return true on success
  918. */
  919. int sfn_fragchr(int unicode, int type, int w, int h, int x, int y, void *data)
  920. {
  921. int i;
  922. if(type == SSFN_FRAG_KERNING && w > 1024) {
  923. if(!quiet) fprintf(stderr, "libsfn: too many kerning groups for U+%06X, truncated to 1024.\n", unicode);
  924. w = 1024;
  925. }
  926. if(ctx.glyphs[unicode].numfrag >= 255) {
  927. if(!quiet) fprintf(stderr, "libsfn: too many fragments for U+%06X, truncated to 255.\n", unicode);
  928. return 1;
  929. }
  930. i = sfn_fragadd(type, w, h, data);
  931. if(i != -1) {
  932. ctx.glyphs[unicode].frags = (int*)realloc(ctx.glyphs[unicode].frags,
  933. (ctx.glyphs[unicode].numfrag + 1) * 3 * sizeof(int));
  934. if(!ctx.glyphs[unicode].frags) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  935. ctx.glyphs[unicode].frags[ctx.glyphs[unicode].numfrag*3+0] = i;
  936. ctx.glyphs[unicode].frags[ctx.glyphs[unicode].numfrag*3+1] = x;
  937. ctx.glyphs[unicode].frags[ctx.glyphs[unicode].numfrag*3+2] = y;
  938. ctx.glyphs[unicode].numfrag++;
  939. return 1;
  940. }
  941. return 0;
  942. }
  943. /**
  944. * Add a color map entry
  945. *
  946. * @param r red
  947. * @param g green
  948. * @param b blue
  949. * @param a alpha
  950. * @return color map index
  951. */
  952. unsigned char sfn_cpaladd(int r, int g, int b, int a)
  953. {
  954. int i, dr, dg, db, m, q;
  955. int64_t d, dm;
  956. if((!r && g<2 && !b && (!a || a==0xFF)) || (r == 0xFF && !g && b == 0xFF)) return 0xFF; /* background */
  957. if(r == 0xFF && g == 0xFF && b == 0xFF && a == 0xFF) return 0xFE; /* foreground */
  958. for(q=1; q<=8; q++) {
  959. m=-1; dm=256;
  960. for(i=0; i<ctx.numcpal && (ctx.cpal[i*4+0] || ctx.cpal[i*4+1] || ctx.cpal[i*4+2]); i++) {
  961. if(a==ctx.cpal[i*4+3] && b==ctx.cpal[i*4+0] && g==ctx.cpal[i*4+1] && r==ctx.cpal[i*4+2]) return i;
  962. if(b>>q==ctx.cpal[i*4+0]>>q && g>>q==ctx.cpal[i*4+1]>>q && r>>q==ctx.cpal[i*4+2]>>q) {
  963. dr = r > ctx.cpal[i*4+2] ? r - ctx.cpal[i*4+2] : ctx.cpal[i*4+2] - r;
  964. dg = g > ctx.cpal[i*4+1] ? g - ctx.cpal[i*4+1] : ctx.cpal[i*4+1] - g;
  965. db = b > ctx.cpal[i*4+0] ? b - ctx.cpal[i*4+0] : ctx.cpal[i*4+0] - b;
  966. d = dr*dr + dg*dg + db*db;
  967. if(d < dm) { dm = d; m = i; }
  968. if(!dm) break;
  969. }
  970. }
  971. if(dm>9+9+9 && i<254) {
  972. ctx.cpal[i*4+3] = a;
  973. ctx.cpal[i*4+2] = r;
  974. ctx.cpal[i*4+1] = g;
  975. ctx.cpal[i*4+0] = b;
  976. ctx.numcpal++;
  977. return i;
  978. }
  979. if(m>=0) {
  980. ctx.cpal[m*4+3] = ((ctx.cpal[m*4+3] + a) >> 1);
  981. ctx.cpal[m*4+2] = ((ctx.cpal[m*4+2] + r) >> 1);
  982. ctx.cpal[m*4+1] = ((ctx.cpal[m*4+1] + g) >> 1);
  983. ctx.cpal[m*4+0] = ((ctx.cpal[m*4+0] + b) >> 1);
  984. return m;
  985. }
  986. }
  987. if(!quiet) fprintf(stderr,"libsfn: unable to add color to color map, should never happen\n");
  988. return 0xFE; /* fallback to foreground */
  989. }
  990. /**
  991. * Add a UNICODE code point to skip from output (make it excluded)
  992. *
  993. * @param unicode code point to skip
  994. */
  995. void sfn_skipadd(int unicode)
  996. {
  997. ctx.skip[unicode >> 3] |= 1 << (unicode & 7);
  998. }
  999. /**
  1000. * Remove a UNICODE code point to skip from output (make it included)
  1001. *
  1002. * @param unicode code point to skip
  1003. */
  1004. void sfn_skipdel(int unicode)
  1005. {
  1006. ctx.skip[unicode >> 3] &= ~(1 << (unicode & 7));
  1007. }
  1008. /**
  1009. * Dump an SSFN font
  1010. *
  1011. * @param font pointer to an SSFN font
  1012. * @param size size of the font buffer
  1013. * @param dump dump level
  1014. * @return true if font is valid and verified
  1015. */
  1016. int sfn_dump(ssfn_font_t *font, int size, int dump)
  1017. {
  1018. char *dump_fam[] = { "SERIF", "SANS", "DECOR", "MONO", "HAND", "?" };
  1019. char *dump_str[] = { "name", "family", "subfamily", "revision", "manufacturer", "license" };
  1020. unsigned char *ptr, *ptr2, *cmd;
  1021. unsigned short *lig;
  1022. ssfn_font_t *end;
  1023. int i, j, k, m, n, o, fn = 0, *fo = NULL, *ko = NULL;
  1024. if(!font || size < 32) return 0;
  1025. end = (ssfn_font_t*)((uint8_t*)font + font->size);
  1026. if(!memcmp(font->magic, SSFN_COLLECTION, 4)) {
  1027. printf("font/x-ssfont Scalable Screen Font Collection\n\n---Header---\nmagic: '%c%c%c%c'\nsize: %d\n",
  1028. font->magic[0], font->magic[1], font->magic[2], font->magic[3], font->size);
  1029. printf("\n---Fonts---\n");
  1030. for(font = (ssfn_font_t*)((uint8_t*)font + 8); font < end; font = (ssfn_font_t*)((uint8_t*)font + font->size)) {
  1031. if(!memcmp(font->magic, "SSFN", 4)) printf("(obsolete SSFN1.0 font) %s\n", (char*)font + 64);
  1032. else printf("%c%c%c%c %d %3d %s\n", SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_BOLD ? 'b':'.',
  1033. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_ITALIC ? 'i':'.',
  1034. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_USRDEF1 ? 'u':'.',
  1035. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_USRDEF2 ? 'U':'.',
  1036. SSFN_TYPE_FAMILY(font->type), font->height,
  1037. (char*)font + sizeof(ssfn_font_t));
  1038. }
  1039. return 1;
  1040. } else
  1041. if(!memcmp(font->magic, "SSFN", 4)) {
  1042. printf("font/x-ssfont Obsolete Scalable Screen Font 1.0 Format\n");
  1043. return 0;
  1044. } else
  1045. if(!memcmp(font->magic, "# Scalab", 8)) {
  1046. printf("text/x-ssfont Scalable Screen Font ASCII Format\n");
  1047. return 1;
  1048. } else
  1049. if(!memcmp(font->magic, SSFN_MAGIC, 4)) {
  1050. printf("font/x-ssfont Scalable Screen Font\n\n---Header---\nmagic: '%c%c%c%c'\nsize: %d\n",
  1051. font->magic[0], font->magic[1], font->magic[2], font->magic[3], font->size);
  1052. printf("type: %02x SSFN_FAMILY_%s%s%s%s%s\n", font->type, dump_fam[SSFN_TYPE_FAMILY(font->type)],
  1053. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_BOLD ? ", SSFN_STYLE_BOLD" : "",
  1054. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_ITALIC ? ", SSFN_STYLE_ITALIC" : "",
  1055. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_USRDEF1 ? ", SSFN_STYLE_USRDEF1" : "",
  1056. SSFN_TYPE_STYLE(font->type) & SSFN_STYLE_USRDEF2 ? ", SSFN_STYLE_USRDEF2" : "");
  1057. ptr = (unsigned char *)font + sizeof(ssfn_font_t);
  1058. printf("features: %02x rev %d\n", font->features, font->features & 0xF);
  1059. printf("width, height: %d %d\n", font->width, font->height);
  1060. printf("baseline: %d\n", font->baseline);
  1061. printf("underline: %d\n", font->underline);
  1062. i = font->fragments_offs && font->characters_offs ? font->characters_offs - font->fragments_offs : 0;
  1063. printf("fragments_offs: 0x%08x (%d bytes)\n", font->fragments_offs, i);
  1064. i = font->characters_offs ? (font->ligature_offs ? font->ligature_offs : (font->kerning_offs ?
  1065. font->kerning_offs : (font->cmap_offs ? font->cmap_offs : font->size - 4))) - font->characters_offs : 0;
  1066. printf("characters_offs: 0x%08x (%d bytes)\n", font->characters_offs, i);
  1067. i = font->ligature_offs ? (font->kerning_offs ?
  1068. font->kerning_offs : (font->cmap_offs ? font->cmap_offs : font->size - 4)) - font->ligature_offs : 0;
  1069. printf("ligature_offs: 0x%08x (%d bytes)\n", font->ligature_offs, i);
  1070. i = font->kerning_offs ? (font->cmap_offs ? font->cmap_offs : font->size - 4) - font->kerning_offs : 0;
  1071. printf("kerning_offs: 0x%08x (%d bytes)\n", font->kerning_offs, i);
  1072. i = font->cmap_offs ? font->size - 4 - font->cmap_offs : 0;
  1073. printf("cmap_offs: 0x%08x (%d bytes)\n", font->cmap_offs, i);
  1074. if(dump != 2 && dump != 99)
  1075. printf("name: \"%s\"%s\n", (unsigned char *)font + sizeof(ssfn_font_t),
  1076. dump < 2 ? " (use -dd to see all strings)" : "");
  1077. if((unsigned int)size != font->size || memcmp((unsigned char*)font + font->size - 4, SSFN_ENDMAGIC, 4))
  1078. { fprintf(stderr, "libsfn: missing end magic or incorrect font size\n"); return 0; }
  1079. if(dump != 99) {
  1080. if(!font->fragments_offs) { fprintf(stderr, "libsfn: missing fragments table\n"); return 0; }
  1081. if(!font->characters_offs) { fprintf(stderr, "libsfn: missing characters table\n"); return 0; }
  1082. if(font->characters_offs <= font->fragments_offs)
  1083. { fprintf(stderr, "libsfn: incorrect characters table offset\n"); return 0; }
  1084. if(font->kerning_offs && (font->kerning_offs <= font->characters_offs || (font->ligature_offs &&
  1085. font->kerning_offs <= font->ligature_offs)))
  1086. { fprintf(stderr, "libsfn: incorrect kerning table offset\n"); return 0; }
  1087. if(font->ligature_offs && font->ligature_offs <= font->characters_offs)
  1088. { fprintf(stderr, "libsfn: incorrect ligature table offset\n"); return 0; }
  1089. if(font->cmap_offs && ((font->size - font->cmap_offs) & 3))
  1090. { fprintf(stderr, "libsfn: incorrect cmap table offset\n"); return 0; }
  1091. }
  1092. if(dump == 2 || dump == 99) {
  1093. printf("\n---String Table---\n");
  1094. ptr = (unsigned char *)font + sizeof(ssfn_font_t);
  1095. for(i=0;i<6;i++) { printf("%d. %-12s \"%s\"\n", i, dump_str[i], ptr); ptr += strlen((char*)ptr)+1; }
  1096. ptr2 = (unsigned char *)font + font->fragments_offs;
  1097. for(i=0;ptr<ptr2;i++) { printf("%d. LIGATURE \"%s\"\n", i, ptr); ptr += strlen((char*)ptr)+1; }
  1098. if(ptr != ptr2) { fprintf(stderr, "libsfn: incorrect string table size\n"); return 0; }
  1099. }
  1100. if(dump == 3 || dump == 4 || dump == 99) {
  1101. if(dump != 4) printf("\n---Fragments Table---");
  1102. if(!font->fragments_offs) { if(dump != 4) printf("\nnot present\n"); }
  1103. else {
  1104. ptr = (unsigned char *)font + font->fragments_offs;
  1105. ptr2 = (unsigned char *)font + font->characters_offs;
  1106. while(ptr < ptr2) {
  1107. fo = (int*)realloc(fo, (fn+1)*sizeof(int));
  1108. fo[fn++] = (int)(ptr - (unsigned char *)font);
  1109. if(dump != 4) printf("\n%06x: %02x ", (uint32_t)((uint8_t*)ptr-(uint8_t*)font), ptr[0]);
  1110. if(!(ptr[0] & 0x80)) {
  1111. j = (ptr[0] & 0x3F);
  1112. if(ptr[0] & 0x40) {
  1113. j <<= 8; j |= ptr[1]; j++;
  1114. if(dump != 4) printf("%02x SSFN_FRAG_CONTOUR n=%d\n",ptr[1],j);
  1115. ptr += 2;
  1116. } else {
  1117. j++;
  1118. if(dump != 4) printf(" SSFN_FRAG_CONTOUR n=%d\n",j);
  1119. ptr++;
  1120. }
  1121. cmd = ptr; ptr += (j+3)/4;
  1122. for(i = 0; i < j; i++) {
  1123. k = (cmd[i / 4] >> ((i & 3) * 2)) & 3;
  1124. if(dump != 4) printf(" %02x:%d=%d", cmd[i / 4], (i & 3) * 2, k);
  1125. switch(k) {
  1126. case SSFN_CONTOUR_MOVE:
  1127. if(dump != 4) printf(" SSFN_CONTOUR_MOVE p=%3d,%3d\n",ptr[0],ptr[1]);
  1128. ptr += 2;
  1129. break;
  1130. case SSFN_CONTOUR_LINE:
  1131. if(dump != 4) printf(" SSFN_CONTOUR_LINE p=%3d,%3d\n",ptr[0],ptr[1]);
  1132. ptr += 2;
  1133. break;
  1134. case SSFN_CONTOUR_QUAD:
  1135. if(dump != 4) printf(" SSFN_CONTOUR_QUAD p=%3d,%3d c1=%3d,%3d\n",ptr[0],ptr[1],ptr[2],ptr[3]);
  1136. ptr += 4;
  1137. break;
  1138. case SSFN_CONTOUR_CUBIC:
  1139. if(dump != 4) printf(" SSFN_CONTOUR_CUBIC p=%3d,%3d c1=%3d,%3d c2=%3d,%3d\n",ptr[0],ptr[1],
  1140. ptr[2],ptr[3],ptr[4],ptr[5]);
  1141. ptr += 6;
  1142. break;
  1143. }
  1144. }
  1145. } else
  1146. if((ptr[0] & 0x60) == 0) {
  1147. j = (ptr[0] & 0x1F) + 1;
  1148. if(dump != 4) printf("%02x SSFN_FRAG_BITMAP p=%d h=%d\n",ptr[1],j,ptr[1]+1);
  1149. j *= ptr[1] + 1;
  1150. for(ptr += 2, i = 0; i < j && i < 16; i++)
  1151. if(dump != 4) printf(" %02x", ptr[i]);
  1152. if(dump != 4) printf("%s\n", j > 15 ? "..." : "");
  1153. ptr += j;
  1154. } else
  1155. if((ptr[0] & 0x60) == 0x20) {
  1156. j = (((ptr[0] & 0x1F) << 8) | ptr[1]) + 1;
  1157. if(dump != 4) printf("%02x %02x %02x SSFN_FRAG_PIXMAP s=%d w=%d h=%d\n",ptr[1],ptr[2],ptr[3],j,
  1158. ptr[2]+1,ptr[3]+1);
  1159. for(ptr += 4, i = 0; i < j && i < 16; i++)
  1160. if(dump != 4) printf(" %02x", ptr[i]);
  1161. if(dump != 4) printf("%s\n", j > 15 ? "..." : "");
  1162. ptr += j;
  1163. } else
  1164. if((ptr[0] & 0x60) == 0x40) {
  1165. if(!font->kerning_offs) { fprintf(stderr, "libsfn: kerning fragment without kerning table\n"); return 0; }
  1166. j = (((ptr[0] & 0x3) << 8) | ptr[1]) + 1;
  1167. if(dump != 4) printf("%02x %02x SSFN_FRAG_KERNING n=%d c=%d\n", ptr[1], ptr[2], j, (ptr[2] >> 2) & 7);
  1168. for(ptr += 2, i = 0; i < j; i++, ptr += 8) {
  1169. k = (((ptr[2] >> 4) & 0xF) << 24) | (((ptr[5] >> 4) & 0xF) << 16) | (ptr[7] << 8) | ptr[6];
  1170. if(dump != 4) {
  1171. printf(" %02x %02x %02x %02x %02x %02x %02x %02x U+%06X..U+%06X o=%06x\n",
  1172. ptr[0],ptr[1],ptr[2],ptr[3],ptr[4],ptr[5],ptr[6],ptr[7],
  1173. ((ptr[2] & 0xF) << 16) | (ptr[1] << 8) | ptr[0],
  1174. ((ptr[5] & 0xF) << 16) | (ptr[4] << 8) | ptr[3],
  1175. k + font->kerning_offs);
  1176. }
  1177. }
  1178. } else {
  1179. j = (ptr[0] & 0x1F) + 1;
  1180. if(dump != 4) printf("SSFN_FRAG_HINTING n=%d\n", j);
  1181. for(ptr++, i = 0; i < j; i++, ptr++)
  1182. if(dump != 4) printf(" %02x (%d)", ptr[0], ptr[0]);
  1183. if(dump != 4) printf("\n");
  1184. }
  1185. }
  1186. if(ptr != ptr2) { fprintf(stderr, "libsfn: incorrect fragments table size\n"); return 0; }
  1187. }
  1188. }
  1189. if(dump == 4 || dump == 99) {
  1190. printf("\n---Characters Table---\n");
  1191. if(!font->characters_offs) printf("not present\n");
  1192. else {
  1193. ptr = (unsigned char *)font + font->characters_offs;
  1194. ptr2 = (unsigned char *)font + (font->ligature_offs ? font->ligature_offs : (font->kerning_offs ?
  1195. font->kerning_offs : (font->cmap_offs ? font->cmap_offs : font->size - 4)));
  1196. for(j = 0; ptr < ptr2;) {
  1197. printf("%06lx:", (unsigned long int)ptr - (unsigned long int)font);
  1198. if(ptr[0] == 0xFF) { printf(" ff --- skip 65536 code points ---\n"); j += 65536; ptr++; }
  1199. else
  1200. if((ptr[0] & 0xC0) == 0xC0) {
  1201. k = (((ptr[0] & 0x3F) << 8) | ptr[1]) + 1;
  1202. printf(" %02x %02x --- skip %5d code points ---\n", ptr[0], ptr[1], k);
  1203. j += k; ptr += 2;
  1204. } else
  1205. if((ptr[0] & 0xC0) == 0x80) {
  1206. k = (ptr[0] & 0x3F) + 1;
  1207. printf(" %02x --- skip %5d code point%s ---\n", ptr[0], k, k>1?"s":"");
  1208. j += k; ptr++;
  1209. } else {
  1210. n = ptr[1]; k = ptr[0];
  1211. printf(" %02x %02x %02x %02x %02x %02x --- U+%06X n=%d f=%d o=%d w=%d h=%d ax=%d ay=%d ---\n",
  1212. ptr[0],ptr[1],ptr[2],ptr[3],ptr[4],ptr[5],j,n,k&0x40?1:0,k&0x3F,
  1213. ptr[2],ptr[3],ptr[4],ptr[5]);
  1214. ptr += 6;
  1215. for(i = 0; i < n; i++) {
  1216. if(ptr[0] == 255 && ptr[1] == 255) {
  1217. printf(" ff ff %02x 00 00 %scolor %d\n",ptr[2],k & 0x40 ? "00 " : "",ptr[2]);
  1218. if(!font->cmap_offs || font->cmap_offs + ptr[2] * 4 >= font->size - 4)
  1219. { printf("\n"); fprintf(stderr, "libsfn: incorrect color index %d for U+%06X\n",
  1220. ptr[2], j); return 0; }
  1221. ptr += k & 0x40 ? 6 : 5;
  1222. } else {
  1223. if(k & 0x40) {
  1224. m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2];
  1225. printf(" %02x %02x %02x %02x %02x %02x x=%3d y=%3d frag=%06x ",ptr[0],ptr[1],
  1226. ptr[2],ptr[3],ptr[4],ptr[5], ptr[0],ptr[1],m);
  1227. ptr += 6;
  1228. } else {
  1229. m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2];
  1230. printf(" %02x %02x %02x %02x %02x x=%3d y=%3d frag=%06x ",ptr[0],ptr[1],ptr[2],
  1231. ptr[3],ptr[4], ptr[0],ptr[1],m);
  1232. ptr += 5;
  1233. }
  1234. for(o = 0; o < fn && m != fo[o]; o++);
  1235. if(o >= fn)
  1236. { printf("\n"); fprintf(stderr, "libsfn: incorrect fragment offset %x for U+%06X\n", m, j);
  1237. return 0; }
  1238. printf(" SSFN_FRAG_");
  1239. cmd = (unsigned char*)font + m;
  1240. if(!(cmd[0] & 0x80)) printf("CONTOUR");
  1241. else if((cmd[0] & 0x60) == 0x00) printf("BITMAP");
  1242. else if((cmd[0] & 0x60) == 0x20) printf("PIXMAP");
  1243. else if((cmd[0] & 0x60) == 0x40) printf("KERNING");
  1244. else printf("HINTING");
  1245. printf("\n");
  1246. }
  1247. }
  1248. j++;
  1249. }
  1250. }
  1251. if(ptr != ptr2)
  1252. { fprintf(stderr, "libsfn: incorrect characters table size\n"); return 0; }
  1253. }
  1254. printf("\n---Ligatures Table---\n");
  1255. if(!font->ligature_offs) printf("not present\n");
  1256. else {
  1257. lig = (unsigned short*)((unsigned char *)font + font->ligature_offs);
  1258. for(i = 0; i < SSFN_LIG_LAST - SSFN_LIG_FIRST + 1 && lig[i]; i++) {
  1259. if(lig[i] >= font->fragments_offs) { fprintf(stderr, "libsfn: incorrect ligature offset\n"); return 0; }
  1260. printf(" U+%04X: \"%s\"\n", SSFN_LIG_FIRST + lig[i], (char*)font + lig[i]);
  1261. }
  1262. }
  1263. }
  1264. if(dump == 5 || dump == 99) {
  1265. printf("\n---Kerning Table---\n");
  1266. if(!font->kerning_offs) { printf("not present\n"); }
  1267. else {
  1268. ptr = (unsigned char *)font + font->kerning_offs;
  1269. ptr2 = (unsigned char *)font + (font->cmap_offs ? font->cmap_offs : font->size - 4);
  1270. while(ptr < ptr2) {
  1271. printf("%06x: %02x", (int)(ptr - (unsigned char *)font), ptr[0]);
  1272. i = ((*ptr++) & 0x7F) + 1;
  1273. if(ptr[-1] & 0x80) {
  1274. printf(" %02x", ptr[0]);
  1275. ptr++;
  1276. } else
  1277. while(i--) printf(" %02x", *ptr++);
  1278. printf("\n");
  1279. }
  1280. if(ptr != ptr2) { fprintf(stderr, "libsfn: incorrect kerning table size\n"); return 0; }
  1281. }
  1282. }
  1283. if(dump == 6 || dump == 99) {
  1284. printf("\n---Color Map Table---\n");
  1285. if(!font->cmap_offs) printf("not present\n");
  1286. else {
  1287. ptr = (unsigned char *)font + font->cmap_offs;
  1288. printf("number of colors: %d\n", (int)((((unsigned char*)end - 4) - ptr) / 4));
  1289. printf(" "); for(i=0;i<16;i++) printf(" %02X",i);
  1290. for(i=0;i<254 && ptr < (unsigned char*)end - 4;i++) {
  1291. if(!(i&15)) printf("\n%02X: ", i);
  1292. printf("%02x%02x%02x%02x ",ptr[3],ptr[2],ptr[1],ptr[0]);
  1293. ptr += 4;
  1294. }
  1295. printf("\n");
  1296. }
  1297. }
  1298. if(fo) free(fo);
  1299. if(ko) free(ko);
  1300. printf("\nFont parsed OK.\n");
  1301. return 1;
  1302. } else
  1303. printf("unknown format\n");
  1304. return 0;
  1305. }
  1306. /**
  1307. * Load / import a font into SSFN context
  1308. *
  1309. * @param filename file to load
  1310. * @param dump dump level (0 no dump)
  1311. * @return true on success
  1312. */
  1313. int sfn_load(char *filename, int dump)
  1314. {
  1315. unsigned char *data = NULL, *data2 = NULL, *o, c;
  1316. char *e;
  1317. int r, size;
  1318. FILE *f;
  1319. skipcleared = 0;
  1320. f = fopen(filename, "rb");
  1321. if(!f) return 0;
  1322. fseek(f, 0, SEEK_END);
  1323. size = (int)ftell(f);
  1324. fseek(f, 0, SEEK_SET);
  1325. if(!size) { fclose(f); return 0; }
  1326. data = (unsigned char*)malloc(size + 1);
  1327. if(!data) { fclose(f); return 0; }
  1328. if(!fread(data, size, 1, f)) { free(data); fclose(f); return 0; }
  1329. fclose(f);
  1330. ctx.total += (long int)size;
  1331. ctx.filename = filename;
  1332. if(data[0] == 0x1f && data[1] == 0x8b) {
  1333. o = data; data += 2;
  1334. if(*data++ != 8 || !size) { free(o); return 0; }
  1335. c = *data++; data += 6;
  1336. if(c & 4) { r = *data++; r += (*data++ << 8); data += r; }
  1337. if(c & 8) { while(*data++ != 0); }
  1338. if(c & 16) { while(*data++ != 0); }
  1339. data2 = (unsigned char*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data, size, 4096, &size, 0);
  1340. free(o);
  1341. if(!data2) return 0;
  1342. data2 = realloc(data2, size + 1);
  1343. if(!data2) return 0;
  1344. data = data2;
  1345. }
  1346. data[size] = 0;
  1347. if(dump > 0) {
  1348. printf("Dumping '%s'\n\n", filename);
  1349. return sfn_dump((ssfn_font_t *)data, size, dump);
  1350. }
  1351. r = 1; e = strrchr(filename, '.'); (void)e;
  1352. if(data[0]=='S' && data[1]=='F' && data[2]=='N' && data[3]=='C') {
  1353. fprintf(stderr, "libsfn: file '%s' is a collection with multiple fonts. Extract fonts first.\n", filename);
  1354. r = 0;
  1355. } else if(data[0]=='S' && data[1]=='F' && data[2]=='N' && data[3]=='2') {
  1356. printf("Loaded '%s' (SSFN BIN, %X - %X)\n", filename, rs, re);
  1357. sfn(data, size);
  1358. } else if(data[0]=='#' && data[1]==' ' && data[2]=='S' && data[3]=='c') {
  1359. printf("Loaded '%s' (SSFN ASCII, %X - %X)\n", filename, rs, re);
  1360. asc((char*)data, size);
  1361. #ifndef USE_NOFOREIGN
  1362. } else if(data[0]==0x72 && data[1]==0xB5 && data[2]==0x4A && data[3]==0x86) {
  1363. printf("Loaded '%s' (PSF2, %X - %X)\n", filename, rs, re);
  1364. psf(data, size);
  1365. } else if(data[8]=='P' && data[9]=='F' && data[10]=='F' && data[11]=='2') {
  1366. printf("Loaded '%s' (PFF2, %X - %X)\n", filename, rs, re);
  1367. pff(data, size);
  1368. } else if((data[0]=='M' && data[1]=='Z') || (!data[0] && (data[1] == 2 || data[1] == 3) && !data[5] && (data[6] > ' ' &&
  1369. data[6] < 127))) {
  1370. printf("Loaded '%s' (WinFNT, %X - %X)\n", filename, rs, re);
  1371. fnt(data, size);
  1372. } else if(data[0]=='S' && data[1]=='T' && data[2]=='A' && data[3]=='R') {
  1373. printf("Loaded '%s' (X11 BDF, %X - %X)\n", filename, rs, re);
  1374. bdf((char*)data, size);
  1375. } else if(data[0]==1 && data[1]=='f' && data[2]=='c' && data[3]=='p') {
  1376. printf("Loaded '%s' (X11 PCF, %X - %X)\n", filename, rs, re);
  1377. pcf(data, size);
  1378. } else if(data[0]=='S' && data[1]=='p' && data[2]=='l' && data[3]=='i' && data[4]=='n') {
  1379. printf("Loaded '%s' (SplineFontDB, %X - %X)\n", filename, rs, re);
  1380. sfd((char*)data, size);
  1381. } else if(data[0]==0xE1 && data[1]==0xE6 && data[2]==0xD5 && data[3]==0x1A) {
  1382. printf("Loaded '%s' (BMF, %X - %X)\n", filename, rs, re);
  1383. bmf(data, size);
  1384. } else if(!memcmp(data, "KBnPbits", 8)) {
  1385. printf("Loaded '%s' (KBnP bin, %X - %X)\n", filename, rs, re);
  1386. kbits(data, size);
  1387. } else if(!memcmp(data, "<?xml", 5) && my_memmem(data, size < 256 ? size : 256, "<kbits>", 7)) {
  1388. printf("Loaded '%s' (KBnP xml, %X - %X)\n", filename, rs, re);
  1389. kbitx((char*)data, size);
  1390. } else if(data[0]==0x89 && data[1]=='P' && data[2]=='N' && data[3]=='G') {
  1391. printf("Loaded '%s' (PNG, %X - %X)\n", filename, rs, re);
  1392. png(data, size);
  1393. } else if(data[0]==0 && (data[1]==0 || data[1]==1) &&
  1394. (data[2]==1 || data[2]==2 || data[2]==9 || data[2]==10) &&
  1395. (data[16]==8 || data[16]==24 || data[16]==32)) {
  1396. printf("Loaded '%s' (TARGA, %X - %X)\n", filename, rs, re);
  1397. tga(data, size);
  1398. } else if((data[0]>='0' && data[0]<='9') || (data[0]>='A' && data[0]<='F')) {
  1399. printf("Loaded '%s' (GNU unifont hex, %X - %X)\n", filename, rs, re);
  1400. hex((char*)data, size);
  1401. } else if(e && !strcmp(e, ".yaff")) {
  1402. printf("Loaded '%s' (YAFF, %X - %X)\n", filename, rs, re);
  1403. yaff((char*)data, size);
  1404. } else if(e && (e[1] == 'f' || e[1] == 'F') && e[2] >= '0' && e[2] <= '9' && e[3] >= '0' && e[3] <= '9') {
  1405. printf("Loaded '%s' (raw ROM, %X - %X)\n", filename, rs, re);
  1406. raw(data, size, atoi(e + 2));
  1407. #ifdef HAS_FT
  1408. } else if(ft2_read(data, size)) {
  1409. printf("Loaded '%s' (FreeType2, %X - %X)\n", filename, rs, re);
  1410. ft2_parse();
  1411. #endif
  1412. #endif
  1413. } else {
  1414. fprintf(stderr, "libsfn: unknown format '%s'\n", filename);
  1415. r = 0;
  1416. }
  1417. if(!ctx.name) sfn_setstr(&ctx.name, filename, 0);
  1418. free(data);
  1419. rs = 0; re = 0x10FFFF;
  1420. return r;
  1421. }
  1422. /**
  1423. * Serialize an SSFN context into a file
  1424. *
  1425. * @param filename file to save to
  1426. * @param ascii true if saving to ASC
  1427. * @param comp true if file should be gzipped
  1428. * @return true on success
  1429. */
  1430. int sfn_save(char *filename, int ascii, int comp)
  1431. {
  1432. char *fam[] = { "Serif", "Sans", "Decorative", "Monospace", "Handwriting", "?" }, *c;
  1433. int unicode, i, j, k, l, o, x, y, h, nc = 0, mc = 0, ml = 0, fs = 0, cs = 0, ks = 0, ls = 0;
  1434. unsigned char *frg = NULL, *chr = NULL, *krn = NULL, *tmp, hint[32], *gz;
  1435. unsigned short int lig[SSFN_LIG_LAST-SSFN_LIG_FIRST+1];
  1436. unsigned long int gzs;
  1437. char *strs = NULL, *crd = NULL;
  1438. sfnkgrp_t kgrp, *kgrpf = NULL;
  1439. ssfn_font_t *hdr;
  1440. sfncont_t *cont, *norm;
  1441. FILE *f;
  1442. uint32_t crc;
  1443. z_stream stream;
  1444. for(i = 0; i < 0x110000; i++) {
  1445. ml += ctx.glyphs[i].numlayer;
  1446. if((iswhitespace(i) && (ctx.glyphs[i].adv_x || ctx.glyphs[i].adv_y)) || ctx.glyphs[i].layers) mc++;
  1447. }
  1448. if(!mc || !ml) {
  1449. fprintf(stderr, "libsfn: no layers in font???\n");
  1450. return 0;
  1451. }
  1452. printf(" Numchars: %d, Numlayers: %d\n", mc, ml);
  1453. if(ascii) {
  1454. /* ----------------------------- output in text format ----------------------------- */
  1455. f = fopen(filename, "w");
  1456. if(f) {
  1457. ctx.filename = filename;
  1458. /* header */
  1459. fprintf(f, "# Scalable Screen Font #\r\n\r\n");
  1460. fprintf(f, "$glyphdim %d %d numchars %d numlayers %d\r\n", ctx.width, ctx.height, mc, ml);
  1461. fprintf(f, "$type %d (%s)\r\n", ctx.family, fam[ctx.family < 5 ? ctx.family : 5]);
  1462. fprintf(f, "$style%s%s%s%s\r\n", !ctx.style ? " regular" : (ctx.style & SSFN_STYLE_BOLD ? " bold" : ""),
  1463. ctx.style & SSFN_STYLE_ITALIC ? " italic" : "", ctx.style & SSFN_STYLE_USRDEF1 ? "usrdef1" : "",
  1464. ctx.style & SSFN_STYLE_USRDEF2 ? "usrdef2" : "");
  1465. fprintf(f,"$baseline %d\r\n$underline %d\r\n", ctx.baseline, ctx.underline);
  1466. fprintf(f,"$name \"%s\"\r\n", ctx.name ? ctx.name : "");
  1467. fprintf(f,"$family \"%s\"\r\n", ctx.familyname ? ctx.familyname : "");
  1468. fprintf(f,"$subfamily \"%s\"\r\n", ctx.subname ? ctx.subname : "");
  1469. fprintf(f,"$revision \"%s\"\r\n", ctx.revision ? ctx.revision : "");
  1470. fprintf(f,"$manufacturer \"%s\"\r\n", ctx.manufacturer ? ctx.manufacturer : "");
  1471. fprintf(f,"$license \"%s\"\r\n", ctx.license ? ctx.license : "");
  1472. /* characters */
  1473. for(unicode = 0; unicode <= 0x10FFFF; unicode++)
  1474. if((iswhitespace(unicode) && (ctx.glyphs[unicode].adv_x || ctx.glyphs[unicode].adv_y)) ||
  1475. ctx.glyphs[unicode].layers) {
  1476. fprintf(f,"\r\n===U+%06X===w%d=h%d=x%d=y%d=o%d=%s%s%s==%s===\r\n", unicode,
  1477. ctx.glyphs[unicode].width, ctx.glyphs[unicode].height,
  1478. ctx.glyphs[unicode].adv_x, ctx.glyphs[unicode].adv_y, ctx.glyphs[unicode].ovl_x,
  1479. unicode < 32 ? "" : (unicode == '\"' ? "\"\\" : "\""), unicode < 32 ? "" :
  1480. (unicode >= SSFN_LIG_FIRST && unicode <= SSFN_LIG_LAST ? (ctx.ligatures[unicode-SSFN_LIG_FIRST] ?
  1481. ctx.ligatures[unicode-SSFN_LIG_FIRST] : "") : utf8(unicode)), unicode < 32 ? "" : "\"=",
  1482. uninames[uniname(unicode)].name);
  1483. /* layers */
  1484. if(!iswhitespace(unicode) && ctx.glyphs[unicode].layers && ctx.glyphs[unicode].numlayer) {
  1485. /* hinting grid */
  1486. if(hinting) {
  1487. if(!ctx.glyphs[unicode].hintv[0] && !ctx.glyphs[unicode].hinth[0]) sfn_hintgen(unicode);
  1488. if(ctx.glyphs[unicode].hintv[0]) {
  1489. fprintf(f,"V");
  1490. for(i = 0; i < ctx.glyphs[unicode].hintv[0] && ctx.glyphs[unicode].hintv[i+1]; i++)
  1491. fprintf(f," %d", ctx.glyphs[unicode].hintv[i+1]);
  1492. fprintf(f,"\r\n");
  1493. }
  1494. if(ctx.glyphs[unicode].hinth[0]) {
  1495. fprintf(f,"H");
  1496. for(i = 0; i < ctx.glyphs[unicode].hinth[0] && ctx.glyphs[unicode].hinth[i+1]; i++)
  1497. fprintf(f," %d", ctx.glyphs[unicode].hinth[i+1]);
  1498. fprintf(f,"\r\n");
  1499. }
  1500. if(ctx.glyphs[unicode].hintv[0] || ctx.glyphs[unicode].hinth[0])
  1501. fprintf(f,"\r\n");
  1502. }
  1503. for(i = 0; i < ctx.glyphs[unicode].numlayer; i++) {
  1504. if(pbar) (*pbar)(0, 0, ++nc, ml, PBAR_WRTCHARS);
  1505. if(i) fprintf(f,"\r\n");
  1506. if(ctx.glyphs[unicode].layers[i].color < 0xFE) {
  1507. fprintf(f,"f %02X%02X%02X%02X\r\n",
  1508. ctx.cpal[ctx.glyphs[unicode].layers[i].color*4+3],
  1509. ctx.cpal[ctx.glyphs[unicode].layers[i].color*4+2],
  1510. ctx.cpal[ctx.glyphs[unicode].layers[i].color*4+1],
  1511. ctx.cpal[ctx.glyphs[unicode].layers[i].color*4]);
  1512. }
  1513. /* layer type */
  1514. switch(ctx.glyphs[unicode].layers[i].type) {
  1515. case SSFN_FRAG_BITMAP:
  1516. for(y = j = 0; y < ctx.glyphs[unicode].height; y++) {
  1517. for(x = 0; x < ctx.glyphs[unicode].width; x++, j++)
  1518. fprintf(f,"%c", ctx.glyphs[unicode].layers[i].data[j] == 0xFE ? 'X' : '.');
  1519. fprintf(f,"\r\n");
  1520. }
  1521. break;
  1522. case SSFN_FRAG_PIXMAP:
  1523. for(y = j = 0; y < ctx.glyphs[unicode].height; y++) {
  1524. for(x = 0; x < ctx.glyphs[unicode].width; x++, j++) {
  1525. k = ctx.glyphs[unicode].layers[i].data[j] * 4;
  1526. if(k == 0xFE) k = 0;
  1527. if(ctx.glyphs[unicode].layers[i].data[j] > 0xFE || !ctx.cpal[k+3])
  1528. fprintf(f,"%s--------", x ? " " : "");
  1529. else
  1530. fprintf(f,"%s%02X%02X%02X%02X", x ? " " : "", ctx.cpal[k+3], ctx.cpal[k+2],
  1531. ctx.cpal[k+1], ctx.cpal[k]);
  1532. }
  1533. fprintf(f,"\r\n");
  1534. }
  1535. break;
  1536. case SSFN_FRAG_CONTOUR:
  1537. cont = (sfncont_t*)ctx.glyphs[unicode].layers[i].data;
  1538. for(j = 0; j < ctx.glyphs[unicode].layers[i].len; j++, cont++)
  1539. switch(cont->type) {
  1540. case SSFN_CONTOUR_MOVE: fprintf(f,"m %d,%d\r\n", cont->px, cont->py); break;
  1541. case SSFN_CONTOUR_LINE: fprintf(f,"l %d,%d\r\n", cont->px, cont->py); break;
  1542. case SSFN_CONTOUR_QUAD: fprintf(f,"q %d,%d %d,%d\r\n", cont->px, cont->py,
  1543. cont->c1x, cont->c1y); break;
  1544. case SSFN_CONTOUR_CUBIC: fprintf(f,"c %d,%d %d,%d %d,%d\r\n", cont->px, cont->py,
  1545. cont->c1x, cont->c1y, cont->c2x, cont->c2y); break;
  1546. }
  1547. break;
  1548. }
  1549. }
  1550. /* kerning layer */
  1551. if(ctx.glyphs[unicode].numkern && ctx.glyphs[unicode].kern) {
  1552. if(i) fprintf(f,"\r\n");
  1553. for(i = j = 0; i < ctx.glyphs[unicode].numkern; i++) {
  1554. if(!ctx.glyphs[unicode].kern[i].x && !ctx.glyphs[unicode].kern[i].y) continue;
  1555. c = utf8(ctx.glyphs[unicode].kern[i].n);
  1556. if(ctx.glyphs[unicode].kern[i].n >= SSFN_LIG_FIRST &&
  1557. ctx.glyphs[unicode].kern[i].n <= SSFN_LIG_LAST)
  1558. sprintf(c, "U+%06X", ctx.glyphs[unicode].kern[i].n);
  1559. fprintf(f,"%s %s %d", !j ? "k" : ",", c, ctx.glyphs[unicode].kern[i].x);
  1560. if(ctx.glyphs[unicode].kern[i].y)
  1561. fprintf(f," %d", ctx.glyphs[unicode].kern[i].y);
  1562. j++;
  1563. }
  1564. if(j) fprintf(f,"\r\n");
  1565. }
  1566. }
  1567. }
  1568. fprintf(f,"\r\n# End #\r\n");
  1569. fclose(f);
  1570. return 1;
  1571. } else
  1572. return 0;
  1573. } else {
  1574. /* ----------------------------- output to optionally gzip compressed binary ----------------------------- */
  1575. ctx.numfrags = 0;
  1576. if(ctx.frags) { free(ctx.frags); ctx.frags = NULL; }
  1577. /* generate fragments */
  1578. for(unicode = 0; unicode <= 0x10FFFF; unicode++) {
  1579. if(ctx.glyphs[unicode].layers) {
  1580. /* hints first (if exists) */
  1581. if(hinting) {
  1582. if(!ctx.glyphs[unicode].hintv[0] && !ctx.glyphs[unicode].hinth[0]) sfn_hintgen(unicode);
  1583. if(ctx.glyphs[unicode].hintv[0]) {
  1584. memset(hint, 0, 32);
  1585. x = ctx.glyphs[unicode].hintv[1];
  1586. for(i = 1; i < ctx.glyphs[unicode].hintv[0] && ctx.glyphs[unicode].hintv[1+i]; i++)
  1587. hint[i-1] = ctx.glyphs[unicode].hintv[1+i] - ctx.glyphs[unicode].hintv[i];
  1588. sfn_fragchr(unicode, SSFN_FRAG_HINTING, ctx.glyphs[unicode].hintv[0] - 1, 0, x + 1, 0, hint);
  1589. }
  1590. if(ctx.glyphs[unicode].hinth[0]) {
  1591. memset(hint, 0, 32);
  1592. y = ctx.glyphs[unicode].hinth[1];
  1593. for(i = 1; i < ctx.glyphs[unicode].hinth[0] && ctx.glyphs[unicode].hinth[1+i]; i++)
  1594. hint[i-1] = ctx.glyphs[unicode].hinth[1+i] - ctx.glyphs[unicode].hinth[i];
  1595. sfn_fragchr(unicode, SSFN_FRAG_HINTING, ctx.glyphs[unicode].hinth[0] - 1, 0, 0, y + 1, hint);
  1596. }
  1597. }
  1598. /* then kerning (if exists) */
  1599. if(ctx.glyphs[unicode].kern) {
  1600. /* vertical kerning */
  1601. memset(&kgrp, 0, sizeof(sfnkgrp_t));
  1602. l = o = 0; kgrpf = NULL;
  1603. for(i = 0; i < ctx.glyphs[unicode].numkern; i++) {
  1604. if(ctx.glyphs[unicode].kern[i].x) {
  1605. if(!kgrp.first) {
  1606. kgrp.first = kgrp.last = ctx.glyphs[unicode].kern[i].n;
  1607. l = 1;
  1608. crd = realloc(crd, l);
  1609. if(!crd) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1610. crd[0] = ctx.glyphs[unicode].kern[i].x;
  1611. } else {
  1612. if(kgrp.last + 127 < ctx.glyphs[unicode].kern[i].n) {
  1613. kgrp.idx = sfn_kposadd(crd, l);
  1614. kgrpf = (sfnkgrp_t*)realloc(kgrpf, (o+1)*sizeof(sfnkgrp_t));
  1615. if(!kgrpf) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1616. memcpy(&kgrpf[o++], &kgrp, sizeof(sfnkgrp_t));
  1617. kgrp.first = kgrp.last = ctx.glyphs[unicode].kern[i].n;
  1618. l = 1;
  1619. crd = realloc(crd, l);
  1620. if(!crd) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1621. crd[0] = ctx.glyphs[unicode].kern[i].x;
  1622. } else {
  1623. crd = realloc(crd, l + ctx.glyphs[unicode].kern[i].n - kgrp.last);
  1624. if(!crd) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1625. for(k = 0; k < ctx.glyphs[unicode].kern[i].n - kgrp.last - 1; k++, l++)
  1626. crd[l] = 0;
  1627. crd[l++] = ctx.glyphs[unicode].kern[i].x;
  1628. kgrp.last = ctx.glyphs[unicode].kern[i].n;
  1629. }
  1630. }
  1631. }
  1632. }
  1633. if(kgrp.first) {
  1634. kgrp.idx = sfn_kposadd(crd, l);
  1635. kgrpf = (sfnkgrp_t*)realloc(kgrpf, (o+1)*sizeof(sfnkgrp_t));
  1636. if(!kgrpf) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1637. memcpy(&kgrpf[o++], &kgrp, sizeof(sfnkgrp_t));
  1638. }
  1639. if(crd) { free(crd); crd = NULL; }
  1640. if(o && kgrpf) {
  1641. if(!sfn_fragchr(unicode, SSFN_FRAG_KERNING, o, 0, 1, 0, kgrpf)) return 0;
  1642. free(kgrpf);
  1643. }
  1644. /* horizontal kerning */
  1645. memset(&kgrp, 0, sizeof(sfnkgrp_t));
  1646. l = o = 0; kgrpf = NULL;
  1647. for(i = 0; i < ctx.glyphs[unicode].numkern; i++) {
  1648. if(ctx.glyphs[unicode].kern[i].y) {
  1649. if(!kgrp.first) {
  1650. kgrp.first = kgrp.last = ctx.glyphs[unicode].kern[i].n;
  1651. l = 1;
  1652. crd = realloc(crd, l);
  1653. if(!crd) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1654. crd[0] = ctx.glyphs[unicode].kern[i].y;
  1655. } else {
  1656. if(kgrp.last + 127 < ctx.glyphs[unicode].kern[i].n) {
  1657. kgrp.idx = sfn_kposadd(crd, l);
  1658. kgrpf = (sfnkgrp_t*)realloc(kgrpf, (o+1)*sizeof(sfnkgrp_t));
  1659. if(!kgrpf) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1660. memcpy(&kgrpf[o++], &kgrp, sizeof(sfnkgrp_t));
  1661. kgrp.first = kgrp.last = ctx.glyphs[unicode].kern[i].n;
  1662. l = 1;
  1663. crd = realloc(crd, l);
  1664. if(!crd) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1665. crd[0] = ctx.glyphs[unicode].kern[i].y;
  1666. } else {
  1667. crd = realloc(crd, l + ctx.glyphs[unicode].kern[i].n - kgrp.last);
  1668. if(!crd) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1669. for(k = 0; k < ctx.glyphs[unicode].kern[i].n - kgrp.last - 1; k++, l++)
  1670. crd[l] = 0;
  1671. crd[l++] = ctx.glyphs[unicode].kern[i].y;
  1672. kgrp.last = ctx.glyphs[unicode].kern[i].n;
  1673. }
  1674. }
  1675. }
  1676. }
  1677. if(kgrp.first) {
  1678. kgrp.idx = sfn_kposadd(crd, l);
  1679. kgrpf = (sfnkgrp_t*)realloc(kgrpf, (o+1)*sizeof(sfnkgrp_t));
  1680. if(!kgrpf) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1681. memcpy(&kgrpf[o++], &kgrp, sizeof(sfnkgrp_t));
  1682. }
  1683. if(crd) { free(crd); crd = NULL; }
  1684. if(o && kgrpf) {
  1685. if(!sfn_fragchr(unicode, SSFN_FRAG_KERNING, o, 0, 0, 1, kgrpf)) return 0;
  1686. free(kgrpf);
  1687. }
  1688. }
  1689. /* layers to fragments */
  1690. for(j = 0; j < ctx.glyphs[unicode].numlayer; j++) {
  1691. if(pbar) (*pbar)(1, 5, ++nc, ml, PBAR_GENFRAG);
  1692. if(ctx.glyphs[unicode].layers[j].color < 0xFE) {
  1693. if(ctx.glyphs[unicode].numfrag == 255) {
  1694. if(!quiet) fprintf(stderr, "libsfn: too many fragments for U+%06X, truncated to 255.\n", unicode);
  1695. } else {
  1696. ctx.glyphs[unicode].frags = (int*)realloc(ctx.glyphs[unicode].frags,
  1697. (ctx.glyphs[unicode].numfrag + 1) * 3 * sizeof(int));
  1698. if(!ctx.glyphs[unicode].frags) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1699. ctx.glyphs[unicode].frags[ctx.glyphs[unicode].numfrag*3+0] =
  1700. ctx.glyphs[unicode].layers[j].color;
  1701. ctx.glyphs[unicode].frags[ctx.glyphs[unicode].numfrag*3+1] = 255;
  1702. ctx.glyphs[unicode].frags[ctx.glyphs[unicode].numfrag*3+2] = 255;
  1703. ctx.glyphs[unicode].numfrag++;
  1704. }
  1705. }
  1706. switch(ctx.glyphs[unicode].layers[j].type) {
  1707. case SSFN_FRAG_CONTOUR:
  1708. /* normalize coordinates */
  1709. cont = (sfncont_t*)ctx.glyphs[unicode].layers[j].data;
  1710. for(i = 0, x = y = 256; i < ctx.glyphs[unicode].layers[j].len; i++, cont++) {
  1711. if(x > cont->px) x = cont->px;
  1712. if(y > cont->py) y = cont->py;
  1713. if(cont->type >= SSFN_CONTOUR_QUAD) {
  1714. if(x > cont->c1x) x = cont->c1x;
  1715. if(y > cont->c1y) y = cont->c1y;
  1716. if(cont->type >= SSFN_CONTOUR_CUBIC) {
  1717. if(x > cont->c2x) x = cont->c2x;
  1718. if(y > cont->c2y) y = cont->c2y;
  1719. }
  1720. }
  1721. }
  1722. if(x > 254) x = 254;
  1723. norm = (sfncont_t*)malloc(ctx.glyphs[unicode].layers[j].len * sizeof(sfncont_t));
  1724. if(!norm) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1725. memset(norm, 0, ctx.glyphs[unicode].layers[j].len * sizeof(sfncont_t));
  1726. /* add to fragments list */
  1727. cont = (sfncont_t*)ctx.glyphs[unicode].layers[j].data;
  1728. for(i = 0; i < ctx.glyphs[unicode].layers[j].len; i++, cont++) {
  1729. norm[i].type = cont->type;
  1730. norm[i].px = cont->px - x;
  1731. norm[i].py = cont->py - y;
  1732. if(cont->type >= SSFN_CONTOUR_QUAD) {
  1733. norm[i].c1x = cont->c1x - x;
  1734. norm[i].c1y = cont->c1y - y;
  1735. if(cont->type >= SSFN_CONTOUR_CUBIC) {
  1736. norm[i].c2x = cont->c2x - x;
  1737. norm[i].c2y = cont->c2y - y;
  1738. }
  1739. }
  1740. }
  1741. if(!sfn_fragchr(unicode, SSFN_FRAG_CONTOUR, ctx.glyphs[unicode].layers[j].len, 0, x, y, norm))
  1742. return 0;
  1743. free(norm);
  1744. break;
  1745. case SSFN_FRAG_BITMAP:
  1746. case SSFN_FRAG_PIXMAP:
  1747. h = ctx.glyphs[unicode].height; x = 1;
  1748. for(y = 0; y < h; y += x) {
  1749. for(;y < h && isempty(ctx.glyphs[unicode].width,
  1750. ctx.glyphs[unicode].layers[j].data + (h - 1) * ctx.glyphs[unicode].width); h--);
  1751. for(;y < h && isempty(ctx.glyphs[unicode].width,
  1752. ctx.glyphs[unicode].layers[j].data + y * ctx.glyphs[unicode].width); y++);
  1753. for(x = 0; (y + x) < h && !isempty(ctx.glyphs[unicode].width,
  1754. ctx.glyphs[unicode].layers[j].data + (y + x) * ctx.glyphs[unicode].width); x++);
  1755. if(x > 0 && !sfn_fragchr(unicode, ctx.glyphs[unicode].layers[j].type, ctx.glyphs[unicode].width,
  1756. x, 0, y, ctx.glyphs[unicode].layers[j].data + y * ctx.glyphs[unicode].width))
  1757. return 0;
  1758. }
  1759. break;
  1760. }
  1761. }
  1762. /* should never reached, just to be on the safe side */
  1763. if(ctx.glyphs[unicode].numfrag > 255) {
  1764. if(!quiet) fprintf(stderr, "libsfn: too many fragments for U+%06X, truncated to 255.\n", unicode);
  1765. ctx.glyphs[unicode].numfrag = 255;
  1766. }
  1767. }
  1768. }
  1769. /* serialize kerning positions */
  1770. qsort(ctx.kpos, ctx.numkpos, sizeof(sfnkpos_t), possrt);
  1771. for(i = ks = 0; i < ctx.numkpos; i++) {
  1772. ctx.kpos[i].pos = -1;
  1773. for(j = 0; krn && j < ks - ctx.kpos[i].len; j++)
  1774. if(!memcmp(krn, ctx.kpos[i].data, ctx.kpos[i].len)) { ctx.kpos[i].pos = j; break; }
  1775. if(ctx.kpos[i].pos == -1) {
  1776. ctx.kpos[i].pos = ks;
  1777. krn = (unsigned char *)realloc(krn, ks + ctx.kpos[i].len);
  1778. if(!krn) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1779. memcpy(krn + ks, ctx.kpos[i].data, ctx.kpos[i].len);
  1780. ks += ctx.kpos[i].len;
  1781. }
  1782. }
  1783. /* generate header and string table */
  1784. memset(lig, 0, sizeof(lig));
  1785. o = y = sizeof(ssfn_font_t) + (ctx.name ? strlen(ctx.name) : 0) + 1 + (ctx.familyname ? strlen(ctx.familyname) : 0) + 1 +
  1786. (ctx.subname ? strlen(ctx.subname) : 0) + 1 + (ctx.revision ? strlen(ctx.revision) : 0) + 1 +
  1787. (ctx.manufacturer ? strlen(ctx.manufacturer) : 0) + 1 + (ctx.license ? strlen(ctx.license) : 0) + 1;
  1788. for(ls = 0; ls < SSFN_LIG_LAST-SSFN_LIG_FIRST+1 && ctx.ligatures[ls] && ctx.ligatures[ls][0]; ls++) {
  1789. if(o + strlen(ctx.ligatures[ls]) + 1 > 65535) break;
  1790. o += strlen(ctx.ligatures[ls]) + 1;
  1791. }
  1792. hdr = (ssfn_font_t*)malloc(o);
  1793. if(!hdr) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1794. memset(hdr, 0, o);
  1795. memcpy(hdr->magic, SSFN_MAGIC, 4);
  1796. hdr->size = o + 4;
  1797. hdr->type = (ctx.family & 0x0F) | ((ctx.style & 0x0F) << 4);
  1798. hdr->width = ctx.width;
  1799. hdr->height = ctx.height;
  1800. hdr->baseline = ctx.baseline;
  1801. hdr->underline = ctx.underline;
  1802. strs = ((char*)hdr) + sizeof(ssfn_font_t);
  1803. if(ctx.name) { j = strlen(ctx.name) + 1; memcpy(strs, ctx.name, j); strs += j; } else strs++;
  1804. if(ctx.familyname) { j = strlen(ctx.familyname) + 1; memcpy(strs, ctx.familyname, j); strs += j; } else strs++;
  1805. if(ctx.subname) { j = strlen(ctx.subname) + 1; memcpy(strs, ctx.subname, j); strs += j; } else strs++;
  1806. if(ctx.revision) { j = strlen(ctx.revision) + 1; memcpy(strs, ctx.revision, j); strs += j; } else strs++;
  1807. if(ctx.manufacturer) { j = strlen(ctx.manufacturer) + 1; memcpy(strs, ctx.manufacturer, j); strs += j; } else strs++;
  1808. if(ctx.license) { j = strlen(ctx.license) + 1; memcpy(strs, ctx.license, j); strs += j; } else strs++;
  1809. for(j = 0; j < ls; j++) {
  1810. lig[j] = y;
  1811. x = strlen(ctx.ligatures[j]) + 1;
  1812. memcpy(strs, ctx.ligatures[j], x);
  1813. strs += x; y += x;
  1814. }
  1815. /* compress fragments */
  1816. for(i = 0; i < ctx.numfrags; i++) {
  1817. if(pbar) (*pbar)(2, 5, i, ctx.numfrags, PBAR_COMPFRAG);
  1818. }
  1819. /* serialize fragments */
  1820. fidx = (int*)malloc(ctx.numfrags * sizeof(int));
  1821. qsort(ctx.frags, ctx.numfrags, sizeof(sfnfrag_t), frgsrt);
  1822. for(i = 0; i < ctx.numfrags; i++)
  1823. fidx[ctx.frags[i].idx] = i;
  1824. hdr->fragments_offs = o;
  1825. for(i = 0; i < ctx.numfrags; i++) {
  1826. if(pbar) (*pbar)(3, 5, i, ctx.numfrags, PBAR_SERFRAG);
  1827. ctx.frags[i].pos = o + fs;
  1828. frg = (unsigned char*)realloc(frg, fs + 5 + ctx.frags[i].len);
  1829. if(!frg) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1830. switch(ctx.frags[i].type) {
  1831. case SSFN_FRAG_CONTOUR:
  1832. if(ctx.frags[i].w>64)
  1833. frg[fs++] = (((ctx.frags[i].w - 1) >> 8) & 0x3F) | 0x40;
  1834. frg[fs++] = (ctx.frags[i].w - 1) & 0xFF;
  1835. k = fs; fs += (ctx.frags[i].w + 3) / 4;
  1836. memset(frg + k, 0, fs - k);
  1837. for(j = 0, cont = (sfncont_t*)ctx.frags[i].data; j < ctx.frags[i].w; j++, cont++) {
  1838. frg[k + (j / 4)] |= cont->type << ((j & 3) * 2);
  1839. frg[fs++] = cont->px;
  1840. frg[fs++] = cont->py;
  1841. if(cont->type >= SSFN_CONTOUR_QUAD) {
  1842. frg[fs++] = cont->c1x;
  1843. frg[fs++] = cont->c1y;
  1844. if(cont->type >= SSFN_CONTOUR_CUBIC) {
  1845. frg[fs++] = cont->c2x;
  1846. frg[fs++] = cont->c2y;
  1847. }
  1848. }
  1849. }
  1850. break;
  1851. case SSFN_FRAG_BITMAP:
  1852. k = ((ctx.frags[i].w + 7) >> 3) & 0x1F;
  1853. frg[fs++] = 0x80 | (k - 1);
  1854. frg[fs++] = ctx.frags[i].h - 1;
  1855. for(y = 0; y < ctx.frags[i].h; y++) {
  1856. memset(frg + fs, 0, k);
  1857. for(x = 0; x < ctx.frags[i].w; x++) {
  1858. if(ctx.frags[i].data[y * ctx.frags[i].w + x] != 0xFF)
  1859. frg[fs + (x >> 3)] |= 1 << (x & 7);
  1860. }
  1861. fs += k;
  1862. }
  1863. break;
  1864. case SSFN_FRAG_PIXMAP:
  1865. tmp = rle_enc(ctx.frags[i].data, ctx.frags[i].w * ctx.frags[i].h, &k);
  1866. if(!tmp || k < 2) return 0;
  1867. frg = (unsigned char*)realloc(frg, fs + 5 + k);
  1868. if(!frg) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1869. frg[fs++] = 0xA0 | (((k - 1) >> 8) & 0x1F);
  1870. frg[fs++] = (k - 1) & 0xFF;
  1871. frg[fs++] = ctx.frags[i].w - 1;
  1872. frg[fs++] = ctx.frags[i].h - 1;
  1873. memcpy(frg + fs, tmp, k);
  1874. fs += k;
  1875. free(tmp);
  1876. break;
  1877. case SSFN_FRAG_KERNING:
  1878. frg[fs++] = (((ctx.frags[i].w - 1) >> 8) & 0x3) | 0xC0 | /*kerning context*/((0 & 7) << 2);
  1879. frg[fs++] = (ctx.frags[i].w - 1) & 0xFF;
  1880. for(j = 0, kgrpf = (sfnkgrp_t*)ctx.frags[i].data; j < ctx.frags[i].w; j++, kgrpf++) {
  1881. /* this is not efficient, but fast enough */
  1882. for(k = x = 0; k < ctx.numkpos; k++)
  1883. if(ctx.kpos[k].idx == kgrpf->idx) { x = ctx.kpos[k].pos; break; }
  1884. frg[fs++] = kgrpf->first & 0xFF;
  1885. frg[fs++] = (kgrpf->first >> 8) & 0xFF;
  1886. frg[fs++] = ((kgrpf->first >> 16) & 0x0F) | ((x >> 20) & 0xF0);
  1887. frg[fs++] = kgrpf->last & 0xFF;
  1888. frg[fs++] = (kgrpf->last >> 8) & 0xFF;
  1889. frg[fs++] = ((kgrpf->last >> 16) & 0x0F) | ((x >> 12) & 0xF0);
  1890. frg[fs++] = x & 0xFF;
  1891. frg[fs++] = (x >> 8) & 0xFF;
  1892. }
  1893. break;
  1894. case SSFN_FRAG_HINTING:
  1895. if(ctx.frags[i].w && ctx.frags[i].data) {
  1896. frg[fs++] = ((ctx.frags[i].w & 31) | 0xE0);
  1897. memcpy(frg + fs, ctx.frags[i].data, ctx.frags[i].w);
  1898. fs += ctx.frags[i].w;
  1899. } else
  1900. frg[fs++] = 0xE0;
  1901. break;
  1902. }
  1903. }
  1904. hdr->size += fs;
  1905. o += fs;
  1906. /* serialize character map */
  1907. hdr->characters_offs = o;
  1908. unicode = -1;
  1909. for(i = nc = 0; i <= 0x10FFFF; i++) {
  1910. if((iswhitespace(i) && (ctx.glyphs[i].adv_x || ctx.glyphs[i].adv_y)) ||
  1911. ctx.glyphs[i].layers) {
  1912. if(pbar) (*pbar)(4, 5, ++nc, mc, PBAR_WRTCHARS);
  1913. j = i - unicode - 1;
  1914. chr = (unsigned char*)realloc(chr, cs+256+ctx.glyphs[i].numfrag*6);
  1915. if(!chr) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1916. while(j > 0) {
  1917. if(j <= 64) { chr[cs++] = ((j-1) & 0x3F) | 0x80; break; }
  1918. else {
  1919. while(j > 65536) { chr[cs++] = 0xFF; j -= 65536; }
  1920. while(j > 16128) { chr[cs++] = 0xFE; chr[cs++] = 0xFF; j -= 16128; }
  1921. if(j > 64) { chr[cs++] = (((j-1) >> 8) & 0x3F) | 0xC0; chr[cs++] = (j-1) & 0xFF; break; }
  1922. }
  1923. }
  1924. k = (ctx.glyphs[i].ovl_x & 0x3F);
  1925. for(j = 0; j < ctx.glyphs[i].numfrag; j++)
  1926. if(ctx.frags[fidx[ctx.glyphs[i].frags[j*3]]].pos > 0xFFFFFF) { k |= 0x40; break; }
  1927. qsort(ctx.glyphs[i].frags, ctx.glyphs[i].numfrag, 3*sizeof(int), frdsrt);
  1928. chr[cs++] = k;
  1929. chr[cs++] = ctx.glyphs[i].numfrag;
  1930. chr[cs++] = ctx.glyphs[i].width;
  1931. chr[cs++] = ctx.glyphs[i].height;
  1932. chr[cs++] = ctx.glyphs[i].adv_x;
  1933. chr[cs++] = ctx.glyphs[i].adv_y;
  1934. for(j = 0; j < ctx.glyphs[i].numfrag; j++) {
  1935. chr[cs++] = ctx.glyphs[i].frags[j*3+1];
  1936. chr[cs++] = ctx.glyphs[i].frags[j*3+2];
  1937. if(ctx.glyphs[i].frags[j*3+1] == 255) {
  1938. memcpy(chr + cs, &ctx.glyphs[i].frags[j*3+0], 3);
  1939. cs += 3;
  1940. if(k & 0x40)
  1941. chr[cs++] = 0;
  1942. } else {
  1943. x = ctx.frags[fidx[ctx.glyphs[i].frags[j*3+0]]].pos;
  1944. chr[cs++] = x & 0xFF;
  1945. chr[cs++] = (x >> 8) & 0xFF;
  1946. chr[cs++] = (x >> 16) & 0xFF;
  1947. if(k & 0x40)
  1948. chr[cs++] = (x >> 24) & 0xFF;
  1949. }
  1950. }
  1951. unicode = i;
  1952. }
  1953. }
  1954. free(fidx);
  1955. j = 0x110000 - unicode;
  1956. chr = (unsigned char*)realloc(chr, cs+256);
  1957. if(!chr) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1958. while(j > 0) {
  1959. if(j <= 64) { chr[cs++] = ((j-1) & 0x3F) | 0x80; break; }
  1960. else {
  1961. while(j > 65536) { chr[cs++] = 0xFF; j -= 65536; }
  1962. while(j > 16128) { chr[cs++] = 0xFE; chr[cs++] = 0xFF; j -= 16128; }
  1963. if(j > 64) { chr[cs++] = (((j-1) >> 8) & 0x3F) | 0xC0; chr[cs++] = (j-1) & 0xFF; break; }
  1964. }
  1965. }
  1966. hdr->size += cs;
  1967. o += cs;
  1968. /* ligatures */
  1969. if(ls) {
  1970. hdr->ligature_offs = o;
  1971. hdr->size += ls*2;
  1972. o += ls*2;
  1973. }
  1974. /* kerning table */
  1975. if(ks) {
  1976. hdr->kerning_offs = o;
  1977. hdr->size += ks;
  1978. o += ks;
  1979. }
  1980. /* color map */
  1981. if(ctx.numcpal) {
  1982. hdr->cmap_offs = o;
  1983. hdr->size += ctx.numcpal * 4;
  1984. }
  1985. /* write out file */
  1986. x = 0;
  1987. if(comp) {
  1988. gzs = hdr->fragments_offs + fs + cs + ls*2 + ks + ctx.numcpal*4 + 4;
  1989. stream.avail_out = compressBound(gzs) + 16;
  1990. gz = malloc(stream.avail_out);
  1991. if(!gz) { fprintf(stderr,"libsfn: memory allocation error\n"); return 0; }
  1992. stream.zalloc = (alloc_func)0;
  1993. stream.zfree = (free_func)0;
  1994. stream.opaque = (voidpf)0;
  1995. if(deflateInit(&stream, 9) != Z_OK) { fprintf(stderr,"libsfn: deflate error\n"); return 0; }
  1996. stream.next_out = (z_const Bytef *)gz + 8;
  1997. if(pbar) (*pbar)(5, 5, 0, 5, PBAR_WRTFILE);
  1998. stream.avail_in = hdr->fragments_offs;
  1999. stream.next_in = (z_const Bytef *)hdr;
  2000. crc = crc32(0, stream.next_in, stream.avail_in);
  2001. deflate(&stream, Z_NO_FLUSH);
  2002. if(pbar) (*pbar)(5, 5, 1, 5, PBAR_WRTFILE);
  2003. stream.avail_in = fs;
  2004. stream.next_in = (z_const Bytef *)frg;
  2005. crc = crc32(crc, stream.next_in, stream.avail_in);
  2006. deflate(&stream, Z_NO_FLUSH);
  2007. if(pbar) (*pbar)(5, 5, 2, 5, PBAR_WRTFILE);
  2008. stream.avail_in = cs;
  2009. stream.next_in = (z_const Bytef *)chr;
  2010. crc = crc32(crc, stream.next_in, stream.avail_in);
  2011. deflate(&stream, Z_NO_FLUSH);
  2012. if(ls) {
  2013. if(pbar) (*pbar)(5, 5, 3, 5, PBAR_WRTFILE);
  2014. stream.avail_in = ls*2;
  2015. stream.next_in = (z_const Bytef *)lig;
  2016. crc = crc32(crc, stream.next_in, stream.avail_in);
  2017. deflate(&stream, Z_NO_FLUSH);
  2018. }
  2019. if(ks) {
  2020. if(pbar) (*pbar)(5, 5, 4, 5, PBAR_WRTFILE);
  2021. stream.avail_in = ks;
  2022. stream.next_in = (z_const Bytef *)krn;
  2023. crc = crc32(crc, stream.next_in, stream.avail_in);
  2024. deflate(&stream, Z_NO_FLUSH);
  2025. }
  2026. if(ctx.numcpal) {
  2027. if(pbar) (*pbar)(5, 5, 5, 5, PBAR_WRTFILE);
  2028. stream.avail_in = ctx.numcpal*4;
  2029. stream.next_in = (z_const Bytef *)ctx.cpal;
  2030. crc = crc32(crc, stream.next_in, stream.avail_in);
  2031. deflate(&stream, Z_NO_FLUSH);
  2032. }
  2033. stream.avail_in = 4;
  2034. stream.next_in = (z_const Bytef *)SSFN_ENDMAGIC;
  2035. crc = crc32(crc, stream.next_in, stream.avail_in);
  2036. deflate(&stream, Z_FINISH);
  2037. memset(gz, 0, 10);
  2038. gz[0] = 0x1f; gz[1] = 0x8b; gz[2] = 0x8; gz[9] = 3;
  2039. f = fopen(filename, "wb");
  2040. if(f) {
  2041. ctx.filename = filename;
  2042. fwrite(gz, stream.total_out + 4, 1, f);
  2043. fwrite(&crc, 4, 1, f);
  2044. fwrite(&gzs, 4, 1, f);
  2045. fclose(f);
  2046. x = stream.total_out + 12;
  2047. } else {
  2048. fprintf(stderr, "libsfn: unable to write '%s'\n", filename);
  2049. }
  2050. free(gz);
  2051. } else {
  2052. f = fopen(filename, "wb");
  2053. if(f) {
  2054. ctx.filename = filename;
  2055. if(pbar) (*pbar)(5, 5, 0, 5, PBAR_WRTFILE);
  2056. fwrite(hdr, hdr->fragments_offs, 1, f);
  2057. if(pbar) (*pbar)(5, 5, 1, 5, PBAR_WRTFILE);
  2058. if(fs) fwrite(frg, fs, 1, f);
  2059. if(pbar) (*pbar)(5, 5, 2, 5, PBAR_WRTFILE);
  2060. if(cs) fwrite(chr, cs, 1, f);
  2061. if(pbar) (*pbar)(5, 5, 3, 5, PBAR_WRTFILE);
  2062. if(ls) fwrite(lig, ls*2, 1, f);
  2063. if(pbar) (*pbar)(5, 5, 4, 5, PBAR_WRTFILE);
  2064. if(ks) fwrite(krn, ks, 1, f);
  2065. if(pbar) (*pbar)(5, 5, 5, 5, PBAR_WRTFILE);
  2066. if(ctx.numcpal) fwrite(ctx.cpal, ctx.numcpal*4, 1, f);
  2067. fwrite(SSFN_ENDMAGIC, 4, 1, f);
  2068. fclose(f);
  2069. x = hdr->size;
  2070. } else {
  2071. fprintf(stderr, "libsfn: unable to write '%s'\n", filename);
  2072. }
  2073. }
  2074. /* free resources */
  2075. for(unicode = 0; unicode <= 0x10FFFF; unicode++) {
  2076. if(ctx.glyphs[unicode].frags) {
  2077. free(ctx.glyphs[unicode].frags);
  2078. ctx.glyphs[unicode].frags = NULL;
  2079. }
  2080. ctx.glyphs[unicode].numfrag = 0;
  2081. }
  2082. if(ctx.frags) {
  2083. for(i = 0; i < ctx.numfrags; i++)
  2084. free(ctx.frags[i].data);
  2085. free(ctx.frags);
  2086. ctx.frags = NULL;
  2087. }
  2088. if(ctx.kpos) {
  2089. for(i = 0; i < ctx.numkpos; i++)
  2090. free(ctx.kpos[i].data);
  2091. free(ctx.kpos);
  2092. ctx.kpos = NULL;
  2093. }
  2094. if(frg) free(frg);
  2095. if(krn) free(krn);
  2096. if(chr) free(chr);
  2097. free(hdr);
  2098. ctx.numfrags = 0;
  2099. }
  2100. return x;
  2101. }
  2102. /**
  2103. * Specify which glyphs to include using a sample file
  2104. *
  2105. * @param filename file with UTF-8 encoded characters
  2106. */
  2107. void sfn_rangesample(char *filename)
  2108. {
  2109. unsigned char *data = NULL, *ptr;
  2110. int size, u;
  2111. FILE *f;
  2112. /* assume ASCII is always included, set skip to the rest */
  2113. if(!skipcleared) {
  2114. skipcleared = 1;
  2115. memset(&ctx.skip, 0, 16);
  2116. memset(&ctx.skip[16], 0xff, sizeof(ctx.skip) - 16);
  2117. }
  2118. f = fopen(filename, "rb");
  2119. if(!f) return;
  2120. fseek(f, 0, SEEK_END);
  2121. size = (int)ftell(f);
  2122. fseek(f, 0, SEEK_SET);
  2123. if(!size) { fclose(f); return; }
  2124. data = (unsigned char*)malloc(size + 5);
  2125. if(!data) { fclose(f); return; }
  2126. memset(data, 0, size + 5);
  2127. if(!fread(data, 1, size, f)) { free(data); fclose(f); return; }
  2128. fclose(f);
  2129. /* remove characters in the file from the skip list */
  2130. for(ptr = data; ptr < data + size;) {
  2131. u = ssfn_utf8((char**)&ptr);
  2132. if(!u) break;
  2133. sfn_skipdel(u);
  2134. }
  2135. free(data);
  2136. }
  2137. /**
  2138. * Set the family type
  2139. *
  2140. * @param t family type
  2141. */
  2142. void sfn_setfamilytype(int t)
  2143. {
  2144. if(t >= 0 && t <= SSFN_FAMILY_HAND) ctx.family = t;
  2145. }
  2146. /**
  2147. * Set one of the string attributes
  2148. *
  2149. * @param s pointer to a string pointer
  2150. * @param n new string
  2151. * @param len length of the string if not zero terminated
  2152. */
  2153. void sfn_setstr(char **s, char *n, int len)
  2154. {
  2155. int i, l = len;
  2156. if(*s) { free(*s); *s = NULL; }
  2157. if(!n) return;
  2158. while(*n == ' ' || *n == '\t') { n++; if(len) l--; }
  2159. if(len && !l) return;
  2160. for(i = 0; (!len || i < l) && n[i] && n[i] != '\"' && n[i] != '\r' && n[i] != '\n'; i++);
  2161. while(i && (n[i-1] == ' ' || n[i-1] == '\t')) i--;
  2162. if(!i) return;
  2163. *s = malloc(i + 1);
  2164. if(!*s) return;
  2165. memcpy(*s, n, i);
  2166. *(*s + i) = 0;
  2167. }
  2168. /**
  2169. * Sanitize context, make sure dimensions and positions are valid
  2170. */
  2171. void sfn_sanitize(int unicode)
  2172. {
  2173. sfncont_t *cont;
  2174. int i, j, k, l, m = 0, n, o, h, s, e;
  2175. if(unicode == -1) { s = 0; e = 0x110000; } else { s = unicode; e = unicode + 1; }
  2176. for(i = s; i < e; i++) {
  2177. if(ctx.glyphs[i].layers) {
  2178. h = 0;
  2179. for(j = 0; j < ctx.glyphs[i].numlayer; j++)
  2180. if(ctx.glyphs[i].layers[j].type == SSFN_FRAG_CONTOUR) {
  2181. ctx.glyphs[i].width = ctx.glyphs[i].height = 0;
  2182. break;
  2183. }
  2184. for(j = 0; j < ctx.glyphs[i].numlayer; j++) {
  2185. if(ctx.glyphs[i].layers[j].type == SSFN_FRAG_CONTOUR) {
  2186. ctx.glyphs[i].layers[j].minx = ctx.glyphs[i].layers[j].miny = 256;
  2187. for(k = 0, cont = (sfncont_t*)ctx.glyphs[i].layers[j].data; k < ctx.glyphs[i].layers[j].len; k++, cont++) {
  2188. if(cont->px > m) m = cont->px;
  2189. if(cont->px + 1 > ctx.glyphs[i].width) ctx.glyphs[i].width = cont->px + 1;
  2190. if(cont->py + 1 > ctx.glyphs[i].height) ctx.glyphs[i].height = cont->py + 1;
  2191. if(cont->px < ctx.glyphs[i].layers[j].minx) ctx.glyphs[i].layers[j].minx = cont->px;
  2192. if(cont->py < ctx.glyphs[i].layers[j].miny) ctx.glyphs[i].layers[j].miny = cont->py;
  2193. if(cont->type >= SSFN_CONTOUR_QUAD) {
  2194. if(cont->c1x > m) m = cont->c1x;
  2195. if(cont->c1x + 1 > ctx.glyphs[i].width) ctx.glyphs[i].width = cont->c1x + 1;
  2196. if(cont->c1y + 1 > ctx.glyphs[i].height) ctx.glyphs[i].height = cont->c1y + 1;
  2197. if(cont->c1x < ctx.glyphs[i].layers[j].minx) ctx.glyphs[i].layers[j].minx = cont->c1x;
  2198. if(cont->c1y < ctx.glyphs[i].layers[j].miny) ctx.glyphs[i].layers[j].miny = cont->c1y;
  2199. if(cont->type >= SSFN_CONTOUR_CUBIC) {
  2200. if(cont->c2x > m) m = cont->c2x;
  2201. if(cont->c2x + 1 > ctx.glyphs[i].width) ctx.glyphs[i].width = cont->c2x + 1;
  2202. if(cont->c2y + 1 > ctx.glyphs[i].height) ctx.glyphs[i].height = cont->c2y + 1;
  2203. if(cont->c2x < ctx.glyphs[i].layers[j].minx) ctx.glyphs[i].layers[j].minx = cont->c2x;
  2204. if(cont->c2y < ctx.glyphs[i].layers[j].miny) ctx.glyphs[i].layers[j].miny = cont->c2y;
  2205. }
  2206. }
  2207. }
  2208. } else {
  2209. ctx.glyphs[i].layers[j].minx = ctx.glyphs[i].layers[j].miny = 256;
  2210. for(l = o = 0; l < ctx.glyphs[i].height; l++)
  2211. for(k = 0; k < ctx.glyphs[i].width; k++)
  2212. if(ctx.glyphs[i].layers[j].data[l * ctx.glyphs[i].width + k] != 0xFF) {
  2213. if(k > o) o = k;
  2214. if(k > m) m = k;
  2215. if(k < ctx.glyphs[i].layers[j].minx) ctx.glyphs[i].layers[j].minx = k;
  2216. if(l < ctx.glyphs[i].layers[j].miny) ctx.glyphs[i].layers[j].miny = l;
  2217. }
  2218. if(propo && ctx.glyphs[i].adv_x && (ctx.glyphs[i].layers[j].minx || o + 1 != ctx.glyphs[i].width)) {
  2219. for(l = 0; l < ctx.glyphs[i].height; l++) {
  2220. for(n = 0, k = ctx.glyphs[i].layers[j].minx; k <= o; k++, n++)
  2221. ctx.glyphs[i].layers[j].data[l * ctx.glyphs[i].width + n] = ctx.glyphs[i].layers[j].data[l * ctx.glyphs[i].width + k];
  2222. for(; n < ctx.glyphs[i].width; n++) ctx.glyphs[i].layers[j].data[l * ctx.glyphs[i].width + n] = 0xFF;
  2223. }
  2224. if(i != 32 && i != 160) ctx.glyphs[i].adv_x = o - ctx.glyphs[i].layers[j].minx + 2 + adv;
  2225. ctx.glyphs[i].layers[j].minx = 0;
  2226. }
  2227. }
  2228. if(ctx.glyphs[i].layers[j].color >= ctx.numcpal || ctx.glyphs[i].layers[j].type == SSFN_FRAG_PIXMAP)
  2229. ctx.glyphs[i].layers[j].color = 0xFE;
  2230. /* try to autodetect base line */
  2231. if(!ctx.baseline && (ctx.glyphs[i].layers[j].type == SSFN_FRAG_BITMAP || ctx.glyphs[i].layers[j].type ==
  2232. SSFN_FRAG_PIXMAP) && ((i >= '0' && i <= '9') || (i >= 'A' && i < 'Q') || (i >= 'a' && i < 'g') ||
  2233. i == 'h' || i == 'i' || (i >= 'k' && i < 'p') || (i >= 'r' && i < 'y') || i == 'z')) {
  2234. if(ctx.glyphs[i].layers[j].type == SSFN_FRAG_CONTOUR) {
  2235. if(ctx.glyphs[i].height > h + 1) h = ctx.glyphs[i].height - 1;
  2236. } else {
  2237. l = ctx.glyphs[i].height - 1;
  2238. for(;0 < l && isempty(ctx.glyphs[i].width,
  2239. ctx.glyphs[i].layers[j].data + l * ctx.glyphs[i].width); l--);
  2240. if(l > h) h = l;
  2241. }
  2242. }
  2243. }
  2244. if(!ctx.baseline) ctx.baseline = h;
  2245. qsort(ctx.glyphs[i].layers, ctx.glyphs[i].numlayer, sizeof(sfnlayer_t), lyrsrt);
  2246. }
  2247. if(ctx.glyphs[i].kern)
  2248. qsort(ctx.glyphs[i].kern, ctx.glyphs[i].numkern, sizeof(sfnkern_t), krnsrt);
  2249. if(ctx.glyphs[i].ovl_x > 63) ctx.glyphs[i].ovl_x = 63;
  2250. if(!ctx.glyphs[i].adv_x && !ctx.glyphs[i].adv_y && m)
  2251. ctx.glyphs[i].adv_x = m + 2 + adv;
  2252. if(ctx.glyphs[i].adv_x) ctx.glyphs[i].adv_y = 0;
  2253. if(ctx.family == SSFN_FAMILY_MONOSPACE && advrecalc) {
  2254. if(ctx.glyphs[i].adv_x) ctx.glyphs[i].adv_x = ((ctx.glyphs[i].width + 7) & ~7) + adv;
  2255. else ctx.glyphs[i].adv_y = ctx.height + adv;
  2256. }
  2257. if(monosize > 0) {
  2258. ctx.glyphs[i].adv_x = ((ctx.glyphs[i].adv_x + monosize - 1) / monosize) * monosize;
  2259. ctx.glyphs[i].adv_y = ((ctx.glyphs[i].adv_y + monosize - 1) / monosize) * monosize;
  2260. }
  2261. }
  2262. ctx.width = ctx.height = 0;
  2263. for(i = 0; i < 0x110000; i++) {
  2264. if(ctx.glyphs[i].width > ctx.width) ctx.width = ctx.glyphs[i].width;
  2265. if(ctx.glyphs[i].height > ctx.height) ctx.height = ctx.glyphs[i].height;
  2266. }
  2267. if(!ctx.baseline || ctx.baseline > ctx.height) ctx.baseline = ctx.height * 80 / 100;
  2268. if(relul) ctx.underline = ctx.baseline + relul;
  2269. if(ctx.underline <= ctx.baseline || ctx.underline > ctx.height)
  2270. ctx.underline = ctx.baseline + (ctx.height - ctx.baseline - 1) / 2;
  2271. if(ctx.family > SSFN_FAMILY_HAND) ctx.family = SSFN_FAMILY_HAND;
  2272. }
  2273. /* add a line to contour */
  2274. static void _sfn_l(int p, int h, int x, int y)
  2275. {
  2276. if(x < 0 || y < 0 || x >= p || y >= h || (
  2277. ((ctx.lx + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((x + (1 << (SSFN_PREC-1))) >> SSFN_PREC) &&
  2278. ((ctx.ly + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((y + (1 << (SSFN_PREC-1))) >> SSFN_PREC))) return;
  2279. if(ctx.ap <= ctx.np) {
  2280. ctx.ap = ctx.np + 512;
  2281. ctx.p = (uint16_t*)realloc(ctx.p, ctx.ap * sizeof(uint16_t));
  2282. if(!ctx.p) { ctx.ap = ctx.np = 0; return; }
  2283. }
  2284. if(!ctx.np) {
  2285. ctx.p[0] = ctx.mx;
  2286. ctx.p[1] = ctx.my;
  2287. ctx.np += 2;
  2288. }
  2289. ctx.p[ctx.np+0] = x;
  2290. ctx.p[ctx.np+1] = y;
  2291. ctx.np += 2;
  2292. ctx.lx = x; ctx.ly = y;
  2293. }
  2294. /* add a Bezier curve to contour */
  2295. static void _sfn_b(int p,int h, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l)
  2296. {
  2297. int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y;
  2298. if(l<4 && (x0!=x3 || y0!=y3)) {
  2299. m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0;
  2300. m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1;
  2301. m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2;
  2302. m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y;
  2303. m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y;
  2304. m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y;
  2305. _sfn_b(p,h, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1);
  2306. _sfn_b(p,h, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1);
  2307. } else
  2308. if(l) _sfn_l(p,h, x3, y3);
  2309. }
  2310. /* convert Bezier to line */
  2311. static int _sfn_b2l(sfncont_t *cont,int i, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l)
  2312. {
  2313. int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y;
  2314. if(l<4 && (x0!=x3 || y0!=y3)) {
  2315. m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0;
  2316. m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1;
  2317. m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2;
  2318. m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y;
  2319. m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y;
  2320. m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y;
  2321. i = _sfn_b2l(cont,i, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1);
  2322. i = _sfn_b2l(cont,i, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1);
  2323. } else
  2324. if(l && (!i || cont[i - 1].px != x3 || cont[i - 1].py != y3)) {
  2325. cont[i].type = SSFN_CONTOUR_LINE;
  2326. cont[i].px = x3;
  2327. cont[i].py = y3;
  2328. i++;
  2329. }
  2330. return i;
  2331. }
  2332. /**
  2333. * Rasterize a layer or glyph
  2334. *
  2335. * @param size size
  2336. * @param unicode code point
  2337. * @param layer layer index or -1 for all
  2338. * @param postproc do postprocess for bitmaps
  2339. * @param g glyph data to return
  2340. */
  2341. int sfn_glyph(int size, int unicode, int layer, int postproc, sfngc_t *g)
  2342. {
  2343. uint8_t ci = 0, cb = 0;
  2344. uint16_t r[640];
  2345. int i, j, k, l, p, m, n, o, w, h, a, A, b, B, nr, x;
  2346. sfncont_t *cont;
  2347. if(unicode < 0 || unicode > 0x10FFFF || !ctx.glyphs[unicode].numlayer || layer >= ctx.glyphs[unicode].numlayer ||
  2348. ctx.height < 1) return 0;
  2349. h = (size > ctx.height ? (size + 4) & ~3 : ctx.height);
  2350. w = ctx.glyphs[unicode].width * h / ctx.height;
  2351. p = w + (ci ? h / SSFN_ITALIC_DIV : 0) + cb;
  2352. g->p = p;
  2353. g->h = h;
  2354. if(p * h >= (260 + 260 / SSFN_ITALIC_DIV) << 8) return 0;
  2355. g->x = ctx.glyphs[unicode].adv_x * h / ctx.height;
  2356. g->y = ctx.glyphs[unicode].adv_y * h / ctx.height;
  2357. g->o = ctx.glyphs[unicode].ovl_x * h / ctx.height;
  2358. memset(&g->data, 0xFF, p * h);
  2359. ctx.lx = ctx.ly = 0;
  2360. for(n = (layer == -1 ? 0 : layer); n < (layer == -1 ? ctx.glyphs[unicode].numlayer : layer + 1); n++) {
  2361. switch(ctx.glyphs[unicode].layers[n].type) {
  2362. case SSFN_FRAG_CONTOUR:
  2363. for(i = 0, ctx.np = 0, cont = (sfncont_t*)ctx.glyphs[unicode].layers[n].data;
  2364. i < ctx.glyphs[unicode].layers[n].len; i++, cont++) {
  2365. k = (cont->px << SSFN_PREC) * h / ctx.height; m = (cont->py << SSFN_PREC) * h / ctx.height;
  2366. switch(cont->type) {
  2367. case SSFN_CONTOUR_MOVE: ctx.mx = ctx.lx = k; ctx.my = ctx.ly = m; break;
  2368. case SSFN_CONTOUR_LINE: _sfn_l(p << SSFN_PREC, h << SSFN_PREC, k, m); break;
  2369. case SSFN_CONTOUR_QUAD:
  2370. a = (cont->c1x << SSFN_PREC) * h / ctx.height;
  2371. A = (cont->c1y << SSFN_PREC) * h / ctx.height;
  2372. _sfn_b(p << SSFN_PREC,h << SSFN_PREC, ctx.lx,ctx.ly, ((a-ctx.lx)/2)+ctx.lx,
  2373. ((A-ctx.ly)/2)+ctx.ly, ((k-a)/2)+a,((m-A)/2)+A, k,m, 0);
  2374. break;
  2375. case SSFN_CONTOUR_CUBIC:
  2376. a = (cont->c1x << SSFN_PREC) * h / ctx.height;
  2377. A = (cont->c1y << SSFN_PREC) * h / ctx.height;
  2378. b = (cont->c2x << SSFN_PREC) * h / ctx.height;
  2379. B = (cont->c2y << SSFN_PREC) * h / ctx.height;
  2380. _sfn_b(p << SSFN_PREC,h << SSFN_PREC, ctx.lx,ctx.ly, a,A, b,B, k,m, 0);
  2381. break;
  2382. }
  2383. }
  2384. if(ctx.mx != ctx.lx || ctx.my != ctx.ly) _sfn_l(p << SSFN_PREC, h << SSFN_PREC, ctx.mx, ctx.my);
  2385. if(ctx.np > 4) {
  2386. for(b = A = B = o = 0; b < h; b++, B += p) {
  2387. a = b << SSFN_PREC;
  2388. for(nr = 0, i = 0; i < ctx.np - 3; i += 2) {
  2389. if( (ctx.p[i+1] < a && ctx.p[i+3] >= a) ||
  2390. (ctx.p[i+3] < a && ctx.p[i+1] >= a)) {
  2391. if((ctx.p[i+1] >> SSFN_PREC) == (ctx.p[i+3] >> SSFN_PREC))
  2392. x = (((int)ctx.p[i]+(int)ctx.p[i+2])>>1);
  2393. else
  2394. x = ((int)ctx.p[i]) + ((a - (int)ctx.p[i+1])*
  2395. ((int)ctx.p[i+2] - (int)ctx.p[i])/
  2396. ((int)ctx.p[i+3] - (int)ctx.p[i+1]));
  2397. x >>= SSFN_PREC;
  2398. if(ci) x += (h - b) / SSFN_ITALIC_DIV;
  2399. if(cb && !o) {
  2400. if(g->data[B + x] == 0xFF) { o = -cb; A = cb; }
  2401. else { o = cb; A = -cb; }
  2402. }
  2403. for(k = 0; k < nr && x > r[k]; k++);
  2404. for(l = nr; l > k; l--) r[l] = r[l-1];
  2405. r[k] = x;
  2406. nr++;
  2407. }
  2408. }
  2409. if(nr > 1 && nr & 1) { r[nr - 2] = r[nr - 1]; nr--; }
  2410. if(nr) {
  2411. for(i = 0; i < nr - 1; i += 2) {
  2412. l = r[i] + o; m = r[i + 1] + A;
  2413. if(l < 0) l = 0;
  2414. if(m > p) m = p;
  2415. if(i > 0 && l < r[i - 1] + A) l = r[i - 1] + A;
  2416. for(; l < m; l++)
  2417. g->data[B + l] = g->data[B + l] == ctx.glyphs[unicode].layers[n].color ?
  2418. 0xFF : ctx.glyphs[unicode].layers[n].color;
  2419. }
  2420. }
  2421. }
  2422. }
  2423. break;
  2424. case SSFN_FRAG_BITMAP:
  2425. case SSFN_FRAG_PIXMAP:
  2426. B = ctx.glyphs[unicode].width; A = ctx.glyphs[unicode].height;
  2427. b = B * h / ctx.height; a = A * h / ctx.height;
  2428. for(j = 0; j < a; j++) {
  2429. k = j * A / a * B;
  2430. for(i = 0; i < b; i++) {
  2431. l = ctx.glyphs[unicode].layers[n].data[k + i * B / b];
  2432. if(l != 0xFF)
  2433. g->data[j * p + i] =
  2434. ctx.glyphs[unicode].layers[n].type == SSFN_FRAG_BITMAP ? ctx.glyphs[unicode].layers[n].color : l;
  2435. }
  2436. }
  2437. if(postproc && ctx.glyphs[unicode].layers[n].type == SSFN_FRAG_BITMAP) {
  2438. B = ctx.glyphs[unicode].layers[n].color;
  2439. m = B == 0xFD ? 0xFC : 0xFD;
  2440. for(k = h; k > ctx.height + 4; k -= 2*ctx.height) {
  2441. for(j = 1; j < a - 1; j++)
  2442. for(i = 1; i < b - 1; i++) {
  2443. l = j * p + i;
  2444. if(g->data[l] == 0xFF && (g->data[l - p] == B ||
  2445. g->data[l + p] == B) && (g->data[l - 1] == B ||
  2446. g->data[l + 1] == B)) g->data[l] = m;
  2447. }
  2448. for(j = 1; j < a - 1; j++)
  2449. for(i = 1; i < b - 1; i++) {
  2450. l = j * p + i;
  2451. if(g->data[l] == m) g->data[l] = B;
  2452. }
  2453. }
  2454. }
  2455. break;
  2456. }
  2457. }
  2458. return 1;
  2459. }
  2460. /**
  2461. * Convert vector layers into bitmaps of size SIZE
  2462. *
  2463. * @param size size in pixels to rasterize to
  2464. */
  2465. void sfn_rasterize(int size)
  2466. {
  2467. uint32_t P;
  2468. unsigned long int sA;
  2469. int i, j, k, m, n, w, x, y, y0, y1, Y0, Y1, x0, x1, X0, X1, X2, xs, ys, yp, pc, nc = 0, numchars = 0;
  2470. sfngc_t g;
  2471. if(size < 8) size = 8;
  2472. if(size > 255) size = 255;
  2473. if(ctx.height < 1) ctx.height = 1;
  2474. for(i = 0; i < 0x110000; i++)
  2475. if(ctx.glyphs[i].numlayer) numchars++;
  2476. for(i = 0; i < 0x110000; i++) {
  2477. /* we must rescale characters without glyphs too, like white spaces */
  2478. ctx.glyphs[i].adv_x = ctx.glyphs[i].adv_x * size / ctx.height;
  2479. ctx.glyphs[i].adv_y = ctx.glyphs[i].adv_y * size / ctx.height;
  2480. ctx.glyphs[i].ovl_x = ctx.glyphs[i].ovl_x * size / ctx.height;
  2481. if(!ctx.glyphs[i].numlayer) {
  2482. ctx.glyphs[i].width = ctx.glyphs[i].width * size / ctx.height;
  2483. ctx.glyphs[i].height = ctx.glyphs[i].height * size / ctx.height;
  2484. continue;
  2485. }
  2486. if(pbar) (*pbar)(0, 0, ++nc, numchars, PBAR_RASTERIZE);
  2487. n = sfn_glyph(size, i, -1, 0, &g);
  2488. for(j = 0; j < ctx.glyphs[i].numlayer; j++)
  2489. if(ctx.glyphs[i].layers[j].data)
  2490. free(ctx.glyphs[i].layers[j].data);
  2491. for(j = 0; j < ctx.glyphs[i].numkern; j++) {
  2492. ctx.glyphs[i].kern[j].x = ctx.glyphs[i].kern[j].x * size / ctx.height;
  2493. ctx.glyphs[i].kern[j].y = ctx.glyphs[i].kern[j].y * size / ctx.height;
  2494. }
  2495. ctx.glyphs[i].numlayer = ctx.glyphs[i].width = ctx.glyphs[i].height = 0;
  2496. if(n) {
  2497. w = g.p * size / g.h;
  2498. n = size > 16 ? 2 : 1;
  2499. if(w < n) w = n;
  2500. ctx.glyphs[i].layers = realloc(ctx.glyphs[i].layers, sizeof(sfnlayer_t));
  2501. if(!ctx.glyphs[i].layers) continue;
  2502. memset(ctx.glyphs[i].layers, 0, sizeof(sfnlayer_t));
  2503. ctx.glyphs[i].layers[0].data = malloc(w * size);
  2504. if(!ctx.glyphs[i].layers[0].data) { sfn_chardel(i); continue; }
  2505. ctx.glyphs[i].numlayer = 1;
  2506. ctx.glyphs[i].width = w;
  2507. ctx.glyphs[i].height = size;
  2508. ctx.glyphs[i].layers[0].type = SSFN_FRAG_BITMAP;
  2509. ctx.glyphs[i].layers[0].len = w * size;
  2510. ctx.glyphs[i].layers[0].color = 0xFE;
  2511. for (y = j = 0; y < size; y++) {
  2512. y0 = (y << 8) * g.h / size; Y0 = y0 >> 8; y1 = ((y + 1) << 8) * g.h / size; Y1 = y1 >> 8;
  2513. for (x = 0; x < w; x++, j++) {
  2514. m = 0; sA = 0;
  2515. x0 = (x << 8) * g.p / w; X0 = x0 >> 8; x1 = ((x + 1) << 8) * g.p / w; X1 = x1 >> 8;
  2516. for(ys = y0; ys < y1; ys += 256) {
  2517. if(ys >> 8 == Y0) { yp = 256 - (ys & 0xFF); ys &= ~0xFF; if(yp > y1 - y0) yp = y1 - y0; }
  2518. else if(ys >> 8 == Y1) yp = y1 & 0xFF;
  2519. else yp = 256;
  2520. X2 = (ys >> 8) * g.p;
  2521. for(xs = x0; xs < x1; xs += 256) {
  2522. if (xs >> 8 == X0) {
  2523. k = 256 - (xs & 0xFF); xs &= ~0xFF; if(k > x1 - x0) k = x1 - x0;
  2524. pc = k == 256 ? yp : (k * yp) >> 8;
  2525. } else
  2526. if (xs >> 8 == X1) { k = x1 & 0xFF; pc = k == 256 ? yp : (k * yp) >> 8; }
  2527. else pc = yp;
  2528. m += pc;
  2529. k = g.data[X2 + (xs >> 8)];
  2530. if(k == 0xFF) continue;
  2531. P = *((uint32_t*)(ctx.cpal + (k << 2)));
  2532. sA += (k == 0xFE || !P ? 255 : ((P >> 24) & 0xFF)) * pc;
  2533. }
  2534. }
  2535. if(m) sA /= m; else sA >>= 8;
  2536. ctx.glyphs[i].layers[0].data[j] = sA > 64 ? 0xFE : 0xFF;
  2537. }
  2538. }
  2539. }
  2540. }
  2541. ctx.width = ctx.height = ctx.baseline = ctx.underline = 0;
  2542. sfn_sanitize(-1);
  2543. }
  2544. /**
  2545. * Convert bitmap layers into vector contours
  2546. */
  2547. void sfn_vectorize()
  2548. {
  2549. int i, j, k, s, n, old = ctx.height, nc = 0, numchars = 0;
  2550. potrace_bitmap_t bm;
  2551. potrace_param_t *param;
  2552. potrace_path_t *p;
  2553. potrace_state_t *st;
  2554. potrace_dpoint_t (*c)[3];
  2555. sfngc_t g;
  2556. sfnlayer_t *lyr;
  2557. param = potrace_param_default();
  2558. if(!param) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  2559. param->turnpolicy = POTRACE_TURNPOLICY_MINORITY;
  2560. param->turdsize = 2; /* curve threshold */
  2561. param->alphamax = 1.3; /* 0.0 polygon, 1.3333 no corners */
  2562. param->opttolerance = 0.5; /* bigger: less accurate, fewer segments */
  2563. for(i = 0; i < 0x110000; i++)
  2564. if(ctx.glyphs[i].numlayer) numchars++;
  2565. memset(&bm, 0, sizeof(potrace_bitmap_t));
  2566. for(i = 0; i < 0x110000; i++) {
  2567. if(!ctx.glyphs[i].numlayer) continue;
  2568. if(pbar) (*pbar)(0, 0, ++nc, numchars, PBAR_VECTORIZE);
  2569. n = sfn_glyph(254, i, -1, 0, &g);
  2570. for(j = 0; j < ctx.glyphs[i].numlayer; j++)
  2571. if(ctx.glyphs[i].layers[j].data)
  2572. free(ctx.glyphs[i].layers[j].data);
  2573. ctx.glyphs[i].numlayer = ctx.glyphs[i].width = ctx.glyphs[i].height = 0;
  2574. if(n) {
  2575. s = g.p > g.h ? g.p : g.h;
  2576. bm.w = g.p;
  2577. bm.h = g.h;
  2578. bm.dy = (g.p + BM_WORDBITS - 1) / BM_WORDBITS;
  2579. n = bm.h * bm.dy * BM_WORDSIZE;
  2580. bm.map = (potrace_word *)realloc(bm.map, n);
  2581. if(!bm.map) { fprintf(stderr,"libsfn: memory allocation error\n"); continue; }
  2582. memset(bm.map, 0, n);
  2583. for(n = k = 0; n < g.h; n++)
  2584. for(j = 0; j < g.p; j++, k++)
  2585. if(g.data[k] != 0xFF) BM_USET(bm, j, n);
  2586. st = potrace_trace(param, &bm);
  2587. if (!st || st->status != POTRACE_STATUS_OK) { fprintf(stderr,"libsfn: error tracing bitmap U+%06X\n", i); continue; }
  2588. p = st->plist;
  2589. while (p != NULL) {
  2590. n = p->curve.n;
  2591. c = p->curve.c;
  2592. unicode = i;
  2593. lyr = sfn_layeradd(i, SSFN_FRAG_CONTOUR, 0, 0, 0, 0, 0xFE, NULL);
  2594. if(!lyr) { fprintf(stderr,"libsfn: memory allocation error\n"); break; }
  2595. sfn_contadd(lyr, SSFN_CONTOUR_MOVE, c[n-1][2].x * 254 / s, c[n-1][2].y * 254 / s, 0,0, 0,0);
  2596. for(j = 0; j < n; j++)
  2597. switch(p->curve.tag[j]) {
  2598. case POTRACE_CORNER:
  2599. sfn_contadd(lyr, SSFN_CONTOUR_LINE, c[j][1].x * 254 / s, c[j][1].y * 254 / s, 0,0, 0,0);
  2600. sfn_contadd(lyr, SSFN_CONTOUR_LINE, c[j][2].x * 254 / s, c[j][2].y * 254 / s, 0,0, 0,0);
  2601. break;
  2602. case POTRACE_CURVETO:
  2603. sfn_contadd(lyr, SSFN_CONTOUR_CUBIC, c[j][2].x * 254 / s, c[j][2].y * 254 / s,
  2604. c[j][0].x * 254 / s, c[j][0].y * 254 / s, c[j][1].x * 254 / s, c[j][1].y * 254 / s);
  2605. break;
  2606. }
  2607. p = p->next;
  2608. }
  2609. potrace_state_free(st);
  2610. }
  2611. }
  2612. if(bm.map) free(bm.map);
  2613. potrace_param_free(param);
  2614. ctx.width = ctx.height = ctx.baseline = ctx.underline = 0;
  2615. sfn_sanitize(-1);
  2616. if(ctx.height > 0 && old > 0) {
  2617. for(i = 0; i < 0x110000; i++) {
  2618. ctx.glyphs[i].adv_x = ctx.glyphs[i].adv_x * ctx.height / old;
  2619. ctx.glyphs[i].adv_y = ctx.glyphs[i].adv_y * ctx.height / old;
  2620. ctx.glyphs[i].ovl_x = ctx.glyphs[i].ovl_x * ctx.height / old;
  2621. for(j = 0; j < ctx.glyphs[i].numkern; j++) {
  2622. ctx.glyphs[i].kern[j].x = ctx.glyphs[i].kern[j].x * ctx.height / old;
  2623. ctx.glyphs[i].kern[j].y = ctx.glyphs[i].kern[j].y * ctx.height / old;
  2624. }
  2625. }
  2626. }
  2627. }
  2628. /**
  2629. * Convert Bezier curves into series of lines
  2630. */
  2631. void sfn_lines()
  2632. {
  2633. int i, j, k, l, lx, ly, mx, my, nc = 0, numchars = 0;
  2634. sfnlayer_t *lyr;
  2635. sfncont_t *cont, *newc;
  2636. for(i = 0; i < 0x110000; i++)
  2637. if(ctx.glyphs[i].numlayer) numchars++;
  2638. for(i = 0; i < 0x110000; i++) {
  2639. if(!ctx.glyphs[i].numlayer) continue;
  2640. if(pbar) (*pbar)(0, 0, ++nc, numchars, PBAR_LINES);
  2641. for(j = 0; j < ctx.glyphs[i].numlayer; j++) {
  2642. lyr = &ctx.glyphs[i].layers[j];
  2643. if(lyr->type == SSFN_FRAG_CONTOUR) {
  2644. /* check if this countour has curves */
  2645. cont = (sfncont_t*)lyr->data;
  2646. for(k = l = 0; k < lyr->len; k++, cont++) {
  2647. switch(cont->type) {
  2648. case SSFN_CONTOUR_MOVE:
  2649. case SSFN_CONTOUR_LINE: l++; break;
  2650. case SSFN_CONTOUR_QUAD:
  2651. case SSFN_CONTOUR_CUBIC: l += 16; break;
  2652. }
  2653. }
  2654. /* convert curves to lines */
  2655. if(l != lyr->len) {
  2656. l++;
  2657. cont = (sfncont_t*)lyr->data;
  2658. newc = (sfncont_t*)malloc(l * sizeof(sfncont_t));
  2659. if(!newc) { fprintf(stderr,"libsfn: memory allocation error\n"); return; }
  2660. for(k = l = mx = my = lx = ly = 0; k < lyr->len; k++, cont++) {
  2661. switch(cont->type) {
  2662. case SSFN_CONTOUR_MOVE: mx = cont->px; my = cont->py; memcpy(&newc[l++], cont, sizeof(sfncont_t)); break;
  2663. case SSFN_CONTOUR_LINE: memcpy(&newc[l++], cont, sizeof(sfncont_t)); break;
  2664. case SSFN_CONTOUR_QUAD:
  2665. l = _sfn_b2l(newc, l, lx,ly, ((cont->c1x-lx)/2)+lx,((cont->c1y-ly)/2)+ly,
  2666. ((cont->px-cont->c1x)/2)+cont->c1x,((cont->py-cont->c1y)/2)+cont->c1y, cont->px,cont->py, 0);
  2667. break;
  2668. case SSFN_CONTOUR_CUBIC:
  2669. l = _sfn_b2l(newc, l, lx,ly, cont->c1x,cont->c1y, cont->c2x,cont->c2y, cont->px,cont->py, 0);
  2670. break;
  2671. }
  2672. lx = cont->px; ly = cont->py;
  2673. }
  2674. /* close path */
  2675. if(mx != lx || my != ly) {
  2676. newc[l].type = SSFN_CONTOUR_LINE;
  2677. newc[l].px = mx;
  2678. newc[l].py = my;
  2679. l++;
  2680. }
  2681. /* replace old contour layer with new, line command only layer */
  2682. newc = (sfncont_t*)realloc(newc, l * sizeof(sfncont_t));
  2683. if(newc) {
  2684. lyr->len = l;
  2685. free(lyr->data);
  2686. lyr->data = (uint8_t*)newc;
  2687. }
  2688. }
  2689. }
  2690. }
  2691. }
  2692. }
  2693. /**
  2694. * Print out a UNICODE blocks coverage report
  2695. */
  2696. void sfn_coverage()
  2697. {
  2698. int i, j, m, n, a, b, d;
  2699. printf("| Coverage | NumChar | Start | End | Description |\n"
  2700. "| -------: | ------: | ------ | ------ | ---------------------------------------------- |\n");
  2701. for(i = 0; i < UNICODE_NUMBLOCKS; i++)
  2702. ublocks[i].cnt = 0;
  2703. for(i = m = 0; i < 0x110000; i++)
  2704. if(ctx.glyphs[i].numlayer) {
  2705. m++;
  2706. for(j = 0; j < UNICODE_NUMBLOCKS; j++)
  2707. if(i >= ublocks[j].start && i <= ublocks[j].end) { ublocks[j].cnt++; m--; break; }
  2708. }
  2709. for(i = a = b = d = 0; i < UNICODE_NUMBLOCKS; i++) {
  2710. if(ublocks[i].cnt) {
  2711. n = ublocks[i].end - ublocks[i].start + 1 - ublocks[i].undef;
  2712. if(ublocks[i].cnt > n) { m += ublocks[i].cnt - n; ublocks[i].cnt = n; };
  2713. a += ublocks[i].cnt; b += n;
  2714. d = ublocks[i].cnt * 1000 / n;
  2715. printf("| %3d.%d%% | %7d | %06X | %06X | %-46s |\n", d/10, d%10,
  2716. ublocks[i].cnt, ublocks[i].start, ublocks[i].end, ublocks[i].name);
  2717. }
  2718. }
  2719. if(m)
  2720. printf("| - | %7d | 000000 | 10FFFF | No Block |\n", m);
  2721. d = a * 1000 / b;
  2722. printf("| -------- | ------- | ---------------------------------------------------------------- |\n"
  2723. "| %3d.%d%% | %7d | = = = = = = = = Overall Coverage = = = = = = = = |\n", d/10, d%10, a);
  2724. }