NetSurf
font_diskfont.c
Go to the documentation of this file.
1/*
2 * Copyright 2008 - 2025 Chris Young <chris@unsatisfactorysoftware.co.uk>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "amiga/os3support.h"
20
21#include <stdlib.h>
22#include <string.h>
23#include <proto/diskfont.h>
24#include <proto/exec.h>
25#include <proto/graphics.h>
26#include <proto/utility.h>
27
28#include <graphics/rpattr.h>
29
30#include "utils/log.h"
31#include "utils/utf8.h"
32#include "utils/nsoption.h"
33
34#include "amiga/font.h"
35#include "amiga/font_diskfont.h"
36#include "amiga/gui.h"
37#include "amiga/plotters.h"
38#include "amiga/utf8.h"
39
40#define MAX_FONT_NAME_SIZE 33
41
43static struct TextFont *prev_font = NULL;
44static struct RastPort *prev_rp = NULL;
45static struct RastPort temp_rp;
46static UBYTE style_set = 0;
47
48static struct TextFont *ami_font_bm_open(struct RastPort *rp, const plot_font_style_t *fstyle)
49{
50 struct TextFont *bmfont = NULL;
51 struct TextAttr tattr;
52 char *fontname;
53 char font[MAX_FONT_NAME_SIZE];
54
55 if(rp == NULL) return NULL;
56
57 tattr.ta_Flags = 0;
58
59 switch(fstyle->family)
60 {
62 fontname = nsoption_charp(font_sans);
63 break;
65 fontname = nsoption_charp(font_serif);
66 break;
68 fontname = nsoption_charp(font_mono);
69 break;
71 fontname = nsoption_charp(font_cursive);
72 break;
74 fontname = nsoption_charp(font_fantasy);
75 break;
76 default:
77 return NULL;
78 break;
79 }
80
81 tattr.ta_Style = FS_NORMAL;
82
83 if (fstyle->flags & FONTF_OBLIQUE)
84 tattr.ta_Style = FSF_ITALIC;
85
86 if (fstyle->flags & FONTF_ITALIC)
87 tattr.ta_Style = FSF_ITALIC;
88
89 if (fstyle->weight >= 700)
90 tattr.ta_Style |= FSF_BOLD;
91
92 if((prev_fstyle != NULL) && (prev_font != NULL) &&
93 (fstyle->family == prev_fstyle->family) &&
94 (fstyle->size == prev_fstyle->size)) {
95 if(rp != prev_rp) {
96 /* We have the correct font open, but it isn't set here */
97 SetRPAttrs(rp, RPTAG_Font, prev_font, TAG_DONE);
98 prev_rp = rp;
99 }
100 /* Current font is correct, just SoftStyle it */
101 NSLOG(netsurf, INFO, "Applying SoftStyle to current font");
102 SetSoftStyle(rp, tattr.ta_Style, style_set);
103 return prev_font;
104 }
105
106 snprintf(font, MAX_FONT_NAME_SIZE, "%s.font", fontname);
107 tattr.ta_Name = font;
108 ULONG fsize = fstyle->size * nsoption_int(screen_ydpi) / 72;
109 tattr.ta_YSize = fsize / PLOT_STYLE_SCALE;
110 NSLOG(netsurf, INFO, "font: %s/%d", tattr.ta_Name, tattr.ta_YSize);
111
112 if(prev_font != NULL) {
113 CloseFont(prev_font);
114 prev_font = NULL;
115 }
116
117 if((bmfont = OpenDiskFont(&tattr))) {
118 SetRPAttrs(rp, RPTAG_Font, bmfont, TAG_DONE);
119 style_set = AskSoftStyle(rp);
120 prev_rp = rp;
121 prev_font = bmfont;
122
123 if(prev_fstyle != NULL) {
124 memcpy(prev_fstyle, fstyle, sizeof(plot_font_style_t));
125 }
126 }
127
128 return bmfont;
129}
130
131static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, size_t length, UWORD offset)
132{
133 size_t chr = 0;
134
135 for(UWORD i = 0; i < offset; i++) {
136 chr = utf8_next(utf8string, length, chr);
137 if(chr > length) return length;
138 }
139
140 return chr;
141}
142
143
145 const char *string, size_t length,
146 int *width)
147{
148 char *localtext = NULL;
149
150 *width = length;
151
152 struct TextFont *bmfont = ami_font_bm_open(&temp_rp, fstyle);
153 if(bmfont == NULL) return NSERROR_INVALID;
154
155 if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
156 return NSERROR_INVALID;
157 }
158
159 *width = TextLength(&temp_rp, localtext, (UWORD)strlen(localtext));
160 free(localtext);
161
162 return NSERROR_OK;
163}
164
165/**
166 * Find the position in a string where an x coordinate falls.
167 *
168 * \param fstyle style for this text
169 * \param string UTF-8 string to measure
170 * \param length length of string
171 * \param x x coordinate to search for
172 * \param char_offset updated to offset in string of actual_x, [0..length]
173 * \param actual_x updated to x coordinate of character closest to x
174 * \return true on success, false on error and error reported
175 */
176
178 const char *string, size_t length,
179 int x, size_t *char_offset, int *actual_x)
180{
181 struct TextExtent extent;
182 struct TextFont *bmfont;
183 char *localtext = NULL;
184 UWORD co = 0;
185
186 bmfont = ami_font_bm_open(&temp_rp, fstyle);
187 if(bmfont == NULL) return NSERROR_INVALID;
188
189 if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
190 return NSERROR_INVALID;
191 }
192
193 co = TextFit(&temp_rp, localtext, (UWORD)strlen(localtext),
194 &extent, NULL, 1, x, 32767);
195 *char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
196 *actual_x = extent.te_Extent.MaxX;
197
198 free(localtext);
199
200 return NSERROR_OK;
201}
202
203
204/**
205 * Find where to split a string to make it fit a width.
206 *
207 * \param fstyle style for this text
208 * \param string UTF-8 string to measure
209 * \param length length of string
210 * \param x width available
211 * \param char_offset updated to offset in string of actual_x, [1..length]
212 * \param actual_x updated to x coordinate of character closest to x
213 * \return true on success, false on error and error reported
214 *
215 * On exit, char_offset indicates first character after split point.
216 *
217 * Note: char_offset of 0 should never be returned.
218 *
219 * Returns:
220 * char_offset giving split point closest to x, where actual_x <= x
221 * else
222 * char_offset giving split point closest to x, where actual_x > x
223 *
224 * Returning char_offset == length means no split possible
225 */
226
228 const char *string, size_t length,
229 int x, size_t *char_offset, int *actual_x)
230{
231 struct TextExtent extent;
232 UWORD co, offset;
233 char *charp;
234 char *localtext;
235
236 struct TextFont *bmfont = ami_font_bm_open(&temp_rp, fstyle);
237 if(bmfont == NULL) return NSERROR_INVALID;
238
239 if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
240 return NSERROR_INVALID;
241 }
242
243 offset = TextFit(&temp_rp, localtext, (UWORD)strlen(localtext),
244 &extent, NULL, 1, (UWORD)x, 32767);
245
246 co = offset;
247 charp = localtext + co;
248
249
250 while((*charp != ' ') && (co > 0)) {
251 charp--;
252 co--;
253 }
254
255 if(co == 0) {
256 co = offset;
257 charp = localtext + co;
258 while((*charp != ' ') && (co < strlen(localtext))) {
259 charp++;
260 co++;
261 }
262 }
263
264 if((co > 0) && (co < strlen(localtext))) {
265 *actual_x = TextLength(&temp_rp, localtext, co);
266 *char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
267 } else {
268 *actual_x = x;
269 *char_offset = length;
270 }
271
272 free(localtext);
273
274 return NSERROR_OK;
275}
276
277static ULONG amiga_bm_nsfont_text(struct RastPort *rp, const char *string, ULONG length,
278 const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
279{
280 if(!string || string[0]=='\0') return 0;
281 if(!length) return 0;
282 if(rp == NULL) return 0;
283
284 struct TextFont *bmfont = ami_font_bm_open(rp, fstyle);
285 char *localtext = NULL;
286 if(bmfont == NULL) return 0;
287 if(utf8_to_local_encoding(string, length, &localtext) == NSERROR_OK) {
288 Move(rp, dx, dy);
289 Text(rp, localtext, (UWORD)strlen(localtext));
290 free(localtext);
291 }
292
293 return 0;
294}
295
301};
302
304{
305 /* Set up table */
307
308 /* Alloc space to hold currently open font - doesn't matter if this fails */
309 prev_fstyle = calloc(1, sizeof(plot_font_style_t));
310
311 /* Init temp RastPort */
312 InitRastPort(&temp_rp);
313}
314
316{
317 if(prev_font != NULL) {
318 CloseFont(prev_font);
319 prev_font = NULL;
320 }
321
322 if(prev_fstyle != NULL) {
323 free(prev_fstyle);
324 prev_fstyle = NULL;
325 }
326}
327
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_INVALID
Invalid data.
Definition: errors.h:49
@ NSERROR_OK
No error.
Definition: errors.h:30
static struct RastPort * prev_rp
Definition: font_diskfont.c:44
static nserror amiga_bm_nsfont_width(const plot_font_style_t *fstyle, const char *string, size_t length, int *width)
void ami_font_diskfont_init(void)
static struct RastPort temp_rp
Definition: font_diskfont.c:45
static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, size_t length, UWORD offset)
static struct TextFont * prev_font
Definition: font_diskfont.c:43
void ami_font_diskfont_fini(void)
static nserror amiga_bm_nsfont_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.
#define MAX_FONT_NAME_SIZE
Definition: font_diskfont.c:40
static ULONG amiga_bm_nsfont_text(struct RastPort *rp, const char *string, ULONG length, const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
static struct TextFont * ami_font_bm_open(struct RastPort *rp, const plot_font_style_t *fstyle)
Definition: font_diskfont.c:48
static UBYTE style_set
Definition: font_diskfont.c:46
const struct ami_font_functions ami_font_diskfont_table
static nserror amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle, const char *string, size_t length, int x, size_t *char_offset, int *actual_x)
Find the position in a string where an x coordinate falls.
static plot_font_style_t * prev_fstyle
Definition: font_diskfont.c:42
struct ami_font_functions * ami_nsfont
Definition: font.c:38
nserror utf8_to_local_encoding(const char *string, size_t len, char **result)
Definition: utf8.c:89
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
Minimal compatibility header for AmigaOS 3.
@ FONTF_ITALIC
Definition: plot_style.h:103
@ FONTF_OBLIQUE
Definition: plot_style.h:104
@ PLOT_FONT_FAMILY_CURSIVE
Definition: plot_style.h:92
@ PLOT_FONT_FAMILY_SANS_SERIF
Definition: plot_style.h:89
@ PLOT_FONT_FAMILY_FANTASY
Definition: plot_style.h:93
@ PLOT_FONT_FAMILY_MONOSPACE
Definition: plot_style.h:91
@ PLOT_FONT_FAMILY_SERIF
Definition: plot_style.h:90
#define PLOT_STYLE_SCALE
Scaling factor for plot styles.
Definition: plot_style.h:45
int width
Definition: gui.c:161
Interface to utility string handling.
Font style for plotting.
Definition: plot_style.h:111
plot_font_generic_family_t family
Generic family to plot with.
Definition: plot_style.h:118
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_charp(OPTION)
Get the value of a string option.
Definition: nsoption.h:335
#define nsoption_int(OPTION)
Get the value of an integer option.
Definition: nsoption.h:317
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
UTF-8 manipulation functions (interface).