From 9c73b1a5d68b3dcb7299ea8017ad1ece1d5c69bb Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Sun, 29 Mar 2020 23:03:20 -0400
Subject: [PATCH] Add filepicker, local bitmap, and texture saving support for
 webp

---
 indra/newview/llfilepicker.cpp                | 47 +++++++++++++++----
 indra/newview/llfilepicker.h                  |  3 +-
 indra/newview/lllocalbitmaps.cpp              | 16 +++++++
 indra/newview/lllocalbitmaps.h                |  3 +-
 indra/newview/llpreviewtexture.cpp            | 15 ++++--
 indra/newview/llviewermenufile.cpp            |  2 +-
 .../newview/skins/default/xui/en/strings.xml  |  3 +-
 7 files changed, 74 insertions(+), 15 deletions(-)

diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 919e2337ef4..377ac761258 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -52,7 +52,7 @@ LLFilePicker LLFilePicker::sInstance;
 
 #if LL_WINDOWS
 #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
-#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
+#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png; *.webp)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png;*.webp\0"
 #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0"
 #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
 #ifdef _CORY_TESTING
@@ -442,7 +442,17 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,
 			L"PNG Images (*.png)\0*.png\0" \
 			L"\0";
 		break;
-	case FFSAVE_TGAPNG:
+	case FFSAVE_WEBP:
+		if (filename.empty())
+		{
+			wcsncpy(mFilesW, L"untitled.webp", FILENAME_BUFFER_SIZE);	/*Flawfinder: ignore*/
+		}
+		mOFN.lpstrDefExt = L"webp";
+		mOFN.lpstrFilter =
+			L"WebP Images (*.webp)\0*.webp\0" \
+			L"\0";
+		break;
+	case FFSAVE_TGAPNGWEBP:
 		if (filename.empty())
 		{
 			wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE);	/*Flawfinder: ignore*/
@@ -452,9 +462,10 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,
 		mOFN.lpstrFilter =
 			L"PNG Images (*.png)\0*.png\0" \
 			L"Targa Images (*.tga)\0*.tga\0" \
+			L"WebP Images (*.webp)\0*.webp\0" \
 			L"\0";
 		break;
-		
+
 	case FFSAVE_JPEG:
 		if (filename.empty())
 		{
@@ -614,6 +625,7 @@ std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) //
             allowedv->push_back("bmpf");
             allowedv->push_back("tpic");
             allowedv->push_back("png");
+			allowedv->push_back("webp");
             break;
         case FFLOAD_EXE:
             allowedv->push_back("app");
@@ -704,10 +716,10 @@ bool	LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena
 			creator = "prvw";
 			extension = "tga";
 			break;
-		case FFSAVE_TGAPNG:
+		case FFSAVE_TGAPNGWEBP:
 			type = "PNG";
 			creator = "prvw";
-			extension = "png,tga";
+			extension = "png,tga,webp";
 			break;
 		case FFSAVE_BMP:
 			type = "BMPf";
@@ -724,6 +736,11 @@ bool	LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena
 			creator = "prvw";
 			extension = "png";
 			break;
+		case FFSAVE_WEBP:
+			type = "WebP";
+			creator = "prvw";
+			extension = "webp";
+			break;
 		case FFSAVE_AVI:
 			type = "\?\?\?\?";
 			creator = "\?\?\?\?";
@@ -1017,6 +1034,10 @@ void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer
 		{
 			picker->mCurrentExtension = ".tga";
 		}
+		else if (filter == LLTrans::getString("webp_image_files"))
+		{
+			picker->mCurrentExtension = ".webp";
+		}
 	}
 
 	// set the default path for this usage context.
@@ -1206,17 +1227,22 @@ static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker)
 {
 	GtkFileFilter *gfilter_tga = gtk_file_filter_new();
 	GtkFileFilter *gfilter_png = gtk_file_filter_new();
+	GtkFileFilter *gfilter_webp = gtk_file_filter_new();
 
 	gtk_file_filter_add_pattern(gfilter_tga, "*.tga");
 	gtk_file_filter_add_mime_type(gfilter_png, "image/png");
-	std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)";
+	gtk_file_filter_add_pattern(gfilter_webp, "*.webp");
+	std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png; *.webp)";
 	gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str());
 	gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str());
+	gtk_file_filter_set_name(gfilter_webp, LLTrans::getString("webp_image_files").c_str());
 
 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
 					gfilter_png);
 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
 					gfilter_tga);
+	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
+					gfilter_webp);
 	return caption;
 }
 
@@ -1262,7 +1288,12 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 				(picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)");
 			suggest_ext = ".png";
 			break;
-		case FFSAVE_TGAPNG:
+		case FFSAVE_WEBP:
+			caption += add_simple_pattern_filter_to_gtkchooser
+			(picker, "*.webp", LLTrans::getString("webp_image_files") + " (*.webp)");
+			suggest_ext = ".webp";
+			break;
+		case FFSAVE_TGAPNGWEBP:
 			caption += add_save_texture_filter_to_gtkchooser(picker);
 			suggest_ext = ".png";
 			break;
@@ -1324,7 +1355,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 
 		rtn = (getFileCount() == 1);
 
-		if(rtn && filter == FFSAVE_TGAPNG)
+		if(rtn && filter == FFSAVE_TGAPNGWEBP)
 		{
 			std::string selected_file = mFiles.back();
 			mFiles.pop_back();
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index c1fa147d2d7..bc8c6eaf5a6 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -110,7 +110,8 @@ class LLFilePicker
 		FFSAVE_PNG = 13,
 		FFSAVE_JPEG = 14,
 		FFSAVE_SCRIPT = 15,
-		FFSAVE_TGAPNG = 16
+		FFSAVE_TGAPNGWEBP = 16,
+		FFSAVE_WEBP = 17
 	};
 
 	// open the dialog. This is a modal operation
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 5a17332fde6..3714bc67352 100644
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -40,6 +40,7 @@
 #include "llimagetga.h"
 #include "llimagejpeg.h"
 #include "llimagepng.h"
+#include "llimagewebp.h"
 
 /* time headers */
 #include <time.h>
@@ -109,6 +110,10 @@ LLLocalBitmap::LLLocalBitmap(std::string filename)
 	{
 		mExtension = ET_IMG_PNG;
 	}
+	else if (temp_exten == "webp")
+	{
+		mExtension = ET_IMG_WEBP;
+	}
 	else
 	{
 		LL_WARNS() << "File of no valid extension given, local bitmap creation aborted." << "\n"
@@ -324,6 +329,17 @@ bool LLLocalBitmap::decodeBitmap(LLPointer<LLImageRaw> rawimg)
 			break;
 		}
 
+		case ET_IMG_WEBP:
+		{
+			LLPointer<LLImageWebP> webp_image = new LLImageWebP;
+			if (webp_image->load(mFilename) && webp_image->decode(rawimg, 0.0f))
+			{
+				rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+				decode_successful = true;
+			}
+			break;
+		}
+
 		default:
 		{
 			// separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index d5ee7efdc64..226dbbe4949 100644
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -80,7 +80,8 @@ class LLLocalBitmap
 			ET_IMG_BMP,
 			ET_IMG_TGA,
 			ET_IMG_JPG,
-			ET_IMG_PNG
+			ET_IMG_PNG,
+			ET_IMG_WEBP
 		};
 
 	private: /* members */
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 90cc18fbe98..d625548c7bb 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -37,6 +37,7 @@
 #include "llfloaterreg.h"
 #include "llimagetga.h"
 #include "llimagepng.h"
+#include "llimagewebp.h"
 #include "llinventory.h"
 #include "llinventorymodel.h"
 #include "llnotificationsutil.h"
@@ -295,7 +296,7 @@ void LLPreviewTexture::saveAs()
 		return;
 
 	std::string filename = getItem() ? LLDir::getScrubbedFileName(getItem()->getName()) : LLStringUtil::null;
-	(new LLFilePickerReplyThread(boost::bind(&LLPreviewTexture::saveTextureToFile, this, _1), LLFilePicker::FFSAVE_TGAPNG, filename))->getFile();
+	(new LLFilePickerReplyThread(boost::bind(&LLPreviewTexture::saveTextureToFile, this, _1), LLFilePicker::FFSAVE_TGAPNGWEBP, filename))->getFile();
 }
 
 void LLPreviewTexture::saveTextureToFile(const std::vector<std::string>& filenames)
@@ -412,8 +413,12 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success,
 
 	if( self && final && success )
 	{
-		const U32 ext_length = 3;
-		std::string extension = self->mSaveFileName.substr( self->mSaveFileName.length() - ext_length);
+		std::string extension;
+		size_t extpos = self->mSaveFileName.rfind(".");
+		if (extpos != std::string::npos)
+		{
+			extension = self->mSaveFileName.substr(extpos + 1);
+		}
 
 		// We only support saving in PNG or TGA format
 		LLPointer<LLImageFormatted> image;
@@ -425,6 +430,10 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success,
 		{
 			image = new LLImageTGA;
 		}
+		else if (extension == "webp")
+		{
+			image = new LLImageWebP;
+		}
 
 		if( image && !image->encode( src, 0 ) )
 		{
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 17945dfdb66..755fed4705c 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -258,7 +258,7 @@ void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames)
 
 #if LL_WINDOWS
 static std::string SOUND_EXTENSIONS = "wav";
-static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
+static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png webp";
 static std::string ANIM_EXTENSIONS =  "bvh anim";
 #ifdef _CORY_TESTING
 static std::string GEOMETRY_EXTENSIONS = "slg";
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index e3163d6c857..112b2cdbda4 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -563,7 +563,8 @@ http://secondlife.com/support for help fixing this problem.
 	<string name="targa_image_files">Targa Images</string>
 	<string name="bitmap_image_files">Bitmap Images</string>
 	<string name="png_image_files">PNG Images</string>
-	<string name="save_texture_image_files">Targa or PNG Images</string>
+	<string name="webp_image_files">WebP Images</string>
+	<string name="save_texture_image_files">Targa, PNG, or WebP Images</string>
 	<string name="avi_movie_file">AVI Movie File</string>
 	<string name="xaf_animation_file">XAF Anim File</string>
 	<string name="xml_file">XML File</string>
-- 
GitLab