1 /*
2 * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
3 * 2008 Vincent Sanders <vince@simtec.co.uk>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <inttypes.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <stdlib.h>
24
25 #include "utils/nsoption.h"
26 #include "utils/utf8.h"
27 #include "netsurf/utf8.h"
28 #include "netsurf/layout.h"
29 #include "netsurf/plot_style.h"
30
31 #include "framebuffer/gui.h"
32 #include "framebuffer/font.h"
33
34 #include <font-ns-sans.h>
35
36 #define GLYPH_LEN 16
37
38 uint8_t code_point[GLYPH_LEN];
39 uint8_t glyph_x2[GLYPH_LEN * 4];
40
41 #define SEVEN_SET ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | \
42 (1 << 4) | (1 << 5) | (1 << 6))
43
44 #define THREE_SSS ((1 << 0) | (1 << 1) | (1 << 2))
45 #define THREE_S_S ((1 << 0) | (1 << 2))
46 #define THREE__SS ((1 << 0) | (1 << 1) )
47 #define THREE_SS_ ( (1 << 1) | (1 << 2))
48 #define THREE_S__ (1 << 2)
49 #define THREE__S_ (1 << 1)
50 #define THREE___S (1 << 0)
51
52 uint8_t frag[16][5] = {
53 { THREE_SSS,
54 THREE_S_S,
55 THREE_S_S,
56 THREE_S_S,
57 THREE_SSS },
58
59 { THREE__S_,
60 THREE_SS_,
61 THREE__S_,
62 THREE__S_,
63 THREE_SSS },
64
65 { THREE_SS_,
66 THREE___S,
67 THREE__S_,
68 THREE_S__,
69 THREE_SSS },
70
71 { THREE_SS_,
72 THREE___S,
73 THREE_SS_,
74 THREE___S,
75 THREE_SS_ },
76
77 { THREE_S_S,
78 THREE_S_S,
79 THREE_SSS,
80 THREE___S,
81 THREE___S },
82
83 { THREE_SSS,
84 THREE_S__,
85 THREE_SSS,
86 THREE___S,
87 THREE_SSS },
88
89 { THREE__SS,
90 THREE_S__,
91 THREE_SSS,
92 THREE_S_S,
93 THREE_SSS },
94
95 { THREE_SSS,
96 THREE___S,
97 THREE__S_,
98 THREE__S_,
99 THREE__S_ },
100
101 { THREE_SSS,
102 THREE_S_S,
103 THREE_SSS,
104 THREE_S_S,
105 THREE_SSS },
106
107 { THREE_SSS,
108 THREE_S_S,
109 THREE_SSS,
110 THREE___S,
111 THREE___S },
112
113 { THREE__S_,
114 THREE_S_S,
115 THREE_SSS,
116 THREE_S_S,
117 THREE_S_S },
118
119 { THREE_SS_,
120 THREE_S_S,
121 THREE_SS_,
122 THREE_S_S,
123 THREE_SS_ },
124
125 { THREE__S_,
126 THREE_S_S,
127 THREE_S__,
128 THREE_S_S,
129 THREE__S_ },
130
131 { THREE_SS_,
132 THREE_S_S,
133 THREE_S_S,
134 THREE_S_S,
135 THREE_SS_ },
136
137 { THREE_SSS,
138 THREE_S__,
139 THREE_SS_,
140 THREE_S__,
141 THREE_SSS },
142
143 { THREE_SSS,
144 THREE_S__,
145 THREE_SS_,
146 THREE_S__,
147 THREE_S__ }
148 };
149
get_codepoint(uint32_t id,bool italic)150 static uint8_t * get_codepoint(uint32_t id, bool italic)
151 {
152 int shift = 0;
153 int l;
154 int r;
155
156 if (!italic)
157 shift = 1;
158
159 l = (id >> 12);
160 r = 0xf & (id >> 8);
161
162 code_point[ 0] = SEVEN_SET << shift;
163
164 code_point[ 2] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift);
165 code_point[ 3] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift);
166 code_point[ 4] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift);
167 code_point[ 5] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift);
168 code_point[ 6] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift);
169
170 shift = 1;
171
172 l = 0xf & (id >> 4);
173 r = 0xf & id;
174
175 code_point[ 8] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift);
176 code_point[ 9] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift);
177 code_point[10] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift);
178 code_point[11] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift);
179 code_point[12] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift);
180
181 code_point[14] = SEVEN_SET << shift;
182
183 return (uint8_t *)code_point;
184 }
185
186
fb_font_init(void)187 bool fb_font_init(void)
188 {
189 return true;
190 }
191
fb_font_finalise(void)192 bool fb_font_finalise(void)
193 {
194 return true;
195 }
196
197 enum fb_font_style
fb_get_font_style(const plot_font_style_t * fstyle)198 fb_get_font_style(const plot_font_style_t *fstyle)
199 {
200 enum fb_font_style style = FB_REGULAR;
201
202 if (fstyle->weight >= 700)
203 style |= FB_BOLD;
204 if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE))
205 style |= FB_ITALIC;
206
207 return style;
208 }
209
210 int
fb_get_font_size(const plot_font_style_t * fstyle)211 fb_get_font_size(const plot_font_style_t *fstyle)
212 {
213 int size = fstyle->size * 10 /
214 (((nsoption_int(font_min_size) * 3 +
215 nsoption_int(font_size)) / 4) * PLOT_STYLE_SCALE);
216 if (size > 2)
217 size = 2;
218 else if (size <= 0)
219 size = 1;
220
221 return size;
222 }
223
224 /** Lookup table to scale 4 bits to 8 bits, so e.g. 0101 --> 00110011 */
225 const uint8_t glyph_lut[16] = {
226 0x00, 0x03, 0x0c, 0x0f,
227 0x30, 0x33, 0x3c, 0x3f,
228 0xc0, 0xc3, 0xcc, 0xcf,
229 0xf0, 0xf3, 0xfc, 0xff
230 };
231
232 static const uint8_t *
glyph_scale_2(const uint8_t * glyph_data)233 glyph_scale_2(const uint8_t *glyph_data)
234 {
235 const uint8_t *glyph_max = glyph_data + GLYPH_LEN;
236 uint8_t *pos = glyph_x2;
237
238 do {
239 *pos++ = glyph_lut[*glyph_data >> 4];
240 *pos++ = glyph_lut[*glyph_data & 0xf];
241 *pos++ = glyph_lut[*glyph_data >> 4];
242 *pos++ = glyph_lut[*glyph_data & 0xf];
243 } while (++glyph_data < glyph_max);
244
245 return glyph_x2;
246 }
247
248 const uint8_t *
fb_get_glyph(uint32_t ucs4,enum fb_font_style style,int scale)249 fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
250 {
251 const uint8_t *glyph_data;
252 unsigned int section;
253 unsigned int offset;
254 uint16_t g_offset;
255
256 /* Internal font has no glyphs beyond U+FFFF and there isn't
257 * space to render a >4 digit codepoint; just show replacement
258 * character. */
259 if (ucs4 > 0xffff)
260 ucs4 = 0xfffd;
261
262 switch (style) {
263 case FB_BOLD_ITALIC:
264 section = fb_bold_italic_section_table[ucs4 / 256];
265 if (section != 0 || ucs4 / 256 == 0) {
266 offset = section * 256 + (ucs4 & 0xff);
267 g_offset = fb_bold_italic_sections[offset] * 16;
268 if (g_offset != 0) {
269 glyph_data = &font_glyph_data[g_offset];
270 break;
271 }
272 }
273 /* Fall through. */
274 case FB_BOLD:
275 section = fb_bold_section_table[ucs4 / 256];
276 if (section != 0 || ucs4 / 256 == 0) {
277 offset = section * 256 + (ucs4 & 0xff);
278 g_offset = fb_bold_sections[offset] * 16;
279 if (g_offset != 0) {
280 glyph_data = &font_glyph_data[g_offset];
281 break;
282 }
283 }
284 /* Fall through. */
285 case FB_ITALIC:
286 section = fb_italic_section_table[ucs4 / 256];
287 if (section != 0 || ucs4 / 256 == 0) {
288 offset = section * 256 + (ucs4 & 0xff);
289 g_offset = fb_italic_sections[offset] * 16;
290 if (g_offset != 0) {
291 glyph_data = &font_glyph_data[g_offset];
292 break;
293 }
294 }
295 /* Fall through. */
296 case FB_REGULAR:
297 section = fb_regular_section_table[ucs4 / 256];
298 if (section != 0 || ucs4 / 256 == 0) {
299 offset = section * 256 + (ucs4 & 0xff);
300 g_offset = fb_regular_sections[offset] * 16;
301 if (g_offset != 0) {
302 glyph_data = &font_glyph_data[g_offset];
303 break;
304 }
305 }
306 /* Fall through. */
307 default:
308 glyph_data = get_codepoint(ucs4, style & FB_ITALIC);
309 break;
310 }
311
312 switch (scale) {
313 case 1:
314 break;
315 case 2:
316 glyph_data = glyph_scale_2(glyph_data);
317 break;
318 default:
319 assert(scale >= 1 && scale <= 2);
320 break;
321 }
322
323 return glyph_data;
324 }
325
utf8_to_local(const char * string,size_t len,char ** result)326 static nserror utf8_to_local(const char *string,
327 size_t len,
328 char **result)
329 {
330 return utf8_to_enc(string, "CP1252", len, result);
331
332 }
333
utf8_from_local(const char * string,size_t len,char ** result)334 static nserror utf8_from_local(const char *string,
335 size_t len,
336 char **result)
337 {
338 *result = malloc(len + 1);
339 if (*result == NULL) {
340 return NSERROR_NOMEM;
341 }
342
343 memcpy(*result, string, len);
344
345 (*result)[len] = '\0';
346
347 return NSERROR_OK;
348 }
349
350
351 /* exported interface documented in framebuffer/freetype_font.h */
352 nserror
fb_font_width(const plot_font_style_t * fstyle,const char * string,size_t length,int * width)353 fb_font_width(const plot_font_style_t *fstyle,
354 const char *string,
355 size_t length,
356 int *width)
357 {
358 size_t nxtchr = 0;
359
360 *width = 0;
361 while (nxtchr < length) {
362 uint32_t ucs4;
363 ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
364 if (codepoint_displayable(ucs4)) {
365 *width += FB_FONT_WIDTH;
366 }
367
368 nxtchr = utf8_next(string, length, nxtchr);
369 }
370
371 *width *= fb_get_font_size(fstyle);
372 return NSERROR_OK;
373 }
374
375
376 /* exported interface documented in framebuffer/freetype_font.h */
377 nserror
fb_font_position(const plot_font_style_t * fstyle,const char * string,size_t length,int x,size_t * char_offset,int * actual_x)378 fb_font_position(const plot_font_style_t *fstyle,
379 const char *string,
380 size_t length,
381 int x,
382 size_t *char_offset,
383 int *actual_x)
384 {
385 const int width = fb_get_font_size(fstyle) * FB_FONT_WIDTH;
386 size_t nxtchr = 0;
387 int x_pos = 0;
388
389 while (nxtchr < length) {
390 uint32_t ucs4;
391 if (abs(x_pos - x) <= (width / 2))
392 break;
393
394 ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
395 if (codepoint_displayable(ucs4)) {
396 x_pos += width;
397 }
398
399 nxtchr = utf8_next(string, length, nxtchr);
400 }
401
402 *actual_x = x_pos;
403
404 *char_offset = nxtchr;
405 return NSERROR_OK;
406 }
407
408
409 /**
410 * Find where to split a string to make it fit a width.
411 *
412 * \param fstyle style for this text
413 * \param string UTF-8 string to measure
414 * \param length length of string, in bytes
415 * \param x width available
416 * \param char_offset updated to offset in string of actual_x, [1..length]
417 * \param actual_x updated to x coordinate of character closest to x
418 * \return true on success, false on error and error reported
419 *
420 * On exit, char_offset indicates first character after split point.
421 *
422 * Note: char_offset of 0 should never be returned.
423 *
424 * Returns:
425 * char_offset giving split point closest to x, where actual_x <= x
426 * else
427 * char_offset giving split point closest to x, where actual_x > x
428 *
429 * Returning char_offset == length means no split possible
430 */
431 static nserror
fb_font_split(const plot_font_style_t * fstyle,const char * string,size_t length,int x,size_t * char_offset,int * actual_x)432 fb_font_split(const plot_font_style_t *fstyle,
433 const char *string,
434 size_t length,
435 int x,
436 size_t *char_offset,
437 int *actual_x)
438 {
439 const int width = fb_get_font_size(fstyle) * FB_FONT_WIDTH;
440 size_t nxtchr = 0;
441 int last_space_x = 0;
442 int last_space_idx = 0;
443
444 *actual_x = 0;
445 while (nxtchr < length) {
446 uint32_t ucs4;
447
448 if (string[nxtchr] == ' ') {
449 last_space_x = *actual_x;
450 last_space_idx = nxtchr;
451 }
452
453 ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
454 if (codepoint_displayable(ucs4)) {
455 *actual_x += width;
456 }
457
458 if (*actual_x > x && last_space_idx != 0) {
459 /* string has exceeded available width and we've
460 * found a space; return previous space */
461 *actual_x = last_space_x;
462 *char_offset = last_space_idx;
463 return NSERROR_OK;
464 }
465
466 nxtchr = utf8_next(string, length, nxtchr);
467 }
468
469 *char_offset = nxtchr;
470
471 return NSERROR_OK;
472 }
473
474
475 static struct gui_layout_table layout_table = {
476 .width = fb_font_width,
477 .position = fb_font_position,
478 .split = fb_font_split,
479 };
480
481 struct gui_layout_table *framebuffer_layout_table = &layout_table;
482
483
484 static struct gui_utf8_table utf8_table = {
485 .utf8_to_local = utf8_to_local,
486 .local_to_utf8 = utf8_from_local,
487 };
488
489 struct gui_utf8_table *framebuffer_utf8_table = &utf8_table;
490
491
492 /*
493 * Local Variables:
494 * c-basic-offset:8
495 * End:
496 */
497