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