Mercurial > ecos
comparison packages/services/gfx/mw/current/src/engine/devfont.caching.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children | e1afd37f2f1d |
comparison
equal
deleted
inserted
replaced
| 207:74c807ddde34 | 208:e0c0827131d1 |
|---|---|
| 1 /* | |
| 2 * Copyright (c) 2000 Greg Haerr <greg@censoft.com> | |
| 3 * T1lib Adobe type1 routines contributed by Vidar Hokstad | |
| 4 * Freetype TrueType routines contributed by Martin Jolicoeur | |
| 5 * Han Zi Ku routines contributed by Tanghao and Jauming | |
| 6 * | |
| 7 * Device-independent font and text drawing routines | |
| 8 * | |
| 9 * These routines do the necessary range checking, clipping, and cursor | |
| 10 * overwriting checks, and then call the lower level device dependent | |
| 11 * routines to actually do the drawing. The lower level routines are | |
| 12 * only called when it is known that all the pixels to be drawn are | |
| 13 * within the device area and are visible. | |
| 14 */ | |
| 15 /*#define NDEBUG*/ | |
| 16 #include <stdio.h> | |
| 17 #include <stdlib.h> | |
| 18 #include <string.h> | |
| 19 #include <assert.h> | |
| 20 #include <string.h> | |
| 21 | |
| 22 #include "device.h" | |
| 23 #if (UNIX | DOS_DJGPP) | |
| 24 #define strcmpi strcasecmp | |
| 25 #endif | |
| 26 | |
| 27 #if HAVE_T1LIB_SUPPORT | |
| 28 #include <t1lib.h> | |
| 29 #define T1LIB_USE_AA_HIGH | |
| 30 | |
| 31 typedef struct { | |
| 32 PMWFONTPROCS fontprocs; /* common hdr*/ | |
| 33 MWCOORD fontsize; | |
| 34 int fontrotation; | |
| 35 int fontattr; | |
| 36 | |
| 37 int fontid; /* t1lib stuff*/ | |
| 38 } MWT1LIBFONT, *PMWT1LIBFONT; | |
| 39 | |
| 40 static int t1lib_init(PSD psd); | |
| 41 static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height,int attr); | |
| 42 static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 43 const void *text, int cc, int flags); | |
| 44 static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); | |
| 45 static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 46 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 47 static void t1lib_destroyfont(PMWFONT pfont); | |
| 48 | |
| 49 /* handling routines for MWT1LIBFONT*/ | |
| 50 static MWFONTPROCS t1lib_procs = { | |
| 51 MWTF_ASCII, /* routines expect ascii*/ | |
| 52 t1lib_getfontinfo, | |
| 53 t1lib_gettextsize, | |
| 54 NULL, /* gettextbits*/ | |
| 55 t1lib_destroyfont, | |
| 56 t1lib_drawtext, | |
| 57 NULL, /* setfontsize*/ | |
| 58 NULL, /* setfontrotation*/ | |
| 59 NULL, /* setfontattr*/ | |
| 60 }; | |
| 61 #endif | |
| 62 | |
| 63 #ifdef T1LIB_USE_AA_HIGH | |
| 64 typedef unsigned long OUTPIXELVAL; | |
| 65 #else | |
| 66 typedef MWPIXELVAL OUTPIXELVAL; | |
| 67 #endif | |
| 68 | |
| 69 #if HAVE_FREETYPE_SUPPORT | |
| 70 #include <freetype/freetype.h> | |
| 71 #include <freetype/ftxkern.h> | |
| 72 #include <freetype/ftnameid.h> | |
| 73 #include <freetype/ftxcmap.h> | |
| 74 #include <freetype/ftxwidth.h> | |
| 75 #include <math.h> | |
| 76 | |
| 77 /************/ | |
| 78 | |
| 79 typedef struct xTT_Glyph_Cache_ { | |
| 80 | |
| 81 TT_Error error; | |
| 82 TT_Glyph glyph; | |
| 83 TT_UShort index; | |
| 84 TT_UShort flags; | |
| 85 | |
| 86 struct xTT_Glyph_Cache_ * l; | |
| 87 struct xTT_Glyph_Cache_ * r; | |
| 88 | |
| 89 } xTT_Glyph_Cache; | |
| 90 | |
| 91 typedef struct xTT_Instance_Object_ { | |
| 92 | |
| 93 TT_Face face; | |
| 94 TT_Instance instance; | |
| 95 | |
| 96 xTT_Glyph_Cache * head; | |
| 97 | |
| 98 } xTT_Instance_Object; | |
| 99 | |
| 100 typedef struct xTT_Instance_ { | |
| 101 | |
| 102 xTT_Instance_Object * instance; | |
| 103 | |
| 104 } xTT_Instance; | |
| 105 | |
| 106 typedef struct xTT_Outline_Object_ { | |
| 107 | |
| 108 TT_Outline outline; | |
| 109 TT_BBox bbox; | |
| 110 | |
| 111 } xTT_Outline_Object; | |
| 112 | |
| 113 typedef struct xTT_Outline_ { | |
| 114 | |
| 115 xTT_Outline_Object * outline; | |
| 116 | |
| 117 } xTT_Outline; | |
| 118 | |
| 119 typedef struct xTT_Glyph_Object_ { | |
| 120 | |
| 121 TT_Glyph * glyph; | |
| 122 | |
| 123 xTT_Outline_Object outline; | |
| 124 | |
| 125 } xTT_Glyph_Object; | |
| 126 | |
| 127 typedef struct xTT_Glyph_ { | |
| 128 | |
| 129 xTT_Glyph_Object * glyph; | |
| 130 | |
| 131 } xTT_Glyph; | |
| 132 | |
| 133 TT_Error | |
| 134 xTT_Glyph_Cache_Find ( xTT_Instance instance, | |
| 135 xTT_Glyph glyph, | |
| 136 TT_UShort glyphIndex, | |
| 137 TT_UShort loadFlags ) | |
| 138 { | |
| 139 xTT_Glyph_Cache * node; | |
| 140 xTT_Glyph_Cache ** inode = &instance.instance->head; | |
| 141 | |
| 142 int miss = 0; | |
| 143 | |
| 144 while ( 1 ) | |
| 145 { | |
| 146 if (*inode == 0) | |
| 147 { | |
| 148 miss = 1; | |
| 149 | |
| 150 node = *inode = calloc(1,sizeof(**inode)); | |
| 151 | |
| 152 if (node == 0) | |
| 153 return TT_Err_Out_Of_Memory; | |
| 154 | |
| 155 node->error = TT_New_Glyph(instance.instance->face,&(node->glyph)); | |
| 156 | |
| 157 if (node->error == 0) | |
| 158 node->error = TT_Load_Glyph(instance.instance->instance, | |
| 159 node->glyph, | |
| 160 (node->index = glyphIndex), | |
| 161 (node->flags = loadFlags)); | |
| 162 | |
| 163 if (node->error != 0) | |
| 164 TT_Done_Glyph(node->glyph); | |
| 165 } | |
| 166 else | |
| 167 { | |
| 168 node = *inode; | |
| 169 } | |
| 170 | |
| 171 if (glyphIndex < node->index) | |
| 172 inode = &node->l; | |
| 173 else if (glyphIndex > node->index) | |
| 174 inode = &node->r; | |
| 175 else if (loadFlags < node->flags) | |
| 176 inode = &node->l; | |
| 177 else if (loadFlags > node->flags) | |
| 178 inode = &node->r; | |
| 179 else | |
| 180 { | |
| 181 static int count [] = { 0, 0 }; | |
| 182 ++count[miss]; | |
| 183 printf("\r(%s | hit %d | miss %d)",__TIME__,count[0],count[1]); | |
| 184 glyph.glyph->glyph = &node->glyph; | |
| 185 return node->error; | |
| 186 } | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 void | |
| 191 xTT_Glyph_Cache_Free ( xTT_Glyph_Cache ** pnode ) | |
| 192 { | |
| 193 xTT_Glyph_Cache * node; | |
| 194 | |
| 195 if (pnode == 0) | |
| 196 return; | |
| 197 | |
| 198 node = *pnode; | |
| 199 | |
| 200 if (node == 0) | |
| 201 return; | |
| 202 | |
| 203 if (node->l) | |
| 204 xTT_Glyph_Cache_Free(&node->l); | |
| 205 | |
| 206 if (node->r) | |
| 207 xTT_Glyph_Cache_Free(&node->r); | |
| 208 | |
| 209 TT_Done_Glyph(node->glyph); | |
| 210 free(node); | |
| 211 | |
| 212 *pnode = 0; | |
| 213 } | |
| 214 | |
| 215 TT_Error | |
| 216 xTT_New_Instance ( TT_Face face, | |
| 217 xTT_Instance * instance ) | |
| 218 { | |
| 219 instance->instance = calloc(1,sizeof(*instance->instance)); | |
| 220 if (instance->instance == 0) | |
| 221 return TT_Err_Out_Of_Memory; | |
| 222 | |
| 223 instance->instance->face = face; | |
| 224 instance->instance->head = 0; | |
| 225 | |
| 226 return TT_New_Instance(face,&instance->instance->instance); | |
| 227 } | |
| 228 | |
| 229 TT_Error | |
| 230 xTT_Done_Instance ( xTT_Instance instance ) | |
| 231 { | |
| 232 TT_Error error; | |
| 233 | |
| 234 xTT_Glyph_Cache_Free(&instance.instance->head); | |
| 235 error = TT_Done_Instance(instance.instance->instance); | |
| 236 | |
| 237 free(instance.instance); | |
| 238 | |
| 239 return error; | |
| 240 } | |
| 241 | |
| 242 TT_Error | |
| 243 xTT_Get_Instance_Metrics ( xTT_Instance instance, | |
| 244 TT_Instance_Metrics * imetrics ) | |
| 245 { | |
| 246 return TT_Get_Instance_Metrics(instance.instance->instance,imetrics); | |
| 247 } | |
| 248 | |
| 249 TT_Error | |
| 250 xTT_Set_Instance_CharSize ( xTT_Instance instance, | |
| 251 TT_F26Dot6 charsize ) | |
| 252 { | |
| 253 xTT_Glyph_Cache_Free(&instance.instance->head); | |
| 254 return TT_Set_Instance_CharSize(instance.instance->instance,charsize); | |
| 255 } | |
| 256 | |
| 257 TT_Error | |
| 258 xTT_Set_Instance_PixelSizes ( xTT_Instance instance, | |
| 259 TT_UShort pixelWidth, | |
| 260 TT_UShort pixelHeight, | |
| 261 TT_F26Dot6 pointSize ) | |
| 262 { | |
| 263 xTT_Glyph_Cache_Free(&instance.instance->head); | |
| 264 return TT_Set_Instance_PixelSizes(instance.instance->instance, | |
| 265 pixelWidth, | |
| 266 pixelHeight, | |
| 267 pointSize); | |
| 268 } | |
| 269 | |
| 270 TT_Error | |
| 271 xTT_Set_Instance_Transform_Flags ( xTT_Instance instance, | |
| 272 TT_Bool rotated, | |
| 273 TT_Bool stretched ) | |
| 274 { | |
| 275 xTT_Glyph_Cache_Free(&instance.instance->head); | |
| 276 return TT_Set_Instance_Resolutions(instance.instance->instance, | |
| 277 rotated, | |
| 278 stretched); | |
| 279 } | |
| 280 | |
| 281 TT_Error | |
| 282 xTT_Set_Instance_Resolutions ( xTT_Instance instance, | |
| 283 TT_UShort xResolution, | |
| 284 TT_UShort yResolution ) | |
| 285 { | |
| 286 xTT_Glyph_Cache_Free(&instance.instance->head); | |
| 287 return TT_Set_Instance_Resolutions(instance.instance->instance, | |
| 288 xResolution, | |
| 289 yResolution); | |
| 290 } | |
| 291 | |
| 292 TT_Error | |
| 293 xTT_New_Glyph ( TT_Face face, | |
| 294 xTT_Glyph * glyph ) | |
| 295 { | |
| 296 glyph->glyph = calloc(1,sizeof(*glyph->glyph)); | |
| 297 if (glyph->glyph == 0) | |
| 298 return TT_Err_Out_Of_Memory; | |
| 299 return 0; | |
| 300 } | |
| 301 | |
| 302 TT_Error | |
| 303 xTT_Done_Glyph ( xTT_Glyph glyph ) | |
| 304 { | |
| 305 free(glyph.glyph); | |
| 306 return 0; | |
| 307 } | |
| 308 | |
| 309 TT_Error | |
| 310 xTT_Load_Glyph ( xTT_Instance instance, | |
| 311 xTT_Glyph glyph, | |
| 312 TT_UShort glyphIndex, | |
| 313 TT_UShort loadFlags ) | |
| 314 { | |
| 315 TT_Error error; | |
| 316 error = xTT_Glyph_Cache_Find(instance,glyph,glyphIndex,loadFlags); | |
| 317 TT_Get_Glyph_Outline(*glyph.glyph->glyph, | |
| 318 &glyph.glyph->outline.outline); | |
| 319 TT_Get_Outline_BBox(&glyph.glyph->outline.outline, | |
| 320 &glyph.glyph->outline.bbox); | |
| 321 return error; | |
| 322 } | |
| 323 | |
| 324 TT_Error | |
| 325 xTT_Get_Glyph_Metrics ( xTT_Glyph glyph, | |
| 326 TT_Glyph_Metrics * metrics ) | |
| 327 { | |
| 328 return TT_Get_Glyph_Metrics(*glyph.glyph->glyph,metrics); | |
| 329 } | |
| 330 | |
| 331 TT_Error | |
| 332 xTT_Get_Glyph_Outline ( xTT_Glyph glyph, | |
| 333 xTT_Outline * outline ) | |
| 334 { | |
| 335 outline->outline = &glyph.glyph->outline; | |
| 336 return 0; | |
| 337 } | |
| 338 | |
| 339 TT_Error | |
| 340 xTT_Get_Outline_BBox ( xTT_Outline * outline, | |
| 341 TT_BBox * bbox ) | |
| 342 { | |
| 343 *bbox = outline->outline->bbox; | |
| 344 return 0; | |
| 345 } | |
| 346 | |
| 347 void | |
| 348 xTT_Transform_Outline ( xTT_Outline * outline, | |
| 349 TT_Matrix * matrix ) | |
| 350 { | |
| 351 TT_Transform_Outline(&outline->outline->outline,matrix); | |
| 352 TT_Get_Outline_BBox(&outline->outline->outline, | |
| 353 &outline->outline->bbox); | |
| 354 } | |
| 355 | |
| 356 TT_Error | |
| 357 xTT_Get_Glyph_Bitmap ( xTT_Glyph glyph, | |
| 358 TT_Raster_Map * bitmap, | |
| 359 TT_F26Dot6 xOffset, | |
| 360 TT_F26Dot6 yOffset ) | |
| 361 { | |
| 362 return TT_Get_Glyph_Bitmap(*glyph.glyph->glyph, | |
| 363 bitmap, | |
| 364 xOffset, | |
| 365 yOffset); | |
| 366 } | |
| 367 | |
| 368 TT_Error | |
| 369 xTT_Get_Glyph_Pixmap ( xTT_Glyph glyph, | |
| 370 TT_Raster_Map * pixmap, | |
| 371 TT_F26Dot6 xOffset, | |
| 372 TT_F26Dot6 yOffset ) | |
| 373 { | |
| 374 return TT_Get_Glyph_Pixmap(*glyph.glyph->glyph, | |
| 375 pixmap, | |
| 376 xOffset, | |
| 377 yOffset); | |
| 378 } | |
| 379 | |
| 380 #ifndef xTT_ALIAS | |
| 381 #define xTT_ALIAS 1 | |
| 382 #endif | |
| 383 | |
| 384 #if xTT_ALIAS | |
| 385 | |
| 386 #define TT_Instance xTT_Instance | |
| 387 #define TT_Outline xTT_Outline | |
| 388 #define TT_Glyph xTT_Glyph | |
| 389 | |
| 390 #define TT_New_Instance xTT_New_Instance | |
| 391 #define TT_Done_Instance xTT_Done_Instance | |
| 392 | |
| 393 #define TT_Get_Instance_Metrics xTT_Get_Instance_Metrics | |
| 394 #define TT_Set_Instance_CharSize xTT_Set_Instance_CharSize | |
| 395 #define TT_Set_Instance_PixelSizes xTT_Set_Instance_PixelSizes | |
| 396 #define TT_Set_Instance_Transform_Flags xTT_Set_Instance_Transform_Flags | |
| 397 #define TT_Set_Instance_Resolutions xTT_Set_Instance_Resolutions | |
| 398 | |
| 399 #define TT_New_Glyph xTT_New_Glyph | |
| 400 #define TT_Done_Glyph xTT_Done_Glyph | |
| 401 | |
| 402 #define TT_Load_Glyph xTT_Load_Glyph | |
| 403 #define TT_Get_Glyph_Metrics xTT_Get_Glyph_Metrics | |
| 404 #define TT_Get_Glyph_Outline xTT_Get_Glyph_Outline | |
| 405 #define TT_Get_Glyph_Bitmap xTT_Get_Glyph_Bitmap | |
| 406 #define TT_Get_Glyph_Pixmap xTT_Get_Glyph_Pixmap | |
| 407 | |
| 408 #define TT_Get_Outline_BBox xTT_Get_Outline_BBox | |
| 409 #define TT_Transform_Outline xTT_Transform_Outline | |
| 410 | |
| 411 #endif | |
| 412 | |
| 413 /************/ | |
| 414 | |
| 415 #ifndef FREETYPE_FONT_DIR | |
| 416 #define FREETYPE_FONT_DIR "/usr/local/microwin/fonts" | |
| 417 #endif | |
| 418 | |
| 419 #if TT_FREETYPE_MAJOR != 1 | TT_FREETYPE_MINOR < 3 | |
| 420 #error "You must link with freetype lib version 1.3.x +, and not freetype 2. \ | |
| 421 Download it at http://www.freetype.org or http://microwindows.org" | |
| 422 #endif | |
| 423 | |
| 424 #ifndef MWFREETYPEFONT_CACHE | |
| 425 #define MWFREETYPEFONT_CACHE 1 | |
| 426 #endif | |
| 427 | |
| 428 #if MWFREETYPEFONT_CACHE | |
| 429 | |
| 430 #ifndef MWFREETYPEFONT_CACHEBITMAP | |
| 431 #define MWFREETYPEFONT_CACHEBITMAP 1 | |
| 432 #endif | |
| 433 | |
| 434 typedef struct mwfreetypefontcache { | |
| 435 unsigned curchar; | |
| 436 void * buffer; | |
| 437 #if MWFREETYPEFONT_CACHEBITMAP | |
| 438 MWPIXELVAL fg; | |
| 439 MWPIXELVAL bg; | |
| 440 MWBOOL usebg; | |
| 441 void * bitmap; | |
| 442 #endif | |
| 443 struct mwfreetypefontcache * l; | |
| 444 struct mwfreetypefontcache * r; | |
| 445 } MWFREETYPEFONTCACHE; | |
| 446 | |
| 447 #endif | |
| 448 | |
| 449 typedef struct { | |
| 450 | |
| 451 PMWFONTPROCS fontprocs; /* common hdr*/ | |
| 452 MWCOORD fontsize; | |
| 453 int fontrotation; | |
| 454 int fontattr; | |
| 455 | |
| 456 TT_Face face; /* freetype stuff*/ | |
| 457 TT_Instance instance; | |
| 458 TT_CharMap char_map; | |
| 459 TT_Kerning directory; | |
| 460 TT_Matrix matrix; | |
| 461 TT_Glyph glyph; | |
| 462 MWBOOL can_kern; | |
| 463 short last_glyph_code; | |
| 464 short last_pen_pos; | |
| 465 | |
| 466 #if MWFREETYPEFONT_CACHE | |
| 467 MWFREETYPEFONTCACHE * glyph_cache; | |
| 468 #endif | |
| 469 | |
| 470 } MWFREETYPEFONT, *PMWFREETYPEFONT; | |
| 471 | |
| 472 static int freetype_init(PSD psd); | |
| 473 static PMWFREETYPEFONT freetype_createfont(const char *name, MWCOORD height, | |
| 474 int attr); | |
| 475 static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); | |
| 476 static void freetype_gettextsize(PMWFONT pfont, const void *text, | |
| 477 int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 478 static void freetype_destroyfont(PMWFONT pfont); | |
| 479 static void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 480 const void *text, int cc, int flags); | |
| 481 static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize); | |
| 482 static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees); | |
| 483 | |
| 484 /* handling routines for MWFREETYPEFONT*/ | |
| 485 static MWFONTPROCS freetype_procs = { | |
| 486 MWTF_UC16, /* routines expect unicode 16*/ | |
| 487 freetype_getfontinfo, | |
| 488 freetype_gettextsize, | |
| 489 NULL, /* gettextbits*/ | |
| 490 freetype_destroyfont, | |
| 491 freetype_drawtext, | |
| 492 freetype_setfontsize, | |
| 493 freetype_setfontrotation, | |
| 494 NULL, /* setfontattr*/ | |
| 495 }; | |
| 496 | |
| 497 static TT_Engine engine; /* THE ONLY freetype engine */ | |
| 498 #endif /* HAVE_FREETYPE_SUPPORT*/ | |
| 499 | |
| 500 #if HAVE_HZK_SUPPORT | |
| 501 /* | |
| 502 * 12x12 and 16x16 ascii and chinese fonts | |
| 503 * Big5 and GB2312 encodings supported | |
| 504 */ | |
| 505 #define MAX_PATH 256 | |
| 506 typedef struct { | |
| 507 int width; | |
| 508 int height; | |
| 509 int size; | |
| 510 unsigned long use_count; | |
| 511 char * pFont; | |
| 512 char file[MAX_PATH + 1]; | |
| 513 } HZKFONT; | |
| 514 | |
| 515 static int use_big5=1; | |
| 516 static HZKFONT CFont[2]; /* font cache*/ | |
| 517 static HZKFONT AFont[2]; /* font cache*/ | |
| 518 | |
| 519 /*jmt: moved inside MWHZKFONT*/ | |
| 520 static int afont_width = 8; | |
| 521 static int cfont_width = 16; | |
| 522 static int font_height = 16; | |
| 523 static char *afont_address; | |
| 524 static char *cfont_address; | |
| 525 | |
| 526 typedef struct { | |
| 527 PMWFONTPROCS fontprocs; /* common hdr*/ | |
| 528 MWCOORD fontsize; | |
| 529 int fontrotation; | |
| 530 int fontattr; | |
| 531 | |
| 532 HZKFONT CFont; /* hzkfont stuff */ | |
| 533 HZKFONT AFont; | |
| 534 int afont_width; | |
| 535 int cfont_width; | |
| 536 int font_height; | |
| 537 char *afont_address; | |
| 538 char *cfont_address; | |
| 539 } MWHZKFONT, *PMWHZKFONT; | |
| 540 | |
| 541 static int hzk_init(PSD psd); | |
| 542 static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height,int fontattr); | |
| 543 static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo); | |
| 544 static void hzk_gettextsize(PMWFONT pfont, const void *text, | |
| 545 int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase); | |
| 546 /*static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap, | |
| 547 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);*/ | |
| 548 static void hzk_destroyfont(PMWFONT pfont); | |
| 549 static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 550 const void *text, int cc, int flags); | |
| 551 static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize); | |
| 552 /*static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees);*/ | |
| 553 | |
| 554 /* handling routines for MWHZKFONT*/ | |
| 555 static MWFONTPROCS hzk_procs = { | |
| 556 MWTF_ASCII, /* routines expect ASCII*/ | |
| 557 hzk_getfontinfo, | |
| 558 hzk_gettextsize, | |
| 559 NULL, /* hzk_gettextbits*/ | |
| 560 hzk_destroyfont, | |
| 561 hzk_drawtext, | |
| 562 hzk_setfontsize, | |
| 563 NULL, /* setfontrotation*/ | |
| 564 NULL, /* setfontattr*/ | |
| 565 }; | |
| 566 | |
| 567 static int | |
| 568 UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii); | |
| 569 #endif /* HAVE_HZK_SUPPORT*/ | |
| 570 | |
| 571 static PMWFONT gr_pfont; /* current font*/ | |
| 572 | |
| 573 /* temp extern decls*/ | |
| 574 extern MWPIXELVAL gr_foreground; | |
| 575 extern MWPIXELVAL gr_background; | |
| 576 extern MWBOOL gr_usebg; | |
| 577 | |
| 578 static int utf8_to_utf16(const unsigned char *utf8, int cc, | |
| 579 unsigned short *unicode16); | |
| 580 | |
| 581 #if FONTMAPPER | |
| 582 /* entry point for font selection*/ | |
| 583 int select_font(const PMWLOGFONT plogfont, char *physname); | |
| 584 #endif | |
| 585 | |
| 586 /* | |
| 587 * Set the font for future calls. | |
| 588 */ | |
| 589 PMWFONT | |
| 590 GdSetFont(PMWFONT pfont) | |
| 591 { | |
| 592 PMWFONT oldfont = gr_pfont; | |
| 593 gr_pfont = pfont; | |
| 594 return oldfont; | |
| 595 } | |
| 596 | |
| 597 /* | |
| 598 * Select a font, based on various parameters. | |
| 599 * If plogfont is specified, name and height parms are ignored | |
| 600 * and instead used from MWLOGFONT. | |
| 601 * | |
| 602 * If height is 0, return builtin font from passed name. | |
| 603 * Otherwise find builtin font best match based on height. | |
| 604 */ | |
| 605 PMWFONT | |
| 606 GdCreateFont(PSD psd, const char *name, MWCOORD height, | |
| 607 const PMWLOGFONT plogfont) | |
| 608 { | |
| 609 int i; | |
| 610 int fontht; | |
| 611 int fontno; | |
| 612 int fontclass; | |
| 613 int fontattr = 0; | |
| 614 PMWFONT pfont; | |
| 615 PMWCOREFONT pf = psd->builtin_fonts; | |
| 616 MWFONTINFO fontinfo; | |
| 617 MWSCREENINFO scrinfo; | |
| 618 char fontname[128]; | |
| 619 | |
| 620 GdGetScreenInfo(psd, &scrinfo); | |
| 621 | |
| 622 /* if plogfont not specified, use name and height*/ | |
| 623 if (!plogfont) { | |
| 624 if (!name) | |
| 625 name = MWFONT_SYSTEM_VAR; | |
| 626 strcpy(fontname, name); | |
| 627 fontclass = MWLF_CLASS_ANY; | |
| 628 } else { | |
| 629 #if FONTMAPPER | |
| 630 /* otherwise, use MWLOGFONT name and height*/ | |
| 631 fontclass = select_font(plogfont, fontname); | |
| 632 #else | |
| 633 if (!name) | |
| 634 name = MWFONT_SYSTEM_VAR; | |
| 635 strcpy(fontname, name); | |
| 636 fontclass = MWLF_CLASS_ANY; | |
| 637 #endif | |
| 638 height = plogfont->lfHeight; | |
| 639 if (plogfont->lfUnderline) | |
| 640 fontattr = MWTF_UNDERLINE; | |
| 641 } | |
| 642 height = abs(height); | |
| 643 | |
| 644 if (!fontclass) | |
| 645 goto first; | |
| 646 | |
| 647 /* use builtin screen fonts, FONT_xxx, if height is 0 */ | |
| 648 if (height == 0 || fontclass == MWLF_CLASS_ANY || | |
| 649 fontclass == MWLF_CLASS_BUILTIN) { | |
| 650 for(i = 0; i < scrinfo.fonts; ++i) { | |
| 651 if(!strcmpi(pf[i].name, fontname)) { | |
| 652 pf[i].fontsize = pf[i].cfont->height; | |
| 653 pf[i].fontattr = fontattr; | |
| 654 return (PMWFONT)&pf[i]; | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 /* return first builtin font*/ | |
| 659 if (height == 0 || fontclass == MWLF_CLASS_BUILTIN) | |
| 660 goto first; | |
| 661 } | |
| 662 | |
| 663 #if HAVE_HZK_SUPPORT | |
| 664 /* Make sure the library is initialized */ | |
| 665 if (hzk_init(psd)) { | |
| 666 pfont = (PMWFONT)hzk_createfont(name, height, fontattr); | |
| 667 if(pfont) | |
| 668 return pfont; | |
| 669 printf("hzk_createfont: %s not found\n", name); | |
| 670 } | |
| 671 #endif | |
| 672 | |
| 673 #if HAVE_FREETYPE_SUPPORT | |
| 674 if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_FREETYPE) { | |
| 675 if (freetype_init(psd)) { | |
| 676 /* auto antialias for height > 14 for kaffe*/ | |
| 677 if (plogfont && plogfont->lfHeight > 14 && | |
| 678 plogfont->lfQuality) | |
| 679 fontattr |= MWTF_ANTIALIAS; | |
| 680 | |
| 681 pfont = (PMWFONT)freetype_createfont(fontname, height, | |
| 682 fontattr); | |
| 683 if(pfont) { | |
| 684 /* temp kaffe kluge*/ | |
| 685 pfont->fontattr |= FS_FREETYPE; | |
| 686 return pfont; | |
| 687 } | |
| 688 DPRINTF("freetype_createfont: %s,%d not found\n", | |
| 689 fontname, height); | |
| 690 } | |
| 691 } | |
| 692 #endif | |
| 693 | |
| 694 #if HAVE_T1LIB_SUPPORT | |
| 695 if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_T1LIB) { | |
| 696 if (t1lib_init(psd)) { | |
| 697 pfont = (PMWFONT)t1lib_createfont(fontname, height, | |
| 698 fontattr); | |
| 699 if(pfont) | |
| 700 return pfont; | |
| 701 DPRINTF("t1lib_createfont: %s,%d not found\n", | |
| 702 fontname, height); | |
| 703 } | |
| 704 } | |
| 705 #endif | |
| 706 | |
| 707 /* find builtin font closest in height*/ | |
| 708 if(height != 0) { | |
| 709 fontno = 0; | |
| 710 height = abs(height); | |
| 711 fontht = MAX_MWCOORD; | |
| 712 for(i = 0; i < scrinfo.fonts; ++i) { | |
| 713 pfont = (PMWFONT)&pf[i]; | |
| 714 GdGetFontInfo(pfont, &fontinfo); | |
| 715 if(fontht > abs(height-fontinfo.height)) { | |
| 716 fontno = i; | |
| 717 fontht = abs(height-fontinfo.height); | |
| 718 } | |
| 719 } | |
| 720 pf[fontno].fontsize = pf[fontno].cfont->height; | |
| 721 pf[fontno].fontattr = fontattr; | |
| 722 return (PMWFONT)&pf[fontno]; | |
| 723 } | |
| 724 | |
| 725 first: | |
| 726 /* Return first builtin font*/ | |
| 727 pf->fontsize = pf->cfont->height; | |
| 728 pf->fontattr = fontattr; | |
| 729 return (PMWFONT)&pf[0]; | |
| 730 } | |
| 731 | |
| 732 /* Set the font size for the passed font*/ | |
| 733 MWCOORD | |
| 734 GdSetFontSize(PMWFONT pfont, MWCOORD fontsize) | |
| 735 { | |
| 736 MWCOORD oldfontsize = pfont->fontsize; | |
| 737 | |
| 738 pfont->fontsize = fontsize; | |
| 739 | |
| 740 if (pfont->fontprocs->SetFontSize) | |
| 741 pfont->fontprocs->SetFontSize(pfont, fontsize); | |
| 742 | |
| 743 return oldfontsize; | |
| 744 } | |
| 745 | |
| 746 /* Set the font rotation angle in tenths of degrees for the passed font*/ | |
| 747 int | |
| 748 GdSetFontRotation(PMWFONT pfont, int tenthdegrees) | |
| 749 { | |
| 750 MWCOORD oldrotation = pfont->fontrotation; | |
| 751 | |
| 752 pfont->fontrotation = tenthdegrees; | |
| 753 | |
| 754 if (pfont->fontprocs->SetFontRotation) | |
| 755 pfont->fontprocs->SetFontRotation(pfont, tenthdegrees); | |
| 756 | |
| 757 return oldrotation; | |
| 758 } | |
| 759 | |
| 760 /* | |
| 761 * Set/reset font attributes (MWTF_KERNING, MWTF_ANTIALIAS) | |
| 762 * for the passed font. | |
| 763 */ | |
| 764 int | |
| 765 GdSetFontAttr(PMWFONT pfont, int setflags, int clrflags) | |
| 766 { | |
| 767 MWCOORD oldattr = pfont->fontattr; | |
| 768 | |
| 769 pfont->fontattr &= ~clrflags; | |
| 770 pfont->fontattr |= setflags; | |
| 771 | |
| 772 if (pfont->fontprocs->SetFontAttr) | |
| 773 pfont->fontprocs->SetFontAttr(pfont, setflags, clrflags); | |
| 774 | |
| 775 return oldattr; | |
| 776 } | |
| 777 | |
| 778 /* Unload and deallocate font*/ | |
| 779 void | |
| 780 GdDestroyFont(PMWFONT pfont) | |
| 781 { | |
| 782 if (pfont->fontprocs->DestroyFont) | |
| 783 pfont->fontprocs->DestroyFont(pfont); | |
| 784 } | |
| 785 | |
| 786 /* Return information about a specified font*/ | |
| 787 MWBOOL | |
| 788 GdGetFontInfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 789 { | |
| 790 if(!pfont || !pfont->fontprocs->GetFontInfo) | |
| 791 return FALSE; | |
| 792 | |
| 793 return pfont->fontprocs->GetFontInfo(pfont, pfontinfo); | |
| 794 } | |
| 795 | |
| 796 /* | |
| 797 * Convert from one encoding to another | |
| 798 * Input cc and returned cc is character count, not bytes | |
| 799 * Return < 0 on error or can't translate | |
| 800 */ | |
| 801 int | |
| 802 GdConvertEncoding(const void *istr, int iflags, int cc, void *ostr, int oflags) | |
| 803 { | |
| 804 const unsigned char *istr8; | |
| 805 const unsigned short *istr16; | |
| 806 const unsigned long *istr32; | |
| 807 unsigned char *ostr8; | |
| 808 unsigned short *ostr16; | |
| 809 unsigned long *ostr32; | |
| 810 unsigned int ch; | |
| 811 int icc; | |
| 812 unsigned short buf16[512]; | |
| 813 | |
| 814 iflags &= MWTF_PACKMASK; | |
| 815 oflags &= MWTF_PACKMASK; | |
| 816 | |
| 817 /* allow -1 for len with ascii*/ | |
| 818 if(cc == -1 && (iflags == MWTF_ASCII)) | |
| 819 cc = strlen((char *)istr); | |
| 820 | |
| 821 /* first check for utf8 input encoding*/ | |
| 822 if(iflags == MWTF_UTF8) { | |
| 823 /* we've only got uc16 now so convert to uc16...*/ | |
| 824 cc = utf8_to_utf16((unsigned char *)istr, cc, | |
| 825 oflags==MWTF_UC16?(unsigned short*) ostr: buf16); | |
| 826 | |
| 827 if(oflags == MWTF_UC16 || cc < 0) | |
| 828 return cc; | |
| 829 | |
| 830 /* will decode again to requested format (probably ascii)*/ | |
| 831 iflags = MWTF_UC16; | |
| 832 istr = buf16; | |
| 833 } | |
| 834 | |
| 835 #if HAVE_HZK_SUPPORT | |
| 836 if(iflags == MWTF_UC16 && oflags == MWTF_ASCII) { | |
| 837 /* only support uc16 convert to ascii now...*/ | |
| 838 cc = UC16_to_GB( istr, cc, ostr); | |
| 839 return cc; | |
| 840 } | |
| 841 #endif | |
| 842 | |
| 843 icc = cc; | |
| 844 istr8 = istr; | |
| 845 istr16 = istr; | |
| 846 istr32 = istr; | |
| 847 ostr8 = ostr; | |
| 848 ostr16 = ostr; | |
| 849 ostr32 = ostr; | |
| 850 | |
| 851 /* Convert between formats. Note that there's no error | |
| 852 * checking here yet. | |
| 853 */ | |
| 854 while(--icc >= 0) { | |
| 855 switch(iflags) { | |
| 856 default: | |
| 857 ch = *istr8++; | |
| 858 break; | |
| 859 case MWTF_UC16: | |
| 860 ch = *istr16++; | |
| 861 break; | |
| 862 case MWTF_UC32: | |
| 863 ch = *istr32++; | |
| 864 } | |
| 865 switch(oflags) { | |
| 866 default: | |
| 867 *ostr8++ = (unsigned char)ch; | |
| 868 break; | |
| 869 case MWTF_UC16: | |
| 870 *ostr16++ = (unsigned short)ch; | |
| 871 break; | |
| 872 case MWTF_UC32: | |
| 873 *ostr32++ = ch; | |
| 874 } | |
| 875 } | |
| 876 return cc; | |
| 877 } | |
| 878 | |
| 879 /* Get the width and height of passed text string in the passed font*/ | |
| 880 void | |
| 881 GdGetTextSize(PMWFONT pfont, const void *str, int cc, MWCOORD *pwidth, | |
| 882 MWCOORD *pheight, MWCOORD *pbase, int flags) | |
| 883 { | |
| 884 const void * text; | |
| 885 unsigned long buf[256]; | |
| 886 int defencoding = pfont->fontprocs->encoding; | |
| 887 | |
| 888 /* convert encoding if required*/ | |
| 889 if((flags & MWTF_PACKMASK) != defencoding) { | |
| 890 cc = GdConvertEncoding(str, flags, cc, buf, defencoding); | |
| 891 flags &= ~MWTF_PACKMASK; | |
| 892 flags |= defencoding; | |
| 893 text = buf; | |
| 894 } else text = str; | |
| 895 | |
| 896 if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII) | |
| 897 cc = strlen((char *)str); | |
| 898 | |
| 899 if(cc <= 0 || !pfont->fontprocs->GetTextSize) { | |
| 900 *pwidth = *pheight = *pbase = 0; | |
| 901 return; | |
| 902 } | |
| 903 | |
| 904 /* calc height and width of string*/ | |
| 905 pfont->fontprocs->GetTextSize(pfont, text, cc, pwidth, pheight, pbase); | |
| 906 } | |
| 907 | |
| 908 /* Draw a text string at a specifed coordinates in the foreground color | |
| 909 * (and possibly the background color), applying clipping if necessary. | |
| 910 * The background color is only drawn if the gr_usebg flag is set. | |
| 911 * Use the current font. | |
| 912 */ | |
| 913 void | |
| 914 GdText(PSD psd, MWCOORD x, MWCOORD y, const void *str, int cc, int flags) | |
| 915 { | |
| 916 const void * text; | |
| 917 unsigned long buf[256]; | |
| 918 int defencoding = gr_pfont->fontprocs->encoding; | |
| 919 | |
| 920 /* convert encoding if required*/ | |
| 921 if((flags & MWTF_PACKMASK) != defencoding) { | |
| 922 cc = GdConvertEncoding(str, flags, cc, buf, defencoding); | |
| 923 flags &= ~MWTF_PACKMASK; | |
| 924 flags |= defencoding; | |
| 925 text = buf; | |
| 926 } else text = str; | |
| 927 | |
| 928 if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII) | |
| 929 cc = strlen((char *)str); | |
| 930 | |
| 931 if(cc <= 0 || !gr_pfont->fontprocs->DrawText) | |
| 932 return; | |
| 933 | |
| 934 /* draw text string*/ | |
| 935 gr_pfont->fontprocs->DrawText(gr_pfont, psd, x, y, text, cc, flags); | |
| 936 } | |
| 937 | |
| 938 /* | |
| 939 * Draw ascii text using COREFONT type font. | |
| 940 */ | |
| 941 void | |
| 942 corefont_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 943 const void *text, int cc, int flags) | |
| 944 { | |
| 945 const unsigned char *str = text; | |
| 946 MWCOORD width; /* width of text area */ | |
| 947 MWCOORD height; /* height of text area */ | |
| 948 MWCOORD base; /* baseline of text*/ | |
| 949 MWCOORD startx, starty; | |
| 950 /* bitmap for characters */ | |
| 951 MWIMAGEBITS bitmap[MAX_CHAR_HEIGHT*MAX_CHAR_WIDTH/MWIMAGE_BITSPERIMAGE]; | |
| 952 | |
| 953 pfont->fontprocs->GetTextSize(pfont, str, cc, &width, &height, &base); | |
| 954 | |
| 955 if(flags & MWTF_BASELINE) | |
| 956 y -= base; | |
| 957 else if(flags & MWTF_BOTTOM) | |
| 958 y -= (height - 1); | |
| 959 startx = x; | |
| 960 starty = y + base; | |
| 961 | |
| 962 switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) { | |
| 963 case CLIP_VISIBLE: | |
| 964 /* | |
| 965 * For size considerations, there's no low-level text | |
| 966 * draw, so we've got to draw all text | |
| 967 * with per-point clipping for the time being | |
| 968 if (gr_usebg) | |
| 969 psd->FillRect(psd, x, y, x + width - 1, y + height - 1, | |
| 970 gr_background); | |
| 971 psd->DrawText(psd, x, y, str, cc, gr_foreground, pfont); | |
| 972 GdFixCursor(psd); | |
| 973 return; | |
| 974 */ | |
| 975 break; | |
| 976 | |
| 977 case CLIP_INVISIBLE: | |
| 978 return; | |
| 979 } | |
| 980 | |
| 981 /* Get the bitmap for each character individually, and then display | |
| 982 * them using clipping for each one. | |
| 983 */ | |
| 984 while (--cc >= 0 && x < psd->xvirtres) { | |
| 985 unsigned int ch = *str++; | |
| 986 #if HAVE_BIG5_SUPPORT | |
| 987 /* chinese big5 decoding*/ | |
| 988 if (ch >= 0xA1 && ch <= 0xF9 && cc >= 1 && | |
| 989 ((*str >= 0x40 && *str <= 0x7E) || | |
| 990 (*str >= 0xA1 && *str <= 0xFE)) ) { | |
| 991 ch = (ch << 8) | *str++; | |
| 992 --cc; | |
| 993 } | |
| 994 #endif | |
| 995 #if HAVE_GB2312_SUPPORT | |
| 996 /* chinese gb2312 decoding*/ | |
| 997 if (ch >= 0xA1 && ch < 0xF8 && cc >= 1 && | |
| 998 *str >= 0xA1 && *str < 0xFF) { | |
| 999 ch = (ch << 8) | *str++; | |
| 1000 --cc; | |
| 1001 } | |
| 1002 #endif | |
| 1003 pfont->fontprocs->GetTextBits(pfont, ch, bitmap, &width, | |
| 1004 &height, &base); | |
| 1005 | |
| 1006 /* note: change to bitmap*/ | |
| 1007 GdBitmap(psd, x, y, width, height, bitmap); | |
| 1008 x += width; | |
| 1009 } | |
| 1010 | |
| 1011 if (pfont->fontattr & MWTF_UNDERLINE) | |
| 1012 GdLine(psd, startx, starty, x, starty, FALSE); | |
| 1013 | |
| 1014 GdFixCursor(psd); | |
| 1015 } | |
| 1016 | |
| 1017 #if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT | |
| 1018 /* | |
| 1019 * Produce blend table from src and dst based on passed alpha table | |
| 1020 * Used because we don't quite yet have GdArea with alphablending, | |
| 1021 * so we pre-blend fg/bg colors for fade effect. | |
| 1022 */ | |
| 1023 static void | |
| 1024 alphablend(PSD psd, OUTPIXELVAL *out, MWPIXELVAL src, MWPIXELVAL dst, | |
| 1025 unsigned char *alpha, int count) | |
| 1026 { | |
| 1027 unsigned int a, d; | |
| 1028 unsigned char r, g, b; | |
| 1029 MWCOLORVAL palsrc, paldst; | |
| 1030 extern MWPALENTRY gr_palette[256]; | |
| 1031 | |
| 1032 while (--count >= 0) { | |
| 1033 a = *alpha++; | |
| 1034 | |
| 1035 #define BITS(pixel,shift,mask) (((pixel)>>shift)&(mask)) | |
| 1036 if(a == 0) | |
| 1037 *out++ = dst; | |
| 1038 else if(a == 255) | |
| 1039 *out++ = src; | |
| 1040 else | |
| 1041 switch(psd->pixtype) { | |
| 1042 case MWPF_TRUECOLOR0888: | |
| 1043 case MWPF_TRUECOLOR888: | |
| 1044 d = BITS(dst, 16, 0xff); | |
| 1045 r = (unsigned char)(((BITS(src, 16, 0xff) - d)*a)>>8) + d; | |
| 1046 d = BITS(dst, 8, 0xff); | |
| 1047 g = (unsigned char)(((BITS(src, 8, 0xff) - d)*a)>>8) + d; | |
| 1048 d = BITS(dst, 0, 0xff); | |
| 1049 b = (unsigned char)(((BITS(src, 0, 0xff) - d)*a)>>8) + d; | |
| 1050 *out++ = (r << 16) | (g << 8) | b; | |
| 1051 break; | |
| 1052 | |
| 1053 case MWPF_TRUECOLOR565: | |
| 1054 d = BITS(dst, 11, 0x1f); | |
| 1055 r = (unsigned char)(((BITS(src, 11, 0x1f) - d)*a)>>8) + d; | |
| 1056 d = BITS(dst, 5, 0x3f); | |
| 1057 g = (unsigned char)(((BITS(src, 5, 0x3f) - d)*a)>>8) + d; | |
| 1058 d = BITS(dst, 0, 0x1f); | |
| 1059 b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d; | |
| 1060 *out++ = (r << 11) | (g << 5) | b; | |
| 1061 break; | |
| 1062 | |
| 1063 case MWPF_TRUECOLOR555: | |
| 1064 d = BITS(dst, 10, 0x1f); | |
| 1065 r = (unsigned char)(((BITS(src, 10, 0x1f) - d)*a)>>8) + d; | |
| 1066 d = BITS(dst, 5, 0x1f); | |
| 1067 g = (unsigned char)(((BITS(src, 5, 0x1f) - d)*a)>>8) + d; | |
| 1068 d = BITS(dst, 0, 0x1f); | |
| 1069 b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d; | |
| 1070 *out++ = (r << 10) | (g << 5) | b; | |
| 1071 break; | |
| 1072 | |
| 1073 case MWPF_TRUECOLOR332: | |
| 1074 d = BITS(dst, 5, 0x07); | |
| 1075 r = (unsigned char)(((BITS(src, 5, 0x07) - d)*a)>>8) + d; | |
| 1076 d = BITS(dst, 2, 0x07); | |
| 1077 g = (unsigned char)(((BITS(src, 2, 0x07) - d)*a)>>8) + d; | |
| 1078 d = BITS(dst, 0, 0x03); | |
| 1079 b = (unsigned char)(((BITS(src, 0, 0x03) - d)*a)>>8) + d; | |
| 1080 *out++ = (r << 5) | (g << 2) | b; | |
| 1081 break; | |
| 1082 | |
| 1083 case MWPF_PALETTE: | |
| 1084 /* reverse lookup palette entry for blend ;-)*/ | |
| 1085 palsrc = GETPALENTRY(gr_palette, src); | |
| 1086 paldst = GETPALENTRY(gr_palette, dst); | |
| 1087 d = REDVALUE(paldst); | |
| 1088 r = (unsigned char)(((REDVALUE(palsrc) - d)*a)>>8) + d; | |
| 1089 d = GREENVALUE(paldst); | |
| 1090 g = (unsigned char)(((GREENVALUE(palsrc) - d)*a)>>8) + d; | |
| 1091 d = BLUEVALUE(paldst); | |
| 1092 b = (unsigned char)(((BLUEVALUE(palsrc) - d)*a)>>8) + d; | |
| 1093 *out++ = GdFindNearestColor(gr_palette, (int)psd->ncolors, | |
| 1094 MWRGB(r, g, b)); | |
| 1095 break; | |
| 1096 } | |
| 1097 } | |
| 1098 } | |
| 1099 #endif /*HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT*/ | |
| 1100 | |
| 1101 #if HAVE_T1LIB_SUPPORT | |
| 1102 /* contributed by Vidar Hokstad*/ | |
| 1103 | |
| 1104 static int | |
| 1105 t1lib_init(PSD psd) | |
| 1106 { | |
| 1107 static int inited = 0; | |
| 1108 | |
| 1109 if (inited) | |
| 1110 return 1; | |
| 1111 | |
| 1112 T1_SetBitmapPad(8); | |
| 1113 if (!T1_InitLib(0)) | |
| 1114 return 0; | |
| 1115 #ifdef T1LIB_USE_AA_HIGH | |
| 1116 T1_AASetLevel(T1_AA_HIGH); | |
| 1117 #else | |
| 1118 T1_AASetLevel(T1_AA_LOW); | |
| 1119 #endif | |
| 1120 #if 0 | |
| 1121 /* kluge: this is required if 16bpp drawarea driver is used*/ | |
| 1122 if(psd->bpp == 16) | |
| 1123 T1_AASetBitsPerPixel(16); | |
| 1124 else | |
| 1125 #endif | |
| 1126 T1_AASetBitsPerPixel(sizeof(MWPIXELVAL)*8); | |
| 1127 | |
| 1128 inited = 1; | |
| 1129 return 1; | |
| 1130 } | |
| 1131 | |
| 1132 static PMWT1LIBFONT | |
| 1133 t1lib_createfont(const char *name, MWCOORD height, int attr) | |
| 1134 { | |
| 1135 PMWT1LIBFONT pf; | |
| 1136 int id; | |
| 1137 char * p; | |
| 1138 char buf[256]; | |
| 1139 | |
| 1140 /* match name against t1 font id's from t1 font database*/ | |
| 1141 for(id=0; id<T1_Get_no_fonts(); ++id) { | |
| 1142 strncpy(buf, T1_GetFontFileName(id), sizeof(buf)); | |
| 1143 | |
| 1144 /* remove extension*/ | |
| 1145 for(p=buf; *p; ++p) { | |
| 1146 if(*p == '.') { | |
| 1147 *p = 0; | |
| 1148 break; | |
| 1149 } | |
| 1150 } | |
| 1151 | |
| 1152 if(!strcmpi(name, buf)) { | |
| 1153 /* allocate font structure*/ | |
| 1154 pf = (PMWT1LIBFONT)calloc(sizeof(MWT1LIBFONT), 1); | |
| 1155 if (!pf) | |
| 1156 return NULL; | |
| 1157 pf->fontprocs = &t1lib_procs; | |
| 1158 GdSetFontSize((PMWFONT)pf, height); | |
| 1159 GdSetFontRotation((PMWFONT)pf, 0); | |
| 1160 GdSetFontAttr((PMWFONT)pf, attr, 0); | |
| 1161 pf->fontid = id; | |
| 1162 return pf; | |
| 1163 } | |
| 1164 } | |
| 1165 return NULL; | |
| 1166 } | |
| 1167 | |
| 1168 /* | |
| 1169 * Draw ascii text string using T1LIB type font | |
| 1170 */ | |
| 1171 static void | |
| 1172 t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y, | |
| 1173 const void *text, int cc, int flags) | |
| 1174 { | |
| 1175 PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; | |
| 1176 const unsigned char *str = text; | |
| 1177 MWCOORD width; /* width of text area */ | |
| 1178 MWCOORD height; /* height of text area */ | |
| 1179 MWCOORD underliney; | |
| 1180 GLYPH * g; /* T1lib glyph structure. Memory handling by T1lib */ | |
| 1181 #ifdef T1LIB_USE_AA_HIGH | |
| 1182 OUTPIXELVAL gvals[17]; | |
| 1183 | |
| 1184 /* Blending array for antialiasing. The steeper the values increase | |
| 1185 * near the end, the sharper the characters look, but also more jagged | |
| 1186 */ | |
| 1187 static unsigned char blend[17] = { | |
| 1188 0x00, 0x00, 0x04, 0x0c, 0x10, 0x14, 0x18, 0x20, | |
| 1189 0x30, 0x38, 0x40, 0x50, 0x70, 0x80, 0xa0, 0xc0, 0xff | |
| 1190 }; | |
| 1191 #else | |
| 1192 OUTPIXELVAL gvals[5]; | |
| 1193 static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff }; | |
| 1194 #endif | |
| 1195 | |
| 1196 /* Check if we should throw out some fonts */ | |
| 1197 | |
| 1198 if (pf->fontattr&MWTF_ANTIALIAS) { | |
| 1199 #ifdef T1LIB_USE_AA_HIGH | |
| 1200 alphablend(psd, gvals, gr_foreground, gr_background, blend, 17); | |
| 1201 T1_AAHSetGrayValues(gvals); | |
| 1202 #else | |
| 1203 alphablend(psd, gvals, gr_foreground, gr_background, blend, 5); | |
| 1204 T1_AASetGrayValues(gvals[0],gvals[1],gvals[2],gvals[3],gvals[4]); | |
| 1205 #endif | |
| 1206 g = T1_AASetString(pf->fontid,(char *)str,cc,0, | |
| 1207 (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, | |
| 1208 pf->fontsize * 1.0, 0); | |
| 1209 | |
| 1210 if (g && g->bits) { | |
| 1211 /*MWPIXELVAL save = gr_background;*/ | |
| 1212 width = g->metrics.rightSideBearing - g->metrics.leftSideBearing; | |
| 1213 height = g->metrics.ascent - g->metrics.descent; | |
| 1214 | |
| 1215 if(flags & MWTF_BASELINE) | |
| 1216 y -= g->metrics.ascent; | |
| 1217 else if(flags & MWTF_BOTTOM) | |
| 1218 y -= (height - 1); | |
| 1219 underliney = y + g->metrics.ascent; | |
| 1220 | |
| 1221 /* FIXME: Looks damn ugly if usebg is false. | |
| 1222 * Will be handled when using alphablending in GdArea... | |
| 1223 */ | |
| 1224 /* clipping handled in GdArea*/ | |
| 1225 /*FIXME kluge for transparency*/ | |
| 1226 /*gr_background = gr_foreground + 1;*/ | |
| 1227 /*gr_usebg = 0;*/ | |
| 1228 GdArea(psd,x,y, width, height, g->bits, MWPF_PIXELVAL); | |
| 1229 /*gr_background = save;*/ | |
| 1230 | |
| 1231 if (pf->fontattr & MWTF_UNDERLINE) | |
| 1232 GdLine(psd, x, underliney, x+width, underliney, FALSE); | |
| 1233 | |
| 1234 } | |
| 1235 } else { | |
| 1236 /* Do non-aa drawing */ | |
| 1237 g = T1_SetString(pf->fontid,(char *)str,cc,0, | |
| 1238 (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, | |
| 1239 pf->fontsize * 1.0, 0); | |
| 1240 | |
| 1241 if (g && g->bits) { | |
| 1242 unsigned char * b; | |
| 1243 int xoff; | |
| 1244 int maxy; | |
| 1245 int xmod; | |
| 1246 | |
| 1247 /* I'm sure this sorry excuse for a bitmap rendering routine can | |
| 1248 * be optimized quite a bit ;) | |
| 1249 */ | |
| 1250 width = g->metrics.rightSideBearing - g->metrics.leftSideBearing; | |
| 1251 height = g->metrics.ascent - g->metrics.descent; | |
| 1252 | |
| 1253 if(flags & MWTF_BASELINE) | |
| 1254 y -= g->metrics.ascent; | |
| 1255 else if(flags & MWTF_BOTTOM) | |
| 1256 y -= (height - 1); | |
| 1257 underliney = y + g->metrics.ascent; | |
| 1258 | |
| 1259 b = g->bits; | |
| 1260 maxy = y + height; | |
| 1261 | |
| 1262 /* if ((x + width) > psd->xvirtres) { | |
| 1263 xmod = (x + width - psd->xvirtres + 7) >> 3; | |
| 1264 width = width + x + width - psd->xvirtres; | |
| 1265 } else xmod = 0; | |
| 1266 */ | |
| 1267 xmod = 0; | |
| 1268 while (y < maxy) { | |
| 1269 unsigned char data; | |
| 1270 xoff = 0; | |
| 1271 while (xoff < width ) { | |
| 1272 if (!(xoff % 8)) { | |
| 1273 data = *b; | |
| 1274 b++; | |
| 1275 } | |
| 1276 | |
| 1277 if (GdClipPoint(psd, x+xoff,y)) { | |
| 1278 if (gr_usebg) { | |
| 1279 psd->DrawPixel(psd,x+xoff,y, | |
| 1280 data & (1 << (xoff % 8)) ? | |
| 1281 gr_foreground : gr_background); | |
| 1282 } else if (data & (1 << (xoff % 8))) { | |
| 1283 psd->DrawPixel(psd,x+xoff,y, gr_foreground); | |
| 1284 } | |
| 1285 } | |
| 1286 xoff++; | |
| 1287 } | |
| 1288 b += xmod; | |
| 1289 y++; | |
| 1290 } | |
| 1291 if (pf->fontattr & MWTF_UNDERLINE) | |
| 1292 GdLine(psd, x, underliney, x+xoff, underliney, FALSE); | |
| 1293 } | |
| 1294 } | |
| 1295 | |
| 1296 if (g && g->bits) { | |
| 1297 /* Save some memory */ | |
| 1298 free(g->bits); | |
| 1299 g->bits = 0; /* Make sure T1lib doesnt try to free it again */ | |
| 1300 } | |
| 1301 | |
| 1302 GdFixCursor(psd); | |
| 1303 } | |
| 1304 | |
| 1305 static MWBOOL | |
| 1306 t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 1307 { | |
| 1308 int i; | |
| 1309 MWCOORD width, height, baseline; | |
| 1310 | |
| 1311 /* FIXME, guess all sizes*/ | |
| 1312 GdGetTextSize(pfont, "A", 1, &width, &height, &baseline, MWTF_ASCII); | |
| 1313 pfontinfo->height = height; | |
| 1314 pfontinfo->maxwidth = width; | |
| 1315 pfontinfo->baseline = 0; | |
| 1316 pfontinfo->firstchar = 32; | |
| 1317 pfontinfo->lastchar = 255; | |
| 1318 pfontinfo->fixed = TRUE; | |
| 1319 for(i=0; i<256; ++i) | |
| 1320 pfontinfo->widths[i] = width; | |
| 1321 return TRUE; | |
| 1322 } | |
| 1323 | |
| 1324 /* Get the width and height of passed text string in the current font*/ | |
| 1325 static void | |
| 1326 t1lib_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 1327 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) | |
| 1328 { | |
| 1329 PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; | |
| 1330 const unsigned char * str = text; | |
| 1331 GLYPH * g; | |
| 1332 | |
| 1333 g = T1_SetString(pf->fontid, (char *)str, cc, 0, | |
| 1334 (pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0); | |
| 1335 *pwidth = g->metrics.rightSideBearing - g->metrics.leftSideBearing; | |
| 1336 *pheight = g->metrics.ascent - g->metrics.descent; | |
| 1337 if(g && g->bits) { | |
| 1338 free(g->bits); | |
| 1339 g->bits = 0; | |
| 1340 } | |
| 1341 #if 0 | |
| 1342 BBox b; | |
| 1343 | |
| 1344 /* FIXME. Something is *VERY* wrong here */ | |
| 1345 b = T1_GetStringBBox(pf->fontid, str, cc, 0, (pf->fontattr&MWTF_KERNING)?T1_KERNING:0); | |
| 1346 | |
| 1347 DPRINTF("b.urx = %d, b.llx = %d\n",b.urx, b.llx); | |
| 1348 DPRINTF("b.ury = %d, b.lly = %d\n",b.ury, b.lly); | |
| 1349 *pwidth = (b.urx - b.llx); | |
| 1350 *pheight = (b.lly - b.ury); | |
| 1351 #endif | |
| 1352 } | |
| 1353 | |
| 1354 static void | |
| 1355 t1lib_destroyfont(PMWFONT pfont) | |
| 1356 { | |
| 1357 PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont; | |
| 1358 | |
| 1359 T1_DeleteAllSizes(pf->fontid); | |
| 1360 free(pf); | |
| 1361 } | |
| 1362 | |
| 1363 #endif /* HAVE_T1LIB_SUPPORT*/ | |
| 1364 | |
| 1365 #if HAVE_FREETYPE_SUPPORT | |
| 1366 static OUTPIXELVAL gray_palette[5]; | |
| 1367 | |
| 1368 static int | |
| 1369 freetype_init(PSD psd) | |
| 1370 { | |
| 1371 static int inited = 0; | |
| 1372 | |
| 1373 if (inited) | |
| 1374 return 1; | |
| 1375 | |
| 1376 /* Init freetype library */ | |
| 1377 if (TT_Init_FreeType (&engine) != TT_Err_Ok) { | |
| 1378 return 0; | |
| 1379 } | |
| 1380 | |
| 1381 /* Init kerning extension */ | |
| 1382 if (TT_Init_Kerning_Extension (engine) != TT_Err_Ok) | |
| 1383 return 0; | |
| 1384 | |
| 1385 inited = 1; | |
| 1386 return 1; | |
| 1387 } | |
| 1388 | |
| 1389 static PMWFREETYPEFONT | |
| 1390 freetype_createfont(const char *name, MWCOORD height, int attr) | |
| 1391 { | |
| 1392 PMWFREETYPEFONT pf; | |
| 1393 unsigned short i, n; | |
| 1394 unsigned short platform, encoding; | |
| 1395 TT_Face_Properties properties; | |
| 1396 char * p; | |
| 1397 char fontname[128]; | |
| 1398 | |
| 1399 /* check for pathname prefix*/ | |
| 1400 if (strchr(name, '/') != NULL) | |
| 1401 strcpy(fontname, name); | |
| 1402 else { | |
| 1403 strcpy(fontname, FREETYPE_FONT_DIR); | |
| 1404 strcat(fontname, "/"); | |
| 1405 strcat(fontname, name); | |
| 1406 } | |
| 1407 | |
| 1408 /* check for extension*/ | |
| 1409 if ((p = strrchr(fontname, '.')) == NULL || | |
| 1410 strcmp(p, ".ttf") != 0) { | |
| 1411 strcat(fontname, ".ttf"); | |
| 1412 } | |
| 1413 | |
| 1414 /* allocate font structure*/ | |
| 1415 pf = (PMWFREETYPEFONT)calloc(sizeof(MWFREETYPEFONT), 1); | |
| 1416 if (!pf) | |
| 1417 return NULL; | |
| 1418 pf->fontprocs = &freetype_procs; | |
| 1419 | |
| 1420 /* Load face */ | |
| 1421 if (TT_Open_Face (engine, fontname, &pf->face) != TT_Err_Ok) | |
| 1422 goto out; | |
| 1423 | |
| 1424 /* Load first kerning table */ | |
| 1425 pf->can_kern = TRUE; | |
| 1426 if (TT_Load_Kerning_Table (pf->face, 0) != TT_Err_Ok) | |
| 1427 pf->can_kern = FALSE; | |
| 1428 else { | |
| 1429 if (TT_Get_Kerning_Directory (pf->face, &pf->directory) | |
| 1430 != TT_Err_Ok) | |
| 1431 pf->can_kern = FALSE; | |
| 1432 else { | |
| 1433 /* Support only version 0 kerning table ... */ | |
| 1434 if ((pf->directory.version != 0) || | |
| 1435 (pf->directory.nTables <= 0) || | |
| 1436 (pf->directory.tables->loaded != 1) || | |
| 1437 (pf->directory.tables->version != 0) || | |
| 1438 (pf->directory.tables->t.kern0.nPairs <= 0)) | |
| 1439 pf->can_kern = FALSE; | |
| 1440 } | |
| 1441 } | |
| 1442 | |
| 1443 /* get face properties and allocate preload arrays */ | |
| 1444 TT_Get_Face_Properties (pf->face, &properties); | |
| 1445 | |
| 1446 #if 0 | |
| 1447 /* | |
| 1448 * Use header information for ascent and descent | |
| 1449 * to compute scaled ascent/descent for current font height. | |
| 1450 */ | |
| 1451 h = properties.os2->sTypoAscender - properties.os2->sTypoDescender | |
| 1452 + properties.os2->sTypoLineGap; | |
| 1453 ascent = properties.os2->sTypoAscender | |
| 1454 + properties.os2->sTypoLineGap/2; | |
| 1455 pf->ascent = (ascent * height + h/2) / h; | |
| 1456 pf->descent = height - pf->ascent; | |
| 1457 #endif | |
| 1458 /* Create a glyph container */ | |
| 1459 if (TT_New_Glyph (pf->face, &pf->glyph) != TT_Err_Ok) | |
| 1460 goto out; | |
| 1461 | |
| 1462 /* create instance */ | |
| 1463 if (TT_New_Instance (pf->face, &pf->instance) != TT_Err_Ok) | |
| 1464 goto out; | |
| 1465 | |
| 1466 /* Set the instance resolution */ | |
| 1467 if (TT_Set_Instance_Resolutions (pf->instance, 96, 96) != TT_Err_Ok) | |
| 1468 goto out; | |
| 1469 | |
| 1470 /* Look for a Unicode charmap: Windows flavor of Apple flavor only */ | |
| 1471 n = properties.num_CharMaps; | |
| 1472 | |
| 1473 for (i = 0; i < n; i++) { | |
| 1474 TT_Get_CharMap_ID (pf->face, i, &platform, &encoding); | |
| 1475 if (((platform == TT_PLATFORM_MICROSOFT) && | |
| 1476 (encoding == TT_MS_ID_UNICODE_CS)) || | |
| 1477 ((platform == TT_PLATFORM_APPLE_UNICODE) && | |
| 1478 (encoding == TT_APPLE_ID_DEFAULT))) | |
| 1479 { | |
| 1480 TT_Get_CharMap (pf->face, i, &pf->char_map); | |
| 1481 i = n + 1; | |
| 1482 } | |
| 1483 } | |
| 1484 if (i == n) { | |
| 1485 DPRINTF("freetype_createfont: no unicode map table\n"); | |
| 1486 goto out; | |
| 1487 } | |
| 1488 | |
| 1489 GdSetFontSize((PMWFONT)pf, height); | |
| 1490 GdSetFontRotation((PMWFONT)pf, 0); | |
| 1491 GdSetFontAttr((PMWFONT)pf, attr, 0); | |
| 1492 | |
| 1493 return pf; | |
| 1494 | |
| 1495 out: | |
| 1496 free(pf); | |
| 1497 return NULL; | |
| 1498 } | |
| 1499 | |
| 1500 static int | |
| 1501 compute_kernval(PMWFREETYPEFONT pf, short current_glyph_code) | |
| 1502 { | |
| 1503 int i = 0; | |
| 1504 int kernval; | |
| 1505 int nPairs = pf->directory.tables->t.kern0.nPairs; | |
| 1506 TT_Kern_0_Pair *pair = pf->directory.tables->t.kern0.pairs; | |
| 1507 | |
| 1508 if (pf->last_glyph_code != -1) { | |
| 1509 while ((pair->left != pf->last_glyph_code) | |
| 1510 && (pair->right != current_glyph_code)) | |
| 1511 { | |
| 1512 pair++; | |
| 1513 i++; | |
| 1514 if (i == nPairs) | |
| 1515 break; | |
| 1516 } | |
| 1517 | |
| 1518 if (i == nPairs) | |
| 1519 kernval = 0; | |
| 1520 else | |
| 1521 /* We round the value (hence the +32) */ | |
| 1522 kernval = (pair->value + 32) & -64; | |
| 1523 } else | |
| 1524 kernval = 0; | |
| 1525 | |
| 1526 return kernval; | |
| 1527 } | |
| 1528 | |
| 1529 static TT_UShort | |
| 1530 Get_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index) | |
| 1531 { | |
| 1532 TT_Glyph_Metrics metrics; | |
| 1533 | |
| 1534 if (TT_Load_Glyph ( pf->instance, pf->glyph, | |
| 1535 TT_Char_Index (pf->char_map,glyph_index), | |
| 1536 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 1537 { | |
| 1538 /* Try to load default glyph: index 0 */ | |
| 1539 if (TT_Load_Glyph ( pf->instance, pf->glyph, 0, | |
| 1540 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 1541 return 0; | |
| 1542 } | |
| 1543 | |
| 1544 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 1545 return((metrics.advance & 0xFFFFFFC0) >> 6); | |
| 1546 } | |
| 1547 | |
| 1548 static MWFREETYPEFONTCACHE * | |
| 1549 find_cache_glyph ( PMWFREETYPEFONT pf, unsigned curchar ) | |
| 1550 { | |
| 1551 MWFREETYPEFONTCACHE ** inode = &pf->glyph_cache; | |
| 1552 | |
| 1553 while (1) | |
| 1554 { | |
| 1555 if (*inode == 0) | |
| 1556 { | |
| 1557 *inode = calloc(sizeof(MWFREETYPEFONTCACHE),1); | |
| 1558 (*inode)->curchar = curchar; | |
| 1559 } | |
| 1560 | |
| 1561 if (curchar < (*inode)->curchar) | |
| 1562 inode = &(*inode)->l; | |
| 1563 else if (curchar > (*inode)->curchar) | |
| 1564 inode = &(*inode)->r; | |
| 1565 else | |
| 1566 return *inode; | |
| 1567 } | |
| 1568 } | |
| 1569 | |
| 1570 static void | |
| 1571 free_cache_glyph ( MWFREETYPEFONTCACHE * node ) | |
| 1572 { | |
| 1573 if (node->l != 0) | |
| 1574 free_cache_glyph(node->l); | |
| 1575 | |
| 1576 if (node->r != 0) | |
| 1577 free_cache_glyph(node->r); | |
| 1578 | |
| 1579 free(node); | |
| 1580 } | |
| 1581 | |
| 1582 /* Render a single glyph*/ | |
| 1583 static void | |
| 1584 drawchar(PMWFREETYPEFONT pf, PSD psd, unsigned curchar, int x_offset, | |
| 1585 int y_offset) | |
| 1586 { | |
| 1587 TT_F26Dot6 xmin, ymin, xmax, ymax, x, y, z; | |
| 1588 unsigned char *src, *srcptr; | |
| 1589 MWPIXELVAL *dst, *dstptr; | |
| 1590 MWPIXELVAL *bitmap; | |
| 1591 int size, width, height; | |
| 1592 TT_Outline outline; | |
| 1593 TT_BBox bbox; | |
| 1594 TT_Raster_Map Raster; | |
| 1595 TT_Error error; | |
| 1596 /*MWPIXELVAL save;*/ | |
| 1597 MWFREETYPEFONTCACHE * cache; | |
| 1598 | |
| 1599 /* we begin by grid-fitting the bounding box */ | |
| 1600 TT_Get_Glyph_Outline (pf->glyph, &outline); | |
| 1601 TT_Get_Outline_BBox (&outline, &bbox); | |
| 1602 | |
| 1603 xmin = (bbox.xMin & -64) >> 6; | |
| 1604 ymin = (bbox.yMin & -64) >> 6; | |
| 1605 xmax = ((bbox.xMax + 63) & -64) >> 6; | |
| 1606 ymax = ((bbox.yMax + 63) & -64) >> 6; | |
| 1607 width = xmax - xmin; | |
| 1608 height = ymax - ymin; | |
| 1609 size = width * height; | |
| 1610 | |
| 1611 /* now re-allocate the raster bitmap */ | |
| 1612 Raster.rows = height; | |
| 1613 Raster.width = width; | |
| 1614 | |
| 1615 if (pf->fontattr&MWTF_ANTIALIAS) | |
| 1616 Raster.cols = (Raster.width + 3) & -4; /* pad to 32-bits */ | |
| 1617 else | |
| 1618 Raster.cols = (Raster.width + 7) & -8; /* pad to 64-bits ??? */ | |
| 1619 | |
| 1620 cache = find_cache_glyph(pf,curchar); | |
| 1621 /* SDR: if cache is 0 here, something really really bad happened */ | |
| 1622 | |
| 1623 Raster.flow = TT_Flow_Up; | |
| 1624 Raster.size = Raster.rows * Raster.cols; | |
| 1625 Raster.bitmap = cache->buffer; | |
| 1626 | |
| 1627 if (Raster.bitmap == 0) | |
| 1628 { | |
| 1629 Raster.bitmap = malloc (Raster.size); | |
| 1630 | |
| 1631 memset (Raster.bitmap, 0, Raster.size); | |
| 1632 | |
| 1633 /* now render the glyph in the small pixmap */ | |
| 1634 | |
| 1635 /* IMPORTANT NOTE: the offset parameters passed to the function */ | |
| 1636 /* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */ | |
| 1637 /* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */ | |
| 1638 /* This is why we _did_ grid-fit the bounding box, especially xmin */ | |
| 1639 /* and ymin. */ | |
| 1640 | |
| 1641 if (!(pf->fontattr&MWTF_ANTIALIAS)) | |
| 1642 error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster, | |
| 1643 -xmin * 64, -ymin * 64); | |
| 1644 else | |
| 1645 error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster, | |
| 1646 -xmin * 64, -ymin * 64); | |
| 1647 | |
| 1648 if (error) { | |
| 1649 free (Raster.bitmap); | |
| 1650 return; | |
| 1651 } | |
| 1652 | |
| 1653 cache->buffer = Raster.bitmap; | |
| 1654 } | |
| 1655 | |
| 1656 #if MWFREETYPEFONT_CACHEBITMAP | |
| 1657 if ((memcmp(&gr_foreground,&cache->fg,sizeof(gr_foreground)) != 0) || | |
| 1658 (memcmp(&gr_background,&cache->bg,sizeof(gr_background)) != 0) || | |
| 1659 (gr_usebg != cache->usebg)) | |
| 1660 { | |
| 1661 if (cache->bitmap) | |
| 1662 { | |
| 1663 free(cache->bitmap); | |
| 1664 cache->bitmap = 0; | |
| 1665 } | |
| 1666 } | |
| 1667 | |
| 1668 bitmap = cache->bitmap; | |
| 1669 #else | |
| 1670 bitmap = 0; | |
| 1671 #endif | |
| 1672 | |
| 1673 if (bitmap == 0) | |
| 1674 { | |
| 1675 bitmap = malloc (size * sizeof (MWPIXELVAL)); | |
| 1676 memset (bitmap, 0, size * sizeof (MWPIXELVAL)); | |
| 1677 | |
| 1678 src = (char *) Raster.bitmap; | |
| 1679 dst = bitmap + (size - width); | |
| 1680 | |
| 1681 for (y = ymin; y < ymax; y++) | |
| 1682 { | |
| 1683 srcptr = src; | |
| 1684 dstptr = dst; | |
| 1685 | |
| 1686 for (x = xmin; x < xmax; x++) | |
| 1687 { | |
| 1688 if (pf->fontattr&MWTF_ANTIALIAS) | |
| 1689 *dstptr++ = gray_palette[(int) *srcptr]; | |
| 1690 else | |
| 1691 { | |
| 1692 for ( z=0; | |
| 1693 z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7); | |
| 1694 z++ ) | |
| 1695 *dstptr++ = ((*srcptr << z) & 0x80) ? gr_foreground : gr_background; | |
| 1696 x += 7; | |
| 1697 } | |
| 1698 | |
| 1699 srcptr++; | |
| 1700 } | |
| 1701 | |
| 1702 src += Raster.cols; | |
| 1703 dst -= width; | |
| 1704 } | |
| 1705 #if MWFREETYPEFONT_CACHEBITMAP | |
| 1706 cache->fg = gr_foreground; | |
| 1707 cache->bg = gr_background; | |
| 1708 cache->usebg = gr_usebg; | |
| 1709 cache->bitmap = bitmap; | |
| 1710 #endif | |
| 1711 } | |
| 1712 | |
| 1713 /* Now draw the bitmap ... */ | |
| 1714 GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height, | |
| 1715 bitmap, MWPF_PIXELVAL); | |
| 1716 | |
| 1717 #if !MWFREETYPEFONT_CACHEBITMAP | |
| 1718 free(bitmap); | |
| 1719 #endif | |
| 1720 } | |
| 1721 | |
| 1722 /* | |
| 1723 * Draw unicode 16 text string using FREETYPE type font | |
| 1724 */ | |
| 1725 static void | |
| 1726 freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, | |
| 1727 const void *text, int cc, int flags) | |
| 1728 { | |
| 1729 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1730 const unsigned short * str = text; | |
| 1731 TT_F26Dot6 x = ax, y = ay; | |
| 1732 TT_Pos vec_x, vec_y; | |
| 1733 int i; | |
| 1734 TT_F26Dot6 startx, starty; | |
| 1735 TT_Outline outline; | |
| 1736 TT_UShort curchar; | |
| 1737 TT_Glyph_Metrics metrics; | |
| 1738 TT_Face_Properties properties; | |
| 1739 TT_Instance_Metrics imetrics; | |
| 1740 TT_F26Dot6 ascent, descent; | |
| 1741 static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff }; | |
| 1742 static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 }; | |
| 1743 | |
| 1744 pf->last_glyph_code = -1; /* reset kerning*/ | |
| 1745 pf->last_pen_pos = -32767; | |
| 1746 | |
| 1747 /* | |
| 1748 * Compute instance ascent & descent values | |
| 1749 * in fractional units (1/64th pixel) | |
| 1750 */ | |
| 1751 TT_Get_Face_Properties (pf->face, &properties); | |
| 1752 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 1753 | |
| 1754 ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000); | |
| 1755 descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000); | |
| 1756 | |
| 1757 /* | |
| 1758 * Offset the starting point if necessary, | |
| 1759 * FreeType always aligns at baseline | |
| 1760 */ | |
| 1761 if (flags&MWTF_BOTTOM) { | |
| 1762 vec_x = 0; | |
| 1763 vec_y = descent; | |
| 1764 TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); | |
| 1765 x -= vec_x / 64; | |
| 1766 y += vec_y / 64; | |
| 1767 } else if (flags&MWTF_TOP) { | |
| 1768 vec_x = 0; | |
| 1769 vec_y = ascent; | |
| 1770 TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); | |
| 1771 x -= vec_x / 64; | |
| 1772 y += vec_y / 64; | |
| 1773 } | |
| 1774 | |
| 1775 /* Set the "graylevels" */ | |
| 1776 if (pf->fontattr&MWTF_ANTIALIAS) { | |
| 1777 TT_Set_Raster_Gray_Palette (engine, virtual_palette); | |
| 1778 | |
| 1779 alphablend(psd, gray_palette, gr_foreground, gr_background, | |
| 1780 blend, 5); | |
| 1781 } | |
| 1782 | |
| 1783 startx = x; | |
| 1784 starty = y; | |
| 1785 for (i = 0; i < cc; i++) { | |
| 1786 curchar = TT_Char_Index (pf->char_map, str[i]); | |
| 1787 | |
| 1788 if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, | |
| 1789 TTLOAD_DEFAULT) != TT_Err_Ok) | |
| 1790 continue; | |
| 1791 | |
| 1792 if (pf->fontrotation) { | |
| 1793 TT_Get_Glyph_Outline (pf->glyph, &outline); | |
| 1794 TT_Transform_Outline (&outline, &pf->matrix); | |
| 1795 } | |
| 1796 | |
| 1797 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 1798 | |
| 1799 if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { | |
| 1800 if (pf->fontrotation) { | |
| 1801 vec_x = compute_kernval(pf, curchar); | |
| 1802 vec_y = 0; | |
| 1803 TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix); | |
| 1804 | |
| 1805 x += vec_x / 64; | |
| 1806 y -= vec_y / 64; | |
| 1807 } else | |
| 1808 x += compute_kernval(pf, curchar) / 64; | |
| 1809 } | |
| 1810 | |
| 1811 drawchar(pf, psd, curchar, x, y); | |
| 1812 | |
| 1813 if (pf->fontrotation) { | |
| 1814 vec_x = metrics.advance; | |
| 1815 vec_y = 0; | |
| 1816 TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix); | |
| 1817 | |
| 1818 x += vec_x / 64; | |
| 1819 y -= vec_y / 64; | |
| 1820 } else { | |
| 1821 x += metrics.advance / 64; | |
| 1822 | |
| 1823 /* Kerning point syndrome avoidance */ | |
| 1824 if (pf->last_pen_pos > x) | |
| 1825 x = pf->last_pen_pos; | |
| 1826 pf->last_pen_pos = x; | |
| 1827 } | |
| 1828 | |
| 1829 pf->last_glyph_code = curchar; | |
| 1830 } | |
| 1831 | |
| 1832 if (pf->fontattr & MWTF_UNDERLINE) | |
| 1833 GdLine(psd, startx, starty, x, y, FALSE); | |
| 1834 } | |
| 1835 | |
| 1836 /* | |
| 1837 * Return information about a specified font. | |
| 1838 */ | |
| 1839 static MWBOOL | |
| 1840 freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 1841 { | |
| 1842 int i; | |
| 1843 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1844 TT_Face_Properties properties; | |
| 1845 TT_Instance_Metrics imetrics; | |
| 1846 TT_UShort last_glyph_index; | |
| 1847 | |
| 1848 TT_Get_Face_Properties (pf->face, &properties); | |
| 1849 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 1850 | |
| 1851 /* Fill up the fields */ | |
| 1852 pfontinfo->height = (((properties.horizontal->Ascender * \ | |
| 1853 imetrics.y_scale)/ 0x10000) >> 6) - | |
| 1854 (((properties.horizontal->Descender * \ | |
| 1855 imetrics.y_scale)/ 0x10000) >> 6); | |
| 1856 pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \ | |
| 1857 imetrics.x_scale)/ 0x10000) >> 6; | |
| 1858 pfontinfo->baseline = ((properties.horizontal->Ascender * \ | |
| 1859 imetrics.y_scale)/ 0x10000) >> 6; | |
| 1860 pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL); | |
| 1861 pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL); | |
| 1862 pfontinfo->fixed = properties.postscript->isFixedPitch; | |
| 1863 | |
| 1864 last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1; | |
| 1865 | |
| 1866 /* Doesn't work ... don't know why ....*/ | |
| 1867 #if 0 | |
| 1868 if (TT_Get_Face_Widths( pf->face, 0, | |
| 1869 last_glyph_index, widths, NULL ) != TT_Err_Ok) { | |
| 1870 return TRUE; | |
| 1871 } | |
| 1872 | |
| 1873 for(i=0; i<=last_glyph_index; i++) | |
| 1874 DPRINTF("widths[%d]: %d\n", i, widths[i]); | |
| 1875 #endif | |
| 1876 | |
| 1877 /* Get glyphs widths */ | |
| 1878 for(i=0; i<=last_glyph_index; i++) | |
| 1879 pfontinfo->widths[i] = Get_Glyph_Width(pf, i); | |
| 1880 | |
| 1881 #if 0 | |
| 1882 DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\ | |
| 1883 x_resolution: %d\ny_resolution: %d\n", | |
| 1884 imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \ | |
| 1885 imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution); | |
| 1886 | |
| 1887 DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\ | |
| 1888 Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\ | |
| 1889 sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\ | |
| 1890 usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\ | |
| 1891 OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\ | |
| 1892 Postscript Say monospaced?: %d\n",\ | |
| 1893 properties.horizontal->Ascender, | |
| 1894 properties.horizontal->Descender, | |
| 1895 properties.horizontal->xMax_Extent, | |
| 1896 (properties.header->Mac_Style & 0x2)?1:0, | |
| 1897 (properties.header->Mac_Style & 0x1)?1:0, | |
| 1898 properties.os2->sTypoAscender, | |
| 1899 properties.os2->sTypoDescender, | |
| 1900 properties.os2->usWinAscent, | |
| 1901 properties.os2->usWinDescent, | |
| 1902 properties.os2->usFirstCharIndex, | |
| 1903 properties.os2->usLastCharIndex, | |
| 1904 (properties.os2->fsSelection & 0x1)?1:0, | |
| 1905 (properties.os2->fsSelection & 0x20)?1:0, | |
| 1906 properties.postscript->isFixedPitch, | |
| 1907 (properties.os2->panose[3] == 9)?1:0); | |
| 1908 #endif | |
| 1909 | |
| 1910 return TRUE; | |
| 1911 } | |
| 1912 | |
| 1913 static void | |
| 1914 freetype_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 1915 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) | |
| 1916 { | |
| 1917 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1918 const unsigned short * str = text; | |
| 1919 TT_F26Dot6 x = 0; | |
| 1920 int i; | |
| 1921 TT_UShort curchar; | |
| 1922 TT_Glyph_Metrics metrics; | |
| 1923 TT_Face_Properties properties; | |
| 1924 TT_Instance_Metrics imetrics; | |
| 1925 | |
| 1926 TT_Get_Face_Properties (pf->face, &properties); | |
| 1927 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 1928 | |
| 1929 pf->last_glyph_code = -1; /* reset kerning*/ | |
| 1930 pf->last_pen_pos = -32767; | |
| 1931 | |
| 1932 for (i = 0; i < cc; i++) { | |
| 1933 curchar = TT_Char_Index (pf->char_map, str[i]); | |
| 1934 | |
| 1935 if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, | |
| 1936 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 1937 continue; | |
| 1938 | |
| 1939 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 1940 | |
| 1941 if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) { | |
| 1942 x += compute_kernval(pf, curchar) / 64; | |
| 1943 } | |
| 1944 | |
| 1945 x += metrics.advance / 64; | |
| 1946 | |
| 1947 /* Kerning point syndrome avoidance */ | |
| 1948 if (pf->last_pen_pos > x) | |
| 1949 x = pf->last_pen_pos; | |
| 1950 pf->last_pen_pos = x; | |
| 1951 | |
| 1952 pf->last_glyph_code = curchar; | |
| 1953 } | |
| 1954 | |
| 1955 *pwidth = x; | |
| 1956 *pheight = (((properties.horizontal->Ascender * | |
| 1957 imetrics.y_scale)/ 0x10000) >> 6) - | |
| 1958 (((properties.horizontal->Descender * | |
| 1959 imetrics.y_scale)/ 0x10000) >> 6); | |
| 1960 /* FIXME: is it what's required ?? */ | |
| 1961 *pbase = (((-properties.horizontal->Descender) * | |
| 1962 imetrics.y_scale)/ 0x10000) >> 6; | |
| 1963 } | |
| 1964 | |
| 1965 static void | |
| 1966 freetype_destroyfont(PMWFONT pfont) | |
| 1967 { | |
| 1968 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1969 | |
| 1970 TT_Close_Face(pf->face); | |
| 1971 | |
| 1972 /*----------*/ | |
| 1973 | |
| 1974 if (pf->glyph_cache != 0) | |
| 1975 free_cache_glyph(pf->glyph_cache); | |
| 1976 | |
| 1977 /*----------*/ | |
| 1978 | |
| 1979 free(pf); | |
| 1980 } | |
| 1981 | |
| 1982 static void | |
| 1983 freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize) | |
| 1984 { | |
| 1985 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 1986 | |
| 1987 pf->fontsize = fontsize; | |
| 1988 | |
| 1989 /* We want real pixel sizes ... not points ...*/ | |
| 1990 TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize, | |
| 1991 pf->fontsize, pf->fontsize * 64 ); | |
| 1992 #if 0 | |
| 1993 /* set charsize (convert to points for freetype)*/ | |
| 1994 TT_Set_Instance_CharSize (pf->instance, | |
| 1995 ((pf->fontsize * 72 + 96/2) / 96) * 64); | |
| 1996 #endif | |
| 1997 } | |
| 1998 | |
| 1999 static void | |
| 2000 freetype_setfontrotation(PMWFONT pfont, int tenthdegrees) | |
| 2001 { | |
| 2002 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 2003 float angle; | |
| 2004 | |
| 2005 pf->fontrotation = tenthdegrees; | |
| 2006 | |
| 2007 /* Build the rotation matrix with the given angle */ | |
| 2008 TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE); | |
| 2009 | |
| 2010 angle = pf->fontrotation * M_PI / 1800; | |
| 2011 pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16)); | |
| 2012 pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16)); | |
| 2013 pf->matrix.xx = pf->matrix.yy; | |
| 2014 pf->matrix.xy = -pf->matrix.yx; | |
| 2015 } | |
| 2016 | |
| 2017 #endif /* HAVE_FREETYPE_SUPPORT*/ | |
| 2018 | |
| 2019 /* UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g. | |
| 2020 * a single 4-byte UTF-8 character is encoded into a surrogate pair. | |
| 2021 * On the other hand, if the UTF-8 string contains surrogate values, this | |
| 2022 * is considered an error and returned as such. | |
| 2023 * | |
| 2024 * The destination array must be able to hold as many Unicode-16 characters | |
| 2025 * as there are ASCII characters in the UTF-8 string. This in case all UTF-8 | |
| 2026 * characters are ASCII characters. No more will be needed. | |
| 2027 * | |
| 2028 * Copyright (c) 2000 Morten Rolland, Screen Media | |
| 2029 */ | |
| 2030 static int | |
| 2031 utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16) | |
| 2032 { | |
| 2033 int count = 0; | |
| 2034 unsigned char c0, c1; | |
| 2035 unsigned long scalar; | |
| 2036 | |
| 2037 while(--cc >= 0) { | |
| 2038 c0 = *utf8++; | |
| 2039 /*DPRINTF("Trying: %02x\n",c0);*/ | |
| 2040 | |
| 2041 if ( c0 < 0x80 ) { | |
| 2042 /* Plain ASCII character, simple translation :-) */ | |
| 2043 *unicode16++ = c0; | |
| 2044 count++; | |
| 2045 continue; | |
| 2046 } | |
| 2047 | |
| 2048 if ( (c0 & 0xc0) == 0x80 ) | |
| 2049 /* Illegal; starts with 10xxxxxx */ | |
| 2050 return -1; | |
| 2051 | |
| 2052 /* c0 must be 11xxxxxx if we get here => at least 2 bytes */ | |
| 2053 scalar = c0; | |
| 2054 if(--cc < 0) | |
| 2055 return -1; | |
| 2056 c1 = *utf8++; | |
| 2057 /*DPRINTF("c1=%02x\n",c1);*/ | |
| 2058 if ( (c1 & 0xc0) != 0x80 ) | |
| 2059 /* Bad byte */ | |
| 2060 return -1; | |
| 2061 scalar <<= 6; | |
| 2062 scalar |= (c1 & 0x3f); | |
| 2063 | |
| 2064 if ( !(c0 & 0x20) ) { | |
| 2065 /* Two bytes UTF-8 */ | |
| 2066 if ( scalar < 0x80 ) | |
| 2067 return -1; /* Overlong encoding */ | |
| 2068 *unicode16++ = scalar & 0x7ff; | |
| 2069 count++; | |
| 2070 continue; | |
| 2071 } | |
| 2072 | |
| 2073 /* c0 must be 111xxxxx if we get here => at least 3 bytes */ | |
| 2074 if(--cc < 0) | |
| 2075 return -1; | |
| 2076 c1 = *utf8++; | |
| 2077 /*DPRINTF("c1=%02x\n",c1);*/ | |
| 2078 if ( (c1 & 0xc0) != 0x80 ) | |
| 2079 /* Bad byte */ | |
| 2080 return -1; | |
| 2081 scalar <<= 6; | |
| 2082 scalar |= (c1 & 0x3f); | |
| 2083 | |
| 2084 if ( !(c0 & 0x10) ) { | |
| 2085 /*DPRINTF("####\n");*/ | |
| 2086 /* Three bytes UTF-8 */ | |
| 2087 if ( scalar < 0x800 ) | |
| 2088 return -1; /* Overlong encoding */ | |
| 2089 if ( scalar >= 0xd800 && scalar < 0xe000 ) | |
| 2090 return -1; /* UTF-16 high/low halfs */ | |
| 2091 *unicode16++ = scalar & 0xffff; | |
| 2092 count++; | |
| 2093 continue; | |
| 2094 } | |
| 2095 | |
| 2096 /* c0 must be 1111xxxx if we get here => at least 4 bytes */ | |
| 2097 c1 = *utf8++; | |
| 2098 if(--cc < 0) | |
| 2099 return -1; | |
| 2100 /*DPRINTF("c1=%02x\n",c1);*/ | |
| 2101 if ( (c1 & 0xc0) != 0x80 ) | |
| 2102 /* Bad byte */ | |
| 2103 return -1; | |
| 2104 scalar <<= 6; | |
| 2105 scalar |= (c1 & 0x3f); | |
| 2106 | |
| 2107 if ( !(c0 & 0x08) ) { | |
| 2108 /* Four bytes UTF-8, needs encoding as surrogates */ | |
| 2109 if ( scalar < 0x10000 ) | |
| 2110 return -1; /* Overlong encoding */ | |
| 2111 scalar -= 0x10000; | |
| 2112 *unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800; | |
| 2113 *unicode16++ = (scalar & 0x3ff) + 0xdc00; | |
| 2114 count += 2; | |
| 2115 continue; | |
| 2116 } | |
| 2117 | |
| 2118 return -1; /* No support for more than four byte UTF-8 */ | |
| 2119 } | |
| 2120 return count; | |
| 2121 } | |
| 2122 | |
| 2123 #if HAVE_HZK_SUPPORT | |
| 2124 | |
| 2125 /* UniCode-16 (MWTF_UC16) to GB(MWTF_ASCII) Chinese Characters conversion. | |
| 2126 * a single 2-byte UC16 character is encoded into a surrogate pair. | |
| 2127 * return -1 ,if error; | |
| 2128 * The destination array must be able to hold as many | |
| 2129 * as there are Unicode-16 characters. | |
| 2130 * | |
| 2131 * Copyright (c) 2000 Tang Hao (TownHall)(tang_hao@263.net). | |
| 2132 */ | |
| 2133 static int | |
| 2134 UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii) | |
| 2135 { | |
| 2136 FILE* fp; | |
| 2137 char buffer[256]; | |
| 2138 unsigned char *uc16p; | |
| 2139 int i=0,j=0, k; | |
| 2140 unsigned char *filebuffer; | |
| 2141 unsigned short *uc16pp,*table; | |
| 2142 unsigned short uc16px; | |
| 2143 int length=31504; | |
| 2144 | |
| 2145 if (use_big5) | |
| 2146 length=54840; | |
| 2147 | |
| 2148 uc16p=(unsigned char *) uc16; | |
| 2149 uc16pp=(unsigned short *) uc16; | |
| 2150 | |
| 2151 strcpy(buffer,HZK_FONT_DIR); | |
| 2152 if (use_big5) | |
| 2153 strcat(buffer,"/BG2UBG.KU"); | |
| 2154 else | |
| 2155 strcat(buffer,"/UGB2GB.KU"); | |
| 2156 if(!(fp = fopen(buffer, "rb"))) | |
| 2157 { | |
| 2158 fprintf (stderr, "Error.\nThe %s file can not be found!\n",buffer); | |
| 2159 return -1; | |
| 2160 } | |
| 2161 | |
| 2162 filebuffer= (unsigned char *)malloc ( length); | |
| 2163 | |
| 2164 if(fread(filebuffer, sizeof(char),length, fp) < length) { | |
| 2165 fprintf (stderr, "Error in reading ugb2gb.ku file!\n"); | |
| 2166 fclose(fp); | |
| 2167 return -1; | |
| 2168 } | |
| 2169 fclose(fp); | |
| 2170 | |
| 2171 if (use_big5) | |
| 2172 { | |
| 2173 table=(unsigned short *)filebuffer; | |
| 2174 while(1) | |
| 2175 { | |
| 2176 if(j>=cc) | |
| 2177 { | |
| 2178 ascii[i]=0; | |
| 2179 break; | |
| 2180 } | |
| 2181 uc16px=*uc16pp; | |
| 2182 if((uc16px)<=0x00ff) | |
| 2183 { | |
| 2184 ascii[i]=(char)(*uc16pp); | |
| 2185 i++; | |
| 2186 } | |
| 2187 else | |
| 2188 { | |
| 2189 ascii[i]=0xa1; ascii[i+1]=0x40; | |
| 2190 for (k=0; k<13710; k++) | |
| 2191 { | |
| 2192 if (*(table+(k*2+1))==(uc16px)) | |
| 2193 { | |
| 2194 ascii[i]=(char)((*(table+(k*2)) & 0xff00) >> 8); | |
| 2195 ascii[i+1]=(char)(*(table+(k*2)) & 0x00ff); | |
| 2196 break; | |
| 2197 } | |
| 2198 } | |
| 2199 i+=2; | |
| 2200 } | |
| 2201 uc16pp++; j++; | |
| 2202 } | |
| 2203 } | |
| 2204 else | |
| 2205 { | |
| 2206 while(1) | |
| 2207 { | |
| 2208 if(j>=cc) | |
| 2209 { | |
| 2210 ascii[i]=0; | |
| 2211 break; | |
| 2212 } | |
| 2213 if((*((uc16p)+j)==0)&&(*((uc16p)+j+1)==0)) | |
| 2214 { | |
| 2215 ascii[i]=0; | |
| 2216 break; | |
| 2217 } | |
| 2218 else | |
| 2219 { | |
| 2220 if(*((uc16p)+j+1)==0) | |
| 2221 { | |
| 2222 ascii[i]=*((uc16p)+j); | |
| 2223 i++; | |
| 2224 j+=2; | |
| 2225 } | |
| 2226 else | |
| 2227 { | |
| 2228 /* to find the place of unicode charater .¶þ·Ö·¨Æ¥Åä*/ | |
| 2229 { | |
| 2230 int p1=0,p2=length-4,p; | |
| 2231 unsigned int c1,c2,c,d; | |
| 2232 c1=((unsigned int )filebuffer[p1])*0x100+(filebuffer[p1+1]); | |
| 2233 c2=((unsigned int )filebuffer[p2])*0x100+(filebuffer[p2+1]); | |
| 2234 d=((unsigned int )*((uc16p)+j))*0x100+*((uc16p)+j+1); | |
| 2235 if(c1==d) | |
| 2236 { | |
| 2237 ascii[i]=filebuffer[p1+2]; | |
| 2238 ascii[i+1]=filebuffer[p1+3]; | |
| 2239 goto findit; | |
| 2240 } | |
| 2241 if(c2==d) | |
| 2242 { | |
| 2243 ascii[i]=filebuffer[p2+2]; | |
| 2244 ascii[i+1]=filebuffer[p2+3]; | |
| 2245 goto findit; | |
| 2246 } | |
| 2247 while(1) | |
| 2248 { | |
| 2249 p=(((p2-p1)/2+p1)>>2)<<2; | |
| 2250 c=((unsigned int )filebuffer[p])*0x100+(filebuffer[p+1]); | |
| 2251 if(d==c) /*find it*/ | |
| 2252 { | |
| 2253 ascii[i]=filebuffer[p+2]; | |
| 2254 ascii[i+1]=filebuffer[p+3]; | |
| 2255 break; | |
| 2256 } | |
| 2257 else if(p2<=p1+4) /*can't find.*/ | |
| 2258 { | |
| 2259 ascii[i]='.';/*((uc16p)+j);*/ | |
| 2260 ascii[i+1]='.';/*((uc16p)+j+1);*/ | |
| 2261 break; | |
| 2262 } | |
| 2263 else if(d<c) | |
| 2264 { | |
| 2265 p2=p; | |
| 2266 c2=c; | |
| 2267 } | |
| 2268 else | |
| 2269 { | |
| 2270 p1=p; | |
| 2271 c1=c; | |
| 2272 } | |
| 2273 } | |
| 2274 } | |
| 2275 findit: | |
| 2276 i+=2; | |
| 2277 j+=2; | |
| 2278 } | |
| 2279 } | |
| 2280 } | |
| 2281 } | |
| 2282 free(filebuffer); | |
| 2283 | |
| 2284 return i; | |
| 2285 } | |
| 2286 | |
| 2287 /************************** functions definition ******************************/ | |
| 2288 | |
| 2289 static int hzk_id( PMWHZKFONT pf ) | |
| 2290 { | |
| 2291 switch(pf->font_height) | |
| 2292 { | |
| 2293 case 12: | |
| 2294 return 0; | |
| 2295 case 16: default: | |
| 2296 return 1; | |
| 2297 } | |
| 2298 } | |
| 2299 | |
| 2300 /* This function get Chinese font info from etc file.*/ | |
| 2301 static MWBOOL GetCFontInfo( PMWHZKFONT pf ) | |
| 2302 { | |
| 2303 int charset; | |
| 2304 | |
| 2305 if (use_big5) | |
| 2306 charset=(13094+408); | |
| 2307 else | |
| 2308 charset=8178; | |
| 2309 | |
| 2310 CFont[hzk_id(pf)].width = pf->cfont_width; | |
| 2311 pf->CFont.width = pf->cfont_width; | |
| 2312 | |
| 2313 CFont[hzk_id(pf)].height = pf->font_height; | |
| 2314 pf->CFont.height = pf->font_height; | |
| 2315 | |
| 2316 CFont[hzk_id(pf)].size = ((pf->CFont.width + 7) / 8) * | |
| 2317 pf->CFont.height * charset; | |
| 2318 pf->CFont.size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset; | |
| 2319 | |
| 2320 if(pf->CFont.size < charset * 8) | |
| 2321 return FALSE; | |
| 2322 | |
| 2323 strcpy(CFont[hzk_id(pf)].file,HZK_FONT_DIR); | |
| 2324 strcpy(pf->CFont.file,HZK_FONT_DIR); | |
| 2325 | |
| 2326 if(pf->font_height==16) | |
| 2327 { | |
| 2328 strcat(CFont[hzk_id(pf)].file,"/hzk16"); | |
| 2329 strcat(pf->CFont.file,"/hzk16"); | |
| 2330 } | |
| 2331 else | |
| 2332 { | |
| 2333 strcat(CFont[hzk_id(pf)].file,"/hzk12"); | |
| 2334 strcat(pf->CFont.file,"/hzk12"); | |
| 2335 } | |
| 2336 | |
| 2337 if (use_big5) | |
| 2338 { | |
| 2339 CFont[hzk_id(pf)].file[strlen(pf->CFont.file)-3]+=use_big5; | |
| 2340 pf->CFont.file[strlen(pf->CFont.file)-3]+=use_big5; | |
| 2341 } | |
| 2342 | |
| 2343 return TRUE; | |
| 2344 } | |
| 2345 | |
| 2346 /* This function get ASCII font info from etc file.*/ | |
| 2347 static MWBOOL GetAFontInfo( PMWHZKFONT pf ) | |
| 2348 { | |
| 2349 AFont[hzk_id(pf)].width = pf->afont_width; | |
| 2350 pf->AFont.width = pf->afont_width; | |
| 2351 | |
| 2352 AFont[hzk_id(pf)].height = pf->font_height; | |
| 2353 pf->AFont.height = pf->font_height; | |
| 2354 | |
| 2355 AFont[hzk_id(pf)].size = ((pf->AFont.width + 7) / 8) * | |
| 2356 pf->AFont.height * 255; | |
| 2357 pf->AFont.size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255; | |
| 2358 | |
| 2359 if(pf->AFont.size < 255 * 8) | |
| 2360 return FALSE; | |
| 2361 | |
| 2362 strcpy(AFont[hzk_id(pf)].file,HZK_FONT_DIR); | |
| 2363 strcpy(pf->AFont.file,HZK_FONT_DIR); | |
| 2364 | |
| 2365 if(pf->font_height==16) | |
| 2366 { | |
| 2367 strcat(AFont[hzk_id(pf)].file,"/asc16"); | |
| 2368 strcat(pf->AFont.file,"/asc16"); | |
| 2369 } | |
| 2370 else | |
| 2371 { | |
| 2372 strcat(AFont[hzk_id(pf)].file,"/asc12"); | |
| 2373 strcat(pf->AFont.file,"/asc12"); | |
| 2374 } | |
| 2375 return TRUE; | |
| 2376 } | |
| 2377 | |
| 2378 /* This function load system font into memory.*/ | |
| 2379 static MWBOOL LoadFont( PMWHZKFONT pf ) | |
| 2380 { | |
| 2381 FILE* fp; | |
| 2382 | |
| 2383 if(!GetCFontInfo(pf)) | |
| 2384 { | |
| 2385 fprintf (stderr, "Get Chinese HZK font info failure!\n"); | |
| 2386 return FALSE; | |
| 2387 } | |
| 2388 if(CFont[hzk_id(pf)].pFont == NULL)/*check font cache*/ | |
| 2389 { | |
| 2390 | |
| 2391 | |
| 2392 /* Allocate system memory for Chinese font.*/ | |
| 2393 if( !(CFont[hzk_id(pf)].pFont = (char *)malloc(pf->CFont.size)) ) | |
| 2394 { | |
| 2395 fprintf (stderr, "Allocate memory for Chinese HZK font failure.\n"); | |
| 2396 return FALSE; | |
| 2397 } | |
| 2398 | |
| 2399 /* Open font file and read information to the system memory.*/ | |
| 2400 fprintf (stderr, "Loading Chinese HZK font from file(%s)..." ,pf->CFont.file); | |
| 2401 if(!(fp = fopen(CFont[hzk_id(pf)].file, "rb"))) | |
| 2402 { | |
| 2403 fprintf (stderr, "Error.\nThe Chinese HZK font file can not be found!\n"); | |
| 2404 return FALSE; | |
| 2405 } | |
| 2406 if(fread(CFont[hzk_id(pf)].pFont, sizeof(char), pf->CFont.size, fp) < pf->CFont.size) | |
| 2407 { | |
| 2408 fprintf (stderr, "Error in reading Chinese HZK font file!\n"); | |
| 2409 fclose(fp); | |
| 2410 return FALSE; | |
| 2411 } | |
| 2412 | |
| 2413 fclose(fp); | |
| 2414 | |
| 2415 CFont[hzk_id(pf)].use_count=0; | |
| 2416 | |
| 2417 fprintf (stderr, "done.\n" ); | |
| 2418 | |
| 2419 } | |
| 2420 cfont_address = CFont[hzk_id(pf)].pFont; | |
| 2421 pf->cfont_address = CFont[hzk_id(pf)].pFont; | |
| 2422 pf->CFont.pFont = CFont[hzk_id(pf)].pFont; | |
| 2423 | |
| 2424 CFont[hzk_id(pf)].use_count++; | |
| 2425 | |
| 2426 if(!GetAFontInfo(pf)) | |
| 2427 { | |
| 2428 fprintf (stderr, "Get ASCII HZK font info failure!\n"); | |
| 2429 return FALSE; | |
| 2430 } | |
| 2431 if(AFont[hzk_id(pf)].pFont == NULL)/*check font cache*/ | |
| 2432 { | |
| 2433 | |
| 2434 | |
| 2435 /* Allocate system memory for ASCII font.*/ | |
| 2436 if( !(AFont[hzk_id(pf)].pFont = (char *)malloc(pf->AFont.size)) ) | |
| 2437 { | |
| 2438 fprintf (stderr, "Allocate memory for ASCII HZK font failure.\n"); | |
| 2439 free(CFont[hzk_id(pf)].pFont); | |
| 2440 CFont[hzk_id(pf)].pFont = NULL; | |
| 2441 return FALSE; | |
| 2442 } | |
| 2443 | |
| 2444 /* Load ASCII font information to the near memory.*/ | |
| 2445 fprintf (stderr, "Loading ASCII HZK font..." ); | |
| 2446 if(!(fp = fopen(AFont[hzk_id(pf)].file, "rb"))) | |
| 2447 { | |
| 2448 fprintf (stderr, "Error.\nThe ASCII HZK font file can not be found!\n"); | |
| 2449 return FALSE; | |
| 2450 } | |
| 2451 if(fread(AFont[hzk_id(pf)].pFont, sizeof(char), pf->AFont.size, fp) < pf->AFont.size) | |
| 2452 { | |
| 2453 fprintf (stderr, "Error in reading ASCII HZK font file!\n"); | |
| 2454 fclose(fp); | |
| 2455 return FALSE; | |
| 2456 } | |
| 2457 | |
| 2458 fclose(fp); | |
| 2459 | |
| 2460 AFont[hzk_id(pf)].use_count=0; | |
| 2461 | |
| 2462 fprintf (stderr, "done.\n" ); | |
| 2463 | |
| 2464 } | |
| 2465 afont_address = AFont[hzk_id(pf)].pFont; | |
| 2466 pf->afont_address = AFont[hzk_id(pf)].pFont; | |
| 2467 pf->AFont.pFont = AFont[hzk_id(pf)].pFont; | |
| 2468 | |
| 2469 AFont[hzk_id(pf)].use_count++; | |
| 2470 | |
| 2471 return TRUE; | |
| 2472 } | |
| 2473 | |
| 2474 /* This function unload system font from memory.*/ | |
| 2475 static void UnloadFont( PMWHZKFONT pf ) | |
| 2476 { | |
| 2477 CFont[hzk_id(pf)].use_count--; | |
| 2478 AFont[hzk_id(pf)].use_count--; | |
| 2479 | |
| 2480 if (!CFont[hzk_id(pf)].use_count) | |
| 2481 { | |
| 2482 free(pf->CFont.pFont); | |
| 2483 free(pf->AFont.pFont); | |
| 2484 | |
| 2485 CFont[hzk_id(pf)].pFont = NULL; | |
| 2486 AFont[hzk_id(pf)].pFont = NULL; | |
| 2487 } | |
| 2488 } | |
| 2489 | |
| 2490 static int | |
| 2491 hzk_init(PSD psd) | |
| 2492 { | |
| 2493 /* FIXME: *.KU file should be opened and | |
| 2494 * read in here...*/ | |
| 2495 return 1; | |
| 2496 } | |
| 2497 | |
| 2498 static PMWHZKFONT | |
| 2499 hzk_createfont(const char *name, MWCOORD height, int attr) | |
| 2500 { | |
| 2501 PMWHZKFONT pf; | |
| 2502 | |
| 2503 if(strcmp(name,"HZKFONT")!=0 && strcmp(name,"HZXFONT")!=0) | |
| 2504 return FALSE; | |
| 2505 | |
| 2506 printf("hzk_createfont(%s,%d)\n",name,height); | |
| 2507 | |
| 2508 use_big5=name[2]-'K'; | |
| 2509 | |
| 2510 /* allocate font structure*/ | |
| 2511 pf = (PMWHZKFONT)calloc(sizeof(MWHZKFONT), 1); | |
| 2512 if (!pf) | |
| 2513 return NULL; | |
| 2514 pf->fontprocs = &hzk_procs; | |
| 2515 | |
| 2516 pf->fontsize=height; | |
| 2517 /*GdSetFontSize((PMWFONT)pf, height);*/ | |
| 2518 GdSetFontRotation((PMWFONT)pf, 0); | |
| 2519 GdSetFontAttr((PMWFONT)pf, attr, 0); | |
| 2520 | |
| 2521 if(height==12) | |
| 2522 { | |
| 2523 afont_width = 6; | |
| 2524 cfont_width = 12; | |
| 2525 font_height = 12; | |
| 2526 | |
| 2527 pf->afont_width = 6; | |
| 2528 pf->cfont_width = 12; | |
| 2529 pf->font_height = 12; | |
| 2530 } | |
| 2531 else | |
| 2532 { | |
| 2533 afont_width = 8; | |
| 2534 cfont_width = 16; | |
| 2535 font_height = 16; | |
| 2536 | |
| 2537 pf->afont_width = 8; | |
| 2538 pf->cfont_width = 16; | |
| 2539 pf->font_height = 16; | |
| 2540 } | |
| 2541 | |
| 2542 /* Load the font library to the system memory.*/ | |
| 2543 if(!LoadFont(pf)) | |
| 2544 return FALSE; | |
| 2545 | |
| 2546 return pf; | |
| 2547 } | |
| 2548 | |
| 2549 int IsBig5(int i) | |
| 2550 { | |
| 2551 if ((i>=0xa140 && i<=0xa3bf) || /* a140-a3bf(!a3e0) */ | |
| 2552 (i>=0xa440 && i<=0xc67e) || /* a440-c67e */ | |
| 2553 (i>=0xc6a1 && i<=0xc8d3) || /* c6a1-c8d3(!c8fe) */ | |
| 2554 (i>=0xc940 && i<=0xf9fe)) /* c940-f9fe */ | |
| 2555 return 1; | |
| 2556 else | |
| 2557 return 0; | |
| 2558 } | |
| 2559 | |
| 2560 /* | |
| 2561 * following several function is used in hzk_drawtext | |
| 2562 */ | |
| 2563 | |
| 2564 static int getnextchar(char* s, unsigned char* cc) | |
| 2565 { | |
| 2566 if( s[0] == '\0') return 0; | |
| 2567 | |
| 2568 cc[0] = (unsigned char)(*s); | |
| 2569 cc[1] = (unsigned char)(*(s + 1)); | |
| 2570 | |
| 2571 if (use_big5) | |
| 2572 { | |
| 2573 if( IsBig5( (int) ( (cc[0] << 8) + cc[1]) ) ) | |
| 2574 return 1; | |
| 2575 } | |
| 2576 else | |
| 2577 { | |
| 2578 if( ((unsigned char)cc[0] > 0xa0) && | |
| 2579 ((unsigned char)cc[1] > 0xa0) ) | |
| 2580 return 1; | |
| 2581 } | |
| 2582 | |
| 2583 cc[1] = '\0'; | |
| 2584 | |
| 2585 return 1; | |
| 2586 } | |
| 2587 | |
| 2588 static void | |
| 2589 expandcchar(PMWHZKFONT pf, int bg, int fg, unsigned char* c, MWPIXELVAL* bitmap) | |
| 2590 { | |
| 2591 int i=0; | |
| 2592 int c1, c2, seq; | |
| 2593 int x,y; | |
| 2594 unsigned char *font; | |
| 2595 int b = 0; /* keep gcc happy with b = 0 - MW */ | |
| 2596 | |
| 2597 int pixelsize; | |
| 2598 pixelsize=sizeof(MWPIXELVAL); | |
| 2599 | |
| 2600 c1 = c[0]; | |
| 2601 c2 = c[1]; | |
| 2602 if (use_big5) | |
| 2603 { | |
| 2604 seq=0; | |
| 2605 /*ladd=loby-(if(loby<127)?64:98)*/ | |
| 2606 c2-=(c2<127?64:98); | |
| 2607 | |
| 2608 /*hadd=(hiby-164)*157*/ | |
| 2609 if (c1>=0xa4)/*standard font*/ | |
| 2610 { | |
| 2611 seq=(((c1-164)*157)+c2); | |
| 2612 if (seq>=5809) seq-=408; | |
| 2613 } | |
| 2614 | |
| 2615 /*hadd=(hiby-161)*157*/ | |
| 2616 if (c1<=0xa3)/*special font*/ | |
| 2617 seq=(((c1-161)*157)+c2)+13094; | |
| 2618 } | |
| 2619 else | |
| 2620 seq=((c1 - 161)*94 + c2 - 161); | |
| 2621 | |
| 2622 font = pf->cfont_address + ((seq) * | |
| 2623 (pf->font_height * ((pf->cfont_width + 7) / 8))); | |
| 2624 | |
| 2625 for (y = 0; y < pf->font_height; y++) | |
| 2626 for (x = 0; x < pf->cfont_width; x++) | |
| 2627 { | |
| 2628 if (x % 8 == 0) | |
| 2629 b = *font++; | |
| 2630 | |
| 2631 if (b & (128 >> (x % 8))) /* pixel */ | |
| 2632 bitmap[i++]=fg; | |
| 2633 else | |
| 2634 bitmap[i++]=bg; | |
| 2635 } | |
| 2636 } | |
| 2637 | |
| 2638 static void expandchar(PMWHZKFONT pf, int bg, int fg, int c, MWPIXELVAL* bitmap) | |
| 2639 { | |
| 2640 int i=0; | |
| 2641 int x,y; | |
| 2642 unsigned char *font; | |
| 2643 int pixelsize; | |
| 2644 int b = 0; /* keep gcc happy with b = 0 - MW */ | |
| 2645 | |
| 2646 pixelsize=sizeof(MWPIXELVAL); | |
| 2647 | |
| 2648 font = pf->afont_address + c * (pf->font_height * | |
| 2649 ((pf->afont_width + 7) / 8)); | |
| 2650 | |
| 2651 for (y = 0; y < pf->font_height; y++) | |
| 2652 for (x = 0; x < pf->afont_width; x++) | |
| 2653 { | |
| 2654 if (x % 8 == 0) | |
| 2655 b = *font++; | |
| 2656 if (b & (128 >> (x % 8))) /* pixel */ | |
| 2657 bitmap[i++]=fg; | |
| 2658 else | |
| 2659 bitmap[i++]=bg; | |
| 2660 } | |
| 2661 } | |
| 2662 | |
| 2663 /* | |
| 2664 * Draw ASCII text string using HZK type font | |
| 2665 */ | |
| 2666 static void | |
| 2667 hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay, | |
| 2668 const void *text, int cc, int flags) | |
| 2669 { | |
| 2670 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2671 | |
| 2672 unsigned char c[2]; | |
| 2673 MWPIXELVAL *bitmap; | |
| 2674 unsigned char s1[3]; | |
| 2675 char *s,*sbegin; | |
| 2676 | |
| 2677 s=(char *)text; | |
| 2678 | |
| 2679 if(cc==1) | |
| 2680 { | |
| 2681 s1[0]=*((unsigned char*)text); | |
| 2682 s1[1]=0x0; | |
| 2683 s1[2]=0x0; | |
| 2684 s=s1; | |
| 2685 } | |
| 2686 | |
| 2687 sbegin=s; | |
| 2688 bitmap = (MWPIXELVAL *)ALLOCA(pf->cfont_width * pf->font_height * | |
| 2689 sizeof(MWPIXELVAL)); | |
| 2690 | |
| 2691 while( getnextchar(s, c) ) | |
| 2692 { | |
| 2693 if( c[1] != '\0') | |
| 2694 { | |
| 2695 expandcchar(pf, gr_background,gr_foreground, | |
| 2696 c, bitmap); | |
| 2697 /* Now draw the bitmap ... */ | |
| 2698 | |
| 2699 if (flags&MWTF_TOP) | |
| 2700 GdArea(psd,ax, ay, pf->cfont_width, | |
| 2701 pf->font_height, bitmap, MWPF_PIXELVAL); | |
| 2702 else | |
| 2703 GdArea(psd,ax, ay-pf->font_height+2, | |
| 2704 pf->cfont_width, pf->font_height, | |
| 2705 bitmap, MWPF_PIXELVAL); | |
| 2706 | |
| 2707 s += 2; | |
| 2708 ax += pf->cfont_width; | |
| 2709 } | |
| 2710 else | |
| 2711 { | |
| 2712 expandchar(pf, gr_background,gr_foreground, | |
| 2713 c[0], bitmap); | |
| 2714 /* Now draw the bitmap ... */ | |
| 2715 | |
| 2716 if (flags&MWTF_TOP) | |
| 2717 GdArea(psd,ax, ay, pf->afont_width, | |
| 2718 pf->font_height, bitmap, MWPF_PIXELVAL); | |
| 2719 else | |
| 2720 GdArea(psd,ax, ay-pf->font_height+2, | |
| 2721 pf->afont_width, pf->font_height, | |
| 2722 bitmap, MWPF_PIXELVAL); | |
| 2723 | |
| 2724 s += 1; | |
| 2725 ax += pf->afont_width; | |
| 2726 } | |
| 2727 | |
| 2728 if(s>=sbegin+cc)break; | |
| 2729 } | |
| 2730 | |
| 2731 FREEA(bitmap); | |
| 2732 } | |
| 2733 | |
| 2734 /* | |
| 2735 * Return information about a specified font. | |
| 2736 */ | |
| 2737 static MWBOOL | |
| 2738 hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo) | |
| 2739 { | |
| 2740 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2741 | |
| 2742 int i; | |
| 2743 | |
| 2744 pfontinfo->height = pf->font_height; | |
| 2745 pfontinfo->maxwidth = pf->cfont_width; | |
| 2746 pfontinfo->baseline = pf->font_height-2; | |
| 2747 pfontinfo->firstchar = 0; | |
| 2748 pfontinfo->lastchar = 0; | |
| 2749 pfontinfo->fixed = TRUE; | |
| 2750 | |
| 2751 for(i=0; i<=256; i++) | |
| 2752 pfontinfo->widths[i] = pf->afont_width; | |
| 2753 | |
| 2754 return TRUE; | |
| 2755 } | |
| 2756 | |
| 2757 static void | |
| 2758 hzk_gettextsize(PMWFONT pfont, const void *text, int cc, | |
| 2759 MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase) | |
| 2760 { | |
| 2761 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2762 | |
| 2763 unsigned char c[2]; | |
| 2764 char *s,*sbegin; | |
| 2765 unsigned char s1[3]; | |
| 2766 | |
| 2767 int ax=0; | |
| 2768 | |
| 2769 | |
| 2770 | |
| 2771 s=(char *)text; | |
| 2772 if(cc==0) | |
| 2773 { | |
| 2774 *pwidth = 0; | |
| 2775 *pheight = pf->font_height; | |
| 2776 *pbase = pf->font_height-2; | |
| 2777 | |
| 2778 } | |
| 2779 if(cc==1) | |
| 2780 { | |
| 2781 s1[0]=*((unsigned char*)text); | |
| 2782 s1[1]=0x0; | |
| 2783 s1[2]=0x0; | |
| 2784 s=s1; | |
| 2785 } | |
| 2786 sbegin=s; | |
| 2787 while( getnextchar(s, c) ) | |
| 2788 { | |
| 2789 if( c[1] != '\0') | |
| 2790 { | |
| 2791 s += 2; | |
| 2792 ax += pf->cfont_width; | |
| 2793 } | |
| 2794 else | |
| 2795 { | |
| 2796 s += 1; | |
| 2797 ax += pf->afont_width; | |
| 2798 } | |
| 2799 if(s>=sbegin+cc)break; | |
| 2800 /* fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/ | |
| 2801 | |
| 2802 } | |
| 2803 /* fprintf(stderr,"ax=%d,\n",ax);*/ | |
| 2804 | |
| 2805 *pwidth = ax; | |
| 2806 *pheight = pf->font_height; | |
| 2807 *pbase = pf->font_height-2; | |
| 2808 } | |
| 2809 | |
| 2810 static void | |
| 2811 hzk_destroyfont(PMWFONT pfont) | |
| 2812 { | |
| 2813 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2814 | |
| 2815 UnloadFont(pf); | |
| 2816 free(pf); | |
| 2817 } | |
| 2818 | |
| 2819 static void | |
| 2820 hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize) | |
| 2821 { | |
| 2822 PMWHZKFONT pf=(PMWHZKFONT)pfont; | |
| 2823 | |
| 2824 /*jmt: hzk_setfontsize not supported*/ | |
| 2825 /*jmt: & pf->fontsize can't be changed*/ | |
| 2826 /*jmt: because of hzk_id() :p*/ | |
| 2827 pf->fontsize=pf->font_height; | |
| 2828 } | |
| 2829 #endif /* HAVE_HZK_SUPPORT*/ | |
| 2830 | |
| 2831 /* FIXME: this routine should work for all font renderers...*/ | |
| 2832 int | |
| 2833 GdGetTextSizeEx(PMWFONT pfont, const void *str, int cc,int nMaxExtent, | |
| 2834 int* lpnFit, int* alpDx,MWCOORD *pwidth,MWCOORD *pheight, | |
| 2835 MWCOORD *pbase, int flags) | |
| 2836 { | |
| 2837 #ifdef HAVE_FREETYPE_SUPPORT | |
| 2838 unsigned short buf[256]; | |
| 2839 unsigned short* text; | |
| 2840 PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont; | |
| 2841 int defencoding = pf->fontprocs->encoding; | |
| 2842 int x = 0; | |
| 2843 int i; | |
| 2844 TT_UShort curchar; | |
| 2845 TT_Glyph_Metrics metrics; | |
| 2846 TT_Face_Properties properties; | |
| 2847 TT_Instance_Metrics imetrics; | |
| 2848 | |
| 2849 if ((cc<0)||(!str)) | |
| 2850 { | |
| 2851 *pwidth = *pheight = *pbase = 0; | |
| 2852 return 0; | |
| 2853 } | |
| 2854 /* convert encoding if required*/ | |
| 2855 if((flags & MWTF_PACKMASK) != defencoding) | |
| 2856 { | |
| 2857 cc = GdConvertEncoding(str, flags, cc, buf, defencoding); | |
| 2858 flags &= ~MWTF_PACKMASK; | |
| 2859 flags |= defencoding; | |
| 2860 text=buf; | |
| 2861 } else text =(unsigned short*)str; | |
| 2862 if(cc <= 0) | |
| 2863 { | |
| 2864 *pwidth = *pheight = *pbase = 0; | |
| 2865 return 0; | |
| 2866 } | |
| 2867 | |
| 2868 TT_Get_Face_Properties (pf->face, &properties); | |
| 2869 TT_Get_Instance_Metrics(pf->instance, &imetrics); | |
| 2870 | |
| 2871 pf->last_glyph_code = -1; /* reset kerning*/ | |
| 2872 pf->last_pen_pos = -32767; | |
| 2873 if (lpnFit) | |
| 2874 *lpnFit=-1; | |
| 2875 for (i = 0; i < cc; i++) | |
| 2876 { | |
| 2877 curchar = TT_Char_Index (pf->char_map,text[i]); | |
| 2878 | |
| 2879 if (TT_Load_Glyph (pf->instance, pf->glyph, curchar, | |
| 2880 TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok) | |
| 2881 { | |
| 2882 printf("Unable to load glyph with index=%d\n",curchar); | |
| 2883 return 0; | |
| 2884 } | |
| 2885 TT_Get_Glyph_Metrics (pf->glyph, &metrics); | |
| 2886 if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) | |
| 2887 { | |
| 2888 x += compute_kernval(pf, curchar) / 64; | |
| 2889 } | |
| 2890 x += metrics.advance / 64; | |
| 2891 if((lpnFit)&&(alpDx)) | |
| 2892 { | |
| 2893 if (x<=nMaxExtent) | |
| 2894 alpDx[i]=x; | |
| 2895 else | |
| 2896 if (*lpnFit==-1) | |
| 2897 (*lpnFit)=i; | |
| 2898 } | |
| 2899 /* Kerning point syndrome avoidance */ | |
| 2900 if (pf->last_pen_pos > x) | |
| 2901 x = pf->last_pen_pos; | |
| 2902 pf->last_pen_pos = x; | |
| 2903 pf->last_glyph_code = curchar; | |
| 2904 } | |
| 2905 if ((lpnFit)&&(*lpnFit==-1)) | |
| 2906 *lpnFit=cc; | |
| 2907 *pwidth = x; | |
| 2908 *pheight = (((properties.horizontal->Ascender * | |
| 2909 imetrics.y_scale)/ 0x10000) >> 6) - | |
| 2910 (((properties.horizontal->Descender * | |
| 2911 imetrics.y_scale)/ 0x10000) >> 6); | |
| 2912 /*FIXME: is it what's required ??*/ | |
| 2913 if (pbase) | |
| 2914 *pbase = (((-properties.horizontal->Descender) * | |
| 2915 imetrics.y_scale)/ 0x10000) >> 6; | |
| 2916 return 1; | |
| 2917 #else /* HAVE_FREETYPE_SUPPORT*/ | |
| 2918 *pwidth = *pheight = *pbase = 0; | |
| 2919 return 0; | |
| 2920 #endif | |
| 2921 } |
