summaryrefslogtreecommitdiff
path: root/content/handlers/image/webp.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2019-02-17 11:50:39 +0000
committerVincent Sanders <vince@kyllikki.org>2019-02-17 11:50:39 +0000
commit160d15b45b45136d273b16fefb59d9071dd77d6d (patch)
tree7be89e0aad92e71c0fd5094132918309fadc31b8 /content/handlers/image/webp.c
parent54371c28f07e638694ad2148e8900e1bae71e3d4 (diff)
downloadnetsurf-160d15b45b45136d273b16fefb59d9071dd77d6d.tar.gz
netsurf-160d15b45b45136d273b16fefb59d9071dd77d6d.tar.bz2
add webp image handlervince/webp
Diffstat (limited to 'content/handlers/image/webp.c')
-rw-r--r--content/handlers/image/webp.c232
1 files changed, 232 insertions, 0 deletions
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 <vince@netsurf-browser.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \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 <stdbool.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#include <webp/decode.h>
+
+#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);