1 /**
2 * \file
3 *
4 * \brief Font and text drawing routines
5 *
6 * Copyright (c) 2010-2015 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46 #include "stddef.h"
47 #include "assert.h"
48
49 #include "gfx_mono.h"
50 #include "gfx_mono_text.h"
51 #include <asf.h>
52
53 #ifndef CONFIG_FONT_PIXELS_PER_BYTE
54 # define CONFIG_FONT_PIXELS_PER_BYTE 8
55 #endif
56
57 #define EXTMEM_BUF_SIZE 20
58
59 #if defined(CONFIG_HUGEMEM) || defined(__DOXYGEN__)
60
61 /**
62 * \internal
63 * \brief Helper function that draws a character from a font in hugemem
64 * to the display
65 *
66 * This function will first calculate the start offset in the font character
67 * data before iterating over the specific character data.
68 *
69 * Only pixels in the character that should be enabled are done so, the caller
70 * is required to prepare the drawing area before printing a character to it.
71 * This is done by the gfx_mono_draw_string() and
72 * gfx_mono_draw_progmem_string() functions.
73 *
74 * \param[in] ch Character to be drawn
75 * \param[in] x X coordinate on screen.
76 * \param[in] y Y coordinate on screen.
77 * \param[in] font Font to draw character in
78 */
gfx_mono_draw_char_hugemem(const char ch,const gfx_coord_t x,const gfx_coord_t y,const struct font * font)79 static void gfx_mono_draw_char_hugemem(const char ch, const gfx_coord_t x,
80 const gfx_coord_t y, const struct font *font)
81 {
82 uint8_t i;
83 uint8_t char_row_size;
84 uint8_t glyph_size;
85 uint16_t glyph_data_offset;
86 uint8_t char_buff[EXTMEM_BUF_SIZE];
87 uint8_t buffer_pos;
88 uint8_t rows_left;
89
90 /* Sanity check on parameters, assert if font is NULL. */
91 Assert(font != NULL);
92
93 gfx_coord_t inc_x = x;
94 gfx_coord_t inc_y = y;
95
96 char_row_size = font->width / CONFIG_FONT_PIXELS_PER_BYTE;
97 if (font->width % CONFIG_FONT_PIXELS_PER_BYTE) {
98 char_row_size++;
99 }
100
101 glyph_size = char_row_size * font->height;
102 glyph_data_offset = glyph_size * ((uint8_t)ch - font->first_char);
103 buffer_pos = EXTMEM_BUF_SIZE;
104 rows_left = font->height;
105
106 do {
107 static uint8_t glyph_byte = 0;
108 uint8_t pixelsToDraw = font->width;
109
110 for (i = 0; i < pixelsToDraw; i++) {
111 if (i % CONFIG_FONT_PIXELS_PER_BYTE == 0) {
112 /* Read another byte from hugemem */
113 if (buffer_pos >= EXTMEM_BUF_SIZE) {
114 hugemem_ptr_t source
115 = font->data.hugemem;
116 source = (hugemem_ptr_t)
117 ((uint32_t)source +
118 glyph_data_offset);
119
120 hugemem_read_block(char_buff, source,
121 EXTMEM_BUF_SIZE);
122
123 glyph_data_offset += EXTMEM_BUF_SIZE;
124 buffer_pos = 0;
125 }
126
127 glyph_byte = char_buff[buffer_pos];
128 buffer_pos++;
129 }
130
131 /* Draw bit of glyph to screen */
132 if ((glyph_byte & 0x80)) {
133 gfx_mono_draw_pixel(inc_x, inc_y,
134 GFX_PIXEL_SET);
135 }
136
137 inc_x += 1;
138 glyph_byte <<= 1;
139 }
140
141 inc_y += 1;
142 inc_x = x;
143 } while (--rows_left > 0);
144 }
145
146 #endif
147
148 /**
149 * \internal
150 * \brief Helper function that draws a character from a font in progmem
151 * to the display
152 *
153 * This function will first calculate the start offset in the font character
154 * data before iterating over the specific character data.
155 *
156 * Only pixels in the character that should be enabled are done so, the caller
157 * is required to prepare the drawing area before printing a character to it.
158 * This is done by the gfx_mono_draw_string() and
159 * gfx_mono_draw_progmem_string() functions.
160 *
161 * \param[in] ch Character to be drawn
162 * \param[in] x X coordinate on screen.
163 * \param[in] y Y coordinate on screen.
164 * \param[in] font Font to draw character in
165 */
gfx_mono_draw_char_progmem(const char ch,const gfx_coord_t x,const gfx_coord_t y,const struct font * font)166 static void gfx_mono_draw_char_progmem(const char ch, const gfx_coord_t x,
167 const gfx_coord_t y, const struct font *font)
168 {
169 uint8_t PROGMEM_PTR_T glyph_data;
170 uint16_t glyph_data_offset;
171 uint8_t char_row_size;
172 uint8_t rows_left;
173 uint8_t i;
174
175 /* Sanity check on parameters, assert if font is NULL. */
176 Assert(font != NULL);
177
178 gfx_coord_t inc_x = x;
179 gfx_coord_t inc_y = y;
180
181 char_row_size = font->width / CONFIG_FONT_PIXELS_PER_BYTE;
182 if (font->width % CONFIG_FONT_PIXELS_PER_BYTE) {
183 char_row_size++;
184 }
185
186 glyph_data_offset = char_row_size * font->height *
187 ((uint8_t)ch - font->first_char);
188 glyph_data = font->data.progmem + glyph_data_offset;
189 rows_left = font->height;
190
191 do {
192 uint8_t glyph_byte = 0;
193 uint8_t pixelsToDraw = font->width;
194
195 for (i = 0; i < pixelsToDraw; i++) {
196 if (i % CONFIG_FONT_PIXELS_PER_BYTE == 0) {
197 glyph_byte = PROGMEM_READ_BYTE(glyph_data);
198 glyph_data++;
199 }
200
201 if ((glyph_byte & 0x80)) {
202 gfx_mono_draw_pixel(inc_x, inc_y,
203 GFX_PIXEL_SET);
204 }
205
206 inc_x += 1;
207 glyph_byte <<= 1;
208 }
209
210 inc_y += 1;
211 inc_x = x;
212 rows_left--;
213 } while (rows_left > 0);
214 }
215
216 /**
217 * \brief Draws a character to the display
218 *
219 * \param[in] c Character to be drawn
220 * \param[in] x X coordinate on screen.
221 * \param[in] y Y coordinate on screen.
222 * \param[in] font Font to draw character in
223 */
gfx_mono_draw_char(const char c,const gfx_coord_t x,const gfx_coord_t y,const struct font * font)224 void gfx_mono_draw_char(const char c, const gfx_coord_t x, const gfx_coord_t y,
225 const struct font *font)
226 {
227 gfx_mono_draw_filled_rect(x, y, font->width, font->height,
228 GFX_PIXEL_CLR);
229
230 switch (font->type) {
231 case FONT_LOC_PROGMEM:
232 gfx_mono_draw_char_progmem(c, x, y, font);
233 break;
234
235 #ifdef CONFIG_HUGEMEM
236 case FONT_LOC_HUGEMEM:
237 gfx_mono_draw_char_hugemem(c, x, y, font);
238 break;
239
240 #endif
241 default:
242 /* Unsupported mode, call assert */
243 Assert(false);
244 break;
245 }
246 }
247
248 /**
249 * \brief Draws a string to the display
250 *
251 * This function will draw a string located in memory to the display.
252 *
253 * \param[in] str Pointer to string
254 * \param[in] x X coordinate on screen.
255 * \param[in] y Y coordinate on screen.
256 * \param[in] font Font to draw string in
257 */
gfx_mono_draw_string(const char * str,gfx_coord_t x,gfx_coord_t y,const struct font * font)258 void gfx_mono_draw_string(const char *str, gfx_coord_t x, gfx_coord_t y,
259 const struct font *font)
260 {
261 /* Save X in order to know where to return to on CR. */
262 const gfx_coord_t start_of_string_position_x = x;
263
264 /* Sanity check on parameters, assert if str or font is NULL. */
265 Assert(str != NULL);
266 Assert(font != NULL);
267
268 /* Draw characters until trailing null byte */
269 do {
270 /* Handle '\n' as newline, draw normal characters. */
271 if (*str == '\n') {
272 x = start_of_string_position_x;
273 y += font->height + 1;
274 } else if (*str == '\r') {
275 /* Skip '\r' characters. */
276 } else {
277 gfx_mono_draw_char(*str, x, y, font);
278 x += font->width;
279 }
280 } while (*(++str));
281 }
282
283 /**
284 * \brief Draws a string located in program memory to the display
285 *
286 * This function will draw a string located in program memory to the display,
287 * this differs from gfx_mono_draw_string() by using constant string data from
288 * the program memory instead of string data in RAM.
289 *
290 * Using program memory for constant strings will reduce the applications need
291 * for RAM, and thus lower the overall size footprint.
292 *
293 * \param[in] str Pointer to string located in program memory
294 * \param[in] x X coordinate on screen.
295 * \param[in] y Y coordinate on screen.
296 * \param[in] font Font to draw string in
297 */
gfx_mono_draw_progmem_string(char PROGMEM_PTR_T str,gfx_coord_t x,gfx_coord_t y,const struct font * font)298 void gfx_mono_draw_progmem_string(char PROGMEM_PTR_T str, gfx_coord_t x,
299 gfx_coord_t y, const struct font *font)
300 {
301 char temp_char;
302
303 /* Sanity check on parameters, assert if str or font is NULL. */
304 Assert(str != NULL);
305 Assert(font != NULL);
306
307 /* Save X in order to know where to return to on CR. */
308 const gfx_coord_t start_of_string_position_x = x;
309
310 /* Draw characters until trailing null byte */
311 temp_char = PROGMEM_READ_BYTE((uint8_t PROGMEM_PTR_T)str);
312
313 while (temp_char) {
314 /* Handle '\n' as newline, draw normal characters. */
315 if (temp_char == '\n') {
316 x = start_of_string_position_x;
317 y += font->height + 1;
318 } else if (temp_char == '\r') {
319 /* Skip '\r' characters. */
320 } else {
321 gfx_mono_draw_char(temp_char, x, y, font);
322 x += font->width;
323 }
324
325 temp_char = PROGMEM_READ_BYTE((uint8_t PROGMEM_PTR_T)(++str));
326 }
327 }
328
329 /**
330 * \brief Computes the bounding box of a string
331 *
332 * \note If string is empty the returned width will be 1 pixel and the height
333 * equal to the font height.
334 *
335 * \param[in] str String to calculate bounding box for
336 * \param[in] font Font used
337 * \param[in] width Pointer to width result
338 * \param[in] height Pointer to height result
339 */
gfx_mono_get_string_bounding_box(const char * str,const struct font * font,gfx_coord_t * width,gfx_coord_t * height)340 void gfx_mono_get_string_bounding_box(const char *str, const struct font *font,
341 gfx_coord_t *width, gfx_coord_t *height)
342 {
343 gfx_coord_t font_width = font->width;
344 gfx_coord_t font_height = font->height;
345
346 gfx_coord_t max_width = 1;
347 gfx_coord_t max_height = font_height;
348 gfx_coord_t x = 0;
349
350 /* Sanity check on parameters, assert if str or font is NULL. */
351 Assert(str != NULL);
352 Assert(font != NULL);
353
354 /* Handle each character until trailing null byte */
355 do {
356 /* Handle '\n' as newline, draw normal characters. */
357 if (*str == '\n') {
358 x = 0;
359 max_height += font_height;
360 } else if (*str == '\r') {
361 /* Skip '\r' characters. */
362 } else {
363 x += font_width;
364 if (x > max_width) {
365 max_width = x;
366 }
367 }
368 } while (*(++str));
369
370 /* Return values through references */
371 *width = max_width;
372 *height = max_height;
373 }
374
375 /**
376 * \brief Computes the bounding box of a string located in program memory
377 *
378 * \note If string is empty the returned width will be 1 pixel and the height
379 * equal to the font height.
380 *
381 * \param[in] str String in program memory to calculate bounding box for
382 * \param[in] font Font used
383 * \param[in] width Pointer to width result
384 * \param[in] height Pointer to height result
385 */
gfx_mono_get_progmem_string_bounding_box(char PROGMEM_PTR_T str,const struct font * font,gfx_coord_t * width,gfx_coord_t * height)386 void gfx_mono_get_progmem_string_bounding_box(char PROGMEM_PTR_T str,
387 const struct font *font, gfx_coord_t *width,
388 gfx_coord_t *height)
389 {
390 gfx_coord_t font_width = font->width;
391 gfx_coord_t font_height = font->height;
392
393 char temp_char;
394 gfx_coord_t max_width = 1;
395 gfx_coord_t max_height = font_height;
396 gfx_coord_t x = 0;
397
398 /* Sanity check on parameters, assert if str or font is NULL. */
399 Assert(str != NULL);
400 Assert(font != NULL);
401
402 /* Handle each character until trailing null byte */
403 temp_char = PROGMEM_READ_BYTE((uint8_t PROGMEM_PTR_T)str);
404
405 while (temp_char) {
406 /* Handle '\n' as newline, draw normal characters. */
407 if (temp_char == '\n') {
408 x = 0;
409 max_height += font_height;
410 } else if (*str == '\r') {
411 /* Skip '\r' characters. */
412 } else {
413 x += font_width;
414 if (x > max_width) {
415 max_width = x;
416 }
417 }
418
419 temp_char = PROGMEM_READ_BYTE((uint8_t PROGMEM_PTR_T)(++str));
420 }
421
422 /* Return values through references */
423 *width = max_width;
424 *height = max_height;
425 }
426