Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
  3.  * Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
  4.  * Copyright 2008 Sean Fox <dyntryx@gmail.com>
  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. /** \file
  22.  * Content for image/gif (implementation)
  23.  *
  24.  * All GIFs are dynamically decompressed using the routines that gifread.c
  25.  * provides. Whilst this allows support for progressive decoding, it is
  26.  * not implemented here as NetSurf currently does not provide such support.
  27.  *
  28.  * [rjw] - Sun 4th April 2004
  29.  */
  30.  
  31. #include <assert.h>
  32. #include <string.h>
  33. #include <stdbool.h>
  34. #include <stdlib.h>
  35. #include <libnsgif.h>
  36.  
  37. #include "utils/config.h"
  38. #include "content/content_protected.h"
  39. #include "content/hlcache.h"
  40. #include "desktop/options.h"
  41. #include "desktop/plotters.h"
  42. #include "image/image.h"
  43. #include "image/bitmap.h"
  44. #include "image/gif.h"
  45. #include "utils/log.h"
  46. #include "utils/messages.h"
  47. #include "utils/schedule.h"
  48. #include "utils/utils.h"
  49.  
  50. typedef struct nsgif_content {
  51.         struct content base;
  52.  
  53.         struct gif_animation *gif; /**< GIF animation data */
  54.         int current_frame;   /**< current frame to display [0...(max-1)] */
  55. } nsgif_content;
  56.  
  57.  
  58. /**
  59.  * Callback for libnsgif; forwards the call to bitmap_create()
  60.  *
  61.  * \param  width   width of image in pixels
  62.  * \param  height  width of image in pixels
  63.  * \return an opaque struct bitmap, or NULL on memory exhaustion
  64.  */
  65. static void *nsgif_bitmap_create(int width, int height)
  66. {
  67.         return bitmap_create(width, height, BITMAP_NEW);
  68. }
  69.  
  70. /* The Bitmap callbacks function table;
  71.  * necessary for interaction with nsgiflib.
  72.  */
  73. static gif_bitmap_callback_vt gif_bitmap_callbacks = {
  74.         .bitmap_create = nsgif_bitmap_create,
  75.         .bitmap_destroy = bitmap_destroy,
  76.         .bitmap_get_buffer = bitmap_get_buffer,
  77.         .bitmap_set_opaque = bitmap_set_opaque,
  78.         .bitmap_test_opaque = bitmap_test_opaque,
  79.         .bitmap_modified = bitmap_modified
  80. };
  81.  
  82. static nserror nsgif_create_gif_data(nsgif_content *c)
  83. {
  84.         union content_msg_data msg_data;
  85.  
  86.         /* Initialise our data structure */
  87.         c->gif = calloc(sizeof(gif_animation), 1);
  88.         if (c->gif == NULL) {
  89.                 msg_data.error = messages_get("NoMemory");
  90.                 content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
  91.                 return NSERROR_NOMEM;
  92.         }
  93.         gif_create(c->gif, &gif_bitmap_callbacks);
  94.         return NSERROR_OK;
  95. }
  96.  
  97.  
  98.  
  99. static nserror nsgif_create(const content_handler *handler,
  100.                 lwc_string *imime_type, const struct http_parameter *params,
  101.                 llcache_handle *llcache, const char *fallback_charset,
  102.                 bool quirks, struct content **c)
  103. {
  104.         nsgif_content *result;
  105.         nserror error;
  106.  
  107.         result = calloc(1, sizeof(nsgif_content));
  108.         if (result == NULL)
  109.                 return NSERROR_NOMEM;
  110.  
  111.         error = content__init(&result->base, handler, imime_type, params,
  112.                         llcache, fallback_charset, quirks);
  113.         if (error != NSERROR_OK) {
  114.                 free(result);
  115.                 return error;
  116.         }
  117.  
  118.         error = nsgif_create_gif_data(result);
  119.         if (error != NSERROR_OK) {
  120.                 free(result);
  121.                 return error;
  122.         }
  123.  
  124.         *c = (struct content *) result;
  125.  
  126.         return NSERROR_OK;
  127. }
  128.  
  129. /**
  130.  * Performs any necessary animation.
  131.  *
  132.  * \param p  The content to animate
  133. */
  134. static void nsgif_animate(void *p)
  135. {
  136.         nsgif_content *gif = p;
  137.         union content_msg_data data;
  138.         int delay;
  139.         int f;
  140.  
  141.         /* Advance by a frame, updating the loop count accordingly */
  142.         gif->current_frame++;
  143.         if (gif->current_frame == (int)gif->gif->frame_count_partial) {
  144.                 gif->current_frame = 0;
  145.  
  146.                 /* A loop count of 0 has a special meaning of infinite */
  147.                 if (gif->gif->loop_count != 0) {
  148.                         gif->gif->loop_count--;
  149.                         if (gif->gif->loop_count == 0) {
  150.                                 gif->current_frame =
  151.                                         gif->gif->frame_count_partial - 1;
  152.                                 gif->gif->loop_count = -1;
  153.                         }
  154.                 }
  155.         }
  156.  
  157.         /* Continue animating if we should */
  158.         if (gif->gif->loop_count >= 0) {
  159.                 delay = gif->gif->frames[gif->current_frame].frame_delay;
  160.                 if (delay < nsoption_int(minimum_gif_delay))
  161.                         delay = nsoption_int(minimum_gif_delay);
  162.                 schedule(delay, nsgif_animate, gif);
  163.         }
  164.  
  165.         if ((!nsoption_bool(animate_images)) ||
  166.             (!gif->gif->frames[gif->current_frame].display)) {
  167.                 return;
  168.         }
  169.  
  170.         /* area within gif to redraw */
  171.         f = gif->current_frame;
  172.         data.redraw.x = gif->gif->frames[f].redraw_x;
  173.         data.redraw.y = gif->gif->frames[f].redraw_y;
  174.         data.redraw.width = gif->gif->frames[f].redraw_width;
  175.         data.redraw.height = gif->gif->frames[f].redraw_height;
  176.  
  177.         /* redraw background (true) or plot on top (false) */
  178.         if (gif->current_frame > 0) {
  179.                 data.redraw.full_redraw =
  180.                                 gif->gif->frames[f - 1].redraw_required;
  181.                 /* previous frame needed clearing: expand the redraw area to
  182.                  * cover it */
  183.                 if (data.redraw.full_redraw) {
  184.                         if (data.redraw.x >
  185.                                         (int)(gif->gif->frames[f - 1].redraw_x)) {
  186.                                 data.redraw.width += data.redraw.x -
  187.                                         gif->gif->frames[f - 1].redraw_x;
  188.                                 data.redraw.x =
  189.                                         gif->gif->frames[f - 1].redraw_x;
  190.                         }
  191.                         if (data.redraw.y >
  192.                                         (int)(gif->gif->frames[f - 1].redraw_y)) {
  193.                                 data.redraw.height += (data.redraw.y -
  194.                                         gif->gif->frames[f - 1].redraw_y);
  195.                                 data.redraw.y =
  196.                                         gif->gif->frames[f - 1].redraw_y;
  197.                         }
  198.                         if ((int)(gif->gif->frames[f - 1].redraw_x +
  199.                                         gif->gif->frames[f - 1].redraw_width) >
  200.                                         (data.redraw.x + data.redraw.width))
  201.                                 data.redraw.width =
  202.                                         gif->gif->frames[f - 1].redraw_x -
  203.                                         data.redraw.x +
  204.                                         gif->gif->frames[f - 1].redraw_width;
  205.                         if ((int)(gif->gif->frames[f - 1].redraw_y +
  206.                                         gif->gif->frames[f - 1].redraw_height) >
  207.                                         (data.redraw.y + data.redraw.height))
  208.                                 data.redraw.height =
  209.                                         gif->gif->frames[f - 1].redraw_y -
  210.                                         data.redraw.y +
  211.                                         gif->gif->frames[f - 1].redraw_height;
  212.                 }
  213.         } else {
  214.                 /* do advanced check */
  215.                 if ((data.redraw.x == 0) && (data.redraw.y == 0) &&
  216.                                 (data.redraw.width == (int)(gif->gif->width)) &&
  217.                                 (data.redraw.height == (int)(gif->gif->height))) {
  218.                         data.redraw.full_redraw = !gif->gif->frames[f].opaque;
  219.                 } else {
  220.                         data.redraw.full_redraw = true;
  221.                         data.redraw.x = 0;
  222.                         data.redraw.y = 0;
  223.                         data.redraw.width = gif->gif->width;
  224.                         data.redraw.height = gif->gif->height;
  225.                 }
  226.         }
  227.  
  228.         /* other data */
  229.         data.redraw.object = (struct content *) gif;
  230.         data.redraw.object_x = 0;
  231.         data.redraw.object_y = 0;
  232.         data.redraw.object_width = gif->base.width;
  233.         data.redraw.object_height = gif->base.height;
  234.  
  235.         content_broadcast(&gif->base, CONTENT_MSG_REDRAW, data);
  236. }
  237.  
  238. static bool nsgif_convert(struct content *c)
  239. {
  240.         nsgif_content *gif = (nsgif_content *) c;
  241.         int res;
  242.         union content_msg_data msg_data;
  243.         const char *data;
  244.         unsigned long size;
  245.         char *title;
  246.  
  247.         /* Get the animation */
  248.         data = content__get_source_data(c, &size);
  249.  
  250.         /* Initialise the GIF */
  251.         do {
  252.                 res = gif_initialise(gif->gif, size, (unsigned char *) data);
  253.                 if (res != GIF_OK && res != GIF_WORKING &&
  254.                                 res != GIF_INSUFFICIENT_FRAME_DATA) {
  255.                         switch (res) {
  256.                         case GIF_FRAME_DATA_ERROR:
  257.                         case GIF_INSUFFICIENT_DATA:
  258.                         case GIF_DATA_ERROR:
  259.                                 msg_data.error = messages_get("BadGIF");
  260.                                 break;
  261.                         case GIF_INSUFFICIENT_MEMORY:
  262.                                 msg_data.error = messages_get("NoMemory");
  263.                                 break;
  264.                         }
  265.                         content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
  266.                         return false;
  267.                 }
  268.         } while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA);
  269.  
  270.         /* Abort on bad GIFs */
  271.         if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) ||
  272.                         (gif->gif->height == 0)) {
  273.                 msg_data.error = messages_get("BadGIF");
  274.                 content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
  275.                 return false;
  276.         }
  277.  
  278.         /* Store our content width, height and calculate size */
  279.         c->width = gif->gif->width;
  280.         c->height = gif->gif->height;
  281.         c->size += (gif->gif->width * gif->gif->height * 4) + 16 + 44;
  282.  
  283.         /* set title text */
  284.         title = messages_get_buff("GIFTitle",
  285.                         nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
  286.                         c->width, c->height);
  287.         if (title != NULL) {
  288.                 content__set_title(c, title);
  289.                 free(title);
  290.         }
  291.  
  292.         /* Schedule the animation if we have one */
  293.         gif->current_frame = 0;
  294.         if (gif->gif->frame_count_partial > 1)
  295.                 schedule(gif->gif->frames[0].frame_delay, nsgif_animate, c);
  296.  
  297.         /* Exit as a success */
  298.         content_set_ready(c);
  299.         content_set_done(c);
  300.  
  301.         /* Done: update status bar */
  302.         content_set_status(c, "");
  303.         return true;
  304. }
  305.  
  306.  
  307. /**
  308.  * Updates the GIF bitmap to display the current frame
  309.  *
  310.  * \param c  the content to update
  311.  */
  312. static gif_result nsgif_get_frame(nsgif_content *gif)
  313. {
  314.         int previous_frame, current_frame, frame;
  315.         gif_result res = GIF_OK;
  316.  
  317.         current_frame = gif->current_frame;
  318.         if (!nsoption_bool(animate_images)) {
  319.                 current_frame = 0;
  320.         }
  321.  
  322.         if (current_frame < gif->gif->decoded_frame)
  323.                 previous_frame = 0;
  324.         else
  325.                 previous_frame = gif->gif->decoded_frame + 1;
  326.  
  327.         for (frame = previous_frame; frame <= current_frame; frame++) {
  328.                 res = gif_decode_frame(gif->gif, frame);
  329.         }
  330.  
  331.         return res;
  332. }
  333.  
  334. static bool nsgif_redraw(struct content *c, struct content_redraw_data *data,
  335.                 const struct rect *clip, const struct redraw_context *ctx)
  336. {
  337.         nsgif_content *gif = (nsgif_content *) c;
  338.  
  339.         if (gif->current_frame != gif->gif->decoded_frame) {
  340.                 if (nsgif_get_frame(gif) != GIF_OK) {
  341.                         return false;
  342.                 }
  343.         }
  344.  
  345.         return image_bitmap_plot(gif->gif->frame_image, data, clip, ctx);
  346. }
  347.  
  348.  
  349. static void nsgif_destroy(struct content *c)
  350. {
  351.         nsgif_content *gif = (nsgif_content *) c;
  352.  
  353.         /* Free all the associated memory buffers */
  354.         schedule_remove(nsgif_animate, c);
  355.         gif_finalise(gif->gif);
  356.         free(gif->gif);
  357. }
  358.  
  359.  
  360. static nserror nsgif_clone(const struct content *old, struct content **newc)
  361. {
  362.         nsgif_content *gif;
  363.         nserror error;
  364.  
  365.         gif = calloc(1, sizeof(nsgif_content));
  366.         if (gif == NULL)
  367.                 return NSERROR_NOMEM;
  368.  
  369.         error = content__clone(old, &gif->base);
  370.         if (error != NSERROR_OK) {
  371.                 content_destroy(&gif->base);
  372.                 return error;
  373.         }
  374.  
  375.         /* Simply replay creation and conversion of content */
  376.         error = nsgif_create_gif_data(gif);
  377.         if (error != NSERROR_OK) {
  378.                 content_destroy(&gif->base);
  379.                 return error;
  380.         }
  381.  
  382.         if (old->status == CONTENT_STATUS_READY ||
  383.                         old->status == CONTENT_STATUS_DONE) {
  384.                 if (nsgif_convert(&gif->base) == false) {
  385.                         content_destroy(&gif->base);
  386.                         return NSERROR_CLONE_FAILED;
  387.                 }
  388.         }
  389.  
  390.         *newc = (struct content *) gif;
  391.  
  392.         return NSERROR_OK;
  393. }
  394.  
  395. static void *nsgif_get_internal(const struct content *c, void *context)
  396. {
  397.         nsgif_content *gif = (nsgif_content *) c;
  398.  
  399.         if (gif->current_frame != gif->gif->decoded_frame) {
  400.                 if (nsgif_get_frame(gif) != GIF_OK)
  401.                         return NULL;
  402.         }
  403.  
  404.         return gif->gif->frame_image;
  405. }
  406.  
  407. static content_type nsgif_content_type(void)
  408. {
  409.         return CONTENT_IMAGE;
  410. }
  411.  
  412. static const content_handler nsgif_content_handler = {
  413.         .create = nsgif_create,
  414.         .data_complete = nsgif_convert,
  415.         .destroy = nsgif_destroy,
  416.         .redraw = nsgif_redraw,
  417.         .clone = nsgif_clone,
  418.         .get_internal = nsgif_get_internal,
  419.         .type = nsgif_content_type,
  420.         .no_share = false,
  421. };
  422.  
  423. static const char *nsgif_types[] = {
  424.         "image/gif"
  425. };
  426.  
  427. CONTENT_FACTORY_REGISTER_TYPES(nsgif, nsgif_types, nsgif_content_handler);
  428.