source: mainline/uspace/lib/draw/font/bitmap_backend.c@ ce52c333

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ce52c333 was 28a5ebd, checked in by Martin Decky <martin@…>, 5 years ago

Use char32_t instead of wchat_t to represent UTF-32 strings

The intention of the native HelenOS string API has been always to
support Unicode in the UTF-8 and UTF-32 encodings as the sole character
representations and ignore the obsolete mess of older single-byte and
multibyte character encodings. Before C11, the wchar_t type has been
slightly misused for the purpose of the UTF-32 strings. The newer
char32_t type is obviously a much more suitable option. The standard
defines char32_t as uint_least32_t, thus we can take the liberty to fix
it to uint32_t.

To maintain compatilibity with the C Standard, the putwchar(wchar_t)
functions has been replaced by our custom putuchar(char32_t) functions
where appropriate.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (c) 2012 Petr Koupy
3 * Copyright (c) 2014 Martin Sucha
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup draw
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <errno.h>
38#include <stdlib.h>
39
40#include <draw/font.h>
41#include <draw/drawctx.h>
42
43typedef struct {
44 surface_t *surface;
45 glyph_metrics_t metrics;
46 bool metrics_loaded;
47} glyph_cache_item_t;
48
49typedef struct {
50 uint16_t points;
51 uint32_t glyph_count;
52 font_metrics_t font_metrics;
53 glyph_cache_item_t *glyph_cache;
54 bitmap_font_decoder_t *decoder;
55 void *decoder_data;
56 bool scale;
57 double scale_ratio;
58} bitmap_backend_data_t;
59
60static errno_t bb_get_font_metrics(void *backend_data, font_metrics_t *font_metrics)
61{
62 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
63
64 *font_metrics = data->font_metrics;
65
66 return EOK;
67}
68
69static errno_t bb_resolve_glyph(void *backend_data, char32_t c, glyph_id_t *glyph_id)
70{
71 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
72 return data->decoder->resolve_glyph(data->decoder_data, c, glyph_id);
73}
74
75static errno_t bb_get_glyph_metrics(void *backend_data, glyph_id_t glyph_id,
76 glyph_metrics_t *glyph_metrics)
77{
78 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
79
80 if (glyph_id >= data->glyph_count)
81 return ENOENT;
82
83 if (data->glyph_cache[glyph_id].metrics_loaded) {
84 *glyph_metrics = data->glyph_cache[glyph_id].metrics;
85 return EOK;
86 }
87
88 glyph_metrics_t gm;
89
90 errno_t rc = data->decoder->load_glyph_metrics(data->decoder_data, glyph_id,
91 &gm);
92 if (rc != EOK)
93 return rc;
94
95 if (data->scale) {
96 gm.left_side_bearing = (metric_t)
97 (data->scale_ratio * gm.left_side_bearing + 0.5);
98 gm.width = (metric_t)
99 (data->scale_ratio * gm.width + 0.5);
100 gm.right_side_bearing = (metric_t)
101 (data->scale_ratio * gm.right_side_bearing + 0.5);
102 gm.ascender = (metric_t)
103 (data->scale_ratio * gm.ascender + 0.5);
104 gm.height = (metric_t)
105 (data->scale_ratio * gm.height + 0.5);
106 }
107
108 data->glyph_cache[glyph_id].metrics = gm;
109 data->glyph_cache[glyph_id].metrics_loaded = true;
110 *glyph_metrics = gm;
111 return EOK;
112}
113
114static errno_t get_glyph_surface(bitmap_backend_data_t *data, glyph_id_t glyph_id,
115 surface_t **result)
116{
117 if (glyph_id >= data->glyph_count)
118 return ENOENT;
119
120 if (data->glyph_cache[glyph_id].surface != NULL) {
121 *result = data->glyph_cache[glyph_id].surface;
122 return EOK;
123 }
124
125 surface_t *raw_surface;
126 errno_t rc = data->decoder->load_glyph_surface(data->decoder_data, glyph_id,
127 &raw_surface);
128 if (rc != EOK)
129 return rc;
130
131 sysarg_t w;
132 sysarg_t h;
133 surface_get_resolution(raw_surface, &w, &h);
134
135 if (!data->scale) {
136 *result = raw_surface;
137 return EOK;
138 }
139
140 source_t source;
141 source_init(&source);
142 source_set_texture(&source, raw_surface, PIXELMAP_EXTEND_TRANSPARENT_BLACK);
143
144 transform_t transform;
145 transform_identity(&transform);
146 transform_translate(&transform, 0.5, 0.5);
147 transform_scale(&transform, data->scale_ratio, data->scale_ratio);
148 source_set_transform(&source, transform);
149
150 surface_coord_t scaled_width = (data->scale_ratio * ((double) w) + 0.5);
151 surface_coord_t scaled_height = (data->scale_ratio * ((double) h) + 0.5);
152
153 surface_t *scaled_surface = surface_create(scaled_width, scaled_height,
154 NULL, 0);
155 if (!scaled_surface) {
156 surface_destroy(raw_surface);
157 return ENOMEM;
158 }
159
160 drawctx_t context;
161 drawctx_init(&context, scaled_surface);
162 drawctx_set_source(&context, &source);
163 drawctx_transfer(&context, 0, 0, scaled_width, scaled_height);
164
165 surface_destroy(raw_surface);
166
167 data->glyph_cache[glyph_id].surface = scaled_surface;
168 *result = scaled_surface;
169 return EOK;
170}
171
172static errno_t bb_render_glyph(void *backend_data, drawctx_t *context,
173 source_t *source, sysarg_t ox, sysarg_t oy, glyph_id_t glyph_id)
174{
175 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
176
177 glyph_metrics_t glyph_metrics;
178 errno_t rc = bb_get_glyph_metrics(backend_data, glyph_id, &glyph_metrics);
179 if (rc != EOK)
180 return rc;
181
182 surface_t *glyph_surface;
183 rc = get_glyph_surface(data, glyph_id, &glyph_surface);
184 if (rc != EOK)
185 return rc;
186
187 native_t x = ox + glyph_metrics.left_side_bearing;
188 native_t y = oy - glyph_metrics.ascender;
189
190 transform_t transform;
191 transform_identity(&transform);
192 transform_translate(&transform, x, y);
193 source_set_transform(source, transform);
194 source_set_mask(source, glyph_surface, false);
195 drawctx_transfer(context, x, y, glyph_metrics.width,
196 glyph_metrics.height);
197
198 return EOK;
199}
200
201static void bb_release(void *backend_data)
202{
203 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
204
205 for (size_t i = 0; i < data->glyph_count; ++i) {
206 if (data->glyph_cache[i].surface) {
207 surface_destroy(data->glyph_cache[i].surface);
208 }
209 }
210 free(data->glyph_cache);
211
212 data->decoder->release(data->decoder_data);
213 free(data);
214}
215
216font_backend_t bitmap_backend = {
217 .get_font_metrics = bb_get_font_metrics,
218 .resolve_glyph = bb_resolve_glyph,
219 .get_glyph_metrics = bb_get_glyph_metrics,
220 .render_glyph = bb_render_glyph,
221 .release = bb_release
222};
223
224errno_t bitmap_font_create(bitmap_font_decoder_t *decoder, void *decoder_data,
225 uint32_t glyph_count, font_metrics_t font_metrics, uint16_t points,
226 font_t **out_font)
227{
228 if (glyph_count == 0)
229 return EINVAL;
230
231 bitmap_backend_data_t *data = malloc(sizeof(bitmap_backend_data_t));
232 if (data == NULL)
233 return ENOMEM;
234
235 data->glyph_count = glyph_count;
236 data->points = points;
237 data->decoder = decoder;
238 data->decoder_data = decoder_data;
239 data->font_metrics = font_metrics;
240 metric_t line_height = (font_metrics.ascender + font_metrics.descender);
241 if (points == line_height) {
242 data->scale = false;
243 data->scale_ratio = 1.0;
244 } else {
245 data->scale = true;
246 data->scale_ratio = ((double) points) / ((double) line_height);
247 line_height = (data->scale_ratio * ((double) line_height));
248 data->font_metrics.ascender = (metric_t)
249 (data->scale_ratio * data->font_metrics.ascender + 0.5);
250 data->font_metrics.descender =
251 line_height - data->font_metrics.ascender;
252 data->font_metrics.leading = (metric_t)
253 (data->scale_ratio * data->font_metrics.leading + 0.5);
254 }
255
256 data->glyph_cache = calloc(data->glyph_count,
257 sizeof(glyph_cache_item_t));
258 if (data->glyph_cache == NULL) {
259 free(data);
260 return ENOMEM;
261 }
262
263 for (size_t i = 0; i < data->glyph_count; ++i) {
264 data->glyph_cache[i].surface = NULL;
265 data->glyph_cache[i].metrics_loaded = false;
266 }
267
268 font_t *font = font_create(&bitmap_backend, data);
269 if (font == NULL) {
270 free(data->glyph_cache);
271 free(data);
272 return ENOMEM;
273 }
274
275 *out_font = font;
276 return EOK;
277}
278
279/** @}
280 */
Note: See TracBrowser for help on using the repository browser.