1 
2 #include "studiox_includes.h"
3 #include "ft2build.h"
4 #include FT_FREETYPE_H
5 #include "gx_studio_font_util.h"
6 
7 #ifdef _DEBUG
8 #define new DEBUG_NEW
9 #endif
10 
11 typedef struct {
12     int ascent;
13     int descent;
14     int max_height;
15 } FONT_METRICS;
16 
17 typedef struct {
18     int glyph;
19     int value;
20 } KERNING_INFO;
21 
22 ///////////////////////////////////////////////////////////////////////////////
gx_studio_font_util_open(const char * font_file,GXS_FONT_LIBRARY_HANDLE ** handle)23 int gx_studio_font_util_open(const char *font_file, GXS_FONT_LIBRARY_HANDLE **handle)
24 {
25     FT_Error      error;
26     GXS_FONT_LIBRARY_HANDLE *font_handle;
27 
28     if(font_file == NULL)
29         return(GXS_FONT_UTIL_INVALID_FILENAME_PTR);
30 
31     font_handle = (GXS_FONT_LIBRARY_HANDLE*)malloc(sizeof(GXS_FONT_LIBRARY_HANDLE));
32     if(font_handle == 0)
33         return(GXS_FONT_UTIL_MALLOC_FAILURE);
34 
35     memset(font_handle, 0, sizeof(GXS_FONT_LIBRARY_HANDLE));
36 
37     error = FT_Init_FreeType(&(font_handle -> library));              /* initialize library */
38     if(error)
39     {
40         free(font_handle);
41         return(GXS_FONT_UTIL_FT_INIT_FREETYPE_ERROR);
42     }
43 
44     error = FT_New_Face(font_handle -> library, font_file, 0, &(font_handle -> face) );/* create face object */
45     if(error)
46     {
47         FT_Done_FreeType( font_handle -> library );
48         free(font_handle);
49         return(GXS_FONT_UTIL_CANNOT_OPEN_FONT_FILE);
50     }
51 
52     font_handle -> size = 0;
53     font_handle -> initialized = 1;
54 
55     *handle = font_handle;
56 
57     return(GXS_FONT_UTIL_SUCCESS);
58 }
59 
60 ///////////////////////////////////////////////////////////////////////////////
gx_studio_font_util_get_glyph(GXS_FONT_LIBRARY_HANDLE * font_handle,int font_index,int pt,int aa,GXS_FONT_DATA * font_data)61 int gx_studio_font_util_get_glyph(GXS_FONT_LIBRARY_HANDLE *font_handle, int font_index, int pt, int aa, GXS_FONT_DATA *font_data)
62 {
63     FT_Glyph_Metrics *metrics;
64     FT_GlyphSlot  slot;
65     FT_Error      error;
66     int           glyph_index;
67 
68     if(font_handle -> initialized != 1)
69         return(GXS_FONT_UTIL_LIBRARY_UNINITIAZLIED);
70 
71     /* set character size */
72     if(font_handle -> size != pt)
73     {
74         error = FT_Set_Char_Size(font_handle -> face, pt * 64, 0, 72, 0);
75         if(error)
76         {
77             return(GXS_FONT_UTIL_SET_CHAR_SIZE_ERROR);
78         }
79         font_handle -> size = pt;
80     }
81 
82     slot = font_handle -> face -> glyph;
83 
84     glyph_index = FT_Get_Char_Index(font_handle -> face, font_index);
85     error = FT_Load_Glyph(font_handle -> face, glyph_index, 0);
86 
87     if(font_handle -> face -> glyph -> format != FT_GLYPH_FORMAT_BITMAP)
88     {
89         if(aa)
90             error = FT_Render_Glyph(font_handle -> face -> glyph, FT_RENDER_MODE_NORMAL);
91         else
92             error = FT_Render_Glyph(font_handle -> face -> glyph, FT_RENDER_MODE_MONO);
93     }
94 
95     if (aa && slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
96     {
97         error = FT_Load_Glyph(font_handle->face, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_RENDER);
98     }
99 
100     metrics = &(font_handle -> face -> glyph -> metrics);
101     font_data -> width = slot -> bitmap.width;
102     font_data -> height = slot -> bitmap.rows;
103     font_data -> pitch = slot -> bitmap.pitch;
104 
105     font_data -> gx_glyph_ascent = (short) ((metrics -> horiBearingY) >> 6);
106     font_data -> gx_glyph_descent = (short)((metrics->height - metrics->horiBearingY) >> 6);
107     font_data -> gx_glyph_advance = (unsigned char) ((metrics -> horiAdvance) >> 6);
108     font_data -> gx_glyph_leading = (char) ((metrics -> horiBearingX) >> 6);
109     font_data -> gx_glyph_data = slot -> bitmap.buffer;
110     return(GXS_FONT_UTIL_SUCCESS);
111 }
112 
113 ///////////////////////////////////////////////////////////////////////////////
gx_studio_font_util_get_kerning_info(GXS_FONT_LIBRARY_HANDLE * font_handle,int font_index,int first_glyph_index,int last_glyph_index,GX_KERNING_GLYPH * kerning_glyph,FontCharMap * map)114 int gx_studio_font_util_get_kerning_info(GXS_FONT_LIBRARY_HANDLE *font_handle, int font_index,
115                                          int first_glyph_index, int last_glyph_index, GX_KERNING_GLYPH *kerning_glyph, FontCharMap *map)
116 {
117     FT_Error      error;
118     FT_Vector     kerning_vector;
119     GX_UBYTE      left_glyph_index;
120     GX_UBYTE      right_glyph_index;
121     INT           index;
122     CArray<KERNING_INFO> kerning_pairs;
123     KERNING_INFO kerning_info;
124     INT           table_size;
125     GX_UBYTE     *left_glyph_ptr;
126     INT           first_glyph = first_glyph_index;
127     INT           last_glyph = last_glyph_index;
128 
129     if (font_handle->initialized != 1)
130         return(GXS_FONT_UTIL_LIBRARY_UNINITIAZLIED);
131 
132     if (FT_HAS_KERNING(font_handle->face) == 0)
133     {
134         // The face object does not contain kerning data.
135         return(GXS_FONT_UTIL_SUCCESS);
136     }
137 
138     if (!map)
139     {
140         return(GXS_FONT_UTIL_SUCCESS);
141     }
142 
143     kerning_pairs.SetSize(0, 1);
144     if (first_glyph > 0xff)
145     {
146         return 0;
147     }
148     if (last_glyph > 0xff)
149     {
150         last_glyph = 0xff;
151     }
152 
153     right_glyph_index = FT_Get_Char_Index(font_handle->face, font_index);
154 
155     if (!right_glyph_index)
156     {
157         // Undefined character code.
158         return(GXS_FONT_UTIL_SUCCESS);
159     }
160 
161     // Get kerning vector between two glyphs in the same face
162     for (index = first_glyph; index <= last_glyph; index++)
163     {
164         if (!map->Test(index))
165         {
166             continue;
167         }
168 
169         left_glyph_index = FT_Get_Char_Index(font_handle->face, index);
170 
171         if (!left_glyph_index)
172         {
173             continue;
174         }
175 
176         memset(&kerning_vector, 0, sizeof(FT_Vector));
177         error = FT_Get_Kerning(font_handle->face, left_glyph_index, right_glyph_index, FT_KERNING_DEFAULT, &kerning_vector);
178         if ((error == 0) && (kerning_vector.x))
179         {
180             kerning_info.glyph = index;
181             kerning_info.value = (kerning_vector.x >> 6);
182             kerning_pairs.Add(kerning_info);
183         }
184     }
185 
186     if (kerning_pairs.GetCount())
187     {
188         // Calculate size of needed buffer. 1 byte size + 2 bytes for each kerning pair.
189         table_size = 1 + kerning_pairs.GetCount() * (sizeof(GX_UBYTE) + sizeof(GX_CHAR));
190 
191         // Allocate memory to load kerning table.
192         kerning_glyph->gx_kerning_table = new GX_UBYTE[table_size];
193         memset(const_cast<GX_UBYTE *>(kerning_glyph->gx_kerning_table), 0, table_size);
194         left_glyph_ptr = (GX_UBYTE *)(kerning_glyph->gx_kerning_table + 1);
195 
196         if (kerning_glyph->gx_kerning_table)
197         {
198             *(const_cast<GX_UBYTE *>(kerning_glyph->gx_kerning_table)) = kerning_pairs.GetCount();
199 
200             for (index = 0; index < kerning_pairs.GetCount(); index++)
201             {
202                 kerning_info = kerning_pairs.GetAt(index);
203                 *left_glyph_ptr++ = (GX_UBYTE)kerning_info.glyph;
204                 *left_glyph_ptr++ = (GX_UBYTE)kerning_info.value;
205             }
206 
207         }
208     }
209 
210     return(GXS_FONT_UTIL_SUCCESS);
211 }
212 
213 ///////////////////////////////////////////////////////////////////////////////
gx_studio_font_util_close(GXS_FONT_LIBRARY_HANDLE * font_handle)214 void gx_studio_font_util_close(GXS_FONT_LIBRARY_HANDLE *font_handle)
215 {
216     if(!font_handle)
217         return;
218 
219     if(font_handle -> initialized == 1)
220     {
221 
222         if(font_handle -> face)
223             FT_Done_Face(font_handle -> face);
224         if(font_handle -> library)
225             FT_Done_FreeType(font_handle -> library);
226     }
227 
228     free(font_handle);
229     return;
230 }
231 
232 ///////////////////////////////////////////////////////////////////////////////
GetRowPitch(INT width,INT bits_per_pix)233 INT GetRowPitch(INT width, INT bits_per_pix)
234 {
235     // Calcualte data size of glyph map
236     INT pitch = width;
237 
238     switch (bits_per_pix)
239     {
240     case 1:
241         pitch += 7;
242         pitch /= 8;
243         break;
244     case 4:
245         pitch ++;
246         pitch /= 2;
247         break;
248     case 8:
249         break;
250     }
251 
252     return pitch;
253 }
254 
255 ///////////////////////////////////////////////////////////////////////////////
GetFontBits(INT font_format)256 INT  GetFontBits(INT font_format)
257 {
258     int font_bits = 8;
259 
260     switch (font_format & GX_FONT_FORMAT_BPP_MASK)
261     {
262     case GX_FONT_FORMAT_1BPP:
263         font_bits = 1;
264         break;
265 
266     case GX_FONT_FORMAT_2BPP:
267         font_bits = 2;
268         break;
269 
270     case GX_FONT_FORMAT_4BPP:
271         font_bits = 4;
272         break;
273 
274     case GX_FONT_FORMAT_8BPP:
275         font_bits = 8;
276         break;
277     }
278 
279     return font_bits;
280 }
281 
282 ///////////////////////////////////////////////////////////////////////////////
IsFontBitsSupported(INT font_bits)283 BOOL IsFontBitsSupported(INT font_bits)
284 {
285     switch (font_bits)
286     {
287     case 1:
288     case 4:
289     case 8:
290         return TRUE;
291     }
292 
293     return FALSE;
294 }
295 
296 ///////////////////////////////////////////////////////////////////////////////
DuplicatesCount(GX_UBYTE * data,int width,int index)297 int DuplicatesCount(GX_UBYTE *data, int width, int index)
298 {
299     int count = 1;
300     GX_UBYTE pre;
301 
302     pre = data[index++];
303 
304     while (index < width)
305     {
306         if (pre == data[index])
307         {
308             pre = data[index];
309             count++;
310         }
311         else
312         {
313             break;
314         }
315 
316         index++;
317     }
318 
319     return count;
320 }
321 
322 ///////////////////////////////////////////////////////////////////////////////
RleEncode(GX_UBYTE * put_data,GX_UBYTE * get_data,int width,int height)323 int RleEncode(GX_UBYTE *put_data, GX_UBYTE *get_data, int width, int height)
324 {
325     int count = 0;
326     int raw_count = 0;
327     int put_index = 0;
328     int row;
329     int compressed_size = 0;
330 
331     for (row = 0; row < height; row++)
332     {
333         int index = 0;
334 
335         while (index < width)
336         {
337 
338             count = DuplicatesCount(get_data, width, index);
339 
340             if (count >= 3)
341             {
342                 if (raw_count)
343                 {
344                     compressed_size += raw_count + 1;
345 
346                     if (put_data)
347                     {
348                         *put_data++ = (raw_count - 1) & 0x7f;
349 
350                         while (raw_count)
351                         {
352                             *put_data++ = get_data[index - raw_count];
353                             raw_count--;
354                         }
355                     }
356                     else
357                     {
358                         raw_count = 0;
359                     }
360                 }
361 
362                 if (count > 128)
363                 {
364                     count = 128;
365                 }
366 
367                 if (put_data)
368                 {
369                     *put_data++ = (count - 1) | 0x80;
370                     *put_data++ = get_data[index];
371                 }
372                 compressed_size += 2;
373                 index += count;
374             }
375             else
376             {
377                 raw_count++;
378                 index++;
379 
380                 if ((raw_count == 128) || (index == width))
381                 {
382                     compressed_size += raw_count + 1;
383 
384                     if (put_data)
385                     {
386                         *put_data++ = (raw_count - 1) & 0x7f;
387 
388                         while (raw_count)
389                         {
390                             *put_data++ = get_data[index - raw_count];
391                             raw_count--;
392                         }
393                     }
394                     else
395                     {
396                         raw_count = 0;
397                     }
398                 }
399             }
400         }
401 
402         get_data += width;
403     }
404 
405     return compressed_size;
406 }
407 
408 ///////////////////////////////////////////////////////////////////////////////
RleEncodeGlyphData(GX_COMPRESSED_GLYPH * glyph,int bits_per_pix)409 void RleEncodeGlyphData(GX_COMPRESSED_GLYPH *glyph, int bits_per_pix)
410 {
411     GX_UBYTE *pGet = (GX_UBYTE *)glyph->gx_glyph_map;
412 
413     int pitch = GetRowPitch(glyph->gx_glyph_width, bits_per_pix);
414     int data_size = pitch * glyph->gx_glyph_height;
415 
416     int compressed_size = RleEncode(NULL, pGet, pitch, glyph->gx_glyph_height);
417 
418     if (compressed_size < data_size)
419     {
420         glyph->gx_glyph_map_size = compressed_size | 0x8000;
421         UCHAR *pPut = new UCHAR[compressed_size];
422         pGet = (GX_UBYTE *)glyph->gx_glyph_map;
423         RleEncode((GX_UBYTE *)pPut, pGet, pitch, glyph->gx_glyph_height);
424 
425         delete glyph->gx_glyph_map;
426         glyph->gx_glyph_map = pPut;
427     }
428     else
429     {
430         glyph->gx_glyph_map_size = data_size;
431     }
432 }
433 
434 ///////////////////////////////////////////////////////////////////////////////
RleDecodeGlyphData(GX_COMPRESSED_GLYPH * glyph,int bits_per_pix)435 GX_UBYTE* RleDecodeGlyphData(GX_COMPRESSED_GLYPH* glyph, int bits_per_pix)
436 {
437     int pitch = GetRowPitch(glyph->gx_glyph_width, bits_per_pix);
438     int data_size = pitch * glyph->gx_glyph_height;
439 
440     if (!data_size)
441     {
442         return GX_NULL;
443     }
444 
445     GX_UBYTE* put_data = new GX_UBYTE[data_size];
446     GX_UBYTE* put_row = put_data;
447     GX_UBYTE* put;
448     GX_CONST GX_UBYTE* glyph_data = glyph->gx_glyph_map;
449 
450     int row, col;
451     GX_UBYTE count;
452     GX_UBYTE alpha;
453 
454     for (row = 0; row < glyph->gx_glyph_height; row++)
455     {
456         col = 0;
457         put = put_row;
458 
459         while (col < pitch)
460         {
461             count = *glyph_data++;
462 
463             if (count & 0x80)
464             {
465                 count = (count & 0x7f) + 1;
466                 alpha = *glyph_data++;
467 
468                 while (count--)
469                 {
470                     *put = alpha;
471 
472                     put++;
473                     col++;
474                 }
475             }
476             else
477             {
478                 count++;
479 
480                 while (count--)
481                 {
482                     alpha = *glyph_data++;
483                     *put = alpha;
484                     put++;
485                     col++;
486                 }
487             }
488         }
489         put_row += pitch;
490     }
491 
492     return put_data;
493 }
494 
495 ///////////////////////////////////////////////////////////////////////////////
CopyGlyphData(GX_GLYPH * put_glyph,GXS_FONT_DATA & glyph,int bits_per_pix,BOOL reversed_order)496 void CopyGlyphData(GX_GLYPH *put_glyph, GXS_FONT_DATA &glyph, int bits_per_pix, BOOL reversed_order)
497 {
498     int bitmap_size;
499     int row;
500     int col;
501     int num_bits;
502     UCHAR *read_data;
503     UCHAR *write_data;
504     UCHAR val;
505     UCHAR in_byte;
506     UCHAR in_mask;
507     UCHAR out_mask;
508 
509     put_glyph->gx_glyph_advance = glyph.gx_glyph_advance;
510     put_glyph->gx_glyph_ascent = glyph.gx_glyph_ascent;
511     put_glyph->gx_glyph_descent = glyph.gx_glyph_descent;
512     put_glyph->gx_glyph_height = ToUByte(glyph.height);
513     put_glyph->gx_glyph_width = ToUByte(glyph.width);
514     put_glyph->gx_glyph_leading = glyph.gx_glyph_leading;
515 
516     bitmap_size = GetRowPitch(glyph.width, bits_per_pix) * glyph.height;
517 
518     if(bitmap_size == 0)
519     {
520         return;
521     }
522 
523     put_glyph->gx_glyph_map = new UCHAR[bitmap_size];
524 
525     switch(bits_per_pix)
526     {
527     case 1:
528         write_data = (UCHAR *) put_glyph->gx_glyph_map;
529 
530         for (row = 0; row < glyph.height; row++)
531         {
532             num_bits = glyph.width;
533             read_data = glyph.gx_glyph_data + (row * glyph.pitch);
534 
535             while(num_bits)
536             {
537                 val = *read_data;
538 
539                 if (reversed_order)
540                 {
541                     // swap the bit order:
542                     in_byte = val;
543                     val = 0;
544                     in_mask = 0x80;
545                     out_mask = 0x01;
546 
547                     while(in_mask)
548                     {
549                         if (in_byte & in_mask)
550                         {
551                             val |= out_mask;
552                         }
553                         in_mask >>= 1;
554                         out_mask <<= 1;
555                     }
556                 }
557                 if (num_bits > 8)
558                 {
559                     *write_data++ = val;
560                     num_bits -= 8;
561                     read_data++;
562                 }
563                 else
564                 {
565                     *write_data++ = val;
566                     num_bits = 0;
567                 }
568             }
569         }
570         break;
571 
572     case 4:
573         // convert 8 bit incoming data to 4 bit outgoing data
574 
575         read_data = glyph.gx_glyph_data;
576         write_data = (UCHAR *) put_glyph->gx_glyph_map;
577 
578         for (row = 0; row < glyph.height; row++)
579         {
580             val = 0;
581             for (col = 0; col < glyph.width; col++)
582             {
583                 in_byte = *read_data++;
584 
585                 if (col & 1)
586                 {
587                     if (reversed_order)
588                     {
589                         val |= (in_byte & 0xf0);    // keep high nibble
590                     }
591                     else
592                     {
593                         val |= (in_byte >> 4);
594                     }
595                     *write_data++ = val;
596                 }
597                 else
598                 {
599                     if (reversed_order)
600                     {
601                         val = in_byte >> 4;
602                     }
603                     else
604                     {
605                         val = in_byte & 0xf0;
606                     }
607                 }
608             }
609 
610             // check for odd width, if so write out last pixel
611             if (glyph.width & 1)
612             {
613                 *write_data++ = val;
614             }
615         }
616         break;
617 
618     default:
619         memcpy_s((UCHAR *) put_glyph->gx_glyph_map, bitmap_size, glyph.gx_glyph_data, bitmap_size);
620         break;
621     }
622 }
623 
624 
625 ///////////////////////////////////////////////////////////////////////////////
GetFontMetrics(GXS_FONT_LIBRARY_HANDLE * handle,int height,FONT_METRICS & metrics,int firstchar,int lastchar,int bits_per_pix,FontCharMap & map)626 void GetFontMetrics(GXS_FONT_LIBRARY_HANDLE *handle,
627     int height, FONT_METRICS &metrics, int firstchar, int lastchar, int bits_per_pix, FontCharMap &map)
628 {
629     int use_char;
630 
631     GXS_FONT_DATA glyph;
632     GX_BOOL anti_alias = GX_TRUE;
633 
634     if (bits_per_pix == 1)
635     {
636         anti_alias = GX_FALSE;
637     }
638 
639     for (use_char = firstchar; use_char <= lastchar; use_char++ )
640     {
641         if (!map.Test(use_char))
642         {
643             continue;
644         }
645 
646         gx_studio_font_util_get_glyph(handle, use_char,
647             height, anti_alias, &glyph);
648 
649         if(glyph.height > metrics.max_height)
650         {
651             metrics.max_height = glyph.height;
652         }
653         if(glyph.gx_glyph_ascent > metrics.ascent)
654         {
655             metrics.ascent = glyph.gx_glyph_ascent;
656         }
657         if(glyph.gx_glyph_descent > metrics.descent)
658         {
659             metrics.descent = glyph.gx_glyph_descent;
660         }
661     }
662 
663     if (metrics.max_height < (metrics.ascent + metrics.descent))
664     {
665         metrics.max_height = (metrics.ascent + metrics.descent);
666     }
667 }
668 
669 
670 ///////////////////////////////////////////////////////////////////////////////
MakeFontPage(GXS_FONT_LIBRARY_HANDLE * handle,int height,FONT_METRICS & metrics,int firstchar,int lastchar,FontCharMap & map,res_info * info,int display)671 GX_FONT *MakeFontPage(GXS_FONT_LIBRARY_HANDLE *handle,
672     int height, FONT_METRICS &metrics, int firstchar, int lastchar, FontCharMap &map, res_info *info, int display)
673 {
674     int use_char;
675     int char_count;
676 
677     GXS_FONT_DATA glyph;
678     GX_FONT *new_font;
679     GX_GLYPH *glyph_array;
680     GX_GLYPH *put_glyph;
681     GX_COMPRESSED_GLYPH *compressed_glyph_array;
682     GX_COMPRESSED_GLYPH *put_compressed_glyph;
683     GX_BOOL anti_alias = GX_TRUE;
684     INT     bits_per_pix = info->font_bits;
685     /* Kerning glyph */
686     GX_BOOL reversed_order = GX_FALSE;
687     GX_KERNING_GLYPH *kerning_glyph_array;
688     GX_KERNING_GLYPH *put_kerning_glyph;
689 
690     studiox_project *project = GetOpenProject();
691 
692     if (!project)
693     {
694         return NULL;
695     }
696 
697     char_count = lastchar - firstchar + 1;
698 
699     new_font = new GX_FONT;
700     new_font->gx_font_first_glyph = firstchar;
701     new_font->gx_font_last_glyph = lastchar;
702     new_font->gx_font_next_page = NULL;
703 
704     if (!IsRenesasDave2D(GetOpenProject()))
705     {
706         /* Compressed mode is only supported by Renesas dave2d.  */
707         info->compress = FALSE;
708     }
709 
710     if (info->compress)
711     {
712         compressed_glyph_array = new GX_COMPRESSED_GLYPH[char_count];
713         memset(compressed_glyph_array, 0, char_count * sizeof(GX_COMPRESSED_GLYPH));
714         new_font->gx_font_glyphs.gx_font_compressed_glyphs = compressed_glyph_array;
715     }
716     else
717     {
718         if (info->font_kerning)
719         {
720             if (FT_HAS_KERNING(handle->face))
721             {
722                 /* allocate memory for kerning glyph */
723                 kerning_glyph_array = new GX_KERNING_GLYPH[char_count];
724                 memset(kerning_glyph_array, 0, char_count * sizeof(GX_KERNING_GLYPH));
725                 new_font->gx_font_glyphs.gx_font_kerning_glyphs = kerning_glyph_array;
726 
727             }
728             else
729             {
730                 /* Set kerning flag to false as the font does not contain kerning information.  */
731                 info->font_kerning = FALSE;
732                 glyph_array = new GX_GLYPH[char_count];
733                 memset(glyph_array, 0, char_count * sizeof(GX_GLYPH));
734                 new_font->gx_font_glyphs.gx_font_normal_glyphs = glyph_array;
735             }
736         }
737         else
738         {
739             glyph_array = new GX_GLYPH[char_count];
740             memset(glyph_array, 0, char_count * sizeof(GX_GLYPH));
741             new_font->gx_font_glyphs.gx_font_normal_glyphs = glyph_array;
742         }
743     }
744 
745     switch(bits_per_pix)
746     {
747     case 1:
748         new_font->gx_font_format = GX_FONT_FORMAT_1BPP;
749         anti_alias = GX_FALSE;
750 
751         if (IsDave2dFontFormat(project, display))
752         {
753             reversed_order = TRUE;
754         }
755         break;
756 
757     case 4:
758         new_font->gx_font_format = GX_FONT_FORMAT_4BPP;
759 
760         if (IsDave2dFontFormat(project, display))
761         {
762             reversed_order = TRUE;
763         }
764         break;
765 
766     case 8:
767         new_font->gx_font_format = GX_FONT_FORMAT_8BPP;
768         break;
769     }
770 
771     if (reversed_order)
772     {
773         new_font->gx_font_format |= GX_FONT_FORMAT_REVERSED_ORDER;
774     }
775 
776     if (info->compress)
777     {
778         new_font->gx_font_format |= GX_FONT_FORMAT_COMPRESSED;
779     }
780 
781     if (info->font_kerning)
782     {
783         new_font->gx_font_format |= GX_FONT_FORMAT_KERNING;
784     }
785 
786     for (use_char = firstchar; use_char <= lastchar; use_char++)
787     {
788         if (!map.Test(use_char))
789         {
790             continue;
791         }
792 
793         gx_studio_font_util_get_glyph(handle, use_char,
794                                       height, anti_alias, &glyph);
795         if (info->compress)
796         {
797             put_compressed_glyph = &(compressed_glyph_array)[use_char - firstchar];
798             CopyGlyphData((GX_GLYPH *)put_compressed_glyph, glyph, bits_per_pix, reversed_order);
799 
800             //Compress glyph data
801             RleEncodeGlyphData(put_compressed_glyph, bits_per_pix);
802         }
803         else
804         {
805             if (info->font_kerning)
806             {
807                 put_kerning_glyph = &kerning_glyph_array[use_char - firstchar];
808                 CopyGlyphData((GX_GLYPH *)put_kerning_glyph, glyph, bits_per_pix, reversed_order);
809                 if (use_char <= 0xff)
810                 {
811                     gx_studio_font_util_get_kerning_info(handle, use_char, firstchar, lastchar, put_kerning_glyph, &map);
812                 }
813             }
814             else
815             {
816                 put_glyph = &glyph_array[use_char - firstchar];
817                 CopyGlyphData(put_glyph, glyph, bits_per_pix, reversed_order);
818             }
819         }
820     }
821 
822     new_font->gx_font_prespace = 0;       /* Line spacing above, pixels               */
823     new_font->gx_font_postspace = 0;
824     new_font->gx_font_line_height = metrics.max_height;
825     new_font->gx_font_baseline = metrics.ascent;
826 
827     return new_font;
828 }
829 
830 ///////////////////////////////////////////////////////////////////////////////
MakeFont(res_info * info,int display,BOOL warn_on_error)831 GX_FONT *MakeFont(res_info *info, int display, BOOL warn_on_error)
832 {
833     font_page_info *pages = info->font_pages;
834     int page_count;
835     int max_char_count;
836     int max_char;
837     int height = info->font_height;
838     int bits_per_pix = info->font_bits;
839     FontCharMap char_map;
840     FONT_METRICS metrics;
841 
842     int page;
843     GXS_FONT_LIBRARY_HANDLE *handle;
844     GX_FONT *head_page = NULL;
845     GX_FONT *last_page = NULL;
846 
847     studiox_project* project = GetOpenProject();
848 
849     if(!project)
850     {
851     	return NULL;
852     }
853 
854 //    GotoProjectDirectory();
855     CString abspath = MakeAbsolutePathname(info->pathinfo);
856     if (gx_studio_font_util_open(CT2A(abspath.GetString()), &handle) != 0)
857     {
858         if (warn_on_error)
859         {
860             CString msg;
861             msg.Format(_T("Font Name = %s\nFailed to open TrueType font file: %s"), info->name, abspath);
862             ErrorMsg(msg);
863         }
864         return NULL;
865     }
866 
867     if (info->font_support_extended_unicode)
868     {
869         // Use 21-bit character map
870         char_map.SetMapSize(262144);
871         page_count = NUM_FONT_CHAR_RANGES + NUM_FONT_EXTENDED_CHAR_RANGES;
872 
873         // extended unicode range is between [0x10000, 0x10ffff],
874         // the total supported character count is 0x110000
875         max_char_count = GX_MAX_GLYPH_CODE + 1;
876         max_char = 0x10ffff;
877     }
878     else
879     {
880         page_count = NUM_FONT_CHAR_RANGES;
881         max_char_count = 0xffff;
882         max_char = 0xffff;
883     }
884 
885     if (info->font_pages_count)
886     {
887         page_count = info->font_pages_count;
888     }
889 
890     for (page = 0; page < page_count; page++)
891     {
892         // map character ranges the user has turned on
893         if (pages[page].enabled && pages[page].first_char <= pages[page].last_char)
894         {
895             char_map.Set(pages[page].first_char, pages[page].last_char);
896         }
897     }
898 
899     if (info->font_charset_include_string_table)
900     {
901         // add characters used in string table
902         FontCharMap *tmap = GetActiveCharacterMap(FALSE);
903         if (tmap)
904         {
905             char_map.Overlay(tmap);
906         }
907     }
908 
909     if (char_map.Test(0xe00, 0xe7f))
910     {
911         // Detected thai glyph code
912         if (char_map.Test(0x0e33))
913         {
914             // The vowel sara am will be split into the character nikhahit and sara aa if it is
915             // appended to a consonant.
916             char_map.Set(0x0e4d, 0x0e4d);
917             char_map.Set(0x0e32, 0x0e32);
918         }
919 
920         // add private user area for thai glyph shaping
921         char_map.Set(0xf700, 0xf71a);
922     }
923 
924     if (char_map.Test(0x600, 0x6ff))
925     {
926         // add arabic presentation forms-b for arabic shaping
927         char_map.Set(0xfe70, 0xfeff);
928 
929         // add arabic presentation forms-a for persion shaping
930         char_map.Set(0xfb50, 0xfbff);
931     }
932 
933     if (char_map.IsEmpty())
934     {
935         gx_studio_font_util_close(handle);
936         return NULL;
937     }
938 
939     int first_char, last_char;
940 
941     metrics.ascent = metrics.descent = metrics.max_height = 0;
942 
943     // first get the font metrics
944     for (first_char = 0; first_char <= max_char; first_char++)
945     {
946         if (char_map.Test(first_char, first_char))
947         {
948             GetFontMetrics(handle, height, metrics, first_char, first_char, bits_per_pix, char_map);
949         }
950     }
951 
952     // now render actual font data pages
953     GX_FONT *newpage;
954 
955     for (first_char = 0; first_char <= max_char;)
956     {
957         last_char = first_char + 127;
958 
959         if (last_char > max_char)
960         {
961             last_char = max_char;
962         }
963 
964         if (char_map.Test(first_char, last_char))
965         {
966             // Make font for characters that defined in character map but not in character ranges.
967             newpage = MakeFontPage(handle, height, metrics, first_char, last_char, char_map, info, display);
968 
969             if (newpage)
970             {
971                 if (!head_page)
972                 {
973                     head_page = newpage;
974                 }
975                 if (last_page)
976                 {
977                     last_page->gx_font_next_page = newpage;
978                 }
979                 last_page = newpage;
980             }
981         }
982 
983         first_char = last_char + 1;
984     }
985 
986     gx_studio_font_util_close(handle);
987     return head_page;
988 }
989 
990 ///////////////////////////////////////////////////////////////////////////////
InsertStringTableGlyphs(FontCharMap * char_map,res_info * info,int display)991 BOOL InsertStringTableGlyphs(FontCharMap *char_map, res_info *info, int display)
992 {
993     BOOL status = TRUE;
994     BOOL found_page;
995     BOOL anti_alias = FALSE;
996     int height = info->font_height;
997     int bits_per_pix = info->font_bits;
998     DWORD char_val;
999     DWORD maxval = char_map->GetMapSize() << 3;
1000     GXS_FONT_LIBRARY_HANDLE *handle;
1001     GXS_FONT_DATA glyph;
1002     GX_FONT *head_page = NULL;
1003     GX_FONT *last_page = NULL;
1004 
1005     if (!char_map)
1006     {
1007         return FALSE;
1008     }
1009 
1010     CString abspath = MakeAbsolutePathname(info->pathinfo);
1011     if (gx_studio_font_util_open(CT2A(abspath.GetString()), &handle) != 0)
1012     {
1013         return FALSE;
1014     }
1015 
1016     if (bits_per_pix > 1)
1017     {
1018         anti_alias = TRUE;
1019     }
1020 
1021     BOOL reversed_order = FALSE;
1022 
1023     switch (bits_per_pix)
1024     {
1025     case 1:
1026     case 4:
1027         if (IsDave2dFontFormat(GetOpenProject(), display))
1028         {
1029             reversed_order = TRUE;
1030         }
1031         break;
1032     }
1033 
1034     for (char_val = 0; char_val < maxval; char_val++)
1035     {
1036         if (char_map->Test(char_val))
1037         {
1038             GX_FONT *page = info->font;
1039             found_page = FALSE;
1040 
1041             while(page)
1042             {
1043                 if (page->gx_font_first_glyph <= char_val &&
1044                     page->gx_font_last_glyph >= char_val)
1045                 {
1046                     found_page = TRUE;
1047 
1048                     if (info->font_kerning)
1049                     {
1050                         GX_KERNING_GLYPH *put_glyph = (GX_KERNING_GLYPH *) &page->gx_font_glyphs.gx_font_kerning_glyphs[char_val - page->gx_font_first_glyph];
1051 
1052                         if ((!put_glyph->gx_glyph_map) && (put_glyph->gx_glyph_advance == 0))
1053                         {
1054                             // get the glyph data, insert into font
1055 
1056                             if (gx_studio_font_util_get_glyph(handle, char_val, height, anti_alias, &glyph) != GXS_FONT_UTIL_SUCCESS)
1057                             {
1058                                 status = FALSE;
1059                                 break;
1060                             }
1061                             CopyGlyphData((GX_GLYPH *)put_glyph, glyph, bits_per_pix, reversed_order);
1062 
1063                             if (put_glyph->gx_kerning_table)
1064                             {
1065                                 delete[] put_glyph->gx_kerning_table;
1066                                 put_glyph->gx_kerning_table = NULL;
1067                                 if (char_val <= 0xff)
1068                                 {
1069                                     gx_studio_font_util_get_kerning_info(handle, char_val, page->gx_font_first_glyph, page->gx_font_last_glyph, put_glyph, char_map);
1070                                 }
1071                             }
1072                         }
1073                     }
1074                     else if (page->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
1075                     {
1076                         GX_COMPRESSED_GLYPH *put_glyph = (GX_COMPRESSED_GLYPH *) &page->gx_font_glyphs.gx_font_compressed_glyphs[char_val - page->gx_font_first_glyph];
1077 
1078                         if ((!put_glyph->gx_glyph_map) && (put_glyph->gx_glyph_advance == 0))
1079                         {
1080                             // get the glyph data, insert into font
1081 
1082                             if (gx_studio_font_util_get_glyph(handle, char_val, height, anti_alias, &glyph) != GXS_FONT_UTIL_SUCCESS)
1083                             {
1084                                 status = FALSE;
1085                                 break;
1086                             }
1087                             CopyGlyphData((GX_GLYPH *)put_glyph, glyph, bits_per_pix, reversed_order);
1088 
1089                             //Compress glyph data
1090                             RleEncodeGlyphData(put_glyph, bits_per_pix);
1091                         }
1092                     }
1093                     else
1094                     {
1095                         GX_GLYPH *put_glyph = (GX_GLYPH *)&page->gx_font_glyphs.gx_font_normal_glyphs[char_val - page->gx_font_first_glyph];
1096 
1097                         if ((!put_glyph->gx_glyph_map) && (put_glyph->gx_glyph_advance == 0))
1098                         {
1099                             // get the glyph data, insert into font
1100 
1101                             if (gx_studio_font_util_get_glyph(handle, char_val, height, anti_alias, &glyph) != GXS_FONT_UTIL_SUCCESS)
1102                             {
1103                                 status = FALSE;
1104                                 break;
1105                             }
1106                             CopyGlyphData(put_glyph, glyph, bits_per_pix, reversed_order);
1107                         }
1108                     }
1109 
1110                     break;
1111                 }
1112                 page = (GX_FONT *) page->gx_font_next_page;
1113             }
1114 
1115             if ((!found_page) || (status != TRUE))
1116             {
1117                 status = FALSE;
1118                 break;
1119             }
1120         }
1121     }
1122 
1123     gx_studio_font_util_close(handle);
1124     return status;
1125 }
1126 
1127 
1128 ///////////////////////////////////////////////////////////////////////////////
DestroyFont(GX_FONT * font)1129 void DestroyFont(GX_FONT *font)
1130 {
1131     GX_GLYPH *glyph;
1132     GX_COMPRESSED_GLYPH *compressed_glyph;
1133     GX_KERNING_GLYPH  *kering_glyph;
1134     const GX_FONT *next_page = NULL;
1135 
1136     while (font)
1137     {
1138         next_page = font->gx_font_next_page;
1139 
1140         int num_chars = font->gx_font_last_glyph - font->gx_font_first_glyph + 1;
1141 
1142         if (font->gx_font_glyphs.gx_font_normal_glyphs)
1143         {
1144             glyph = (GX_GLYPH *) font->gx_font_glyphs.gx_font_normal_glyphs;
1145 
1146             for (int index = 0; index < num_chars; index++)
1147             {
1148                 if (glyph->gx_glyph_map)
1149                 {
1150                     delete [] glyph->gx_glyph_map;
1151                     glyph->gx_glyph_map = NULL;
1152                 }
1153 
1154                 if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
1155                 {
1156                     compressed_glyph = (GX_COMPRESSED_GLYPH *)glyph;
1157                     compressed_glyph++;
1158                     glyph = (GX_GLYPH *)compressed_glyph;
1159                 }
1160                 else if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
1161                 {
1162                     kering_glyph = (GX_KERNING_GLYPH *)glyph;
1163                     if (kering_glyph->gx_kerning_table)
1164                     {
1165                         delete[] kering_glyph->gx_kerning_table;
1166                         kering_glyph->gx_kerning_table = NULL;
1167                     }
1168                     kering_glyph++;
1169                     glyph = (GX_GLYPH *)kering_glyph;
1170                 }
1171                 else
1172                 {
1173                     glyph++;
1174                 }
1175             }
1176             delete [] font->gx_font_glyphs.gx_font_normal_glyphs;
1177             font->gx_font_glyphs.gx_font_normal_glyphs = NULL;
1178         }
1179         delete font;
1180         font = (GX_FONT *) next_page;
1181     }
1182 }
1183 
1184 ///////////////////////////////////////////////////////////////////////////////
FindFirstValidGlyph(const GX_FONT * page,GX_CHAR_CODE glyph_start)1185 GX_CHAR_CODE FindFirstValidGlyph(const GX_FONT *page, GX_CHAR_CODE glyph_start)
1186 {
1187     GX_CHAR_CODE index;
1188     GX_COMPRESSED_GLYPH *compressed_glyph;
1189     GX_KERNING_GLYPH *kerning_glyph;
1190     while(1)
1191     {
1192         if (glyph_start > page->gx_font_last_glyph)
1193         {
1194             break;
1195         }
1196         index = glyph_start - page->gx_font_first_glyph;
1197 
1198         if (page->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
1199         {
1200             compressed_glyph = (GX_COMPRESSED_GLYPH *)page->gx_font_glyphs.gx_font_compressed_glyphs;
1201             if (compressed_glyph[index].gx_glyph_map != NULL ||
1202                 compressed_glyph[index].gx_glyph_advance != 0)
1203             {
1204                 break;
1205             }
1206         }
1207         else if (page->gx_font_format & GX_FONT_FORMAT_KERNING)
1208         {
1209             kerning_glyph = (GX_KERNING_GLYPH *)page->gx_font_glyphs.gx_font_kerning_glyphs;
1210             if (kerning_glyph[index].gx_glyph_map != NULL ||
1211                 kerning_glyph[index].gx_glyph_advance != 0)
1212             {
1213                 break;
1214             }
1215         }
1216         else
1217         {
1218             if (page->gx_font_glyphs.gx_font_normal_glyphs[index].gx_glyph_map != NULL ||
1219                 page->gx_font_glyphs.gx_font_normal_glyphs[index].gx_glyph_advance != 0)
1220             {
1221                 break;
1222             }
1223         }
1224         glyph_start++;
1225     }
1226     return glyph_start;
1227 }
1228 
1229 #define MAX_FONT_DEAD_BLOCK 64
1230 
1231 ///////////////////////////////////////////////////////////////////////////////
FindDeadGlyphBlock(const GX_FONT * page,GX_CHAR_CODE glyph_end)1232 GX_CHAR_CODE FindDeadGlyphBlock(const GX_FONT *page, GX_CHAR_CODE glyph_end)
1233 {
1234     GX_CHAR_CODE dead_count = 0;
1235     GX_CHAR_CODE stop_point = glyph_end;
1236     GX_CHAR_CODE index;
1237     GX_CONST GX_COMPRESSED_GLYPH *compressed_glyph;
1238     GX_CONST GX_KERNING_GLYPH *kerning_glyph;
1239 
1240     index = stop_point;
1241 
1242     if (page->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
1243     {
1244         compressed_glyph = page->gx_font_glyphs.gx_font_compressed_glyphs;
1245 
1246         while (index <= page->gx_font_last_glyph)
1247         {
1248             if (compressed_glyph[index - page->gx_font_first_glyph].gx_glyph_map == NULL &&
1249                 compressed_glyph[index - page->gx_font_first_glyph].gx_glyph_advance == 0)
1250             {
1251                 dead_count++;
1252 
1253                 if (dead_count > MAX_FONT_DEAD_BLOCK)
1254                 {
1255                     break;
1256                 }
1257             }
1258             else
1259             {
1260                 stop_point = index;
1261                 dead_count = 0;
1262             }
1263             index++;
1264         }
1265     }
1266     else if (page->gx_font_format & GX_FONT_FORMAT_KERNING)
1267     {
1268         kerning_glyph = page->gx_font_glyphs.gx_font_kerning_glyphs;
1269 
1270         while (index <= page->gx_font_last_glyph)
1271         {
1272             if (kerning_glyph[index - page->gx_font_first_glyph].gx_glyph_map == NULL &&
1273                 kerning_glyph[index - page->gx_font_first_glyph].gx_glyph_advance == 0)
1274             {
1275                 dead_count++;
1276 
1277                 if (dead_count > MAX_FONT_DEAD_BLOCK)
1278                 {
1279                     break;
1280                 }
1281             }
1282             else
1283             {
1284                 stop_point = index;
1285                 dead_count = 0;
1286             }
1287             index++;
1288         }
1289     }
1290     else
1291     {
1292 
1293         while (index <= page->gx_font_last_glyph)
1294         {
1295             if (page->gx_font_glyphs.gx_font_normal_glyphs[index - page->gx_font_first_glyph].gx_glyph_map == NULL &&
1296                 page->gx_font_glyphs.gx_font_normal_glyphs[index - page->gx_font_first_glyph].gx_glyph_advance == 0)
1297             {
1298                 dead_count++;
1299 
1300                 if (dead_count > MAX_FONT_DEAD_BLOCK)
1301                 {
1302                     break;
1303                 }
1304             }
1305             else
1306             {
1307                 stop_point = index;
1308                 dead_count = 0;
1309             }
1310             index++;
1311         }
1312     }
1313     return stop_point;
1314 }
1315 
1316 ///////////////////////////////////////////////////////////////////////////////
CopyGlyphs(GX_FONT * dest,const GX_FONT * src)1317 void CopyGlyphs(GX_FONT *dest, const GX_FONT *src)
1318 {
1319     int char_count = dest->gx_font_last_glyph - dest->gx_font_first_glyph + 1;
1320 
1321     GX_GLYPH *glyph_array = new GX_GLYPH[char_count];
1322     memset(glyph_array, 0, char_count * sizeof(GX_GLYPH));
1323     dest->gx_font_glyphs.gx_font_normal_glyphs = glyph_array;
1324 
1325     GX_GLYPH *put = glyph_array;
1326     const GX_GLYPH *get = &src->gx_font_glyphs.gx_font_normal_glyphs[dest->gx_font_first_glyph - src->gx_font_first_glyph];
1327 
1328     int bitmap_size = 0;
1329 
1330     while(char_count--)
1331     {
1332         *put = *get;
1333         put->gx_glyph_map = NULL;
1334         bitmap_size = GetRowPitch(put->gx_glyph_width, GetFontBits(dest->gx_font_format));
1335         bitmap_size *= put->gx_glyph_height;
1336 
1337         if(bitmap_size != 0)
1338         {
1339             put->gx_glyph_map = new UCHAR[bitmap_size];
1340             memcpy_s((GX_UBYTE *) put->gx_glyph_map, bitmap_size, get->gx_glyph_map, bitmap_size);
1341         }
1342         else
1343         {
1344             put->gx_glyph_map = GX_NULL;
1345         }
1346 
1347         put++;
1348         get++;
1349     }
1350 }
1351 
1352 ///////////////////////////////////////////////////////////////////////////////
CopyKerningGlyphs(GX_FONT * dest,const GX_FONT * src)1353 void CopyKerningGlyphs(GX_FONT *dest, const GX_FONT *src)
1354 {
1355     int char_count = dest->gx_font_last_glyph - dest->gx_font_first_glyph + 1;
1356     GX_KERNING_GLYPH *glyph_array = new GX_KERNING_GLYPH[char_count];
1357     memset(glyph_array, 0, char_count * sizeof(GX_KERNING_GLYPH));
1358     dest->gx_font_glyphs.gx_font_kerning_glyphs = glyph_array;
1359 
1360     GX_KERNING_GLYPH *put = glyph_array;
1361     const GX_KERNING_GLYPH *get = &src->gx_font_glyphs.gx_font_kerning_glyphs[dest->gx_font_first_glyph - src->gx_font_first_glyph];
1362 
1363     int bitmap_size = 0;
1364     while (char_count--)
1365     {
1366         *put = *get;
1367         bitmap_size = GetRowPitch(put->gx_glyph_width, GetFontBits(dest->gx_font_format));
1368         bitmap_size *= put->gx_glyph_height;
1369 
1370         if (bitmap_size != 0)
1371         {
1372             put->gx_glyph_map = new UCHAR[bitmap_size];
1373             memcpy_s((GX_UBYTE *)put->gx_glyph_map, bitmap_size, get->gx_glyph_map, bitmap_size);
1374         }
1375         else
1376         {
1377             put->gx_glyph_map = GX_NULL;
1378         }
1379         put -> gx_kerning_table = GX_NULL;
1380 
1381         if (get -> gx_kerning_table)
1382         {
1383             /* Copy kerning table if there's one */
1384             INT table_size = *(get->gx_kerning_table);
1385             table_size = 1 + (table_size * (sizeof(GX_UBYTE) + sizeof(GX_CHAR)));
1386             put->gx_kerning_table = new GX_UBYTE[table_size];
1387             memcpy_s((GX_UBYTE *)put->gx_kerning_table, table_size, get->gx_kerning_table, table_size);
1388         }
1389         put++;
1390         get++;
1391     }
1392 }
1393 
1394 ///////////////////////////////////////////////////////////////////////////////
CopyCompressedGlyphs(GX_FONT * dest,const GX_FONT * src)1395 void CopyCompressedGlyphs(GX_FONT *dest, const GX_FONT *src)
1396 {
1397     int char_count = dest->gx_font_last_glyph - dest->gx_font_first_glyph + 1;
1398 
1399     GX_COMPRESSED_GLYPH *glyph_array = new GX_COMPRESSED_GLYPH[char_count];
1400     memset(glyph_array, 0, char_count * sizeof(GX_COMPRESSED_GLYPH));
1401     dest->gx_font_glyphs.gx_font_compressed_glyphs = glyph_array;
1402 
1403     GX_COMPRESSED_GLYPH *put = glyph_array;
1404     const GX_COMPRESSED_GLYPH *get = &src->gx_font_glyphs.gx_font_compressed_glyphs[dest->gx_font_first_glyph - src->gx_font_first_glyph];
1405 
1406     int bitmap_size = 0;
1407 
1408     while (char_count--)
1409     {
1410         *put = *get;
1411         bitmap_size = put->gx_glyph_map_size & 0x7fff;
1412 
1413         if (bitmap_size != 0)
1414         {
1415             put->gx_glyph_map = new UCHAR[bitmap_size];
1416             memcpy_s((GX_UBYTE *)put->gx_glyph_map, bitmap_size, get->gx_glyph_map, bitmap_size);
1417         }
1418         else
1419         {
1420             put->gx_glyph_map = GX_NULL;
1421         }
1422 
1423         put++;
1424         get++;
1425     }
1426 }
1427 
1428 ///////////////////////////////////////////////////////////////////////////////
optimize_font(GX_FONT * src_font)1429 GX_FONT *optimize_font(GX_FONT *src_font)
1430 {
1431     GX_FONT *head_page = NULL;
1432     GX_FONT *last_page = NULL;
1433     GX_FONT *current_page = NULL;
1434     const GX_FONT *src_page = src_font;
1435 
1436     while (src_page)
1437     {
1438         GX_CHAR_CODE first_glyph = src_page->gx_font_first_glyph;
1439         GX_CHAR_CODE last_glyph = src_page->gx_font_last_glyph;
1440 
1441         while(first_glyph <= src_page->gx_font_last_glyph)
1442         {
1443             // skip leading NULL glyphs
1444             first_glyph = FindFirstValidGlyph(src_page, first_glyph);
1445 
1446             if (first_glyph <= src_page->gx_font_last_glyph)
1447             {
1448                 // stop if there is a large dead section
1449                 last_glyph = FindDeadGlyphBlock(src_page, first_glyph);
1450 
1451                 // make a font page for first to last:
1452                 current_page = new GX_FONT;
1453                 memset(current_page, 0, sizeof(GX_FONT));
1454                 current_page->gx_font_baseline = src_page->gx_font_baseline;
1455                 current_page->gx_font_first_glyph = first_glyph;
1456                 current_page->gx_font_last_glyph = last_glyph;
1457                 current_page->gx_font_format = src_page->gx_font_format;
1458                 current_page->gx_font_line_height = src_page->gx_font_line_height;
1459                 current_page->gx_font_postspace = src_page->gx_font_postspace;
1460                 current_page->gx_font_prespace = src_page->gx_font_prespace;
1461 
1462                 if (src_page->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
1463                 {
1464                     CopyCompressedGlyphs(current_page, src_page);
1465                 }
1466                 else if(src_page->gx_font_format & GX_FONT_FORMAT_KERNING)
1467                 {
1468                     CopyKerningGlyphs(current_page, src_page);
1469                 }
1470                 else
1471                 {
1472                     CopyGlyphs(current_page, src_page);
1473                 }
1474 
1475                 if (last_page)
1476                 {
1477                     last_page->gx_font_next_page = current_page;
1478                 }
1479                 else
1480                 {
1481                     head_page = current_page;
1482                 }
1483                 last_page = current_page;
1484                 first_glyph = last_glyph + 1;
1485             }
1486         }
1487         src_page = src_page->gx_font_next_page;
1488     }
1489     return head_page;
1490 }
1491 
1492 ///////////////////////////////////////////////////////////////////////////////
MakeOptimizedFont(res_info * info,int display,BOOL warn_on_error)1493 GX_FONT *MakeOptimizedFont(res_info *info, int display, BOOL warn_on_error)
1494 {
1495     GX_FONT *optimized = GX_NULL;
1496     GX_FONT *new_font = MakeFont(info, display, warn_on_error);
1497 
1498     if (new_font)
1499     {
1500         optimized = optimize_font(new_font);
1501         DestroyFont(new_font);
1502     }
1503     return optimized;
1504 }
1505 
1506 ///////////////////////////////////////////////////////////////////////////////
GetFontStorage(res_info * info,studiox_project * project,int display)1507 INT  GetFontStorage(res_info *info, studiox_project *project, int display)
1508 {
1509     // return the size (in byte) of output font
1510 
1511     const GX_FONT *font_page;
1512     const GX_FONT *head_page;
1513     long datasize = 0;
1514     long kerning_datasize = 0;
1515     GX_CHAR_CODE charval;
1516     GX_CHAR_CODE index;
1517     const GX_GLYPH *glyph;
1518     const GX_COMPRESSED_GLYPH *compressed_glyph;
1519     const GX_KERNING_GLYPH *kerning_glyph;
1520     GX_UBYTE Kerning_pairs_count;
1521     int pitch;
1522 
1523     /* Make the font again, with optimization  */
1524     head_page = MakeOptimizedFont(info, display);
1525 
1526     if (!head_page)
1527     {
1528         return datasize;
1529     }
1530 
1531     font_page = head_page;
1532 
1533     /* Calculate font size.  */
1534     while (font_page)
1535     {
1536         for (charval = font_page->gx_font_first_glyph; charval <= font_page->gx_font_last_glyph; charval++)
1537         {
1538             index = charval - font_page->gx_font_first_glyph;
1539 
1540             if (font_page->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
1541             {
1542                 compressed_glyph = &font_page->gx_font_glyphs.gx_font_compressed_glyphs[index];
1543                 datasize += (compressed_glyph->gx_glyph_map_size & 0x7fff);
1544             }
1545             else if (font_page->gx_font_format & GX_FONT_FORMAT_KERNING)
1546             {
1547                 kerning_glyph = &font_page->gx_font_glyphs.gx_font_kerning_glyphs[index];
1548                 pitch = GetRowPitch(kerning_glyph->gx_glyph_width, info->font_bits);
1549                 datasize += pitch * kerning_glyph->gx_glyph_height;
1550                 if (kerning_glyph->gx_kerning_table)
1551                 {
1552                     Kerning_pairs_count = *(kerning_glyph->gx_kerning_table);
1553                     /* Add the kerning table size. */
1554                     kerning_datasize += 1 + Kerning_pairs_count * (sizeof(GX_CHAR) + sizeof(GX_UBYTE));
1555                 }
1556             }
1557             else
1558             {
1559                 glyph = &font_page->gx_font_glyphs.gx_font_normal_glyphs[index];
1560                 pitch = GetRowPitch(glyph->gx_glyph_width, info->font_bits);
1561                 datasize += pitch * glyph->gx_glyph_height;
1562             }
1563         }
1564 
1565         font_page = font_page->gx_font_next_page;
1566     }
1567     DestroyFont((GX_FONT *)head_page);
1568 
1569     /* if kerning info size is bigger than 5 kB*/
1570     if (kerning_datasize > 5120)
1571     {
1572         if (kerning_datasize > datasize)
1573         {
1574             /* kerning info data size is bigger than the glyph size.
1575                Show notification dialog that the font size is so large. */
1576             CString message ("Generate kerning info of font ");
1577             message += info->name;
1578             message += " is selected and it will take lots of memory. Make sure it is wanted.";
1579             Notify(CW2A(message));
1580         }
1581     }
1582 
1583     return (datasize + kerning_datasize);
1584 }
1585 
1586 
1587 ////////////////////////////////////////////////////////////////////////////////
GetPixelmapStorage(res_info * info)1588 INT GetPixelmapStorage(res_info *info)
1589 {
1590     int storage = 0;
1591 
1592     if (info->raw)
1593     {
1594         CString path = MakeAbsolutePathname(info->pathinfo);
1595         FILE *file = _tfopen(path.GetBuffer(), _T("rb"));
1596 
1597         if (!file)
1598         {
1599             return 0;
1600         }
1601 
1602         fseek(file, 0, SEEK_END);
1603         storage = ftell(file);
1604         fclose(file);
1605     }
1606     else
1607     {
1608         GX_PIXELMAP *map;
1609 
1610         for (int index = 0; index < info->GetPixelmapFrameCount(); index++)
1611         {
1612             map = info->GetPixelmap(index);
1613 
1614             if (map)
1615             {
1616                 storage += map->gx_pixelmap_data_size;
1617 
1618                 if (map->gx_pixelmap_aux_data_size)
1619                 {
1620                     if (info->output_color_format != GX_COLOR_FORMAT_8BIT_PALETTE ||
1621                         (info->palette_type == PALETTE_TYPE_PRIVATE && index == 0))
1622                     {
1623                         storage += map->gx_pixelmap_aux_data_size;
1624                     }
1625                 }
1626             }
1627         }
1628     }
1629 
1630     return storage;
1631 }