FreeBASIC  0.91.0
gfx_drawstring.c
Go to the documentation of this file.
1 /* advanced graphical string drawing routine */
2 
3 #include "fb_gfx.h"
4 
5 /*
6  * User font format:
7  *
8  * Basically a GET/PUT buffer, where the first pixels data line holds the
9  * font header:
10  *
11  * offset | description
12  * --------+--------------------------------------------------------------
13  * 0 | Font header version (currently must be 0)
14  * 1 | First ascii character supported
15  * 2 | Last ascii character supported
16  * 3-(3+n) | n-th supported character width
17  *
18  * The font height is computed as the height of the buffer minus 1, and the
19  * actual glyph shapes start on the second buffer line, one after another in
20  * the same row, starting with first supported ascii character up to the
21  * last one.
22  *
23  */
24 
25 typedef struct FBGFX_CHAR
26 {
27  unsigned int width;
28  unsigned char *data;
29 } FBGFX_CHAR;
30 
31 
32 
33 /*:::::*/
35  (
36  void *target,
37  float fx,
38  float fy,
39  int flags,
40  FBSTRING *string,
41  unsigned int color,
42  void *font,
43  int mode,
44  PUTTER *putter,
45  BLENDER *blender,
46  void *param
47  )
48 {
50  FBGFX_CHAR char_data[256], *ch;
51  PUT_HEADER *header;
52  int font_height, x, y, px, py, i, w, h, pitch, bpp, first, last;
53  int offset, bytes_count, res = fb_ErrorSetNum( FB_RTERROR_OK );
54  unsigned char *data, *width;
55 
56  if ((!__fb_gfx) || (!string) || (!string->data)) {
57  if (!string)
59  goto exit_error_unlocked;
60  }
61 
62  fb_hPrepareTarget(context, target);
63 
64  if (mode != PUT_MODE_ALPHA) {
65  if (flags & DEFAULT_COLOR_1)
66  color = context->fg_color;
67  else
68  color = fb_hFixColor(context->target_bpp, color);
69  }
70 
71  fb_hSetPixelTransfer(context, color);
72 
73  fb_hFixRelative(context, flags, &fx, &fy, NULL, NULL);
74 
75  fb_hTranslateCoord(context, fx, fy, &x, &y);
76 
77  DRIVER_LOCK();
78 
79  if (font) {
80  /* user passed a custom font */
81 
82  header = (PUT_HEADER *)font;
83  if (header->type == PUT_HEADER_NEW) {
84  bpp = header->bpp;
85  font_height = header->height - 1;
86  pitch = header->pitch;
87  data = (unsigned char *)font + sizeof(PUT_HEADER);
88  }
89  else {
90  bpp = header->old.bpp;
91  if (!bpp)
92  bpp = context->target_bpp;
93  font_height = header->old.height - 1;
94  pitch = header->old.width * bpp;
95  data = (unsigned char *)font + 4;
96  }
97 
98  if ((y + font_height <= context->view_y) || (y >= context->view_y + context->view_h))
99  goto exit_error;
100 
101  if ((bpp != context->target_bpp) || (pitch < 4) || (font_height <= 0) || (data[0] != 0)) {
103  goto exit_error;
104  }
105 
106  first = (int)data[1];
107  last = (int)data[2];
108  width = &data[3];
109  if (first > last)
110  SWAP(first, last);
111  fb_hMemSet(char_data, 0, sizeof(FBGFX_CHAR) * 256);
112  data += pitch;
113  if (y < context->view_y) {
114  data += (pitch * (context->view_y - y));
115  font_height -= (context->view_y - y);
116  y = context->view_y;
117  }
118  if (y + font_height > context->view_y + context->view_h)
119  font_height -= ((y + font_height) - (context->view_y + context->view_h));
120 
121  for (w = 0, i = first; i <= last; i++) {
122  char_data[i].width = (unsigned int)width[i - first];
123  char_data[i].data = data;
124  data += (char_data[i].width * bpp);
125  w += char_data[i].width;
126  }
127  if (w > (pitch / __fb_gfx->bpp)) {
129  goto exit_error;
130  }
131 
132  for (i = 0; i < FB_STRSIZE(string); i++) {
133 
134  if (x >= context->view_x + context->view_w)
135  break;
136 
137  ch = &char_data[(unsigned char)string->data[i]];
138  data = ch->data;
139  if (!data) {
140  /* character not found */
141  x += font_height;
142  continue;
143  }
144  w = ch->width;
145  h = font_height;
146  px = x;
147 
148  if (x + w >= context->view_x) {
149 
150  if (x < context->view_x) {
151  data += ((context->view_x - x) * bpp);
152  w -= (context->view_x - x);
153  px = context->view_x;
154  }
155  if (x + w > context->view_x + context->view_w)
156  w -= ((x + w) - (context->view_x + context->view_w));
157  putter(data, context->line[y] + (px * bpp), w, h, pitch, context->target_pitch, color, blender, param);
158 
159  }
160  x += ch->width;
161  }
162  }
163  else {
164  /* use default font */
165 
166  font_height = __fb_gfx->font->h;
167  w = __fb_gfx->font->w;
168  bytes_count = BYTES_PER_PIXEL(w);
169  offset = 0;
170 
171  if ((x + (w * FB_STRSIZE(string)) <= context->view_x) || (x >= context->view_x + context->view_w) ||
172  (y + font_height <= context->view_y) || (y >= context->view_y + context->view_h)) {
173  goto exit_error;
174  }
175 
176  if (y < context->view_y) {
177  offset = (bytes_count * (context->view_y - y));
178  font_height -= (context->view_y - y);
179  y = context->view_y;
180  }
181  if (y + font_height > context->view_y + context->view_h)
182  font_height -= ((y + font_height) - (context->view_y + context->view_h));
183 
184  first = 0;
185  if (x < context->view_x) {
186  first = (context->view_x - x) / w;
187  x += (first * w);
188  }
189  last = FB_STRSIZE(string);
190  if (x + ((last - first) * w) > context->view_x + context->view_w)
191  last -= ((x + ((last - first) * w) - (context->view_x + context->view_w)) / w);
192 
193  for (i = first; i < last; i++, x += w) {
194 
195  if (x + w <= context->view_x)
196  continue;
197 
198  if (x >= context->view_x + context->view_w)
199  break;
200 
201  data = (unsigned char *)__fb_gfx->font->data + ((unsigned char)string->data[i] * bytes_count * __fb_gfx->font->h) + offset;
202  for (py = 0; py < font_height; py++) {
203  for (px = 0; px < w; px++) {
204  if ((*data & (1 << (px & 0x7))) && (x + px >= context->view_x) && (x + px < context->view_x + context->view_w))
205  context->put_pixel(context, x + px, y + py, color);
206  if ((px & 0x7) == 0x7)
207  data++;
208  }
209  }
210  }
211  }
212 
213  SET_DIRTY(context, y, font_height);
214 
215 exit_error:
216  DRIVER_UNLOCK();
217 
218 exit_error_unlocked:
219  fb_hStrDelTemp(string);
220 
221  if (res != FB_RTERROR_OK)
222  return fb_ErrorSetNum(res);
223  else
224  return res;
225 }
226