/** * Handle notification that a CSS object is done * * \param css CSS object * \param pw Private data */ void nscss_content_done(struct content_css_data *css, void *pw) { union content_msg_data msg_data; struct content *c = pw; uint32_t i; size_t size; css_error error; /* Retrieve the size of this sheet */ error = css_stylesheet_size(css->sheet, &size); if (error != CSS_OK) { msg_data.error = "?"; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); content_set_error(c); return; } c->size += size; /* Add on the size of the imported sheets */ for (i = 0; i < css->import_count; i++) { if (css->imports[i].c != NULL) { struct content *import = hlcache_handle_get_content( css->imports[i].c); if (import != NULL) { c->size += import->size; } } } /* Finally, catch the content's users up with reality */ content_set_ready(c); content_set_done(c); }
void content_convert(struct content *c) { assert(c); assert(c->status == CONTENT_STATUS_LOADING || c->status == CONTENT_STATUS_ERROR); if (c->status != CONTENT_STATUS_LOADING) return; if (c->locked == true) return; LOG("content "URL_FMT_SPC" (%p)", nsurl_access(llcache_handle_get_url(c->llcache)), c); if (c->handler->data_complete != NULL) { c->locked = true; if (c->handler->data_complete(c) == false) { content_set_error(c); } /* Conversion to the READY state will unlock the content */ } else { content_set_ready(c); content_set_done(c); } }
static bool javascript_convert(struct content *c) { content_set_ready(c); content_set_done(c); return true; }
static bool nspng_convert(struct content *c) { nspng_content *png_c = (nspng_content *) c; char *title; assert(png_c->png != NULL); assert(png_c->info != NULL); /* clean up png structures */ png_destroy_read_struct(&png_c->png, &png_c->info, 0); /* set title text */ title = messages_get_buff("PNGTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } if (png_c->bitmap != NULL) { bitmap_set_opaque(png_c->bitmap, bitmap_test_opaque(png_c->bitmap)); bitmap_modified(png_c->bitmap); } image_cache_add(c, png_c->bitmap, png_cache_convert); content_set_ready(c); content_set_done(c); content_set_status(c, ""); return true; }
static bool nsico_convert(struct content *c) { nsico_content *ico = (nsico_content *) c; struct bmp_image *bmp; bmp_result res; union content_msg_data msg_data; const char *data; unsigned long size; char *title; /* set the ico data */ data = content__get_source_data(c, &size); /* analyse the ico */ res = ico_analyse(ico->ico, size, (unsigned char *) data); switch (res) { case BMP_OK: break; case BMP_INSUFFICIENT_MEMORY: msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; case BMP_INSUFFICIENT_DATA: case BMP_DATA_ERROR: msg_data.error = messages_get("BadICO"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* Store our content width, height and calculate size */ c->width = ico->ico->width; c->height = ico->ico->height; c->size += (ico->ico->width * ico->ico->height * 4) + 16 + 44; /* set title text */ title = messages_get_buff("ICOTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } /* select largest icon to ensure one can be selected */ bmp = ico_find(ico->ico, 255, 255); if (bmp == NULL) { /* return error */ LOG("Failed to select icon"); return false; } content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
/** * Convert a CONTENT_JPEG for display. */ static bool nsjpeg_convert(struct content *c) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf setjmp_buffer; struct jpeg_source_mgr source_mgr = { 0, 0, nsjpeg_init_source, nsjpeg_fill_input_buffer, nsjpeg_skip_input_data, jpeg_resync_to_restart, nsjpeg_term_source }; union content_msg_data msg_data; const char *data; unsigned long size; char title[100]; /* check image header is valid and get width/height */ data = content__get_source_data(c, &size); cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = nsjpeg_error_exit; jerr.output_message = nsjpeg_error_log; if (setjmp(setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); msg_data.error = nsjpeg_error_buffer; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } jpeg_create_decompress(&cinfo); cinfo.client_data = &setjmp_buffer; source_mgr.next_input_byte = (unsigned char *) data; source_mgr.bytes_in_buffer = size; cinfo.src = &source_mgr; jpeg_read_header(&cinfo, TRUE); cinfo.out_color_space = JCS_RGB; cinfo.dct_method = JDCT_ISLOW; jpeg_calc_output_dimensions(&cinfo); c->width = cinfo.output_width; c->height = cinfo.output_height; c->size = c->width * c->height * 4; jpeg_destroy_decompress(&cinfo); image_cache_add(c, NULL, jpeg_cache_convert); snprintf(title, sizeof(title), messages_get("JPEGTitle"), c->width, c->height, size); content__set_title(c, title); content_set_ready(c); content_set_done(c); content_set_status(c, ""); /* Done: update status bar */ return true; }
bool amiga_dt_picture_convert(struct content *c) { LOG(("amiga_dt_picture_convert")); union content_msg_data msg_data; int width, height; char title[100]; const uint8 *data; UBYTE *bm_buffer; ULONG size; Object *dto; struct BitMapHeader *bmh; unsigned int bm_flags = BITMAP_NEW; int bm_format = PBPAFMT_RGBA; /* This is only relevant for picture datatypes... */ data = (uint8 *)content__get_source_data(c, &size); if(dto = NewDTObject(NULL, DTA_SourceType, DTST_MEMORY, DTA_SourceAddress, data, DTA_SourceSize, size, DTA_GroupID, GID_PICTURE, PDTA_DestMode, PMODE_V43, TAG_DONE)) { if(GetDTAttrs(dto, PDTA_BitMapHeader, &bmh, TAG_DONE)) { width = (int)bmh->bmh_Width; height = (int)bmh->bmh_Height; } else return false; DisposeDTObject(dto); } else return false; c->width = width; c->height = height; c->size = width * height * 4; image_cache_add(c, NULL, amiga_dt_picture_cache_convert); /* snprintf(title, sizeof(title), "image (%lux%lu, %lu bytes)", width, height, size); content__set_title(c, title); */ content_set_ready(c); content_set_done(c); content_set_status(c, ""); return true; }
static bool nsbmp_convert(struct content *c) { nsbmp_content *bmp = (nsbmp_content *) c; bmp_result res; union content_msg_data msg_data; uint32_t swidth; const char *data; unsigned long size; char *title; /* set the bmp data */ data = content__get_source_data(c, &size); /* analyse the BMP */ res = bmp_analyse(bmp->bmp, size, (unsigned char *) data); switch (res) { case BMP_OK: break; case BMP_INSUFFICIENT_MEMORY: msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; case BMP_INSUFFICIENT_DATA: case BMP_DATA_ERROR: msg_data.error = messages_get("BadBMP"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* Store our content width and description */ c->width = bmp->bmp->width; c->height = bmp->bmp->height; swidth = bmp->bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bmp->bitmap) * bmp->bmp->width; c->size += (swidth * bmp->bmp->height) + 16 + 44; /* set title text */ title = messages_get_buff("BMPTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } /* exit as a success */ bmp->bitmap = bmp->bmp->bitmap; guit->bitmap->modified(bmp->bitmap); content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
static bool svg_convert(struct content *c) { /*c->title = malloc(100); if (c->title) snprintf(c->title, 100, messages_get("svgTitle"), width, height, c->source_size);*/ //c->size += ?; content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
bool amiga_dt_picture_convert(struct content *c) { LOG(("amiga_dt_picture_convert")); union content_msg_data msg_data; int width, height; char *title; UBYTE *bm_buffer; Object *dto; struct BitMapHeader *bmh; unsigned int bm_flags = BITMAP_NEW; int bm_format = PBPAFMT_RGBA; char *filetype; if(dto = amiga_dt_picture_newdtobject((struct amiga_dt_picture_content *)c)) { if(GetDTAttrs(dto, PDTA_BitMapHeader, &bmh, TAG_DONE)) { width = (int)bmh->bmh_Width; height = (int)bmh->bmh_Height; } else return false; } else return false; c->width = width; c->height = height; c->size = width * height * 4; /* set title text */ if(filetype = amiga_dt_picture_datatype(c)) { title = messages_get_buff("DataTypesTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), filetype, c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } free(filetype); } image_cache_add(c, NULL, amiga_dt_picture_cache_convert); content_set_ready(c); content_set_done(c); content_set_status(c, ""); return true; }
bool amiga_dt_picture_convert(struct content *c) { NSLOG(netsurf, INFO, "amiga_dt_picture_convert"); int width, height; char *title; Object *dto; struct BitMapHeader *bmh; char *filetype; if((dto = amiga_dt_picture_newdtobject((struct amiga_dt_picture_content *)c))) { if(GetDTAttrs(dto, PDTA_BitMapHeader, &bmh, TAG_DONE)) { width = (int)bmh->bmh_Width; height = (int)bmh->bmh_Height; } else return false; } else return false; c->width = width; c->height = height; c->size = width * height * 4; /* set title text */ if((filetype = amiga_dt_picture_datatype(c))) { title = messages_get_buff("DataTypesTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), filetype, c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } free(filetype); } image_cache_add(c, NULL, amiga_dt_picture_cache_convert); content_set_ready(c); content_set_done(c); content_set_status(c, ""); return true; }
static bool rsvg_convert(struct content *c) { rsvg_content *d = (rsvg_content *) c; union content_msg_data msg_data; RsvgDimensionData rsvgsize; GError *err = NULL; if (rsvg_handle_close(d->rsvgh, &err) == FALSE) { LOG(("rsvg_handle_close returned an error: %s", err->message)); msg_data.error = err->message; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } assert(err == NULL); /* we should now be able to query librsvg for the natural size of the * graphic, so we can create our bitmap. */ rsvg_handle_get_dimensions(d->rsvgh, &rsvgsize); c->width = rsvgsize.width; c->height = rsvgsize.height; if ((d->bitmap = bitmap_create(c->width, c->height, BITMAP_NEW)) == NULL) { LOG(("Failed to create bitmap for rsvg render.")); msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } if ((d->cs = cairo_image_surface_create_for_data( (unsigned char *)bitmap_get_buffer(d->bitmap), CAIRO_FORMAT_ARGB32, c->width, c->height, bitmap_get_rowstride(d->bitmap))) == NULL) { LOG(("Failed to create Cairo image surface for rsvg render.")); msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } if ((d->ct = cairo_create(d->cs)) == NULL) { LOG(("Failed to create Cairo drawing context for rsvg render.")); msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } rsvg_handle_render_cairo(d->rsvgh, d->ct); rsvg_argb_to_abgr(bitmap_get_buffer(d->bitmap), c->width, c->height, bitmap_get_rowstride(d->bitmap)); bitmap_modified(d->bitmap); content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
static bool nssprite_convert(struct content *c) { nssprite_content *nssprite = (nssprite_content *) c; union content_msg_data msg_data; struct rosprite_mem_context* ctx; const char *data; unsigned long size; char *title; data = content__get_source_data(c, &size); ERRCHK(rosprite_create_mem_context((uint8_t *) data, size, &ctx)); struct rosprite_area* sprite_area; ERRCHK(rosprite_load(rosprite_mem_reader, ctx, &sprite_area)); rosprite_destroy_mem_context(ctx); nssprite->sprite_area = sprite_area; assert(sprite_area->sprite_count > 0); struct rosprite* sprite = sprite_area->sprites[0]; nssprite->bitmap = guit->bitmap->create(sprite->width, sprite->height, BITMAP_NEW); if (!nssprite->bitmap) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } uint32_t* imagebuf = (uint32_t *)guit->bitmap->get_buffer(nssprite->bitmap); if (!imagebuf) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } unsigned char *spritebuf = (unsigned char *)sprite->image; /* reverse byte order of each word */ for (uint32_t y = 0; y < sprite->height; y++) { for (uint32_t x = 0; x < sprite->width; x++) { int offset = 4 * (y * sprite->width + x); *imagebuf = (spritebuf[offset] << 24) | (spritebuf[offset + 1] << 16) | (spritebuf[offset + 2] << 8) | (spritebuf[offset + 3]); imagebuf++; } } c->width = sprite->width; c->height = sprite->height; /* set title text */ title = messages_get_buff("SpriteTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } guit->bitmap->modified(nssprite->bitmap); content_set_ready(c); content_set_done(c); content_set_status(c, ""); /* Done: update status bar */ return true; }
bool amiga_icon_convert(struct content *c) { amiga_icon_content *icon_c = (amiga_icon_content *)c; union content_msg_data msg_data; struct DiskObject *dobj; ULONG *imagebuf; unsigned char *imagebufptr = NULL; ULONG size; int width = 0, height = 0; long format = 0; int err = 0; uint8 r, g, b, a; ULONG offset; const char *url; char *filename; char *p; ULONG trans, pals1; struct ColorRegister *pal1; url = nsurl_access(content_get_url(c)); filename = url_to_path(url); /* This loader will only work on local files, so fail if not a local path */ if(filename == NULL) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } p = strstr(filename, ".info"); *p = '\0'; dobj = GetIconTagList(filename, NULL); if(dobj == NULL) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } err = IconControl(dobj, ICONCTRLA_GetImageDataFormat,&format, ICONCTRLA_GetWidth,&width, ICONCTRLA_GetHeight,&height, TAG_DONE); /* Check icon is direct mapped (truecolour) or palette-mapped colour. We need additional code to handle planar icons */ if((format != IDFMT_DIRECTMAPPED) && (format==IDFMT_PALETTEMAPPED)) { if(dobj) FreeDiskObject(dobj); return false; } icon_c->bitmap = bitmap_create(width, height, BITMAP_NEW); if (!icon_c->bitmap) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); if(dobj) FreeDiskObject(dobj); return false; } imagebuf = (ULONG *) bitmap_get_buffer(icon_c->bitmap); if (!imagebuf) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); if(dobj) FreeDiskObject(dobj); return false; } err = IconControl(dobj, ICONCTRLA_GetImageData1, &imagebufptr, TAG_DONE); if(format==IDFMT_PALETTEMAPPED) { IconControl(dobj, ICONCTRLA_GetTransparentColor1, &trans, ICONCTRLA_GetPalette1, &pal1, ICONCTRLA_GetPaletteSize1, &pals1, TAG_DONE); imagebufptr = (unsigned char *) amiga_icon_convertcolouricon32((UBYTE *)imagebufptr, width, height, trans, pals1, pal1, 0xff); } /* Decoded data is ARGB, so ensure correct byte order */ size = width * height * 4; for (offset = 0; offset < size; offset += 4) { b = imagebufptr[offset+3]; g = imagebufptr[offset+2]; r = imagebufptr[offset+1]; a = imagebufptr[offset]; *imagebuf = r << 24 | g << 16 | b << 8 | a; imagebuf++; } c->width = width; c->height = height; bitmap_modified(icon_c->bitmap); content_set_ready(c); content_set_done(c); content_set_status(c, ""); if(dobj) FreeDiskObject(dobj); if(format==IDFMT_PALETTEMAPPED) FreeVec(imagebufptr); return true; }
bool artworks_convert(struct content *c) { artworks_content *aw = (artworks_content *) c; union content_msg_data msg_data; const char *source_data; unsigned long source_size; void *init_workspace; void *init_routine; os_error *error; int used = -1; /* slightly better with older OSLib versions */ char *title; /* check whether AWViewer has been seen and we can therefore locate the ArtWorks rendering modules */ xos_read_var_val_size("Alias$LoadArtWorksModules", 0, os_VARTYPE_STRING, &used, NULL, NULL); if (used >= 0) { LOG("Alias$LoadArtWorksModules not defined"); msg_data.error = messages_get("AWNotSeen"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* load the modules, or do nothing if they're already loaded */ error = xos_cli("LoadArtWorksModules"); if (error) { LOG("xos_cli: 0x%x: %s", error->errnum, error->errmess); msg_data.error = error->errmess; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* lookup the addresses of the init and render routines */ error = (os_error*)_swix(AWRender_FileInitAddress, _OUT(0) | _OUT(1), &init_routine, &init_workspace); if (error) { LOG("AWRender_FileInitAddress: 0x%x: %s", error->errnum, error->errmess); msg_data.error = error->errmess; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } error = (os_error*)_swix(AWRender_RenderAddress, _OUT(0) | _OUT(1), &aw->render_routine, &aw->render_workspace); if (error) { LOG("AWRender_RenderAddress: 0x%x: %s", error->errnum, error->errmess); msg_data.error = error->errmess; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } source_data = content__get_source_data(c, &source_size); /* initialise (convert file to new format if required) */ error = awrender_init(&source_data, &source_size, init_routine, init_workspace); if (error) { LOG("awrender_init: 0x%x : %s", error->errnum, error->errmess); msg_data.error = error->errmess; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } error = (os_error*)_swix(AWRender_DocBounds, _IN(0) | _OUT(2) | _OUT(3) | _OUT(4) | _OUT(5), source_data, &aw->x0, &aw->y0, &aw->x1, &aw->y1); if (error) { LOG("AWRender_DocBounds: 0x%x: %s", error->errnum, error->errmess); msg_data.error = error->errmess; content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } LOG("bounding box: %d,%d,%d,%d", aw->x0, aw->y0, aw->x1, aw->y1); /* create the resizable workspace required by the ArtWorksRenderer rendering routine */ aw->size = INITIAL_BLOCK_SIZE; aw->block = malloc(INITIAL_BLOCK_SIZE); if (!aw->block) { LOG("failed to create block for ArtworksRenderer"); msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } c->width = (aw->x1 - aw->x0) / 512; c->height = (aw->y1 - aw->y0) / 512; title = messages_get_buff("ArtWorksTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
static bool rsvg_convert(struct content *c) { rsvg_content *d = (rsvg_content *) c; RsvgDimensionData rsvgsize; GError *err = NULL; if (rsvg_handle_close(d->rsvgh, &err) == FALSE) { NSLOG(netsurf, INFO, "rsvg_handle_close returned an error: %s", err->message); content_broadcast_errorcode(c, NSERROR_SVG_ERROR); return false; } assert(err == NULL); /* we should now be able to query librsvg for the natural size of the * graphic, so we can create our bitmap. */ rsvg_handle_get_dimensions(d->rsvgh, &rsvgsize); c->width = rsvgsize.width; c->height = rsvgsize.height; if ((d->bitmap = guit->bitmap->create(c->width, c->height, BITMAP_NEW)) == NULL) { NSLOG(netsurf, INFO, "Failed to create bitmap for rsvg render."); content_broadcast_errorcode(c, NSERROR_NOMEM); return false; } if ((d->cs = cairo_image_surface_create_for_data( (unsigned char *)guit->bitmap->get_buffer(d->bitmap), CAIRO_FORMAT_ARGB32, c->width, c->height, guit->bitmap->get_rowstride(d->bitmap))) == NULL) { NSLOG(netsurf, INFO, "Failed to create Cairo image surface for rsvg render."); content_broadcast_errorcode(c, NSERROR_NOMEM); return false; } if ((d->ct = cairo_create(d->cs)) == NULL) { NSLOG(netsurf, INFO, "Failed to create Cairo drawing context for rsvg render."); content_broadcast_errorcode(c, NSERROR_NOMEM); return false; } rsvg_handle_render_cairo(d->rsvgh, d->ct); rsvg_argb_to_abgr(guit->bitmap->get_buffer(d->bitmap), c->width, c->height, guit->bitmap->get_rowstride(d->bitmap)); guit->bitmap->modified(d->bitmap); content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }
static bool nsgif_convert(struct content *c) { nsgif_content *gif = (nsgif_content *) c; int res; union content_msg_data msg_data; const char *data; unsigned long size; char *title; /* Get the animation */ data = content__get_source_data(c, &size); /* Initialise the GIF */ do { res = gif_initialise(gif->gif, size, (unsigned char *) data); if (res != GIF_OK && res != GIF_WORKING && res != GIF_INSUFFICIENT_FRAME_DATA) { switch (res) { case GIF_FRAME_DATA_ERROR: case GIF_INSUFFICIENT_DATA: case GIF_DATA_ERROR: msg_data.error = messages_get("BadGIF"); break; case GIF_INSUFFICIENT_MEMORY: msg_data.error = messages_get("NoMemory"); break; } content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } } while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA); /* Abort on bad GIFs */ if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) || (gif->gif->height == 0)) { msg_data.error = messages_get("BadGIF"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); return false; } /* Store our content width, height and calculate size */ c->width = gif->gif->width; c->height = gif->gif->height; c->size += (gif->gif->width * gif->gif->height * 4) + 16 + 44; /* set title text */ title = messages_get_buff("GIFTitle", nsurl_access_leaf(llcache_handle_get_url(c->llcache)), c->width, c->height); if (title != NULL) { content__set_title(c, title); free(title); } /* Schedule the animation if we have one */ gif->current_frame = 0; if (gif->gif->frame_count_partial > 1) guit->browser->schedule(gif->gif->frames[0].frame_delay * 10, nsgif_animate, c); /* Exit as a success */ content_set_ready(c); content_set_done(c); /* Done: update status bar */ content_set_status(c, ""); return true; }