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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 38d150e was 38d150e, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Prefer to get memory allocation functions through the standard stdlib header.

  • 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 "../font.h"
41#include "../drawctx.h"
42#include "bitmap_backend.h"
43
44typedef struct {
45 surface_t *surface;
46 glyph_metrics_t metrics;
47 bool metrics_loaded;
48} glyph_cache_item_t;
49
50typedef struct {
51 uint16_t points;
52 uint32_t glyph_count;
53 font_metrics_t font_metrics;
54 glyph_cache_item_t *glyph_cache;
55 bitmap_font_decoder_t *decoder;
56 void *decoder_data;
57 bool scale;
58 double scale_ratio;
59} bitmap_backend_data_t;
60
61static int bb_get_font_metrics(void *backend_data, font_metrics_t *font_metrics)
62{
63 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
64
65 *font_metrics = data->font_metrics;
66
67 return EOK;
68}
69
70static int bb_resolve_glyph(void *backend_data, wchar_t c, glyph_id_t *glyph_id)
71{
72 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
73 return data->decoder->resolve_glyph(data->decoder_data, c, glyph_id);
74}
75
76static int bb_get_glyph_metrics(void *backend_data, glyph_id_t glyph_id,
77 glyph_metrics_t *glyph_metrics)
78{
79 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
80
81 if (glyph_id >= data->glyph_count)
82 return ENOENT;
83
84 if (data->glyph_cache[glyph_id].metrics_loaded) {
85 *glyph_metrics = data->glyph_cache[glyph_id].metrics;
86 return EOK;
87 }
88
89 glyph_metrics_t gm;
90
91 int rc = data->decoder->load_glyph_metrics(data->decoder_data, glyph_id,
92 &gm);
93 if (rc != EOK)
94 return rc;
95
96 if (data->scale) {
97 gm.left_side_bearing = (metric_t)
98 (data->scale_ratio * gm.left_side_bearing + 0.5);
99 gm.width = (metric_t)
100 (data->scale_ratio * gm.width + 0.5);
101 gm.right_side_bearing = (metric_t)
102 (data->scale_ratio * gm.right_side_bearing + 0.5);
103 gm.ascender = (metric_t)
104 (data->scale_ratio * gm.ascender + 0.5);
105 gm.height = (metric_t)
106 (data->scale_ratio * gm.height + 0.5);
107 }
108
109
110
111 data->glyph_cache[glyph_id].metrics = gm;
112 data->glyph_cache[glyph_id].metrics_loaded = true;
113 *glyph_metrics = gm;
114 return EOK;
115}
116
117static int get_glyph_surface(bitmap_backend_data_t *data, glyph_id_t glyph_id,
118 surface_t **result)
119{
120 if (glyph_id >= data->glyph_count)
121 return ENOENT;
122
123 if (data->glyph_cache[glyph_id].surface != NULL) {
124 *result = data->glyph_cache[glyph_id].surface;
125 return EOK;
126 }
127
128 surface_t *raw_surface;
129 int rc = data->decoder->load_glyph_surface(data->decoder_data, glyph_id,
130 &raw_surface);
131 if (rc != EOK)
132 return rc;
133
134 sysarg_t w;
135 sysarg_t h;
136 surface_get_resolution(raw_surface, &w, &h);
137
138 if (!data->scale) {
139 *result = raw_surface;
140 return EOK;
141 }
142
143 source_t source;
144 source_init(&source);
145 source_set_texture(&source, raw_surface, PIXELMAP_EXTEND_TRANSPARENT_BLACK);
146
147 transform_t transform;
148 transform_identity(&transform);
149 transform_translate(&transform, 0.5, 0.5);
150 transform_scale(&transform, data->scale_ratio, data->scale_ratio);
151 source_set_transform(&source, transform);
152
153 surface_coord_t scaled_width = (data->scale_ratio * ((double) w) + 0.5);
154 surface_coord_t scaled_height = (data->scale_ratio * ((double) h) + 0.5);
155
156 surface_t *scaled_surface = surface_create(scaled_width, scaled_height,
157 NULL, 0);
158 if (!scaled_surface) {
159 surface_destroy(raw_surface);
160 return ENOMEM;
161 }
162
163 drawctx_t context;
164 drawctx_init(&context, scaled_surface);
165 drawctx_set_source(&context, &source);
166 drawctx_transfer(&context, 0, 0, scaled_width, scaled_height);
167
168 surface_destroy(raw_surface);
169
170 data->glyph_cache[glyph_id].surface = scaled_surface;
171 *result = scaled_surface;
172 return EOK;
173}
174
175static int bb_render_glyph(void *backend_data, drawctx_t *context,
176 source_t *source, sysarg_t ox, sysarg_t oy, glyph_id_t glyph_id)
177{
178 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
179
180 glyph_metrics_t glyph_metrics;
181 int rc = bb_get_glyph_metrics(backend_data, glyph_id, &glyph_metrics);
182 if (rc != EOK)
183 return rc;
184
185 surface_t *glyph_surface;
186 rc = get_glyph_surface(data, glyph_id, &glyph_surface);
187 if (rc != EOK)
188 return rc;
189
190 native_t x = ox + glyph_metrics.left_side_bearing;
191 native_t y = oy - glyph_metrics.ascender;
192
193 transform_t transform;
194 transform_identity(&transform);
195 transform_translate(&transform, x, y);
196 source_set_transform(source, transform);
197 source_set_mask(source, glyph_surface, false);
198 drawctx_transfer(context, x, y, glyph_metrics.width,
199 glyph_metrics.height);
200
201 return EOK;
202}
203
204static void bb_release(void *backend_data)
205{
206 bitmap_backend_data_t *data = (bitmap_backend_data_t *) backend_data;
207
208 for (size_t i = 0; i < data->glyph_count; ++i) {
209 if (data->glyph_cache[i].surface) {
210 surface_destroy(data->glyph_cache[i].surface);
211 }
212 }
213 free(data->glyph_cache);
214
215 data->decoder->release(data->decoder_data);
216}
217
218font_backend_t bitmap_backend = {
219 .get_font_metrics = bb_get_font_metrics,
220 .resolve_glyph = bb_resolve_glyph,
221 .get_glyph_metrics = bb_get_glyph_metrics,
222 .render_glyph = bb_render_glyph,
223 .release = bb_release
224};
225
226int bitmap_font_create(bitmap_font_decoder_t *decoder, void *decoder_data,
227 uint32_t glyph_count, font_metrics_t font_metrics, uint16_t points,
228 font_t **out_font)
229{
230 if (glyph_count == 0)
231 return EINVAL;
232
233 bitmap_backend_data_t *data = malloc(sizeof(bitmap_backend_data_t));
234 if (data == NULL)
235 return ENOMEM;
236
237 data->glyph_count = glyph_count;
238 data->points = points;
239 data->decoder = decoder;
240 data->decoder_data = decoder_data;
241 data->font_metrics = font_metrics;
242 metric_t line_height = (font_metrics.ascender + font_metrics.descender);
243 if (points == line_height) {
244 data->scale = false;
245 data->scale_ratio = 1.0;
246 }
247 else {
248 data->scale = true;
249 data->scale_ratio = ((double) points) / ((double) line_height);
250 line_height = (data->scale_ratio * ((double) line_height));
251 data->font_metrics.ascender = (metric_t)
252 (data->scale_ratio * data->font_metrics.ascender + 0.5);
253 data->font_metrics.descender =
254 line_height - data->font_metrics.ascender;
255 data->font_metrics.leading = (metric_t)
256 (data->scale_ratio * data->font_metrics.leading + 0.5);
257 }
258
259 data->glyph_cache = calloc(data->glyph_count,
260 sizeof(glyph_cache_item_t));
261 if (data->glyph_cache == NULL) {
262 free(data);
263 return ENOMEM;
264 }
265
266 for (size_t i = 0; i < data->glyph_count; ++i) {
267 data->glyph_cache[i].surface = NULL;
268 data->glyph_cache[i].metrics_loaded = false;
269 }
270
271 font_t *font = font_create(&bitmap_backend, data);
272 if (font == NULL) {
273 free(data->glyph_cache);
274 free(data);
275 return ENOMEM;
276 }
277
278 *out_font = font;
279 return EOK;
280}
281
282/** @}
283 */
Note: See TracBrowser for help on using the repository browser.