NetSurf
bitmap.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
3  * Copyright 2005 Richard Wilson <info@tinct.net>
4  * Copyright 2008 Adrian Lees <adrianl@users.sourceforge.net>
5  *
6  * This file is part of NetSurf, http://www.netsurf-browser.org/
7  *
8  * NetSurf is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * NetSurf is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /**
22  * \file
23  * RISC OS implementation of bitmap operations.
24  *
25  * This implements the interface given by image/bitmap.h using RISC OS
26  * sprites.
27  */
28 
29 #include <assert.h>
30 #include <stdbool.h>
31 #include <string.h>
32 #include <swis.h>
33 #include <rufl.h>
34 #include <unixlib/local.h>
35 #include <oslib/colourtrans.h>
36 #include <oslib/osfile.h>
37 #include <oslib/osfind.h>
38 #include <oslib/osgbpb.h>
39 #include <oslib/osspriteop.h>
40 #include <oslib/wimp.h>
41 
42 #include "utils/nsoption.h"
43 #include "utils/filename.h"
44 #include "utils/log.h"
45 #include "utils/messages.h"
46 #include "netsurf/plotters.h"
47 #include "netsurf/content.h"
48 
49 #include "riscos/gui.h"
50 #include "riscos/image.h"
51 #include "riscos/palettes.h"
53 #include "riscos/tinct.h"
54 #include "riscos/bitmap.h"
55 
56 /** Colour in the overlay sprite that allows the bitmap to show through */
57 #define OVERLAY_INDEX 0xfe
58 
59 /** Size of buffer used when constructing mask data to be saved */
60 #define SAVE_CHUNK_SIZE 4096
61 
62 /**
63  * Whether we can use 32bpp sprites
64  */
65 static int thumbnail_32bpp_available = -1;
66 
67 /**
68  * Sprite output context saving
69  */
71  osspriteop_save_area *save_area;
72  int context1;
73  int context2;
74  int context3;
75 };
76 
77 /**
78  * Initialise a bitmaps sprite area.
79  *
80  * \param bitmap the bitmap to initialise
81  * \return true if bitmap initialised else false.
82  */
83 
84 static bool bitmap_initialise(struct bitmap *bitmap)
85 {
86  unsigned int area_size;
87  osspriteop_area *sprite_area;
88  osspriteop_header *sprite;
89 
90  assert(!bitmap->sprite_area);
91 
92  area_size = 16 + 44 + bitmap->width * bitmap->height * 4;
93  if (bitmap->clear)
94  bitmap->sprite_area = calloc(1, area_size);
95  else
96  bitmap->sprite_area = malloc(area_size);
97 
98  if (!bitmap->sprite_area)
99  return false;
100 
101  /* area control block */
102  sprite_area = bitmap->sprite_area;
103  sprite_area->size = area_size;
104  sprite_area->sprite_count = 1;
105  sprite_area->first = 16;
106  sprite_area->used = area_size;
107 
108  /* sprite control block */
109  sprite = (osspriteop_header *) (sprite_area + 1);
110  sprite->size = area_size - 16;
111  memset(sprite->name, 0x00, 12);
112  strncpy(sprite->name, "bitmap", 12);
113  sprite->width = bitmap->width - 1;
114  sprite->height = bitmap->height - 1;
115  sprite->left_bit = 0;
116  sprite->right_bit = 31;
117  sprite->image = sprite->mask = 44;
118  sprite->mode = tinct_SPRITE_MODE;
119 
120  return true;
121 }
122 
123 
124 /* exported interface documented in riscos/bitmap.h */
126 {
127  struct bitmap *bitmap;
128 
129  if (width == 0 || height == 0)
130  return NULL;
131 
132  bitmap = calloc(1, sizeof(struct bitmap));
133  if (!bitmap)
134  return NULL;
135  bitmap->width = width;
136  bitmap->height = height;
137  bitmap->opaque = (flags & BITMAP_OPAQUE) == BITMAP_OPAQUE;
138  bitmap->clear = (flags & BITMAP_CLEAR) == BITMAP_CLEAR;
139 
140  return bitmap;
141 }
142 
143 
144 /* exported interface documented in riscos/bitmap.h */
145 unsigned char *riscos_bitmap_get_buffer(void *vbitmap)
146 {
147  struct bitmap *bitmap = (struct bitmap *) vbitmap;
148  assert(bitmap);
149 
150  /* dynamically create the buffer */
151  if (bitmap->sprite_area == NULL) {
152  if (!bitmap_initialise(bitmap))
153  return NULL;
154  }
155 
156  /* image data area should exist */
157  if (bitmap->sprite_area)
158  return ((unsigned char *) (bitmap->sprite_area)) + 16 + 44;
159 
160  return NULL;
161 }
162 
163 
164 /**
165  * Sets whether a bitmap should be plotted opaque
166  *
167  * \param vbitmap a bitmap, as returned by bitmap_create()
168  * \param opaque whether the bitmap should be plotted opaque
169  */
170 static void bitmap_set_opaque(void *vbitmap, bool opaque)
171 {
172  struct bitmap *bitmap = (struct bitmap *) vbitmap;
173  assert(bitmap);
174 
175  bitmap->opaque = opaque;
176 }
177 
178 
179 /**
180  * Find the width of a pixel row in bytes.
181  *
182  * \param vbitmap A bitmap, as returned by riscos_bitmap_create()
183  * \return width of a pixel row in the bitmap
184  */
185 static size_t bitmap_get_rowstride(void *vbitmap)
186 {
187  struct bitmap *bitmap = (struct bitmap *) vbitmap;
188  return bitmap->width * 4;
189 }
190 
191 
192 /**
193  * Tests whether a bitmap has an opaque alpha channel
194  *
195  * \param vbitmap a bitmap, as returned by bitmap_create()
196  * \return whether the bitmap is opaque
197  */
198 static bool bitmap_test_opaque(void *vbitmap)
199 {
200  struct bitmap *bitmap = (struct bitmap *) vbitmap;
201  unsigned char *sprite;
202  unsigned int width, height, size;
203  osspriteop_header *sprite_header;
204  unsigned *p, *ep;
205 
206  assert(bitmap);
207 
208  sprite = riscos_bitmap_get_buffer(bitmap);
209  if (!sprite)
210  return false;
211 
212  width = bitmap_get_rowstride(bitmap);
213 
214  sprite_header = (osspriteop_header *) (bitmap->sprite_area + 1);
215 
216  height = (sprite_header->height + 1);
217 
218  size = width * height;
219 
220  p = (void *) sprite;
221 
222  ep = (void *) (sprite + (size & ~31));
223  while (p < ep) {
224  /* \todo prefetch(p, 128)? */
225  if (((p[0] & p[1] & p[2] & p[3] & p[4] & p[5] & p[6] & p[7])
226  & 0xff000000U) != 0xff000000U)
227  return false;
228  p += 8;
229  }
230 
231  ep = (void *) (sprite + size);
232  while (p < ep) {
233  if ((*p & 0xff000000U) != 0xff000000U) return false;
234  p++;
235  }
236 
237  return true;
238 }
239 
240 
241 /* exported interface documented in riscos/bitmap.h */
242 bool riscos_bitmap_get_opaque(void *vbitmap)
243 {
244  struct bitmap *bitmap = (struct bitmap *) vbitmap;
245  assert(bitmap);
246  return bitmap->opaque;
247 }
248 
249 
250 /* exported interface documented in riscos/bitmap.h */
251 void riscos_bitmap_destroy(void *vbitmap)
252 {
253  struct bitmap *bitmap = (struct bitmap *) vbitmap;
254 
255  assert(bitmap);
256 
257  /* destroy bitmap */
258  if (bitmap->sprite_area) {
259  free(bitmap->sprite_area);
260  }
261 
262  free(bitmap);
263 }
264 
265 
266 /* exported interface documented in riscos/bitmap.h */
267 bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
268 {
269  struct bitmap *bitmap = (struct bitmap *) vbitmap;
270  os_error *error;
271 
272  if (bitmap == NULL) {
273  ro_warn_user("SaveError", messages_get("SprIsNull"));
274  return false;
275  }
276 
277  if (!bitmap->sprite_area) {
278  riscos_bitmap_get_buffer(bitmap);
279  }
280  if (!bitmap->sprite_area)
281  return false;
282 
283  if (riscos_bitmap_get_opaque(bitmap)) {
284  error = xosspriteop_save_sprite_file(osspriteop_USER_AREA,
285  (bitmap->sprite_area), path);
286  if (error) {
287  NSLOG(netsurf, INFO,
288  "xosspriteop_save_sprite_file: 0x%x: %s",
289  error->errnum,
290  error->errmess);
291  ro_warn_user("SaveError", error->errmess);
292  return false;
293  }
294  return true;
295  } else {
296  /* to make the saved sprite useful we must convert from 'Tinct'
297  * format to either a bi-level mask or a Select-style full
298  * alpha channel */
299  osspriteop_area *area = bitmap->sprite_area;
300  osspriteop_header *hdr = (void *) ((char *) area + area->first);
301  unsigned width = hdr->width + 1, height = hdr->height + 1;
302  unsigned image_size = height * width * 4;
303  unsigned char *chunk_buf;
304  unsigned *p, *elp, *eip;
305  unsigned mask_size;
306  size_t chunk_pix;
307  struct {
308  osspriteop_area area;
309  osspriteop_header hdr;
310  } file_hdr;
311  os_fw fw;
312 
313  /* we only support 32bpp sprites */
314  if ((((unsigned)hdr->mode >> 27)&15) != 6) {
315  assert(!"Unsupported sprite format in bitmap_save");
316  return false;
317  }
318 
319  chunk_buf = malloc(SAVE_CHUNK_SIZE);
320  if (!chunk_buf) {
321  ro_warn_user("NoMemory", NULL);
322  return false;
323  }
324 
325  file_hdr.area = *area;
326  file_hdr.hdr = *hdr;
327 
328  if (flags & BITMAP_SAVE_FULL_ALPHA) {
329  mask_size = ((width + 3) & ~3) * height;
330  chunk_pix = SAVE_CHUNK_SIZE;
331  file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode
332  | (1U<<31));
333  } else {
334  mask_size = (((width + 31) & ~31)/8) * height;
335  chunk_pix = SAVE_CHUNK_SIZE<<3;
336  file_hdr.hdr.mode = (os_mode)((unsigned)file_hdr.hdr.mode
337  & ~(1U<<31));
338  }
339 
340  file_hdr.area.sprite_count = 1;
341  file_hdr.area.first = sizeof(file_hdr.area);
342  file_hdr.area.used = sizeof(file_hdr) + image_size + mask_size;
343 
344  file_hdr.hdr.image = sizeof(file_hdr.hdr);
345  file_hdr.hdr.mask = file_hdr.hdr.image + image_size;
346  file_hdr.hdr.size = file_hdr.hdr.mask + mask_size;
347 
348  error = xosfind_openoutw(0, path, NULL, &fw);
349  if (error) {
350  NSLOG(netsurf, INFO, "xosfind_openoutw: 0x%x: %s",
351  error->errnum, error->errmess);
352  free(chunk_buf);
353  ro_warn_user("SaveError", error->errmess);
354  return false;
355  }
356 
357  p = (void *) ((char *) hdr + hdr->image);
358 
359  /* write out the area header, sprite header and image data */
360  error = xosgbpb_writew(fw, (byte*)&file_hdr + 4,
361  sizeof(file_hdr)-4, NULL);
362  if (!error)
363  error = xosgbpb_writew(fw, (byte*)p, image_size, NULL);
364  if (error) {
365  NSLOG(netsurf, INFO, "xosgbpb_writew: 0x%x: %s",
366  error->errnum, error->errmess);
367  free(chunk_buf);
368  xosfind_closew(fw);
369  ro_warn_user("SaveError", error->errmess);
370  return false;
371  }
372 
373  /* then write out the mask data in chunks */
374  eip = p + (width * height); /* end of image */
375  elp = p + width; /* end of line */
376 
377  while (p < eip) {
378  unsigned char *dp = chunk_buf;
379  unsigned *ep = p + chunk_pix;
380  if (ep > elp) ep = elp;
381 
382  if (flags & BITMAP_SAVE_FULL_ALPHA) {
383  while (p < ep) {
384  *dp++ = ((unsigned char*)p)[3];
385  p++;
386  }
387  }
388  else {
389  unsigned char mb = 0;
390  int msh = 0;
391  while (p < ep) {
392  if (((unsigned char*)p)[3]) mb |= (1 << msh);
393  if (++msh >= 8) {
394  *dp++ = mb;
395  msh = 0;
396  mb = 0;
397  }
398  p++;
399  }
400  if (msh > 0) *dp++ = mb;
401  }
402 
403  if (p >= elp) { /* end of line yet? */
404  /* align to word boundary */
405  while ((int)dp & 3) *dp++ = 0;
406  /* advance end of line pointer */
407  elp += width;
408  }
409  error = xosgbpb_writew(fw, (byte*)chunk_buf, dp-chunk_buf, NULL);
410  if (error) {
411  NSLOG(netsurf, INFO,
412  "xosgbpb_writew: 0x%x: %s",
413  error->errnum,
414  error->errmess);
415  free(chunk_buf);
416  xosfind_closew(fw);
417  ro_warn_user("SaveError", error->errmess);
418  return false;
419  }
420  }
421 
422  error = xosfind_closew(fw);
423  if (error) {
424  NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
425  error->errnum, error->errmess);
426  ro_warn_user("SaveError", error->errmess);
427  }
428 
429  error = xosfile_set_type(path, osfile_TYPE_SPRITE);
430  if (error) {
431  NSLOG(netsurf, INFO, "xosfile_set_type: 0x%x: %s",
432  error->errnum, error->errmess);
433  ro_warn_user("SaveError", error->errmess);
434  }
435 
436  free(chunk_buf);
437  return true;
438  }
439 }
440 
441 
442 /**
443  * The bitmap image has changed, so flush any persistent cache.
444  *
445  * \param vbitmap a bitmap, as returned by bitmap_create()
446  */
447 static void bitmap_modified(void *vbitmap)
448 {
449  (void)(vbitmap);
450 }
451 
452 
453 /**
454  * Get the width of a bitmap.
455  *
456  * \param vbitmap A bitmap, as returned by bitmap_create()
457  * \return The bitmaps width in pixels.
458  */
459 static int bitmap_get_width(void *vbitmap)
460 {
461  struct bitmap *bitmap = (struct bitmap *) vbitmap;
462  return bitmap->width;
463 }
464 
465 
466 /**
467  * Get the height of a bitmap.
468  *
469  * \param vbitmap A bitmap, as returned by bitmap_create()
470  * \return The bitmaps height in pixels.
471  */
472 static int bitmap_get_height(void *vbitmap)
473 {
474  struct bitmap *bitmap = (struct bitmap *) vbitmap;
475  return bitmap->height;
476 }
477 
478 
479 /* exported interface documented in riscos/bitmap.h */
481  const osspriteop_header *s)
482 {
483  const os_colour *palette;
484  const byte *sp, *mp;
485  bool masked = false;
486  bool alpha = false;
487  os_error *error;
488  int dp_offset;
489  int sp_offset;
490  unsigned *dp;
491  int x, y;
492  int w, h;
493 
494  assert(sprite_bpp(s) == 8);
495 
496  if ((unsigned)s->mode & 0x80000000U)
497  alpha = true;
498 
499  error = xosspriteop_read_sprite_info(osspriteop_PTR,
500  (osspriteop_area *)0x100,
501  (osspriteop_id)s,
502  &w, &h, NULL, NULL);
503  if (error) {
504  NSLOG(netsurf, INFO, "xosspriteop_read_sprite_info: 0x%x:%s",
505  error->errnum, error->errmess);
506  return;
507  }
508  sp_offset = ((s->width + 1) * 4) - w;
509 
510  if (w > bitmap->width)
511  w = bitmap->width;
512  if (h > bitmap->height)
513  h = bitmap->height;
514 
515  dp_offset = bitmap_get_rowstride(bitmap) / 4;
516 
517  dp = (void*)riscos_bitmap_get_buffer(bitmap);
518  if (!dp)
519  return;
520  sp = (byte*)s + s->image;
521  mp = (byte*)s + s->mask;
522 
523  sp += s->left_bit / 8;
524  mp += s->left_bit / 8;
525 
526  if (s->image > (int)sizeof(*s))
527  palette = (os_colour*)(s + 1);
528  else
529  palette = default_palette8;
530 
531  if (s->mask != s->image) {
532  masked = true;
533  bitmap_set_opaque(bitmap, false);
534  }
535 
536  /* (partially-)transparent pixels in the overlayed sprite retain
537  * their transparency in the output bitmap; opaque sprite pixels
538  * are also propagated to the bitmap, except those which are the
539  * OVERLAY_INDEX colour which allow the original bitmap contents to
540  * show through */
541  for (y = 0; y < h; y++) {
542  unsigned *sdp = dp;
543  for(x = 0; x < w; x++) {
544  os_colour d = ((unsigned)palette[(*sp) << 1]) >> 8;
545  if (*sp++ == OVERLAY_INDEX)
546  d = *dp;
547  if (masked) {
548  if (alpha)
549  d |= ((*mp << 24) ^ 0xff000000U);
550  else if (*mp)
551  d |= 0xff000000U;
552  }
553  *dp++ = d;
554  mp++;
555  }
556  dp = sdp + dp_offset;
557  sp += sp_offset;
558  mp += sp_offset;
559  }
560 }
561 
562 
563 /**
564  * Creates an 8bpp canvas.
565  *
566  * \param bitmap the bitmap to clone the size of
567  * \return a sprite area containing an 8bpp sprite
568  */
569 static osspriteop_area *thumbnail_create_8bpp(struct bitmap *bitmap)
570 {
571  unsigned image_size = ((bitmap->width + 3) & ~3) * bitmap->height;
572  bool opaque = riscos_bitmap_get_opaque(bitmap);
573  osspriteop_header *sprite_header = NULL;
574  osspriteop_area *sprite_area = NULL;
575  unsigned area_size;
576 
577  /* clone the sprite */
578  area_size = sizeof(osspriteop_area) +
579  sizeof(osspriteop_header) +
580  image_size +
581  2048;
582 
583  if (!opaque) area_size += image_size;
584 
585  sprite_area = (osspriteop_area *)malloc(area_size);
586  if (!sprite_area) {
587  NSLOG(netsurf, INFO, "no memory for malloc()");
588  return NULL;
589  }
590  sprite_area->size = area_size;
591  sprite_area->sprite_count = 1;
592  sprite_area->first = 16;
593  sprite_area->used = area_size;
594  sprite_header = (osspriteop_header *)(sprite_area + 1);
595  sprite_header->size = area_size - sizeof(osspriteop_area);
596  memset(sprite_header->name, 0x00, 12);
597  strcpy(sprite_header->name, "bitmap");
598  sprite_header->left_bit = 0;
599  sprite_header->height = bitmap->height - 1;
600  sprite_header->mode = os_MODE8BPP90X90;
601  sprite_header->right_bit = ((bitmap->width << 3) - 1) & 31;
602  sprite_header->width = ((bitmap->width + 3) >> 2) - 1;
603  sprite_header->image = sizeof(osspriteop_header) + 2048;
604  sprite_header->mask = sizeof(osspriteop_header) + 2048;
605  if (!opaque) sprite_header->mask += image_size;
606 
607  /* create the palette. we don't read the necessary size like
608  * we really should as we know it's going to have 256 entries
609  * of 8 bytes = 2048. */
610  xcolourtrans_read_palette((osspriteop_area *)os_MODE8BPP90X90,
611  (osspriteop_id)0,
612  (os_palette *)(sprite_header + 1), 2048,
613  (colourtrans_palette_flags)(1 << 1), 0);
614  return sprite_area;
615 }
616 
617 
618 /**
619  * Switches output to the specified sprite and returns the previous context.
620  */
621 static struct thumbnail_save_area*
622 thumbnail_switch_output(osspriteop_area *sprite_area,
623  osspriteop_header *sprite_header)
624 {
626  int size;
627 
628  /* create a save area */
629  save_area = calloc(sizeof(struct thumbnail_save_area), 1);
630  if (save_area == NULL) return NULL;
631 
632  /* allocate OS_SpriteOp save area */
633  if (xosspriteop_read_save_area_size(osspriteop_PTR, sprite_area,
634  (osspriteop_id)sprite_header, &size)) {
635  free(save_area);
636  return NULL;
637  }
638 
639  /* create the save area */
640  save_area->save_area = malloc((unsigned)size);
641  if (save_area->save_area == NULL) {
642  free(save_area);
643  return NULL;
644  }
645  save_area->save_area->a[0] = 0;
646 
647  /* switch output to sprite */
648  if (xosspriteop_switch_output_to_sprite(osspriteop_PTR, sprite_area,
649  (osspriteop_id)sprite_header, save_area->save_area,
650  0, &save_area->context1, &save_area->context2,
651  &save_area->context3)) {
652  free(save_area->save_area);
653  free(save_area);
654  return NULL;
655  }
656  return save_area;
657 }
658 
659 
660 /**
661  * Restores output to the specified context, and destroys it.
662  */
664 {
665  /* we don't care if we err, as there's nothing we can do about it */
666  xosspriteop_switch_output_to_sprite(osspriteop_PTR,
667  (osspriteop_area *)save_area->context1,
668  (osspriteop_id)save_area->context2,
669  (osspriteop_save_area *)save_area->context3,
670  0, 0, 0, 0);
671  free(save_area->save_area);
672  free(save_area);
673 }
674 
675 
676 /**
677  * Convert a bitmap to 8bpp.
678  *
679  * \param bitmap the bitmap to convert
680  * \return a sprite area containing an 8bpp sprite
681  */
682 osspriteop_area *riscos_bitmap_convert_8bpp(struct bitmap *bitmap)
683 {
685  osspriteop_area *sprite_area = NULL;
686  osspriteop_header *sprite_header = NULL;
687 
688  sprite_area = thumbnail_create_8bpp(bitmap);
689  if (!sprite_area)
690  return NULL;
691  sprite_header = (osspriteop_header *)(sprite_area + 1);
692 
693 
694  /* switch output and redraw */
695  save_area = thumbnail_switch_output(sprite_area, sprite_header);
696  if (save_area == NULL) {
697  if (thumbnail_32bpp_available != 1)
698  free(sprite_area);
699  return false;
700  }
701  _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
702  (osspriteop_header *)(bitmap->sprite_area + 1),
703  0, 0,
705  thumbnail_restore_output(save_area);
706 
707  if (sprite_header->image != sprite_header->mask) {
708  /* build the sprite mask from the alpha channel */
709  void *buf = riscos_bitmap_get_buffer(bitmap);
710  unsigned *dp = (unsigned *) buf;
711  if (!dp)
712  return sprite_area;
713  int w = bitmap_get_width(bitmap);
714  int h = bitmap_get_height(bitmap);
715  int dp_offset = bitmap_get_rowstride(bitmap) / 4 - w;
716  int mp_offset = ((sprite_header->width + 1) * 4) - w;
717  byte *mp = (byte*)sprite_header + sprite_header->mask;
718  bool alpha = ((unsigned)sprite_header->mode & 0x80000000U) != 0;
719 
720  while (h-- > 0) {
721  int x = 0;
722  for(x = 0; x < w; x++) {
723  unsigned d = *dp++;
724  if (alpha)
725  *mp++ = (d >> 24) ^ 0xff;
726  else
727  *mp++ = (d < 0xff000000U) ? 0 : 0xff;
728  }
729  dp += dp_offset;
730  mp += mp_offset;
731  }
732  }
733 
734  return sprite_area;
735 }
736 
737 
738 
739 
740 /**
741  * Check to see whether 32bpp sprites are available.
742  *
743  * Rather than using Wimp_ReadSysInfo we test if 32bpp sprites are available
744  * in case the user has a 3rd party patch to enable them.
745  */
746 static void thumbnail_test(void)
747 {
748  unsigned int area_size;
749  osspriteop_area *sprite_area;
750 
751  /* try to create a 1x1 32bpp sprite */
752  area_size = sizeof(osspriteop_area) +
753  sizeof(osspriteop_header) + sizeof(int);
754  if ((sprite_area = (osspriteop_area *)malloc(area_size)) == NULL) {
755  NSLOG(netsurf, INFO,
756  "Insufficient memory to perform sprite test.");
757  return;
758  }
759  sprite_area->size = area_size + 1;
760  sprite_area->sprite_count = 0;
761  sprite_area->first = 16;
762  sprite_area->used = 16;
763  if (xosspriteop_create_sprite(osspriteop_NAME, sprite_area,
764  "test", false, 1, 1, (os_mode)tinct_SPRITE_MODE))
766  else
768  free(sprite_area);
769 }
770 
771 
772 /* exported interface documented in riscos/bitmap.h */
774  struct hlcache_handle *content)
775 {
777  osspriteop_area *sprite_area = NULL;
778  osspriteop_header *sprite_header = NULL;
779  struct redraw_context ctx = {
780  .interactive = false,
781  .background_images = true,
782  .plot = &ro_plotters
783  };
784 
785  assert(content);
786  assert(bitmap);
787 
788  NSLOG(netsurf, INFO, "content %p in bitmap %p", content, bitmap);
789 
790  /* check if we have access to 32bpp sprites natively */
791  if (thumbnail_32bpp_available == -1) {
792  thumbnail_test();
793  }
794 
795  /* if we don't support 32bpp sprites then we redirect to an 8bpp
796  * image and then convert back.
797  */
798  if (thumbnail_32bpp_available != 1) {
799  sprite_area = thumbnail_create_8bpp(bitmap);
800  if (!sprite_area)
801  return false;
802  sprite_header = (osspriteop_header *)(sprite_area + 1);
803  } else {
804  const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap);
805  if (!pixbufp || !bitmap->sprite_area)
806  return false;
807  sprite_area = bitmap->sprite_area;
808  sprite_header = (osspriteop_header *)(sprite_area + 1);
809  }
810 
811  /* set up the plotters */
812  ro_plot_origin_x = 0;
813  ro_plot_origin_y = bitmap->height * 2;
814 
815  /* switch output and redraw */
816  save_area = thumbnail_switch_output(sprite_area, sprite_header);
817  if (!save_area) {
818  if (thumbnail_32bpp_available != 1)
819  free(sprite_area);
820  return false;
821  }
822  rufl_invalidate_cache();
823  colourtrans_set_gcol(os_COLOUR_WHITE, colourtrans_SET_BG_GCOL,
824  os_ACTION_OVERWRITE, 0);
825 
826  /* render the content */
827  content_scaled_redraw(content, bitmap->width, bitmap->height, &ctx);
828 
829  thumbnail_restore_output(save_area);
830  rufl_invalidate_cache();
831 
832  /* if we changed to 8bpp then go back to 32bpp */
833  if (thumbnail_32bpp_available != 1) {
834  const uint8_t *pixbufp = riscos_bitmap_get_buffer(bitmap);
835  _kernel_oserror *error;
836 
837  if (!pixbufp || !bitmap->sprite_area) {
838  free(sprite_area);
839  return false;
840  }
841  error = _swix(Tinct_ConvertSprite, _INR(2,3),
842  sprite_header,
843  (osspriteop_header *)(bitmap->sprite_area + 1));
844  free(sprite_area);
845  if (error)
846  return false;
847  }
848 
849  bitmap_modified(bitmap);
850 
851  return NSERROR_OK;
852 }
853 
856  .destroy = riscos_bitmap_destroy,
857  .set_opaque = bitmap_set_opaque,
858  .get_opaque = riscos_bitmap_get_opaque,
859  .test_opaque = bitmap_test_opaque,
860  .get_buffer = riscos_bitmap_get_buffer,
861  .get_rowstride = bitmap_get_rowstride,
862  .get_width = bitmap_get_width,
863  .get_height = bitmap_get_height,
864  .modified = bitmap_modified,
865  .render = riscos_bitmap_render,
866 };
867 
Target independent plotting interface.
int bitmap_get_height(void *bitmap)
get height of a bitmap.
Definition: bitmap.c:355
const struct plotter_table ro_plotters
RISC OS plotter operation table.
Definition: plotters.c:727
#define Tinct_ConvertSprite
Converts a paletted sprite into its 32bpp equivalent.
Definition: tinct.h:90
Interface to utility string handling.
static bool bitmap_test_opaque(void *vbitmap)
Tests whether a bitmap has an opaque alpha channel.
Definition: bitmap.c:198
static struct gui_bitmap_table bitmap_table
Definition: bitmap.c:854
Localised message support (interface).
Public content interface.
static void thumbnail_test(void)
Check to see whether 32bpp sprites are available.
Definition: bitmap.c:746
#define OVERLAY_INDEX
Colour in the overlay sprite that allows the bitmap to show through.
Definition: bitmap.c:57
#define Tinct_Plot
Plots a sprite at the specified coordinates with a constant 0xff value for the alpha channel...
Definition: tinct.h:64
static nserror bitmap(const struct redraw_context *ctx, struct bitmap *bitmap, int x, int y, int width, int height, colour bg, bitmap_flags_t flags)
Plot a bitmap.
Definition: plot.c:857
int ro_plot_origin_x
Definition: plotters.c:40
bool riscos_bitmap_get_opaque(void *vbitmap)
Gets whether a bitmap should be plotted opaque.
Definition: bitmap.c:242
static void bitmap_set_opaque(void *vbitmap, bool opaque)
Sets whether a bitmap should be plotted opaque.
Definition: bitmap.c:170
#define colourtrans_SET_BG_GCOL
After OSLib 6.90, there was a rename of colourtrans defines in order to avoid namespace clashes: svn ...
Definition: oslib_pre7.h:36
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
Option reading and saving interface.
static size_t bitmap_get_rowstride(void *vbitmap)
Find the width of a pixel row in bytes.
Definition: bitmap.c:185
nserror
Enumeration of error codes.
Definition: errors.h:29
int height
height of bitmap
Definition: bitmap.c:70
Palette definitions for sprites.
image is opaque
Definition: bitmap.h:60
Tinct SWI numbers and flags for version 0.11.
High-level cache handle.
Definition: hlcache.c:65
Content which corresponds to a single URL.
static bool bitmap_initialise(struct bitmap *bitmap)
Initialise a bitmaps sprite area.
Definition: bitmap.c:84
bool clear
Whether the bitmap should be initialised to zeros.
Definition: bitmap.h:43
struct osspriteop_area * sprite_area
Uncompressed data, or NULL.
Definition: bitmap.h:45
No error.
Definition: errors.h:30
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:115
uint32 size
Definition: bitmap.c:73
RISC OS wimp toolkit bitmap.
Definition: bitmap.c:68
struct gui_bitmap_table * riscos_bitmap_table
bitmap operations table
Definition: bitmap.c:868
static void thumbnail_restore_output(struct thumbnail_save_area *save_area)
Restores output to the specified context, and destroys it.
Definition: bitmap.c:663
void * riscos_bitmap_create(int width, int height, enum gui_bitmap_flags flags)
Create a bitmap.
Definition: bitmap.c:125
gui_bitmap_flags
Bitmap creation flags.
Definition: bitmap.h:58
Bitmap operations.
Definition: bitmap.h:71
memory should be wiped to 0
Definition: bitmap.h:61
static struct thumbnail_save_area * thumbnail_switch_output(osspriteop_area *sprite_area, osspriteop_header *sprite_header)
Switches output to the specified sprite and returns the previous context.
Definition: bitmap.c:622
byte sprite_bpp(const osspriteop_header *s)
Returns the bit depth of a sprite.
Definition: sprite.c:249
int ro_plot_origin_y
Definition: plotters.c:41
Redraw context.
Definition: plotters.h:51
bool opaque
Whether the bitmap is opaque.
Definition: bitmap.c:74
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
int height
Definition: gui.c:181
bool riscos_bitmap_save(void *vbitmap, const char *path, unsigned flags)
Save a bitmap in the platform&#39;s native format.
Definition: bitmap.c:267
#define SAVE_CHUNK_SIZE
Size of buffer used when constructing mask data to be saved.
Definition: bitmap.c:60
#define tinct_SPRITE_MODE
Definition: tinct.h:156
Sprite output context saving.
Definition: bitmap.c:70
static void bitmap_modified(void *vbitmap)
The bitmap image has changed, so flush any persistent cache.
Definition: bitmap.c:447
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
int width
width of bitmap
Definition: bitmap.c:69
void riscos_bitmap_destroy(void *vbitmap)
Free a bitmap.
Definition: bitmap.c:251
nserror riscos_bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
Render content into bitmap.
Definition: bitmap.c:773
Content for image/x-riscos-sprite (RISC OS interface).
static osspriteop_area * thumbnail_create_8bpp(struct bitmap *bitmap)
Creates an 8bpp canvas.
Definition: bitmap.c:569
nserror ro_warn_user(const char *warning, const char *detail)
Display a warning for a serious problem (eg memory exhaustion).
Definition: gui.c:2140
int bitmap_get_width(void *bitmap)
get width of a bitmap.
Definition: bitmap.c:338
osspriteop_area * riscos_bitmap_convert_8bpp(struct bitmap *bitmap)
Convert a bitmap to 8bpp.
Definition: bitmap.c:682
static int thumbnail_32bpp_available
Whether we can use 32bpp sprites.
Definition: bitmap.c:65
bool content_scaled_redraw(struct hlcache_handle *h, int width, int height, const struct redraw_context *ctx)
Redraw a content with scale set for horizontal fit.
Definition: content.c:583
unsigned char * riscos_bitmap_get_buffer(void *vbitmap)
Return a pointer to the pixel data in a bitmap.
Definition: bitmap.c:145
int width
Definition: gui.c:180
const os_colour default_palette8[]
Definition: palettes.c:63
osspriteop_save_area * save_area
Definition: bitmap.c:71
#define BITMAP_SAVE_FULL_ALPHA
save with full alpha channel (if not opaque)
Definition: bitmap.h:33
void riscos_bitmap_overlay_sprite(struct bitmap *bitmap, const osspriteop_header *s)
Definition: bitmap.c:480
void *(* create)(int width, int height, enum gui_bitmap_flags flags)
Create a new bitmap.
Definition: bitmap.h:82
#define tinct_ERROR_DIFFUSE
Definition: tinct.h:136