1 /*
2  * Copyright 2008 François Revol <mmu_man@users.sourceforge.net>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * \file
21  * BeOS implementation of generic bitmaps.
22  *
23  * This implements the interface given by image/bitmap.h using BBitmap.
24  */
25 
26 #define __STDBOOL_H__	1
27 #include <assert.h>
28 #include <sys/param.h>
29 #include <string.h>
30 #include <Bitmap.h>
31 #include <BitmapStream.h>
32 #include <File.h>
33 #include <GraphicsDefs.h>
34 #include <TranslatorFormats.h>
35 #include <TranslatorRoster.h>
36 #include <View.h>
37 #include <stdlib.h>
38 
39 extern "C" {
40 #include "utils/log.h"
41 #include "netsurf/plotters.h"
42 #include "netsurf/content_type.h"
43 #include "netsurf/browser_window.h"
44 #include "netsurf/bitmap.h"
45 #include "netsurf/content.h"
46 }
47 
48 #include "beos/bitmap.h"
49 #include "beos/gui.h"
50 #include "beos/scaffolding.h"
51 #include "beos/plotters.h"
52 
53 
54 struct bitmap {
55         BBitmap *primary;
56         BBitmap *shadow; // in NetSurf's ABGR order
57         BBitmap *pretile_x;
58         BBitmap *pretile_y;
59         BBitmap *pretile_xy;
60         bool opaque;
61 };
62 
63 #define MIN_PRETILE_WIDTH 256
64 #define MIN_PRETILE_HEIGHT 256
65 
66 #warning TODO: check rgba order
67 #warning TODO: add correct locking (not strictly required)
68 
69 
70 /**
71  * Convert to BeOS RGBA32_LITTLE (strictly BGRA) from NetSurf's favoured ABGR format.
72  *
73  * Copies the converted data elsewhere.  Operation is rotate left 8 bits.
74  *
75  * \param src       Source 32-bit pixels arranged in ABGR order.
76  * \param dst       Output data in BGRA order.
77  * \param width     Width of the bitmap
78  * \param height    Height of the bitmap
79  * \param rowstride Number of bytes to skip after each row (this implementation
80  *                  requires this to be a multiple of 4.)
81  */
nsbeos_rgba_to_bgra(void * src,void * dst,int width,int height,size_t rowstride)82 static inline void nsbeos_rgba_to_bgra(void *src,
83                                        void *dst,
84                                        int width,
85                                        int height,
86                                        size_t rowstride)
87 {
88         struct abgr { uint8 a, b, g, r; };
89         struct rgba { uint8 r, g, b ,a; };
90         struct bgra { uint8 b, g, r, a; };
91         struct rgba *from = (struct rgba *)src;
92         struct bgra *to = (struct bgra *)dst;
93 
94         rowstride >>= 2;
95 
96         for (int y = 0; y < height; y++) {
97                 for (int x = 0; x < width; x++) {
98                         to[x].b = from[x].b;
99                         to[x].g = from[x].g;
100                         to[x].r = from[x].r;
101                         to[x].a = from[x].a;
102                         /*
103                           if (from[x].a == 0)
104                           *(rgb_color *)&to[x] = B_TRANSPARENT_32_BIT;
105                           */
106                 }
107                 from += rowstride;
108                 to += rowstride;
109         }
110 }
111 
112 
113 /**
114  * Create a bitmap.
115  *
116  * \param  width   width of image in pixels
117  * \param  height  width of image in pixels
118  * \param  state   a flag word indicating the initial state
119  * \return an opaque struct bitmap, or NULL on memory exhaustion
120  */
bitmap_create(int width,int height,unsigned int state)121 static void *bitmap_create(int width, int height, unsigned int state)
122 {
123         struct bitmap *bmp = (struct bitmap *)malloc(sizeof(struct bitmap));
124         if (bmp == NULL)
125                 return NULL;
126 
127         int32 flags = 0;
128         if (state & BITMAP_CLEAR_MEMORY)
129                 flags |= B_BITMAP_CLEAR_TO_WHITE;
130 
131         BRect frame(0, 0, width - 1, height - 1);
132         //XXX: bytes per row ?
133         bmp->primary = new BBitmap(frame, flags, B_RGBA32);
134         bmp->shadow = new BBitmap(frame, flags, B_RGBA32);
135 
136         bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL;
137 
138         bmp->opaque = (state & BITMAP_OPAQUE) != 0;
139 
140         return bmp;
141 }
142 
143 
144 /**
145  * Sets whether a bitmap should be plotted opaque
146  *
147  * \param  vbitmap  a bitmap, as returned by bitmap_create()
148  * \param  opaque   whether the bitmap should be plotted opaque
149  */
bitmap_set_opaque(void * vbitmap,bool opaque)150 static void bitmap_set_opaque(void *vbitmap, bool opaque)
151 {
152         struct bitmap *bitmap = (struct bitmap *)vbitmap;
153         assert(bitmap);
154         bitmap->opaque = opaque;
155 }
156 
157 
158 /**
159  * Tests whether a bitmap has an opaque alpha channel
160  *
161  * \param  vbitmap  a bitmap, as returned by bitmap_create()
162  * \return whether  the bitmap is opaque
163  */
bitmap_test_opaque(void * vbitmap)164 static bool bitmap_test_opaque(void *vbitmap)
165 {
166         struct bitmap *bitmap = (struct bitmap *)vbitmap;
167         assert(bitmap);
168         /* todo: test if bitmap is opaque */
169         return false;
170 }
171 
172 
173 /**
174  * Gets whether a bitmap should be plotted opaque
175  *
176  * \param  vbitmap  a bitmap, as returned by bitmap_create()
177  */
bitmap_get_opaque(void * vbitmap)178 static bool bitmap_get_opaque(void *vbitmap)
179 {
180         struct bitmap *bitmap = (struct bitmap *)vbitmap;
181         assert(bitmap);
182         return bitmap->opaque;
183 }
184 
185 
186 /**
187  * Return a pointer to the pixel data in a bitmap.
188  *
189  * \param  vbitmap  a bitmap, as returned by bitmap_create()
190  * \return pointer to the pixel buffer
191  *
192  * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
193  * of rows. The width of a row in bytes is given by bitmap_get_rowstride().
194  */
195 
bitmap_get_buffer(void * vbitmap)196 static unsigned char *bitmap_get_buffer(void *vbitmap)
197 {
198         struct bitmap *bitmap = (struct bitmap *)vbitmap;
199         assert(bitmap);
200         return (unsigned char *)(bitmap->shadow->Bits());
201 }
202 
203 
204 /**
205  * Find the width of a pixel row in bytes.
206  *
207  * \param  vbitmap  a bitmap, as returned by bitmap_create()
208  * \return width of a pixel row in the bitmap
209  */
bitmap_get_rowstride(void * vbitmap)210 static size_t bitmap_get_rowstride(void *vbitmap)
211 {
212         struct bitmap *bitmap = (struct bitmap *)vbitmap;
213         assert(bitmap);
214         return (bitmap->primary->BytesPerRow());
215 }
216 
217 
218 /**
219  * Find the bytes per pixels of a bitmap.
220  *
221  * \param  vbitmap  a bitmap, as returned by bitmap_create()
222  * \return bytes per pixels of the bitmap
223  */
bitmap_get_bpp(void * vbitmap)224 static size_t bitmap_get_bpp(void *vbitmap)
225 {
226         struct bitmap *bitmap = (struct bitmap *)vbitmap;
227         assert(bitmap);
228         return 4;
229 }
230 
231 
232 /**
233  * Free pretiles of a bitmap.
234  *
235  * \param bitmap The bitmap to free the pretiles of.
236  */
nsbeos_bitmap_free_pretiles(struct bitmap * bitmap)237 static void nsbeos_bitmap_free_pretiles(struct bitmap *bitmap)
238 {
239 #define FREE_TILE(XY) if (bitmap->pretile_##XY) delete (bitmap->pretile_##XY); bitmap->pretile_##XY = NULL
240         FREE_TILE(x);
241         FREE_TILE(y);
242         FREE_TILE(xy);
243 #undef FREE_TILE
244 }
245 
246 
247 /**
248  * Free a bitmap.
249  *
250  * \param  vbitmap  a bitmap, as returned by bitmap_create()
251  */
bitmap_destroy(void * vbitmap)252 static void bitmap_destroy(void *vbitmap)
253 {
254         struct bitmap *bitmap = (struct bitmap *)vbitmap;
255         assert(bitmap);
256         nsbeos_bitmap_free_pretiles(bitmap);
257         delete bitmap->primary;
258         delete bitmap->shadow;
259         free(bitmap);
260 }
261 
262 
263 /**
264  * Save a bitmap in the platform's native format.
265  *
266  * \param  vbitmap  a bitmap, as returned by bitmap_create()
267  * \param  path     pathname for file
268  * \param  flags    modify the behaviour of the save
269  * \return true on success, false on error and error reported
270  */
bitmap_save(void * vbitmap,const char * path,unsigned flags)271 static bool bitmap_save(void *vbitmap, const char *path, unsigned flags)
272 {
273         struct bitmap *bitmap = (struct bitmap *)vbitmap;
274         BTranslatorRoster *roster = BTranslatorRoster::Default();
275         BBitmapStream stream(bitmap->primary);
276         BFile file(path, B_WRITE_ONLY | B_CREATE_FILE);
277         uint32 type = B_PNG_FORMAT;
278 
279         if (file.InitCheck() < B_OK)
280                 return false;
281 
282         if (roster->Translate(&stream, NULL, NULL, &file, type) < B_OK)
283                 return false;
284 
285         return true;
286 }
287 
288 
289 /**
290  * The bitmap image has changed, so flush any persistant cache.
291  *
292  * \param  vbitmap  a bitmap, as returned by bitmap_create()
293  */
bitmap_modified(void * vbitmap)294 void bitmap_modified(void *vbitmap)
295 {
296         struct bitmap *bitmap = (struct bitmap *)vbitmap;
297         // convert the shadow (ABGR) to into the primary bitmap
298         nsbeos_rgba_to_bgra(bitmap->shadow->Bits(), bitmap->primary->Bits(),
299                             bitmap->primary->Bounds().Width() + 1,
300                             bitmap->primary->Bounds().Height() + 1,
301                             bitmap->primary->BytesPerRow());
302         nsbeos_bitmap_free_pretiles(bitmap);
303 }
304 
305 
bitmap_get_width(void * vbitmap)306 static int bitmap_get_width(void *vbitmap)
307 {
308         struct bitmap *bitmap = (struct bitmap *)vbitmap;
309         return bitmap->primary->Bounds().Width() + 1;
310 }
311 
312 
bitmap_get_height(void * vbitmap)313 static int bitmap_get_height(void *vbitmap)
314 {
315         struct bitmap *bitmap = (struct bitmap *)vbitmap;
316         return bitmap->primary->Bounds().Height() + 1;
317 }
318 
319 
320 static BBitmap *
nsbeos_bitmap_generate_pretile(BBitmap * primary,int repeat_x,int repeat_y)321 nsbeos_bitmap_generate_pretile(BBitmap *primary, int repeat_x, int repeat_y)
322 {
323         int width = primary->Bounds().Width() + 1;
324         int height = primary->Bounds().Height() + 1;
325         size_t primary_stride = primary->BytesPerRow();
326         BRect frame(0, 0, width * repeat_x - 1, height * repeat_y - 1);
327         BBitmap *result = new BBitmap(frame, 0, B_RGBA32);
328 
329         char *target_buffer = (char *)result->Bits();
330         int x,y,row;
331         /* This algorithm won't work if the strides are not multiples */
332         assert((size_t)(result->BytesPerRow()) ==
333                (primary_stride * repeat_x));
334 
335         if (repeat_x == 1 && repeat_y == 1) {
336                 delete result;
337                 // just return a copy
338                 return new BBitmap(primary);
339         }
340 
341         for (y = 0; y < repeat_y; ++y) {
342                 char *primary_buffer = (char *)primary->Bits();
343                 for (row = 0; row < height; ++row) {
344                         for (x = 0; x < repeat_x; ++x) {
345                                 memcpy(target_buffer,
346                                        primary_buffer, primary_stride);
347                                 target_buffer += primary_stride;
348                         }
349                         primary_buffer += primary_stride;
350                 }
351         }
352         return result;
353 
354 }
355 
356 
357 /**
358  * The primary image associated with this bitmap object.
359  *
360  * \param  bitmap  a bitmap, as returned by bitmap_create()
361  */
362 BBitmap *
nsbeos_bitmap_get_primary(struct bitmap * bitmap)363 nsbeos_bitmap_get_primary(struct bitmap* bitmap)
364 {
365         return bitmap->primary;
366 }
367 
368 
369 /**
370  * The X-pretiled image associated with this bitmap object.
371  *
372  * \param  bitmap  a bitmap, as returned by bitmap_create()
373  */
374 BBitmap *
nsbeos_bitmap_get_pretile_x(struct bitmap * bitmap)375 nsbeos_bitmap_get_pretile_x(struct bitmap* bitmap)
376 {
377         if (!bitmap->pretile_x) {
378                 int width = bitmap->primary->Bounds().Width() + 1;
379                 int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
380                 NSLOG(netsurf, INFO, "Pretiling %p for X*%d", bitmap, xmult);
381                 bitmap->pretile_x = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, 1);
382         }
383         return bitmap->pretile_x;
384 
385 }
386 
387 
388 /**
389  * The Y-pretiled image associated with this bitmap object.
390  *
391  * \param  bitmap  a bitmap, as returned by bitmap_create()
392  */
393 BBitmap *
nsbeos_bitmap_get_pretile_y(struct bitmap * bitmap)394 nsbeos_bitmap_get_pretile_y(struct bitmap* bitmap)
395 {
396         if (!bitmap->pretile_y) {
397                 int height = bitmap->primary->Bounds().Height() + 1;
398                 int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
399                 NSLOG(netsurf, INFO, "Pretiling %p for Y*%d", bitmap, ymult);
400                 bitmap->pretile_y = nsbeos_bitmap_generate_pretile(bitmap->primary, 1, ymult);
401         }
402         return bitmap->pretile_y;
403 }
404 
405 
406 /**
407  * The XY-pretiled image associated with this bitmap object.
408  *
409  * \param  bitmap  a bitmap, as returned by bitmap_create()
410  */
411 BBitmap *
nsbeos_bitmap_get_pretile_xy(struct bitmap * bitmap)412 nsbeos_bitmap_get_pretile_xy(struct bitmap* bitmap)
413 {
414         if (!bitmap->pretile_xy) {
415                 int width = bitmap->primary->Bounds().Width() + 1;
416                 int height = bitmap->primary->Bounds().Height() + 1;
417                 int xmult = (MIN_PRETILE_WIDTH + width - 1)/width;
418                 int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height;
419                 NSLOG(netsurf, INFO, "Pretiling %p for X*%d Y*%d", bitmap,
420                       xmult, ymult);
421                 bitmap->pretile_xy = nsbeos_bitmap_generate_pretile(bitmap->primary, xmult, ymult);
422         }
423         return bitmap->pretile_xy;
424 }
425 
426 
427 /**
428  * Create a thumbnail of a page.
429  *
430  * \param  bitmap   the bitmap to draw to
431  * \param  content  content structure to thumbnail
432  * \return true on success and bitmap updated else false
433  */
bitmap_render(struct bitmap * bitmap,hlcache_handle * content)434 static nserror bitmap_render(struct bitmap *bitmap, hlcache_handle *content)
435 {
436         BBitmap *thumbnail;
437         BBitmap *small;
438         BBitmap *big;
439         BView *oldView;
440         BView *view;
441         BView *thumbView;
442         float width;
443         float height;
444         int big_width;
445         int big_height;
446         int depth;
447 
448         struct redraw_context ctx;
449         ctx.interactive = false;
450         ctx.background_images = true;
451         ctx.plot = &nsbeos_plotters;
452 
453         assert(content);
454         assert(bitmap);
455 
456         thumbnail = nsbeos_bitmap_get_primary(bitmap);
457         width = thumbnail->Bounds().Width();
458         height = thumbnail->Bounds().Height();
459         depth = 32;
460 
461         big_width = MIN(content_get_width(content), 1024);
462         big_height = (int)(((big_width * height) + (width / 2)) / width);
463 
464         BRect contentRect(0, 0, big_width - 1, big_height - 1);
465         big = new BBitmap(contentRect, B_BITMAP_ACCEPTS_VIEWS, B_RGB32);
466 
467         if (big->InitCheck() < B_OK) {
468                 delete big;
469                 return NSERROR_NOMEM;
470         }
471 
472         small = new BBitmap(thumbnail->Bounds(),
473                             B_BITMAP_ACCEPTS_VIEWS, B_RGB32);
474 
475         if (small->InitCheck() < B_OK) {
476                 delete small;
477                 delete big;
478                 return NSERROR_NOMEM;
479         }
480 
481         //XXX: _lock ?
482         // backup the current gc
483         oldView = nsbeos_current_gc();
484 
485         view = new BView(contentRect, "thumbnailer",
486                          B_FOLLOW_NONE, B_WILL_DRAW);
487         big->AddChild(view);
488 
489         thumbView = new BView(small->Bounds(), "thumbnail",
490                               B_FOLLOW_NONE, B_WILL_DRAW);
491         small->AddChild(thumbView);
492 
493         view->LockLooper();
494 
495         /* impose our view on the content... */
496         nsbeos_current_gc_set(view);
497 
498         /* render the content */
499         content_scaled_redraw(content, big_width, big_height, &ctx);
500 
501         view->Sync();
502         view->UnlockLooper();
503 
504         // restore the current gc
505         nsbeos_current_gc_set(oldView);
506 
507 
508         // now scale it down
509         //XXX: use Zeta's bilinear scaler ?
510         //#ifdef B_ZETA_VERSION
511         //	err = ScaleBitmap(*shot, *scaledBmp);
512         //#else
513         thumbView->LockLooper();
514         thumbView->DrawBitmap(big, big->Bounds(), small->Bounds());
515         thumbView->Sync();
516         thumbView->UnlockLooper();
517 
518         small->LockBits();
519         thumbnail->LockBits();
520 
521         // copy it to the bitmap
522         memcpy(thumbnail->Bits(), small->Bits(), thumbnail->BitsLength());
523 
524         thumbnail->UnlockBits();
525         small->UnlockBits();
526 
527         bitmap_modified(bitmap);
528 
529         // cleanup
530         small->RemoveChild(thumbView);
531         delete thumbView;
532         delete small;
533         big->RemoveChild(view);
534         delete view;
535         delete big;
536 
537         return NSERROR_OK;
538 }
539 
540 
541 static struct gui_bitmap_table bitmap_table = {
542         /*.create =*/ bitmap_create,
543         /*.destroy =*/ bitmap_destroy,
544         /*.set_opaque =*/ bitmap_set_opaque,
545         /*.get_opaque =*/ bitmap_get_opaque,
546         /*.test_opaque =*/ bitmap_test_opaque,
547         /*.get_buffer =*/ bitmap_get_buffer,
548         /*.get_rowstride =*/ bitmap_get_rowstride,
549         /*.get_width =*/ bitmap_get_width,
550         /*.get_height =*/ bitmap_get_height,
551         /*.get_bpp =*/ bitmap_get_bpp,
552         /*.save =*/ bitmap_save,
553         /*.modified =*/ bitmap_modified,
554         /*.render =*/ bitmap_render,
555 };
556 
557 struct gui_bitmap_table *beos_bitmap_table = &bitmap_table;
558