From 070c74b64822b40d2f80164ce5e207720506ef2e Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 17 Feb 2019 12:09:17 +0000 Subject: add webp image handler --- content/handlers/image/Makefile | 1 + content/handlers/image/image.c | 7 ++ content/handlers/image/webp.c | 232 ++++++++++++++++++++++++++++++++++++++++ content/handlers/image/webp.h | 29 +++++ 4 files changed, 269 insertions(+) create mode 100644 content/handlers/image/webp.c create mode 100644 content/handlers/image/webp.h (limited to 'content') diff --git a/content/handlers/image/Makefile b/content/handlers/image/Makefile index e5ac3b555..1c27f74d7 100644 --- a/content/handlers/image/Makefile +++ b/content/handlers/image/Makefile @@ -12,5 +12,6 @@ S_IMAGE_$(NETSURF_USE_PNG) += png.c S_IMAGE_$(NETSURF_USE_NSSVG) += svg.c S_IMAGE_$(NETSURF_USE_RSVG) += rsvg.c S_IMAGE_$(NETSURF_USE_VIDEO) += video.c +S_IMAGE_$(NETSURF_USE_WEBP) += webp.c S_IMAGE := $(S_IMAGE_YES) diff --git a/content/handlers/image/image.c b/content/handlers/image/image.c index 675fdd691..4eb366e0b 100644 --- a/content/handlers/image/image.c +++ b/content/handlers/image/image.c @@ -35,6 +35,7 @@ #include "image/png.h" #include "image/rsvg.h" #include "image/svg.h" +#include "image/webp.h" #include "image/image.h" /** @@ -94,6 +95,12 @@ nserror image_init(void) return error; #endif +#ifdef WITH_WEBP + error = nswebp_init(); + if (error != NSERROR_OK) + return error; +#endif + return error; } diff --git a/content/handlers/image/webp.c b/content/handlers/image/webp.c new file mode 100644 index 000000000..66a86c9f4 --- /dev/null +++ b/content/handlers/image/webp.c @@ -0,0 +1,232 @@ +/* + * Copyright 2019 Vincent Sanders + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file + * implementation of content handling for image/webp + * + * This implementation uses the google webp library. + * Image cache handling is performed by the generic NetSurf handler. + */ + +#include +#include +#include + +#include + +#include "utils/utils.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "netsurf/bitmap.h" +#include "content/llcache.h" +#include "content/content_protected.h" +#include "desktop/gui_internal.h" + +#include "image/image_cache.h" + +#include "webp.h" + +/** + * Content create entry point. + * + * create a content object for the webp + */ +static nserror +webp_create(const content_handler *handler, + lwc_string *imime_type, + const struct http_parameter *params, + llcache_handle *llcache, + const char *fallback_charset, + bool quirks, + struct content **c) +{ + struct content *webp_c; /* webp content object */ + nserror res; + + webp_c = calloc(1, sizeof(struct content)); + if (webp_c == NULL) { + return NSERROR_NOMEM; + } + + res = content__init(webp_c, + handler, + imime_type, + params, + llcache, + fallback_charset, + quirks); + if (res != NSERROR_OK) { + free(webp_c); + return res; + } + + *c = webp_c; + + return NSERROR_OK; +} + +/** + * create a bitmap from webp content. + */ +static struct bitmap * +webp_cache_convert(struct content *c) +{ + const uint8_t *source_data; /* webp source data */ + unsigned long source_size; /* length of webp source data */ + VP8StatusCode webpres; + WebPBitstreamFeatures webpfeatures; + unsigned int bmap_flags; + uint8_t *pixels = NULL; + uint8_t *decoded; + size_t rowstride; + struct bitmap *bitmap = NULL; + + source_data = (uint8_t *)content__get_source_data(c, &source_size); + + webpres = WebPGetFeatures(source_data, source_size, &webpfeatures); + + if (webpres != VP8_STATUS_OK) { + return NULL; + } + + if (webpfeatures.has_alpha == 0) { + bmap_flags = BITMAP_NEW | BITMAP_OPAQUE; + } else { + bmap_flags = BITMAP_NEW; + } + + /* create bitmap */ + bitmap = guit->bitmap->create(webpfeatures.width, + webpfeatures.height, + bmap_flags); + if (bitmap == NULL) { + /* empty bitmap could not be created */ + return NULL; + } + + pixels = guit->bitmap->get_buffer(bitmap); + if (pixels == NULL) { + /* bitmap with no buffer available */ + guit->bitmap->destroy(bitmap); + return NULL; + } + + rowstride = guit->bitmap->get_rowstride(bitmap); + + decoded = WebPDecodeBGRAInto(source_data, + source_size, + pixels, + webpfeatures.width * webpfeatures.height * 4, + rowstride); + if (decoded == NULL) { + /* decode failed */ + guit->bitmap->destroy(bitmap); + return NULL; + } + + return bitmap; +} + +/** + * Convert the webp source data content. + * + * This ensures there is valid webp source data in the content object + * and then adds it to the image cache ready to be converted on + * demand. + * + * \param c The webp content object + * \return true on successful processing of teh webp content else false + */ +static bool webp_convert(struct content *c) +{ + int res; + unsigned long data_size; + const uint8_t* data; + int width; + int height; + + data = (uint8_t *)content__get_source_data(c, &data_size); + + res = WebPGetInfo(data, data_size, &width, &height); + if (res == 0) { + NSLOG(netsurf, INFO, "WebPGetInfo failed:%p", c); + return false; + } + + c->width = width; + c->height = height; + c->size = c->width * c->height * 4; + + image_cache_add(c, NULL, webp_cache_convert); + + content_set_ready(c); + content_set_done(c); + + return true; +} + +/** + * Clone content. + */ +static nserror webp_clone(const struct content *old, struct content **new_c) +{ + struct content *webp_c; /* cloned webp content */ + nserror res; + + webp_c = calloc(1, sizeof(struct content)); + if (webp_c == NULL) { + return NSERROR_NOMEM; + } + + res = content__clone(old, webp_c); + if (res != NSERROR_OK) { + content_destroy(webp_c); + return res; + } + + /* re-convert if the content is ready */ + if ((old->status == CONTENT_STATUS_READY) || + (old->status == CONTENT_STATUS_DONE)) { + if (webp_convert(webp_c) == false) { + content_destroy(webp_c); + return NSERROR_CLONE_FAILED; + } + } + + *new_c = webp_c; + + return NSERROR_OK; +} + +static const content_handler webp_content_handler = { + .create = webp_create, + .data_complete = webp_convert, + .destroy = image_cache_destroy, + .redraw = image_cache_redraw, + .clone = webp_clone, + .get_internal = image_cache_get_internal, + .type = image_cache_content_type, + .no_share = false, +}; + +static const char *webp_types[] = { + "image/webp" +}; + +CONTENT_FACTORY_REGISTER_TYPES(nswebp, webp_types, webp_content_handler); diff --git a/content/handlers/image/webp.h b/content/handlers/image/webp.h new file mode 100644 index 000000000..b219f2576 --- /dev/null +++ b/content/handlers/image/webp.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Vincent Sanders + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file + * Interface to image/webp content handlers + */ + +#ifndef _NETSURF_IMAGE_WEBP_H_ +#define _NETSURF_IMAGE_WEBP_H_ + +nserror nswebp_init(void); + +#endif -- cgit v1.2.3