NetSurf
font_internal.c
Go to the documentation of this file.
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/utils.h"
27#include "utils/utf8.h"
28#include "netsurf/utf8.h"
29#include "netsurf/layout.h"
30#include "netsurf/plot_style.h"
31
32#include "framebuffer/gui.h"
33#include "framebuffer/font.h"
34
35#include <font-ns-sans.h>
36
37#define GLYPH_LEN 16
38
40uint8_t glyph_x2[GLYPH_LEN * 4];
41
42#define SEVEN_SET ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | \
43 (1 << 4) | (1 << 5) | (1 << 6))
44
45#define THREE_SSS ((1 << 0) | (1 << 1) | (1 << 2))
46#define THREE_S_S ((1 << 0) | (1 << 2))
47#define THREE__SS ((1 << 0) | (1 << 1) )
48#define THREE_SS_ ( (1 << 1) | (1 << 2))
49#define THREE_S__ (1 << 2)
50#define THREE__S_ (1 << 1)
51#define THREE___S (1 << 0)
52
53uint8_t frag[16][5] = {
54 { THREE_SSS,
58 THREE_SSS },
59
60 { THREE__S_,
64 THREE_SSS },
65
66 { THREE_SS_,
70 THREE_SSS },
71
72 { THREE_SS_,
76 THREE_SS_ },
77
78 { THREE_S_S,
82 THREE___S },
83
84 { THREE_SSS,
88 THREE_SSS },
89
90 { THREE__SS,
94 THREE_SSS },
95
96 { THREE_SSS,
100 THREE__S_ },
101
102 { THREE_SSS,
103 THREE_S_S,
104 THREE_SSS,
105 THREE_S_S,
106 THREE_SSS },
107
108 { THREE_SSS,
109 THREE_S_S,
110 THREE_SSS,
111 THREE___S,
112 THREE___S },
113
114 { THREE__S_,
115 THREE_S_S,
116 THREE_SSS,
117 THREE_S_S,
118 THREE_S_S },
119
120 { THREE_SS_,
121 THREE_S_S,
122 THREE_SS_,
123 THREE_S_S,
124 THREE_SS_ },
125
126 { THREE__S_,
127 THREE_S_S,
128 THREE_S__,
129 THREE_S_S,
130 THREE__S_ },
131
132 { THREE_SS_,
133 THREE_S_S,
134 THREE_S_S,
135 THREE_S_S,
136 THREE_SS_ },
137
138 { THREE_SSS,
139 THREE_S__,
140 THREE_SS_,
141 THREE_S__,
142 THREE_SSS },
143
144 { THREE_SSS,
145 THREE_S__,
146 THREE_SS_,
147 THREE_S__,
148 THREE_S__ }
149};
150
151static uint8_t * get_codepoint(uint32_t id, bool italic)
152{
153 int shift = 0;
154 int l;
155 int r;
156
157 if (!italic)
158 shift = 1;
159
160 l = (id >> 12);
161 r = 0xf & (id >> 8);
162
163 code_point[ 0] = SEVEN_SET << shift;
164
165 code_point[ 2] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift);
166 code_point[ 3] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift);
167 code_point[ 4] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift);
168 code_point[ 5] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift);
169 code_point[ 6] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift);
170
171 shift = 1;
172
173 l = 0xf & (id >> 4);
174 r = 0xf & id;
175
176 code_point[ 8] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift);
177 code_point[ 9] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift);
178 code_point[10] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift);
179 code_point[11] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift);
180 code_point[12] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift);
181
182 code_point[14] = SEVEN_SET << shift;
183
184 return (uint8_t *)code_point;
185}
186
187
188bool fb_font_init(void)
189{
190 return true;
191}
192
194{
195 return true;
196}
197
198enum fb_font_style
200{
201 enum fb_font_style style = FB_REGULAR;
202
203 if (fstyle->weight >= 700)
204 style |= FB_BOLD;
205 if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE))
206 style |= FB_ITALIC;
207
208 return style;
209}
210
211int
213{
214 int size = fstyle->size * 10 /
215 (((nsoption_int(font_min_size) * 3 +
216 nsoption_int(font_size)) / 4) * PLOT_STYLE_SCALE);
217 if (size > 2)
218 size = 2;
219 else if (size <= 0)
220 size = 1;
221
222 return size;
223}
224
225/** Lookup table to scale 4 bits to 8 bits, so e.g. 0101 --> 00110011 */
226const uint8_t glyph_lut[16] = {
227 0x00, 0x03, 0x0c, 0x0f,
228 0x30, 0x33, 0x3c, 0x3f,
229 0xc0, 0xc3, 0xcc, 0xcf,
230 0xf0, 0xf3, 0xfc, 0xff
231};
232
233static const uint8_t *
234glyph_scale_2(const uint8_t *glyph_data)
235{
236 const uint8_t *glyph_max = glyph_data + GLYPH_LEN;
237 uint8_t *pos = glyph_x2;
238
239 do {
240 *pos++ = glyph_lut[*glyph_data >> 4];
241 *pos++ = glyph_lut[*glyph_data & 0xf];
242 *pos++ = glyph_lut[*glyph_data >> 4];
243 *pos++ = glyph_lut[*glyph_data & 0xf];
244 } while (++glyph_data < glyph_max);
245
246 return glyph_x2;
247}
248
249const uint8_t *
250fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
251{
252 const uint8_t *glyph_data;
253 unsigned int section;
254 unsigned int offset;
255 uint16_t g_offset;
256
257 /* Internal font has no glyphs beyond U+FFFF and there isn't
258 * space to render a >4 digit codepoint; just show replacement
259 * character. */
260 if (ucs4 > 0xffff)
261 ucs4 = 0xfffd;
262
263 switch (style) {
264 case FB_BOLD_ITALIC:
265 section = fb_bold_italic_section_table[ucs4 / 256];
266 if (section != 0 || ucs4 / 256 == 0) {
267 offset = section * 256 + (ucs4 & 0xff);
268 g_offset = fb_bold_italic_sections[offset] * 16;
269 if (g_offset != 0) {
270 glyph_data = &font_glyph_data[g_offset];
271 break;
272 }
273 }
275
276 case FB_BOLD:
277 section = fb_bold_section_table[ucs4 / 256];
278 if (section != 0 || ucs4 / 256 == 0) {
279 offset = section * 256 + (ucs4 & 0xff);
280 g_offset = fb_bold_sections[offset] * 16;
281 if (g_offset != 0) {
282 glyph_data = &font_glyph_data[g_offset];
283 break;
284 }
285 }
287
288 case FB_ITALIC:
289 section = fb_italic_section_table[ucs4 / 256];
290 if (section != 0 || ucs4 / 256 == 0) {
291 offset = section * 256 + (ucs4 & 0xff);
292 g_offset = fb_italic_sections[offset] * 16;
293 if (g_offset != 0) {
294 glyph_data = &font_glyph_data[g_offset];
295 break;
296 }
297 }
299
300 case FB_REGULAR:
301 section = fb_regular_section_table[ucs4 / 256];
302 if (section != 0 || ucs4 / 256 == 0) {
303 offset = section * 256 + (ucs4 & 0xff);
304 g_offset = fb_regular_sections[offset] * 16;
305 if (g_offset != 0) {
306 glyph_data = &font_glyph_data[g_offset];
307 break;
308 }
309 }
311
312 default:
313 glyph_data = get_codepoint(ucs4, style & FB_ITALIC);
314 break;
315 }
316
317 switch (scale) {
318 case 1:
319 break;
320 case 2:
321 glyph_data = glyph_scale_2(glyph_data);
322 break;
323 default:
324 assert(scale >= 1 && scale <= 2);
325 break;
326 }
327
328 return glyph_data;
329}
330
331static nserror utf8_to_local(const char *string,
332 size_t len,
333 char **result)
334{
335 return utf8_to_enc(string, "CP1252", len, result);
336
337}
338
339static nserror utf8_from_local(const char *string,
340 size_t len,
341 char **result)
342{
343 *result = malloc(len + 1);
344 if (*result == NULL) {
345 return NSERROR_NOMEM;
346 }
347
348 memcpy(*result, string, len);
349
350 (*result)[len] = '\0';
351
352 return NSERROR_OK;
353}
354
355
356/* exported interface documented in framebuffer/freetype_font.h */
359 const char *string,
360 size_t length,
361 int *width)
362{
363 size_t nxtchr = 0;
364
365 *width = 0;
366 while (nxtchr < length) {
367 uint32_t ucs4;
368 ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
369 if (codepoint_displayable(ucs4)) {
371 }
372
373 nxtchr = utf8_next(string, length, nxtchr);
374 }
375
376 *width *= fb_get_font_size(fstyle);
377 return NSERROR_OK;
378}
379
380
381/* exported interface documented in framebuffer/freetype_font.h */
384 const char *string,
385 size_t length,
386 int x,
387 size_t *char_offset,
388 int *actual_x)
389{
390 const int width = fb_get_font_size(fstyle) * FB_FONT_WIDTH;
391 size_t nxtchr = 0;
392 int x_pos = 0;
393
394 while (nxtchr < length) {
395 uint32_t ucs4;
396 if (abs(x_pos - x) <= (width / 2))
397 break;
398
399 ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
400 if (codepoint_displayable(ucs4)) {
401 x_pos += width;
402 }
403
404 nxtchr = utf8_next(string, length, nxtchr);
405 }
406
407 *actual_x = x_pos;
408
409 *char_offset = nxtchr;
410 return NSERROR_OK;
411}
412
413
414/**
415 * Find where to split a string to make it fit a width.
416 *
417 * \param fstyle style for this text
418 * \param string UTF-8 string to measure
419 * \param length length of string, in bytes
420 * \param x width available
421 * \param char_offset updated to offset in string of actual_x, [1..length]
422 * \param actual_x updated to x coordinate of character closest to x
423 * \return true on success, false on error and error reported
424 *
425 * On exit, char_offset indicates first character after split point.
426 *
427 * Note: char_offset of 0 should never be returned.
428 *
429 * Returns:
430 * char_offset giving split point closest to x, where actual_x <= x
431 * else
432 * char_offset giving split point closest to x, where actual_x > x
433 *
434 * Returning char_offset == length means no split possible
435 */
436static nserror
438 const char *string,
439 size_t length,
440 int x,
441 size_t *char_offset,
442 int *actual_x)
443{
444 const int width = fb_get_font_size(fstyle) * FB_FONT_WIDTH;
445 size_t nxtchr = 0;
446 int last_space_x = 0;
447 int last_space_idx = 0;
448
449 *actual_x = 0;
450 while (nxtchr < length) {
451 uint32_t ucs4;
452
453 if (string[nxtchr] == ' ') {
454 last_space_x = *actual_x;
455 last_space_idx = nxtchr;
456 }
457
458 ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
459 if (codepoint_displayable(ucs4)) {
460 *actual_x += width;
461 }
462
463 if (*actual_x > x && last_space_idx != 0) {
464 /* string has exceeded available width and we've
465 * found a space; return previous space */
466 *actual_x = last_space_x;
467 *char_offset = last_space_idx;
468 return NSERROR_OK;
469 }
470
471 nxtchr = utf8_next(string, length, nxtchr);
472 }
473
474 *char_offset = nxtchr;
475
476 return NSERROR_OK;
477}
478
479
482 .position = fb_font_position,
483 .split = fb_font_split,
484};
485
487
488
489static struct gui_utf8_table utf8_table = {
491 .local_to_utf8 = utf8_from_local,
492};
493
495
496
497/*
498 * Local Variables:
499 * c-basic-offset:8
500 * End:
501 */
STATIC char result[100]
Definition: arexx.c:77
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
#define THREE__SS
Definition: font_internal.c:47
const uint8_t * fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale)
struct gui_utf8_table * framebuffer_utf8_table
static struct gui_utf8_table utf8_table
#define THREE_S__
Definition: font_internal.c:49
bool fb_font_finalise(void)
Finalise framebuffer font handling.
bool fb_font_init(void)
Initialise framebuffer font handling.
#define THREE_SSS
Definition: font_internal.c:45
uint8_t code_point[GLYPH_LEN]
Definition: font_internal.c:39
static uint8_t * get_codepoint(uint32_t id, bool italic)
struct gui_layout_table * framebuffer_layout_table
int fb_get_font_size(const plot_font_style_t *fstyle)
#define THREE_SS_
Definition: font_internal.c:48
#define THREE___S
Definition: font_internal.c:51
#define SEVEN_SET
Definition: font_internal.c:42
nserror fb_font_width(const plot_font_style_t *fstyle, const char *string, size_t length, int *width)
enum fb_font_style fb_get_font_style(const plot_font_style_t *fstyle)
#define THREE__S_
Definition: font_internal.c:50
#define THREE_S_S
Definition: font_internal.c:46
static nserror utf8_from_local(const char *string, size_t len, char **result)
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)
Find where to split a string to make it fit a width.
const uint8_t glyph_lut[16]
Lookup table to scale 4 bits to 8 bits, so e.g.
uint8_t frag[16][5]
Definition: font_internal.c:53
static nserror utf8_to_local(const char *string, size_t len, char **result)
#define GLYPH_LEN
Definition: font_internal.c:37
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)
static struct gui_layout_table layout_table
uint8_t glyph_x2[GLYPH_LEN *4]
Definition: font_internal.c:40
static const uint8_t * glyph_scale_2(const uint8_t *glyph_data)
fb_font_style
Definition: font_internal.h:33
@ FB_BOLD
Definition: font_internal.h:36
@ FB_BOLD_ITALIC
Definition: font_internal.h:37
@ FB_REGULAR
Definition: font_internal.h:34
@ FB_ITALIC
Definition: font_internal.h:35
#define codepoint_displayable(u)
Definition: font_internal.h:43
#define FB_FONT_WIDTH
Definition: font_internal.h:29
Interface to platform-specific layout operation table.
Interface to platform-specific utf8 operations.
Netsurf additional integer type formatting macros.
plotter style interfaces, generic styles and style colour helpers.
@ FONTF_ITALIC
Definition: plot_style.h:103
@ FONTF_OBLIQUE
Definition: plot_style.h:104
#define PLOT_STYLE_SCALE
Scaling factor for plot styles.
Definition: plot_style.h:45
int width
Definition: gui.c:159
Interface to utility string handling.
nserror(* width)(const struct plot_font_style *fstyle, const char *string, size_t length, int *width)
Measure the width of a string.
Definition: layout.h:49
User interface utf8 characterset conversion routines.
Definition: utf8.h:31
nserror(* utf8_to_local)(const char *string, size_t len, char **result)
Convert a UTF-8 encoded string into the system local encoding.
Definition: utf8.h:40
Font style for plotting.
Definition: plot_style.h:111
plot_font_flags_t flags
Font flags.
Definition: plot_style.h:121
plot_style_fixed size
Font size, in pt.
Definition: plot_style.h:119
int weight
Font weight: value in range [100,900] as per CSS.
Definition: plot_style.h:120
Option reading and saving interface.
#define nsoption_int(OPTION)
Get the value of an integer option.
Definition: nsoption.h:279
uint32_t utf8_to_ucs4(const char *s_in, size_t l)
Convert a UTF-8 multibyte sequence into a single UCS4 character.
Definition: utf8.c:41
size_t utf8_next(const char *s, size_t l, size_t o)
Find next legal UTF-8 char in string.
Definition: utf8.c:129
nserror utf8_to_enc(const char *string, const char *encname, size_t len, char **result)
Convert a UTF8 string into the named encoding.
Definition: utf8.c:314
UTF-8 manipulation functions (interface).
Interface to a number of general purpose functionality.
#define fallthrough
switch fall through
Definition: utils.h:115