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