1 /*******************************************************
2 
3    CoolReader Engine C-compatible API
4 
5    lvfnt.cpp:  Unicode Antialiased Bitmap Font
6 
7    (c) Vadim Lopatin, 2000-2006
8    This source code is distributed under the terms of
9    GNU General Public License
10    See LICENSE file for details
11 
12 *******************************************************/
13 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include "../include/lvfnt.h"
18 
19 #define MIN_FONT_SIZE 2048
20 #define MAX_FONT_SIZE 0x100000
21 
22 #ifndef __cplusplus
lvfontIsUnicodeSpace(lChar32 code)23 int lvfontIsUnicodeSpace( lChar32 code )
24 {
25     /* TODO: add other space codes here */
26     return (code==0x0020);
27 }
28 #endif
29 
lvfontGetHeader(const lvfont_handle pfont)30 const lvfont_header_t * lvfontGetHeader( const lvfont_handle pfont )
31 {
32     return (const tag_lvfont_header *) pfont;
33 }
34 
lvfontGetDecodeTable(const lvfont_handle pfont)35 const hrle_decode_info_t * lvfontGetDecodeTable( const lvfont_handle pfont )
36 {
37     return (hrle_decode_info_t *)
38         ((const lUInt8*)pfont + ((const tag_lvfont_header *) pfont)->decodeTableOffset);
39 }
40 
lvfontGetGlyph(const lvfont_handle pfont,lUInt16 code)41 const lvfont_glyph_t * lvfontGetGlyph( const lvfont_handle pfont, lUInt16 code )
42 {
43     const tag_lvfont_header * hdr = (const tag_lvfont_header *) pfont;
44     if ( code>hdr->maxCode )
45         return NULL;
46     lUInt32 rangeoffset = hdr->rangesOffset[(code>>6) & 0x3FF ];
47     if ( rangeoffset == 0 || rangeoffset>hdr->fileSize )
48         return NULL;
49     const lvfont_range_t * range = (const lvfont_range_t *)
50         ( ((const char *)pfont) + rangeoffset );
51     lUInt32 glyphoffset = range->glyphsOffset[code & 0x3F];
52     if ( glyphoffset == 0 || glyphoffset>hdr->fileSize )
53         return NULL;
54     return (const lvfont_glyph_t *)
55         ( ((const char *)range) + glyphoffset );
56 }
57 
lvfontOpen(const char * fname,lvfont_handle * pfont)58 int lvfontOpen( const char * fname, lvfont_handle * pfont )
59 {
60     static lvByteOrderConv cnv;
61 
62     FILE * f = fopen( fname, "rb" );
63     if (f == NULL)
64         return 0;
65     fseek( f, 0, SEEK_END );
66     lUInt32 sz = ftell(f);
67     if (sz < MIN_FONT_SIZE || sz > MAX_FONT_SIZE )
68     {
69         fclose(f);
70         return 0;
71     }
72     *pfont = (lvfont_handle) malloc( sz );
73     fseek( f, 0, SEEK_SET );
74     fread( *pfont, sz, 1, f );
75     fclose(f);
76     tag_lvfont_header * hdr = (tag_lvfont_header *)lvfontGetHeader( *pfont );
77 
78     cnv.lsf( &hdr->fileSize );
79 
80     if (   hdr->fileSize != sz
81         || hdr->magic[0]!='L'
82         || hdr->magic[1]!='F'
83         || hdr->magic[2]!='N'
84         || hdr->magic[3]!='T'
85         || hdr->version[0]!='1'
86         || hdr->version[1]!='.'
87         || hdr->version[2]!='0'
88         || hdr->version[3]!='0' )
89     {
90         free( *pfont );
91         return 0;
92     }
93     if (cnv.msf()) {
94         cnv.rev( &hdr->minCode );
95         cnv.rev( &hdr->maxCode );
96         cnv.rev( &hdr->decodeTableOffset );
97         int ntables = (hdr->maxCode >> 6);
98         for ( int i=0; i<ntables; i++ ) {
99             cnv.rev( &hdr->rangesOffset[i] );
100             int rangeoffset = hdr->rangesOffset[i];
101             if ( rangeoffset<=0 || rangeoffset>(int)sz )
102                 continue;
103             lvfont_range_t * range = (lvfont_range_t *)
104                 ( ((const char *)*pfont) + rangeoffset );
105 
106             for ( int j=0; j<64; j++ ) {
107                 cnv.rev( &range->glyphsOffset[j] );
108                 int glyphoffset = range->glyphsOffset[j];
109                 if ( glyphoffset<=0 || glyphoffset+rangeoffset>=(int)sz )
110                     continue;
111                 lvfont_glyph_t * glyph =  (lvfont_glyph_t *)
112                     ( ((const char *)range) + glyphoffset );
113                 cnv.rev( &glyph->glyphSize );
114             }
115 
116         }
117     }
118     return 1;
119 }
120 
lvfontClose(lvfont_handle pfont)121 void lvfontClose( lvfont_handle pfont )
122 {
123     if (pfont)
124     {
125         free(pfont);
126     }
127 }
128 
lvfontMeasureText(const lvfont_handle pfont,const lChar32 * text,int len,lUInt16 * widths,lUInt8 * flags,int max_width,lChar32 def_char)129 lUInt16 lvfontMeasureText( const lvfont_handle pfont,
130                     const lChar32 * text, int len,
131                     lUInt16 * widths,
132                     lUInt8 * flags,
133                     int max_width,
134                     lChar32 def_char
135                  )
136 {
137     lUInt16 wsum = 0;
138     lUInt16 nchars = 0;
139     const lvfont_glyph_t * glyph;
140     lUInt16 gwidth = 0;
141     lUInt16 hyphwidth = 0;
142     lUInt8 bflags;
143     int isSpace;
144     lChar32 ch;
145     int hwStart, hwEnd;
146 
147     glyph = lvfontGetGlyph( pfont, UNICODE_SOFT_HYPHEN_CODE );
148     hyphwidth = glyph ? glyph->width : 0;
149 
150     for ( ; wsum < max_width && nchars < len; nchars++ )
151     {
152         bflags = 0;
153         ch = text[nchars];
154         isSpace = lvfontIsUnicodeSpace(ch);
155         if (isSpace ||  ch == UNICODE_SOFT_HYPHEN_CODE )
156             bflags |= LCHAR_ALLOW_WRAP_AFTER;
157         if (ch == '-')
158             bflags |= LCHAR_DEPRECATED_WRAP_AFTER;
159         if (isSpace)
160             bflags |= LCHAR_IS_SPACE;
161         glyph = lvfontGetGlyph( pfont, ch );
162         if (!glyph && def_char)
163              glyph = lvfontGetGlyph( pfont, def_char );
164         gwidth = glyph ? glyph->width : 0;
165         widths[nchars] = wsum + gwidth;
166         if ( ch != UNICODE_SOFT_HYPHEN_CODE )
167             wsum += gwidth; /* don't include hyphens to width */
168         flags[nchars] = bflags;
169     }
170 
171 #ifdef __cplusplus
172     //try to add hyphen
173     for (hwStart=nchars-1; hwStart>0; hwStart--)
174     {
175         if (lvfontIsUnicodeSpace(text[hwStart]))
176         {
177             hwStart++;
178             break;
179         }
180     }
181     for (hwEnd=nchars; hwEnd<len; hwEnd++)
182     {
183         lChar32 ch = text[hwEnd];
184         if (lvfontIsUnicodeSpace(ch))
185             break;
186         if (flags[hwEnd-1]&LCHAR_ALLOW_WRAP_AFTER)
187             break;
188         if (ch=='.' || ch==',' || ch=='!' || ch=='?' || ch=='?')
189             break;
190 
191     }
192     HyphMan::hyphenate(text+hwStart, hwEnd-hwStart, widths+hwStart, flags+hwStart, hyphwidth, max_width);
193 #endif
194 
195     return nchars;
196 }
197 
lvfontUnpackGlyph(const lUInt8 * packed,const hrle_decode_info_t * table,lUInt8 * unpacked,int unp_size)198 void lvfontUnpackGlyph( const lUInt8 * packed, const hrle_decode_info_t * table, lUInt8 * unpacked, int unp_size )
199 {
200     lUInt16  b;
201     hrle_decode_table_t code;
202     int      srcshift;
203     int      srcdata;
204     int      srccount;
205     int inx;
206 
207     srcshift = 0; //(srcskip & 3);
208     // srccount = 0;
209     /* newline */
210     lUInt8 * unp_end = unpacked + unp_size;
211     for (;unpacked<unp_end;)
212     {
213         // read source
214         b = (((lUInt16)(packed[0]))<<8) | (packed[1]);
215         inx = (b >> (16 - table->bitcount - srcshift)) & table->rightmask;
216         code = table->table[inx];
217         srcdata = code.value << 6;
218         srccount = code.count;
219         srcshift += code.codelen;
220         if (srcshift & 8)
221         {
222             srcshift &= 7;
223             packed++;
224         }
225         // write to dest
226         for (;srccount;srccount--)
227             *unpacked++ = srcdata;
228     }
229 }
230 
231