From 522bcf17b759910040225c209f7851fbb0640c56 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Tue, 30 Nov 2010 20:52:30 -0800
Subject: [PATCH] SOCIAL-311 PARTIAL FIX Media browser has too many oddities to
 be useful for viewer web apps

---
 indra/newview/CMakeLists.txt                  |   2 +
 indra/newview/llfloaterwebcontent.cpp         | 276 ++++++++++++++++++
 indra/newview/llfloaterwebcontent.h           |  71 +++++
 indra/newview/llviewerfloaterreg.cpp          |   2 +
 indra/newview/llviewermenu.cpp                |   9 +-
 indra/newview/llweb.cpp                       |   8 +
 indra/newview/llweb.h                         |   4 +
 .../default/xui/en/floater_web_content.xml    | 124 ++++++++
 .../skins/default/xui/en/menu_login.xml       |   7 +
 .../skins/default/xui/en/menu_viewer.xml      |   9 +-
 10 files changed, 510 insertions(+), 2 deletions(-)
 create mode 100644 indra/newview/llfloaterwebcontent.cpp
 create mode 100644 indra/newview/llfloaterwebcontent.h
 create mode 100644 indra/newview/skins/default/xui/en/floater_web_content.xml

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d44b0ce6799..ef572268ca0 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -220,6 +220,7 @@ set(viewer_SOURCE_FILES
     llfloaterurlentry.cpp
     llfloatervoiceeffect.cpp
     llfloaterwater.cpp
+    llfloaterwebcontent.cpp
     llfloaterwhitelistentry.cpp
     llfloaterwindlight.cpp
     llfloaterwindowsize.cpp
@@ -752,6 +753,7 @@ set(viewer_HEADER_FILES
     llfloaterurlentry.h
     llfloatervoiceeffect.h
     llfloaterwater.h
+    llfloaterwebcontent.h
     llfloaterwhitelistentry.h
     llfloaterwindlight.h
     llfloaterwindowsize.h
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
new file mode 100644
index 00000000000..138ddeabdac
--- /dev/null
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -0,0 +1,276 @@
+/** 
+ * @file llfloaterwebcontent.cpp
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterwebcontent.h"
+
+#include "llfloaterreg.h"
+#include "llparcel.h"
+#include "llpluginclassmedia.h"
+#include "lluictrlfactory.h"
+#include "llmediactrl.h"
+#include "llviewerwindow.h"
+#include "llviewercontrol.h"
+#include "llviewerparcelmgr.h"
+#include "llweb.h"
+#include "llui.h"
+#include "roles_constants.h"
+
+#include "llurlhistory.h"
+#include "llviewermedia.h"
+#include "llviewerparcelmedia.h"
+#include "llcombobox.h"
+#include "llwindow.h"
+#include "lllayoutstack.h"
+#include "llcheckboxctrl.h"
+
+#include "llnotifications.h"
+
+// TEMP
+#include "llsdutil.h"
+
+LLFloaterWebContent::LLFloaterWebContent(const LLSD& key)
+	: LLFloater(key)
+{
+}
+
+//static 
+void LLFloaterWebContent::create(const std::string &url, const std::string& target, const std::string& uuid)
+{
+	lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
+	
+	std::string tag = target;
+	
+	if(target.empty() || target == "_blank")
+	{
+		if(!uuid.empty())
+		{
+			tag = uuid;
+		}
+		else
+		{
+			// create a unique tag for this instance
+			LLUUID id;
+			id.generate();
+			tag = id.asString();
+		}
+	}
+	
+	S32 browser_window_limit = gSavedSettings.getS32("MediaBrowserWindowLimit");
+	
+	if(LLFloaterReg::findInstance("web_content", tag) != NULL)
+	{
+		// There's already a web browser for this tag, so we won't be opening a new window.
+	}
+	else if(browser_window_limit != 0)
+	{
+		// showInstance will open a new window.  Figure out how many web browsers are already open, 
+		// and close the least recently opened one if this will put us over the limit.
+		
+		LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
+		lldebugs << "total instance count is " << instances.size() << llendl;
+		
+		for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
+		{
+			lldebugs << "    " << (*iter)->getKey() << llendl;
+		}
+		
+		if(instances.size() >= (size_t)browser_window_limit)
+		{
+			// Destroy the least recently opened instance
+			(*instances.begin())->closeFloater();
+		}
+	}
+
+	LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
+	llassert(browser);
+	if(browser)
+	{
+		browser->mUUID = uuid;
+
+		// tell the browser instance to load the specified URL
+		browser->openMedia(url, target);
+		LLViewerMedia::proxyWindowOpened(target, uuid);
+	}
+}
+
+//static 
+void LLFloaterWebContent::closeRequest(const std::string &uuid)
+{
+	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+	{
+		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+		lldebugs << "    " << i->mUUID << llendl;
+		if (i && i->mUUID == uuid)
+		{
+			i->closeFloater(false);
+			return;
+ 		}
+ 	}
+}
+
+//static 
+void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
+{
+	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
+	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
+	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+	{
+		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
+		lldebugs << "    " << i->mUUID << llendl;
+		if (i && i->mUUID == uuid)
+		{
+			i->geometryChanged(x, y, width, height);
+			return;
+		}
+	}
+}
+	
+void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
+{	
+	// Make sure the layout of the browser control is updated, so this calculation is correct.
+	LLLayoutStack::updateClass();
+		
+	// TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
+	LLCoordWindow window_size;
+	getWindow()->getSize(&window_size);
+
+	// Adjust width and height for the size of the chrome on the web Browser window.
+	width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
+	height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
+	
+	LLRect geom;
+	geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
+
+	lldebugs << "geometry change: " << geom << llendl;
+	
+	handleReshape(geom,false);
+}
+
+void LLFloaterWebContent::openMedia(const std::string& web_url, const std::string& target)
+{
+	mWebBrowser->setHomePageUrl(web_url);
+	mWebBrowser->setTarget(target);
+	mWebBrowser->navigateTo(web_url);
+	setCurrentURL(web_url);
+}
+
+void LLFloaterWebContent::draw()
+{
+//	getChildView("go")->setEnabled(!mAddressCombo->getValue().asString().empty());
+
+	getChildView("back")->setEnabled(mWebBrowser->canNavigateBack());
+	getChildView("forward")->setEnabled(mWebBrowser->canNavigateForward());
+
+	LLFloater::draw();
+}
+
+BOOL LLFloaterWebContent::postBuild()
+{
+	mWebBrowser = getChild<LLMediaCtrl>("webbrowser");
+	mWebBrowser->addObserver(this);
+
+	childSetAction("back", onClickBack, this);
+	childSetAction("forward", onClickForward, this);
+	childSetAction("reload", onClickRefresh, this);
+	childSetAction("go", onClickGo, this);
+
+	return TRUE;
+}
+
+//virtual
+void LLFloaterWebContent::onClose(bool app_quitting)
+{
+	LLViewerMedia::proxyWindowClosed(mUUID);
+	destroy();
+}
+
+void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+	if(event == MEDIA_EVENT_LOCATION_CHANGED)
+	{
+		setCurrentURL(self->getLocation());
+	}
+	else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+	{
+		// This is the event these flags are sent with.
+		getChildView("back")->setEnabled(self->getHistoryBackAvailable());
+		getChildView("forward")->setEnabled(self->getHistoryForwardAvailable());
+	}
+	else if(event == MEDIA_EVENT_CLOSE_REQUEST)
+	{
+		// The browser instance wants its window closed.
+		closeFloater();
+	}
+	else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
+	{
+		geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
+	}
+}
+
+void LLFloaterWebContent::setCurrentURL(const std::string& url)
+{
+	mCurrentURL = url;
+
+	getChildView("back")->setEnabled(mWebBrowser->canNavigateBack());
+	getChildView("forward")->setEnabled(mWebBrowser->canNavigateForward());
+	getChildView("reload")->setEnabled(TRUE);
+}
+
+//static 
+void LLFloaterWebContent::onClickRefresh(void* user_data)
+{
+	LLFloaterWebContent* self = (LLFloaterWebContent*)user_data;
+
+	self->mWebBrowser->navigateTo(self->mCurrentURL);
+}
+
+//static 
+void LLFloaterWebContent::onClickForward(void* user_data)
+{
+	LLFloaterWebContent* self = (LLFloaterWebContent*)user_data;
+
+	self->mWebBrowser->navigateForward();
+}
+
+//static 
+void LLFloaterWebContent::onClickBack(void* user_data)
+{
+	LLFloaterWebContent* self = (LLFloaterWebContent*)user_data;
+
+	self->mWebBrowser->navigateBack();
+}
+
+//static 
+void LLFloaterWebContent::onClickGo(void* user_data)
+{
+//	LLFloaterWebContent* self = (LLFloaterWebContent*)user_data;
+
+//	self->mWebBrowser->navigateTo(self->mAddressCombo->getValue().asString());
+}
diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h
new file mode 100644
index 00000000000..71346aa80ef
--- /dev/null
+++ b/indra/newview/llfloaterwebcontent.h
@@ -0,0 +1,71 @@
+/** 
+ * @file llfloaterwebcontent.h
+ * @brief floater for displaying web content - e.g. profiles and search (eventually)
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERWEBCONTENT_H
+#define LL_LLFLOATERWEBCONTENT_H
+
+#include "llfloater.h"
+#include "llmediactrl.h"
+
+class LLMediaCtrl;
+
+class LLFloaterWebContent : 
+	public LLFloater, 
+	public LLViewerMediaObserver
+{
+public:
+    LOG_CLASS(LLFloaterWebContent);
+	LLFloaterWebContent(const LLSD& key);
+
+	static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
+
+	static void closeRequest(const std::string &uuid);
+	static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
+	void geometryChanged(S32 x, S32 y, S32 width, S32 height);
+	
+	/*virtual*/ BOOL postBuild();
+	/*virtual*/ void onClose(bool app_quitting);
+	/*virtual*/ void draw();
+
+	// inherited from LLViewerMediaObserver
+	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
+
+	void openMedia(const std::string& media_url, const std::string& target);
+	void setCurrentURL(const std::string& url);
+
+	static void onClickRefresh(void* user_data);
+	static void onClickBack(void* user_data);
+	static void onClickForward(void* user_data);
+	static void onClickGo(void* user_data);
+
+private:
+	LLMediaCtrl* mWebBrowser;
+	std::string mCurrentURL;
+	std::string mUUID;
+};
+
+#endif  // LL_LLFLOATERWEBCONTENT_H
+
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index b3f14b441d4..9e44652d385 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -60,6 +60,7 @@
 #include "llfloaterhardwaresettings.h"
 #include "llfloaterhelpbrowser.h"
 #include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
 #include "llfloatermediasettings.h"
 #include "llfloaterhud.h"
 #include "llfloaterimagepreview.h"
@@ -250,6 +251,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
 	LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>);
 
+	LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWebContent>);	
 	LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);	
 	LLFloaterWindowSizeUtil::registerFloater();
 	LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);	
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2874a6ec793..a16f53083c6 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7175,6 +7175,12 @@ void handle_web_browser_test(const LLSD& param)
 	LLWeb::loadURLInternal(url);
 }
 
+void handle_web_content_test(const LLSD& param)
+{
+	std::string url = param.asString();
+	LLWeb::loadWebURLInternal(url);
+}
+
 void handle_buy_currency_test(void*)
 {
 	std::string url =
@@ -7925,7 +7931,8 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");
 
 	// Advanced > UI
-	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2));
+	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test,	_2));	// sigh! this one opens the MEDIA browser
+	commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2));	// this one opens the Web Content floater
 	view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
 	view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
 	view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 73a37a69932..91a713be56c 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -35,6 +35,7 @@
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llfloatermediabrowser.h"
+#include "llfloaterwebcontent.h"
 #include "llfloaterreg.h"
 #include "lllogininstance.h"
 #include "llparcel.h"
@@ -102,6 +103,13 @@ void LLWeb::loadURLInternal(const std::string &url, const std::string& target, c
 	LLFloaterMediaBrowser::create(url, target, uuid);
 }
 
+// static
+// Explicitly open a Web URL using the Web content floater
+void LLWeb::loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid)
+{
+	LLFloaterWebContent::create(url, target, uuid);
+}
+
 
 // static
 void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid)
diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h
index 29153765832..3fe5a4dcad9 100644
--- a/indra/newview/llweb.h
+++ b/indra/newview/llweb.h
@@ -57,6 +57,10 @@ class LLWeb
 	static void loadURLExternal(const std::string& url, const std::string& uuid);
 	static void loadURLExternal(const std::string& url, bool async, const std::string& uuid = LLStringUtil::null);
 
+	// Explicitly open a Web URL using the Web content floater vs. the more general media browser
+	static void loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid);
+	static void loadWebURLInternal(const std::string &url) { loadWebURLInternal(url, LLStringUtil::null, LLStringUtil::null); }
+
 	/// Returns escaped url (eg, " " to "%20") - used by all loadURL methods
 	static std::string escapeURL(const std::string& url);
 	/// Expands various strings like [LANG], [VERSION], etc. in a URL
diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml
new file mode 100644
index 00000000000..777c67261a8
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_web_content.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="440"
+ layout="topleft"
+ min_height="140"
+ min_width="467"
+ name="floater_web_content"
+ help_topic="floater_web_content"
+ save_rect="true"
+ auto_tile="true"
+ title="WEB CONTENT"
+ width="820">
+    <floater.string
+     name="home_page_url">
+        http://www.secondlife.com
+    </floater.string>
+    <layout_stack
+     bottom="440"
+     follows="left|right|top|bottom"
+     layout="topleft"
+     left="10"
+     name="stack1"
+     orientation="vertical" 
+     top="20"
+     width="800">
+        <layout_panel
+         auto_resize="false"
+         default_tab_group="1" 
+         height="20"
+         layout="topleft"
+         left="0"
+         min_height="20"
+         name="nav_controls"
+         top="400"
+         user_resize="false"
+         width="800">
+            <button
+             follows="left|top"
+             height="20"
+             label="Back"
+             layout="topleft"
+             left="0"
+             name="back"
+             top="0"
+             width="55">
+				<button.commit_callback
+				function="MediaBrowser.Back" />
+			</button>
+            <button
+             follows="left|top"
+             height="20"
+             label="Forward"
+             layout="topleft"
+             left_pad="3"
+             name="forward"
+             top_delta="0"
+             width="68">
+				<button.commit_callback
+				function="MediaBrowser.Forward" />
+			</button>
+            <button
+             enabled="false"
+             follows="left|top"
+             height="20"
+             label="Reload"
+             layout="topleft"
+             left_pad="2"
+             name="reload"
+             top_delta="0"
+             width="70">
+				<button.commit_callback
+				function="MediaBrowser.Refresh" />
+			</button>
+            <combo_box
+             allow_text_entry="true"
+             follows="left|top|right"
+             tab_group="1"
+             height="20"
+             layout="topleft"
+             left_pad="5"
+             max_chars="1024"
+             name="address"
+             combo_editor.select_on_focus="true"
+             top_delta="0"
+             width="540">
+				<combo_box.commit_callback
+				function="MediaBrowser.EnterAddress" />
+			</combo_box>
+            <button
+             enabled="false"
+             follows="right|top"
+             height="20"
+             label="Go"
+             layout="topleft"
+             left_pad="5"
+             name="go"
+             top_delta="0"
+             width="55">
+				<button.commit_callback
+				function="MediaBrowser.Go" />
+			</button>
+        </layout_panel>
+    
+        <layout_panel
+         height="40"
+         layout="topleft"
+         left_delta="0"
+         name="external_controls"
+         top_delta="0"
+         user_resize="false"
+         width="540">
+          <web_browser
+             bottom="-30"
+             follows="all"
+             layout="topleft"
+             left="0"
+             name="webbrowser"
+             top="0"
+             width="540" />
+        </layout_panel>
+    </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index 4f982cc8e9a..2f47d4e201c 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -182,6 +182,13 @@
            function="Advanced.WebBrowserTest"
            parameter="http://join.secondlife.com/"/>
         </menu_item_call>
+      <menu_item_call
+       label="Web Content Floater Test"
+       name="Web Content Floater Test">
+        <menu_item_call.on_click
+         function="Advanced.WebContentTest"
+         parameter="http://www.google.com"/>
+      </menu_item_call>
       <menu_item_separator/>
       <menu_item_check
         label="Show Grid Picker"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 796b15551a8..e98cdb0ccfe 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2615,7 +2615,14 @@
                  function="Advanced.WebBrowserTest"
                  parameter="http://secondlife.com/app/search/slurls.html"/>
             </menu_item_call>
-            <menu_item_call
+          <menu_item_call
+           label="Web Content Browser Test"
+           name="Web Content Browser Test">
+            <menu_item_call.on_click
+             function="Advanced.WebContentTest"
+             parameter="http://secondlife.com/app/search/slurls.html"/>
+          </menu_item_call>
+          <menu_item_call
              label="Dump SelectMgr"
              name="Dump SelectMgr">
                 <menu_item_call.on_click
-- 
GitLab