Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3584 | sourcerer | 1 | /* |
2 | * Copyright 2009 Vincent Sanders |
||
3 | * |
||
4 | * This file is part of libnsfb, http://www.netsurf-browser.org/ |
||
5 | * Licenced under the MIT License, |
||
6 | * http://www.opensource.org/licenses/mit-license.php |
||
7 | */ |
||
8 | |||
9 | #include |
||
10 | #include |
||
11 | #include |
||
12 | |||
13 | #include "libnsfb.h" |
||
14 | #include "libnsfb_plot.h" |
||
15 | #include "libnsfb_plot_util.h" |
||
16 | |||
17 | #include "nsfb.h" |
||
18 | #include "plot.h" |
||
19 | |||
20 | static inline uint8_t * |
||
21 | get_xy_loc(nsfb_t *nsfb, int x, int y) |
||
22 | { |
||
23 | return (uint8_t *)(nsfb->ptr + (y * nsfb->linelen) + (x * 3)); |
||
24 | } |
||
25 | |||
26 | #if __BYTE_ORDER == __BIG_ENDIAN |
||
27 | static inline nsfb_colour_t pixel_to_colour(uint8_t pixel) |
||
28 | { |
||
29 | return (pixel >> 8) & ~0xFF000000U; |
||
30 | } |
||
31 | |||
32 | /* convert a colour value to a 32bpp pixel value ready for screen output */ |
||
33 | static inline uint32_t colour_to_pixel(nsfb_colour_t c) |
||
34 | { |
||
35 | return (c << 8); |
||
36 | } |
||
37 | #else /* __BYTE_ORDER == __BIG_ENDIAN */ |
||
38 | static inline nsfb_colour_t pixel_to_colour(uint32_t pixel) |
||
39 | { |
||
40 | return ((pixel & 0xFF) << 16) | |
||
41 | ((pixel & 0xFF00)) | |
||
42 | ((pixel & 0xFF0000) >> 16); |
||
43 | } |
||
44 | |||
45 | /* convert a colour value to a 32bpp pixel value ready for screen output */ |
||
46 | static inline uint32_t colour_to_pixel(nsfb_colour_t c) |
||
47 | { |
||
48 | return ((c & 0xff0000) >> 16) | (c & 0xff00) | ((c & 0xff) << 16); |
||
49 | } |
||
50 | #endif |
||
51 | |||
52 | #define SIGN(x) ((x<0) ? -1 : ((x>0) ? 1 : 0)) |
||
53 | |||
54 | static bool |
||
55 | line(nsfb_t *nsfb, int linec, nsfb_bbox_t *line, nsfb_plot_pen_t *pen) |
||
56 | { |
||
57 | int w; |
||
58 | uint32_t ent; |
||
59 | uint32_t *pvideo; |
||
60 | int x, y, i; |
||
61 | int dx, dy, sdy; |
||
62 | int dxabs, dyabs; |
||
63 | |||
64 | ent = colour_to_pixel(pen->stroke_colour); |
||
65 | |||
66 | for (;linec > 0; linec--) { |
||
67 | |||
68 | if (line->y0 == line->y1) { |
||
69 | /* horizontal line special cased */ |
||
70 | |||
71 | if (!nsfb_plot_clip_ctx(nsfb, line)) { |
||
72 | /* line outside clipping */ |
||
73 | line++; |
||
74 | continue; |
||
75 | } |
||
76 | |||
77 | pvideo = get_xy_loc(nsfb, line->x0, line->y0); |
||
78 | |||
79 | w = line->x1 - line->x0; |
||
80 | while (w-- > 0) |
||
81 | *(pvideo + w) = ent; |
||
82 | |||
83 | } else { |
||
84 | /* standard bresenham line */ |
||
85 | |||
86 | if (!nsfb_plot_clip_line_ctx(nsfb, line)) { |
||
87 | /* line outside clipping */ |
||
88 | line++; |
||
89 | continue; |
||
90 | } |
||
91 | |||
92 | /* the horizontal distance of the line */ |
||
93 | dx = line->x1 - line->x0; |
||
94 | dxabs = abs (dx); |
||
95 | |||
96 | /* the vertical distance of the line */ |
||
97 | dy = line->y1 - line->y0; |
||
98 | dyabs = abs (dy); |
||
99 | |||
100 | sdy = dx ? SIGN(dy) * SIGN(dx) : SIGN(dy); |
||
101 | |||
102 | if (dx >= 0) |
||
103 | pvideo = get_xy_loc(nsfb, line->x0, line->y0); |
||
104 | else |
||
105 | pvideo = get_xy_loc(nsfb, line->x1, line->y1); |
||
106 | |||
107 | x = dyabs >> 1; |
||
108 | y = dxabs >> 1; |
||
109 | |||
110 | if (dxabs >= dyabs) { |
||
111 | /* the line is more horizontal than vertical */ |
||
112 | for (i = 0; i < dxabs; i++) { |
||
113 | *pvideo = ent; |
||
114 | |||
115 | pvideo++; |
||
116 | y += dyabs; |
||
117 | if (y >= dxabs) { |
||
118 | y -= dxabs; |
||
119 | pvideo += sdy * (nsfb->linelen>>2); |
||
120 | } |
||
121 | } |
||
122 | } else { |
||
123 | /* the line is more vertical than horizontal */ |
||
124 | for (i = 0; i < dyabs; i++) { |
||
125 | *pvideo = ent; |
||
126 | pvideo += sdy * (nsfb->linelen >> 2); |
||
127 | |||
128 | x += dxabs; |
||
129 | if (x >= dyabs) { |
||
130 | x -= dyabs; |
||
131 | pvideo++; |
||
132 | } |
||
133 | } |
||
134 | } |
||
135 | |||
136 | } |
||
137 | line++; |
||
138 | } |
||
139 | return true; |
||
140 | } |
||
141 | |||
142 | |||
143 | |||
144 | static bool fill(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t c) |
||
145 | { |
||
146 | int w; |
||
147 | uint32_t *pvid; |
||
148 | uint32_t ent; |
||
149 | uint32_t llen; |
||
150 | uint32_t width; |
||
151 | uint32_t height; |
||
152 | |||
153 | if (!nsfb_plot_clip_ctx(nsfb, rect)) |
||
154 | return true; /* fill lies outside current clipping region */ |
||
155 | |||
156 | ent = colour_to_pixel(c); |
||
157 | width = rect->x1 - rect->x0; |
||
158 | height = rect->y1 - rect->y0; |
||
159 | llen = (nsfb->linelen >> 2) - width; |
||
160 | |||
161 | pvid = get_xy_loc(nsfb, rect->x0, rect->y0); |
||
162 | |||
163 | while (height-- > 0) { |
||
164 | w = width; |
||
165 | while (w >= 16) { |
||
166 | *pvid++ = ent; *pvid++ = ent; |
||
167 | *pvid++ = ent; *pvid++ = ent; |
||
168 | *pvid++ = ent; *pvid++ = ent; |
||
169 | *pvid++ = ent; *pvid++ = ent; |
||
170 | *pvid++ = ent; *pvid++ = ent; |
||
171 | *pvid++ = ent; *pvid++ = ent; |
||
172 | *pvid++ = ent; *pvid++ = ent; |
||
173 | *pvid++ = ent; *pvid++ = ent; |
||
174 | w-=16; |
||
175 | } |
||
176 | while (w >= 4) { |
||
177 | *pvid++ = ent; *pvid++ = ent; |
||
178 | *pvid++ = ent; *pvid++ = ent; |
||
179 | w-=4; |
||
180 | } |
||
181 | while (w > 0) { |
||
182 | *pvid++ = ent; |
||
183 | w--; |
||
184 | } |
||
185 | pvid += llen; |
||
186 | } |
||
187 | |||
188 | return true; |
||
189 | } |
||
190 | |||
191 | |||
192 | |||
193 | |||
194 | static bool point(nsfb_t *nsfb, int x, int y, nsfb_colour_t c) |
||
195 | { |
||
196 | uint32_t *pvideo; |
||
197 | |||
198 | /* check point lies within clipping region */ |
||
199 | if ((x < nsfb->clip.x0) || |
||
200 | (x >= nsfb->clip.x1) || |
||
201 | (y < nsfb->clip.y0) || |
||
202 | (y >= nsfb->clip.y1)) |
||
203 | return true; |
||
204 | |||
205 | pvideo = get_xy_loc(nsfb, x, y); |
||
206 | |||
207 | if ((c & 0xFF000000) != 0) { |
||
208 | if ((c & 0xFF000000) != 0xFF000000) { |
||
209 | c = nsfb_plot_ablend(c, pixel_to_colour(*pvideo)); |
||
210 | } |
||
211 | |||
212 | *pvideo = colour_to_pixel(c); |
||
213 | } |
||
214 | return true; |
||
215 | } |
||
216 | |||
217 | static bool |
||
218 | glyph1(nsfb_t *nsfb, |
||
219 | nsfb_bbox_t *loc, |
||
220 | const uint8_t *pixel, |
||
221 | int pitch, |
||
222 | nsfb_colour_t c) |
||
223 | { |
||
224 | uint32_t *pvideo; |
||
225 | int xloop, yloop; |
||
226 | int xoff, yoff; /* x and y offset into image */ |
||
227 | int x = loc->x0; |
||
228 | int y = loc->y0; |
||
229 | int width = loc->x1 - loc->x0; |
||
230 | int height = loc->y1 - loc->y0; |
||
231 | uint32_t fgcol; |
||
232 | const uint8_t *fntd; |
||
233 | uint8_t row; |
||
234 | |||
235 | if (!nsfb_plot_clip_ctx(nsfb, loc)) |
||
236 | return true; |
||
237 | |||
238 | if (height > (loc->y1 - loc->y0)) |
||
239 | height = (loc->y1 - loc->y0); |
||
240 | |||
241 | if (width > (loc->x1 - loc->x0)) |
||
242 | width = (loc->x1 - loc->x0); |
||
243 | |||
244 | xoff = loc->x0 - x; |
||
245 | yoff = loc->y0 - y; |
||
246 | |||
247 | pvideo = get_xy_loc(nsfb, loc->x0, loc->y0); |
||
248 | |||
249 | fgcol = colour_to_pixel(c); |
||
250 | |||
251 | for (yloop = yoff; yloop < height; yloop++) { |
||
252 | fntd = pixel + (yloop * (pitch>>3)) + (xoff>>3); |
||
253 | row = (*fntd++) << (xoff & 3); |
||
254 | for (xloop = xoff; xloop < width ; xloop++) { |
||
255 | if (((xloop % 8) == 0) && (xloop != 0)) { |
||
256 | row = *fntd++; |
||
257 | } |
||
258 | |||
259 | if ((row & 0x80) != 0) { |
||
260 | *(pvideo + xloop) = fgcol; |
||
261 | } |
||
262 | row = row << 1; |
||
263 | |||
264 | } |
||
265 | |||
266 | pvideo += (nsfb->linelen >> 2); |
||
267 | } |
||
268 | |||
269 | return true; |
||
270 | } |
||
271 | |||
272 | static bool |
||
273 | glyph8(nsfb_t *nsfb, |
||
274 | nsfb_bbox_t *loc, |
||
275 | const uint8_t *pixel, |
||
276 | int pitch, |
||
277 | nsfb_colour_t c) |
||
278 | { |
||
279 | uint32_t *pvideo; |
||
280 | nsfb_colour_t abpixel; /* alphablended pixel */ |
||
281 | int xloop, yloop; |
||
282 | int xoff, yoff; /* x and y offset into image */ |
||
283 | int x = loc->x0; |
||
284 | int y = loc->y0; |
||
285 | int width = loc->x1 - loc->x0; |
||
286 | int height = loc->y1 - loc->y0; |
||
287 | uint32_t fgcol; |
||
288 | |||
289 | if (!nsfb_plot_clip_ctx(nsfb, loc)) |
||
290 | return true; |
||
291 | |||
292 | if (height > (loc->y1 - loc->y0)) |
||
293 | height = (loc->y1 - loc->y0); |
||
294 | |||
295 | if (width > (loc->x1 - loc->x0)) |
||
296 | width = (loc->x1 - loc->x0); |
||
297 | |||
298 | xoff = loc->x0 - x; |
||
299 | yoff = loc->y0 - y; |
||
300 | |||
301 | pvideo = get_xy_loc(nsfb, loc->x0, loc->y0); |
||
302 | |||
303 | fgcol = c & 0xFFFFFF; |
||
304 | |||
305 | for (yloop = 0; yloop < height; yloop++) { |
||
306 | for (xloop = 0; xloop < width; xloop++) { |
||
307 | abpixel = (pixel[((yoff + yloop) * pitch) + xloop + xoff] << 24) | fgcol; |
||
308 | if ((abpixel & 0xFF000000) != 0) { |
||
309 | /* pixel is not transparent */ |
||
310 | if ((abpixel & 0xFF000000) != 0xFF000000) { |
||
311 | abpixel = nsfb_plot_ablend(abpixel, |
||
312 | pixel_to_colour(*(pvideo + xloop))); |
||
313 | } |
||
314 | |||
315 | *(pvideo + xloop) = colour_to_pixel(abpixel); |
||
316 | } |
||
317 | } |
||
318 | pvideo += (nsfb->linelen >> 2); |
||
319 | } |
||
320 | |||
321 | return true; |
||
322 | } |
||
323 | |||
324 | static bool |
||
325 | bitmap(nsfb_t *nsfb, |
||
326 | const nsfb_bbox_t *loc, |
||
327 | const nsfb_colour_t *pixel, |
||
328 | int bmp_width, |
||
329 | int bmp_height, |
||
330 | int bmp_stride, |
||
331 | bool alpha) |
||
332 | { |
||
333 | uint32_t *pvideo; |
||
334 | nsfb_colour_t abpixel = 0; /* alphablended pixel */ |
||
335 | int xloop, yloop; |
||
336 | int xoff, yoff; /* x and y offset into image */ |
||
337 | int x = loc->x0; |
||
338 | int y = loc->y0; |
||
339 | int width = loc->x1 - loc->x0; |
||
340 | int height = loc->y1 - loc->y0; |
||
341 | nsfb_bbox_t clipped; /* clipped display */ |
||
342 | |||
343 | /* TODO here we should scale the image from bmp_width to width, for |
||
344 | * now simply crop. |
||
345 | */ |
||
346 | if (width > bmp_width) |
||
347 | width = bmp_width; |
||
348 | |||
349 | if (height > bmp_height) |
||
350 | height = bmp_height; |
||
351 | |||
352 | /* The part of the scaled image actually displayed is cropped to the |
||
353 | * current context. |
||
354 | */ |
||
355 | clipped.x0 = x; |
||
356 | clipped.y0 = y; |
||
357 | clipped.x1 = x + width; |
||
358 | clipped.y1 = y + height; |
||
359 | |||
360 | if (!nsfb_plot_clip_ctx(nsfb, &clipped)) { |
||
361 | return true; |
||
362 | } |
||
363 | |||
364 | if (height > (clipped.y1 - clipped.y0)) |
||
365 | height = (clipped.y1 - clipped.y0); |
||
366 | |||
367 | if (width > (clipped.x1 - clipped.x0)) |
||
368 | width = (clipped.x1 - clipped.x0); |
||
369 | |||
370 | xoff = clipped.x0 - x; |
||
371 | yoff = (clipped.y0 - y) * bmp_width; |
||
372 | height = height * bmp_stride + yoff; |
||
373 | |||
374 | /* plot the image */ |
||
375 | pvideo = get_xy_loc(nsfb, clipped.x0, clipped.y0); |
||
376 | |||
377 | if (alpha) { |
||
378 | for (yloop = yoff; yloop < height; yloop += bmp_stride) { |
||
379 | for (xloop = 0; xloop < width; xloop++) { |
||
380 | abpixel = pixel[yloop + xloop + xoff]; |
||
381 | if ((abpixel & 0xFF000000) != 0) { |
||
382 | if ((abpixel & 0xFF000000) != 0xFF000000) { |
||
383 | abpixel = nsfb_plot_ablend(abpixel, |
||
384 | pixel_to_colour(*(pvideo + xloop))); |
||
385 | } |
||
386 | |||
387 | *(pvideo + xloop) = colour_to_pixel(abpixel); |
||
388 | } |
||
389 | } |
||
390 | pvideo += (nsfb->linelen >> 2); |
||
391 | } |
||
392 | } else { |
||
393 | for (yloop = yoff; yloop < height; yloop += bmp_stride) { |
||
394 | for (xloop = 0; xloop < width; xloop++) { |
||
395 | abpixel = pixel[yloop + xloop + xoff]; |
||
396 | *(pvideo + xloop) = colour_to_pixel(abpixel); |
||
397 | } |
||
398 | pvideo += (nsfb->linelen >> 2); |
||
399 | } |
||
400 | } |
||
401 | return true; |
||
402 | } |
||
403 | |||
404 | static bool readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer) |
||
405 | { |
||
406 | uint32_t *pvideo; |
||
407 | int xloop, yloop; |
||
408 | int width; |
||
409 | |||
410 | if (!nsfb_plot_clip_ctx(nsfb, rect)) { |
||
411 | return true; |
||
412 | } |
||
413 | |||
414 | width = rect->x1 - rect->x0; |
||
415 | |||
416 | pvideo = get_xy_loc(nsfb, rect->x0, rect->y0); |
||
417 | |||
418 | for (yloop = rect->y0; yloop < rect->y1; yloop += 1) { |
||
419 | for (xloop = 0; xloop < width; xloop++) { |
||
420 | *buffer = pixel_to_colour(*(pvideo + xloop)); |
||
421 | buffer++; |
||
422 | } |
||
423 | pvideo += (nsfb->linelen >> 2); |
||
424 | } |
||
425 | return true; |
||
426 | } |
||
427 | |||
428 | const nsfb_plotter_fns_t _nsfb_24bpp_plotters = { |
||
429 | .line = line, |
||
430 | .fill = fill, |
||
431 | .point = point, |
||
432 | .bitmap = bitmap, |
||
433 | .glyph8 = glyph8, |
||
434 | .glyph1 = glyph1, |
||
435 | .readrect = readrect, |
||
436 | }; |
||
437 | |||
438 | /* |
||
439 | * Local Variables: |
||
440 | * c-basic-offset:8 |
||
441 | * End: |
||
442 | */>>>>>>><>>>><>>><>>>>>>0)>><>><>><> |