From 42c6a67dcac26e9c313dc96b2493a167b09f13a1 Mon Sep 17 00:00:00 2001
From: Leon Krause <lk@leonkrause.com>
Date: Sun, 16 Sep 2018 19:37:36 +0200
Subject: [PATCH] Implement OS::set_icon in HTML5 platform

---
 platform/javascript/os_javascript.cpp | 52 +++++++++++++++++++++++++++
 platform/javascript/os_javascript.h   |  1 +
 2 files changed, 53 insertions(+)

diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 3515eeeb603..b0ec3c42458 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -39,6 +39,7 @@
 #include "unix/file_access_unix.h"
 
 #include <emscripten.h>
+#include <png.h>
 #include <stdlib.h>
 
 #include "dom_keys.inc"
@@ -912,6 +913,57 @@ void OS_JavaScript::set_window_title(const String &p_title) {
 	/* clang-format on */
 }
 
+void OS_JavaScript::set_icon(const Ref<Image> &p_icon) {
+
+	ERR_FAIL_COND(p_icon.is_null());
+	Ref<Image> icon = p_icon;
+	if (icon->is_compressed()) {
+		icon = icon->duplicate();
+		ERR_FAIL_COND(icon->decompress() != OK)
+	}
+	if (icon->get_format() != Image::FORMAT_RGBA8) {
+		if (icon == p_icon)
+			icon = icon->duplicate();
+		icon->convert(Image::FORMAT_RGBA8);
+	}
+
+	png_image png_meta;
+	memset(&png_meta, 0, sizeof png_meta);
+	png_meta.version = PNG_IMAGE_VERSION;
+	png_meta.width = icon->get_width();
+	png_meta.height = icon->get_height();
+	png_meta.format = PNG_FORMAT_RGBA;
+
+	PoolByteArray png;
+	size_t len;
+	PoolByteArray::Read r = icon->get_data().read();
+	ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, r.ptr(), 0, NULL));
+
+	png.resize(len);
+	PoolByteArray::Write w = png.write();
+	ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, w.ptr(), &len, 0, r.ptr(), 0, NULL));
+	w = PoolByteArray::Write();
+
+	r = png.read();
+	/* clang-format off */
+	EM_ASM_ARGS({
+		var PNG_PTR = $0;
+		var PNG_LEN = $1;
+
+		var png = new Blob([HEAPU8.slice(PNG_PTR, PNG_PTR + PNG_LEN)], { type: "image/png" });
+		var url = URL.createObjectURL(png);
+		var link = document.getElementById('-gd-engine-icon');
+		if (link === null) {
+			link = document.createElement('link');
+			link.rel = 'icon';
+			link.id = '-gd-engine-icon';
+			document.head.appendChild(link);
+		}
+		link.href = url;
+	}, r.ptr(), len);
+	/* clang-format on */
+}
+
 String OS_JavaScript::get_executable_path() const {
 
 	return OS::get_executable_path();
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index f40fb8fc7e6..ddcbf8c7c9c 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -135,6 +135,7 @@ public:
 
 	virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
 	virtual void set_window_title(const String &p_title);
+	virtual void set_icon(const Ref<Image> &p_icon);
 	String get_executable_path() const;
 	virtual Error shell_open(String p_uri);
 	virtual String get_name();