summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.hgtags1
-rwxr-xr-xdoc/contributions.txt1
-rwxr-xr-xindra/llcommon/llmemory.cpp3
-rwxr-xr-xindra/llcommon/llmemory.h2
-rw-r--r--indra/llcommon/lluriparser.cpp10
-rwxr-xr-xindra/llimage/llimagebmp.cpp14
-rwxr-xr-xindra/llimage/llimagetga.cpp6
-rwxr-xr-xindra/llmath/llvolume.cpp30
-rwxr-xr-xindra/llmath/llvolume.h4
-rwxr-xr-xindra/llplugin/llpluginclassmedia.cpp258
-rwxr-xr-xindra/llplugin/llpluginclassmedia.h9
-rwxr-xr-xindra/llprimitive/llprimitive.cpp52
-rwxr-xr-xindra/llprimitive/llprimitive.h5
-rwxr-xr-xindra/llprimitive/llprimtexturelist.cpp11
-rwxr-xr-xindra/llprimitive/llprimtexturelist.h2
-rwxr-xr-xindra/llprimitive/lltextureentry.cpp4
-rwxr-xr-xindra/llprimitive/lltextureentry.h4
-rwxr-xr-xindra/llui/lldockablefloater.cpp2
-rw-r--r--indra/llui/llfolderviewitem.cpp45
-rwxr-xr-xindra/llui/llfolderviewitem.h4
-rwxr-xr-xindra/llui/llfolderviewmodel.h2
-rwxr-xr-xindra/llui/llmenugl.cpp58
-rwxr-xr-xindra/llui/llmenugl.h5
-rwxr-xr-xindra/llui/llsearcheditor.cpp13
-rwxr-xr-xindra/llui/llsearcheditor.h2
-rwxr-xr-xindra/llui/lltextbase.cpp53
-rwxr-xr-xindra/llui/lltextbase.h8
-rwxr-xr-xindra/llui/llurlentry.cpp88
-rwxr-xr-xindra/llui/llurlentry.h24
-rwxr-xr-xindra/llui/llurlregistry.cpp47
-rwxr-xr-xindra/llui/tests/llurlentry_test.cpp172
-rwxr-xr-xindra/llwindow/llwindow.cpp4
-rwxr-xr-xindra/llwindow/llwindowmacosx-objc.h1
-rwxr-xr-xindra/newview/app_settings/settings.xml2
-rwxr-xr-xindra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl3
-rwxr-xr-xindra/newview/app_settings/shaders/class1/deferred/bumpF.glsl24
-rwxr-xr-xindra/newview/installers/windows/installer_template.nsi4
-rwxr-xr-xindra/newview/llagent.cpp2
-rwxr-xr-xindra/newview/llagentdata.cpp1
-rwxr-xr-xindra/newview/llagentdata.h1
-rwxr-xr-xindra/newview/llappearancemgr.cpp4
-rwxr-xr-xindra/newview/llappviewer.cpp9
-rwxr-xr-xindra/newview/llappviewermacosx.cpp50
-rwxr-xr-xindra/newview/llcallingcard.cpp25
-rwxr-xr-xindra/newview/llcallingcard.h3
-rwxr-xr-xindra/newview/llchathistory.cpp4
-rwxr-xr-xindra/newview/llconversationlog.h3
-rwxr-xr-xindra/newview/llconversationmodel.cpp19
-rwxr-xr-xindra/newview/lldrawpoolavatar.cpp22
-rwxr-xr-xindra/newview/lldrawpoolbump.cpp1
-rw-r--r--indra/newview/llexperienceassociationresponder.cpp9
-rwxr-xr-xindra/newview/llfavoritesbar.cpp384
-rwxr-xr-xindra/newview/llfavoritesbar.h26
-rwxr-xr-xindra/newview/llfloaterabout.cpp93
-rwxr-xr-xindra/newview/llfloaterabout.h3
-rwxr-xr-xindra/newview/llfloaterbump.cpp32
-rwxr-xr-xindra/newview/llfloaterbump.h4
-rw-r--r--indra/newview/llfloaterfacebook.cpp6
-rwxr-xr-xindra/newview/llfloaterimcontainer.cpp74
-rwxr-xr-xindra/newview/llfloaterimcontainer.h2
-rwxr-xr-xindra/newview/llfloaterjoystick.cpp14
-rwxr-xr-xindra/newview/llfloaterjoystick.h5
-rwxr-xr-xindra/newview/llfloaterland.cpp3
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp6
-rwxr-xr-xindra/newview/llfloaterperms.cpp86
-rwxr-xr-xindra/newview/llfloaterperms.h33
-rwxr-xr-xindra/newview/llfloaterpreference.cpp25
-rwxr-xr-xindra/newview/llfloaterpreference.h3
-rwxr-xr-xindra/newview/llfloaterreporter.cpp2
-rwxr-xr-xindra/newview/llfloatersnapshot.cpp8
-rwxr-xr-xindra/newview/llfloatertos.cpp6
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp6
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.cpp23
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.h1
-rwxr-xr-xindra/newview/llgroupmgr.cpp88
-rwxr-xr-xindra/newview/llgroupmgr.h7
-rwxr-xr-xindra/newview/llinventorybridge.cpp78
-rwxr-xr-xindra/newview/llinventorybridge.h2
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp2
-rwxr-xr-xindra/newview/llinventoryfunctions.h6
-rwxr-xr-xindra/newview/lllocalbitmaps.cpp2
-rwxr-xr-xindra/newview/lllocationinputctrl.cpp5
-rwxr-xr-xindra/newview/lllogchat.cpp16
-rwxr-xr-xindra/newview/lllogchat.h1
-rwxr-xr-xindra/newview/llmanipscale.cpp16
-rwxr-xr-xindra/newview/llmaniptranslate.cpp8
-rwxr-xr-xindra/newview/llmediactrl.cpp33
-rwxr-xr-xindra/newview/llmediactrl.h5
-rwxr-xr-xindra/newview/llmoveview.cpp10
-rwxr-xr-xindra/newview/llnamelistctrl.cpp15
-rwxr-xr-xindra/newview/llnamelistctrl.h17
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp3
-rw-r--r--indra/newview/llpanelexperiencelisteditor.cpp6
-rw-r--r--indra/newview/llpanelexperiencelisteditor.h3
-rw-r--r--indra/newview/llpanelexperiencepicker.cpp42
-rwxr-xr-xindra/newview/llpanelface.h2
-rwxr-xr-xindra/newview/llpanelgroup.cpp4
-rwxr-xr-xindra/newview/llpanelgroupgeneral.cpp5
-rwxr-xr-xindra/newview/llpanelgroupinvite.cpp92
-rwxr-xr-xindra/newview/llpanelgrouproles.cpp136
-rwxr-xr-xindra/newview/llpanelgrouproles.h3
-rwxr-xr-xindra/newview/llpanellandmarkinfo.cpp1
-rwxr-xr-xindra/newview/llpanelmaininventory.cpp2
-rwxr-xr-xindra/newview/llpanelmediasettingsgeneral.cpp4
-rwxr-xr-xindra/newview/llpanelobject.cpp11
-rwxr-xr-xindra/newview/llpanelpeople.cpp18
-rwxr-xr-xindra/newview/llpanelpeople.h1
-rwxr-xr-xindra/newview/llpanelpicks.cpp2
-rwxr-xr-xindra/newview/llpanelplaces.cpp16
-rwxr-xr-xindra/newview/llpaneltopinfobar.cpp5
-rwxr-xr-xindra/newview/llpreviewscript.cpp10
-rwxr-xr-xindra/newview/llpreviewtexture.cpp1
-rwxr-xr-xindra/newview/llselectmgr.cpp27
-rwxr-xr-xindra/newview/llsidepaneltaskinfo.cpp24
-rwxr-xr-xindra/newview/llslurl.cpp7
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp109
-rw-r--r--indra/newview/llsnapshotlivepreview.h2
-rwxr-xr-xindra/newview/llspeakers.cpp17
-rwxr-xr-xindra/newview/llstartup.cpp22
-rwxr-xr-xindra/newview/lltexturecache.cpp9
-rwxr-xr-xindra/newview/lltooldraganddrop.cpp3
-rwxr-xr-xindra/newview/llurllineeditorctrl.cpp2
-rwxr-xr-xindra/newview/llviewermedia.h1
-rwxr-xr-xindra/newview/llviewermenu.cpp25
-rwxr-xr-xindra/newview/llviewermessage.cpp32
-rwxr-xr-xindra/newview/llviewerobject.cpp32
-rwxr-xr-xindra/newview/llviewerobject.h2
-rwxr-xr-xindra/newview/llviewerstats.cpp5
-rwxr-xr-xindra/newview/llviewerwindow.cpp20
-rwxr-xr-xindra/newview/llviewerwindow.h2
-rwxr-xr-xindra/newview/llvoavatar.cpp22
-rwxr-xr-xindra/newview/llvoavatar.h2
-rwxr-xr-xindra/newview/llvovolume.cpp161
-rwxr-xr-xindra/newview/llvovolume.h6
-rwxr-xr-xindra/newview/llworldmap.cpp1
-rwxr-xr-xindra/newview/skins/default/xui/da/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/da/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/de/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/de/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about.xml8
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about_land.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_bumps.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_experiences.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_inventory.xml16
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_login.xml6
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_email.xml21
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml10
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml98
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_list_editor.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_main_inventory.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_people.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_advanced.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_setup.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml2
-rwxr-xr-xindra/newview/skins/default/xui/es/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/es/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/fr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/panel_login.xml3
-rwxr-xr-xindra/newview/skins/default/xui/it/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/it/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ja/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ja/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pl/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/pl/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pt/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/pt/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ru/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ru/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/tr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/tr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/zh/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/zh/notifications.xml3
-rwxr-xr-xindra/viewer_components/updater/llupdaterservice.cpp56
-rwxr-xr-xindra/viewer_components/updater/llupdaterservice.h1
175 files changed, 2384 insertions, 1122 deletions
diff --git a/.hgtags b/.hgtags
index 0cc10b0100..a7b8fd0a66 100755
--- a/.hgtags
+++ b/.hgtags
@@ -508,3 +508,4 @@ d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release
3a62616f3dd8bd512fcdfd29ef033b2505b11213 3.8.2-release
60572f718879f786f6bc8b5c9373ebebf4693078 3.8.3-release
27e3cf444c4cc645884960a61325a9ee0e9a2d0f 3.8.4-release
+e821ef17c6edea4a59997719d8ba416d8c16e143 3.8.5-release
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 211d4fcf08..7493e96c39 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -185,6 +185,7 @@ Ansariel Hiller
BUG-3764
STORM-1984
STORM-1979
+ MAINT-5533
Aralara Rajal
Arare Chantilly
CHUIBUG-191
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index ae11988df8..3a8eabac09 100755
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -2176,8 +2176,7 @@ void* ll_aligned_malloc_fallback( size_t size, int align )
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
- unsigned int for_alloc = sysinfo.dwPageSize;
- while(for_alloc < size) for_alloc += sysinfo.dwPageSize;
+ unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize;
void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
if(NULL == p) {
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index d3a9bbc4ae..0fb257aab1 100755
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -98,7 +98,7 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library
- // change preprocessro code to: #if 1 && defined(LL_WINDOWS)
+ // change preprocessor code to: #if 1 && defined(LL_WINDOWS)
#if 0 && defined(LL_WINDOWS)
void* ll_aligned_malloc_fallback( size_t size, int align );
diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp
index d98bc297e5..82d0dc8b4b 100644
--- a/indra/llcommon/lluriparser.cpp
+++ b/indra/llcommon/lluriparser.cpp
@@ -238,12 +238,12 @@ void LLUriParser::glueSecond(std::string& uri) const
{
uri += '?';
uri += mQuery;
+ }
- if (mFragment.size())
- {
- uri += '#';
- uri += mFragment;
- }
+ if (mFragment.size())
+ {
+ uri += '#';
+ uri += mFragment;
}
}
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp
index 8573fe0d91..a2ce2fee86 100755
--- a/indra/llimage/llimagebmp.cpp
+++ b/indra/llimage/llimagebmp.cpp
@@ -443,6 +443,10 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
mBitfieldMask[2] = 0x000000FF;
}
+ if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
S32 src_row_span = getWidth() * 4;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
@@ -476,6 +480,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
S32 src_row_span = getWidth() * 1;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
+ if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
+
for( S32 row = 0; row < getHeight(); row++ )
{
for( S32 col = 0; col < getWidth(); col++ )
@@ -501,6 +510,11 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
S32 src_row_span = getWidth() * 3;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
+ if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
+
for( S32 row = 0; row < getHeight(); row++ )
{
for( S32 col = 0; col < getWidth(); col++ )
diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp
index 4eb8dc7440..d0ae105ba7 100755
--- a/indra/llimage/llimagetga.cpp
+++ b/indra/llimage/llimagetga.cpp
@@ -437,7 +437,13 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu
// Origin is the bottom left
U8* dst = raw_image->getData();
U8* src = getData() + mDataOffset;
+
S32 pixels = getWidth() * getHeight();
+
+ if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
if (getComponents() == 4)
{
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 4703e6cf1a..8608e45a91 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2536,6 +2536,8 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
U32 cur_influence = 0;
LLVector4 wght(0,0,0,0);
+ U32 joints[4] = {0,0,0,0};
+ LLVector4 joints_with_weights(0,0,0,0);
while (joint != END_INFLUENCES && idx < weights.size())
{
@@ -2543,7 +2545,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
influence |= ((U16) weights[idx++] << 8);
F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
- wght.mV[cur_influence++] = (F32) joint + w;
+ wght.mV[cur_influence] = w;
+ joints[cur_influence] = joint;
+ cur_influence++;
if (cur_influence >= 4)
{
@@ -2554,8 +2558,16 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
joint = weights[idx++];
}
}
-
- face.mWeights[cur_vertex].loadua(wght.mV);
+ F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW];
+ if (wsum <= 0.f)
+ {
+ wght = LLVector4(0.99999f,0.f,0.f,0.f);
+ }
+ for (U32 k=0; k<4; k++)
+ {
+ joints_with_weights[k] = (F32) joints[k] + wght[k];
+ }
+ face.mWeights[cur_vertex].loadua(joints_with_weights.mV);
cur_vertex++;
}
@@ -5584,7 +5596,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
{
resizeVertices(num_vertices+1);
- if (!partial_build)
+ //if (!partial_build)
{
resizeIndices(num_indices+3);
}
@@ -5592,7 +5604,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
else
{
resizeVertices(num_vertices);
- if (!partial_build)
+ //if (!partial_build)
{
resizeIndices(num_indices);
}
@@ -5714,10 +5726,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LL_CHECK_MEMORY
- if (partial_build)
- {
- return TRUE;
- }
+ //if (partial_build)
+ //{
+ // return TRUE;
+ //}
if (mTypeMask & HOLLOW_MASK)
{
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 625f7cff02..1da2d0c6b1 100755
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -190,8 +190,12 @@ const U8 LL_SCULPT_TYPE_MESH = 5;
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
+// for value checks, assign new value after adding new types
+const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH;
+
const U8 LL_SCULPT_FLAG_INVERT = 64;
const U8 LL_SCULPT_FLAG_MIRROR = 128;
+const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR;
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index b48f664a2a..fd04fc4b62 100755
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file llpluginclassmedia.cpp
* @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2008&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$
* @endcond
@@ -41,7 +41,7 @@ static int nextPowerOf2( int value )
{
next_power_of_2 <<= 1;
}
-
+
return next_power_of_2;
}
@@ -63,19 +63,19 @@ LLPluginClassMedia::~LLPluginClassMedia()
}
bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
-{
+{
LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
-
+
mPlugin = new LLPluginProcessParent(this);
mPlugin->setSleepTime(mSleepTime);
-
+
// Queue up the media init message -- it will be sent after all the currently queued messages.
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
message.setValue("target", mTarget);
sendMessage(message);
-
+
mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
return true;
@@ -115,7 +115,7 @@ void LLPluginClassMedia::reset()
mTextureHeight = 0;
mMediaWidth = 0;
mMediaHeight = 0;
- mDirtyRect = LLRect::null;
+ mDirtyRect = LLRect::null;
mAutoScaleMedia = false;
mRequestedVolume = 1.0f;
mPriority = PRIORITY_NORMAL;
@@ -132,7 +132,7 @@ void LLPluginClassMedia::reset()
mMediaName.clear();
mMediaDescription.clear();
mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
-
+
// media_browser class
mNavigateURI.clear();
mNavigateResultCode = -1;
@@ -140,13 +140,15 @@ void LLPluginClassMedia::reset()
mHistoryBackAvailable = false;
mHistoryForwardAvailable = false;
mStatusText.clear();
- mProgressPercent = 0;
+ mProgressPercent = 0;
mClickURL.clear();
mClickNavType.clear();
mClickTarget.clear();
mClickUUID.clear();
mStatusCode = 0;
-
+
+ mClickEnforceTarget = false;
+
// media_time class
mCurrentTime = 0.0f;
mDuration = 0.0f;
@@ -160,7 +162,7 @@ void LLPluginClassMedia::idle(void)
{
mPlugin->idle();
}
-
+
if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
{
// Can't process a size change at this time
@@ -177,7 +179,7 @@ void LLPluginClassMedia::idle(void)
else
{
mRequestedTextureWidth = mRequestedMediaWidth;
-
+
if(mPadding > 1)
{
// Pad up to a multiple of the specified number of bytes per row
@@ -187,7 +189,7 @@ void LLPluginClassMedia::idle(void)
{
rowbytes += mPadding - pad;
}
-
+
if(rowbytes % mRequestedTextureDepth == 0)
{
mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
@@ -199,7 +201,7 @@ void LLPluginClassMedia::idle(void)
}
}
-
+
// Size change has been requested but not initiated yet.
size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
@@ -214,22 +216,22 @@ void LLPluginClassMedia::idle(void)
mPlugin->removeSharedMemory(mTextureSharedMemoryName);
mTextureSharedMemoryName.clear();
}
-
+
mTextureSharedMemorySize = newsize;
mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
if(!mTextureSharedMemoryName.empty())
{
void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-
+
// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
memset( addr, 0x00, newsize );
-
+
// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
// so it may not be worthwhile.
// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
}
}
-
+
// This is our local indicator that a change is in progress.
mTextureWidth = -1;
mTextureHeight = -1;
@@ -238,7 +240,7 @@ void LLPluginClassMedia::idle(void)
// This invalidates any existing dirty rect.
resetDirty();
-
+
// Send a size change message to the plugin
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
@@ -252,11 +254,11 @@ void LLPluginClassMedia::idle(void)
message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
message.setValueReal("background_a", mBackgroundColor.mV[VW]);
mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
-
+
LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
}
}
-
+
if(mPlugin && mPlugin->isRunning())
{
// Send queued messages
@@ -322,11 +324,11 @@ void LLPluginClassMedia::setSizeInternal(void)
mRequestedMediaWidth = mDefaultMediaWidth;
mRequestedMediaHeight = mDefaultMediaHeight;
}
-
+
// Save these for size/interest calculations
mFullMediaWidth = mRequestedMediaWidth;
mFullMediaHeight = mRequestedMediaHeight;
-
+
if(mAllowDownsample)
{
switch(mPriority)
@@ -340,19 +342,19 @@ void LLPluginClassMedia::setSizeInternal(void)
mRequestedMediaHeight /= 2;
}
break;
-
+
default:
// Don't adjust texture size
break;
}
}
-
+
if(mAutoScaleMedia)
{
mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
}
-
+
if(mRequestedMediaWidth > 2048)
mRequestedMediaWidth = 2048;
@@ -380,9 +382,9 @@ bool LLPluginClassMedia::textureValid(void)
mRequestedMediaWidth != mMediaWidth ||
mRequestedMediaHeight != mMediaHeight ||
getBitsData() == NULL
- )
+ )
return false;
-
+
return true;
}
@@ -406,8 +408,8 @@ void LLPluginClassMedia::resetDirty(void)
std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
{
std::string result;
-
-
+
+
if(modifiers & MASK_CONTROL)
{
result += "control|";
@@ -430,7 +432,7 @@ std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
{
result += "meta|";
}
-*/
+*/
return result;
}
@@ -538,11 +540,11 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
// Don't spam unnecessary mouse move events.
return;
}
-
+
mLastMouseX = x;
mLastMouseY = y;
}
-
+
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
std::string temp;
switch(type)
@@ -557,7 +559,7 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
message.setValueS32("button", button);
message.setValueS32("x", x);
-
+
// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
if(!mRequestedTextureCoordsOpenGL)
{
@@ -567,42 +569,42 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
message.setValueS32("y", y);
message.setValue("modifiers", translateModifiers(modifiers));
-
+
sendMessage(message);
}
bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
{
bool result = true;
-
+
// FIXME:
// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
// For now, return false for the ones the webkit plugin won't handle properly.
-
+
switch(key_code)
{
- case KEY_BACKSPACE:
- case KEY_TAB:
- case KEY_RETURN:
- case KEY_PAD_RETURN:
- case KEY_SHIFT:
- case KEY_CONTROL:
- case KEY_ALT:
- case KEY_CAPSLOCK:
- case KEY_ESCAPE:
- case KEY_PAGE_UP:
- case KEY_PAGE_DOWN:
- case KEY_END:
- case KEY_HOME:
- case KEY_LEFT:
- case KEY_UP:
- case KEY_RIGHT:
- case KEY_DOWN:
- case KEY_INSERT:
+ case KEY_BACKSPACE:
+ case KEY_TAB:
+ case KEY_RETURN:
+ case KEY_PAD_RETURN:
+ case KEY_SHIFT:
+ case KEY_CONTROL:
+ case KEY_ALT:
+ case KEY_CAPSLOCK:
+ case KEY_ESCAPE:
+ case KEY_PAGE_UP:
+ case KEY_PAGE_DOWN:
+ case KEY_END:
+ case KEY_HOME:
+ case KEY_LEFT:
+ case KEY_UP:
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ case KEY_INSERT:
case KEY_DELETE:
- // These will be handled
+ // These will be handled
break;
-
+
default:
// regular ASCII characters will also be handled
if(key_code >= KEY_SPECIAL)
@@ -613,7 +615,7 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
break;
}
-#if LL_DARWIN
+#if LL_DARWIN
if(modifiers & MASK_ALT)
{
// Option-key modified characters should be handled by the unicode input path instead of this one.
@@ -632,17 +634,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
case KEY_EVENT_REPEAT: temp = "repeat"; break;
}
message.setValue("event", temp);
-
+
message.setValueS32("key", key_code);
-
-
message.setValue("modifiers", translateModifiers(modifiers));
message.setValueLLSD("native_key_data", native_key_data);
-
+
sendMessage(message);
}
-
+
return result;
}
@@ -653,10 +653,10 @@ void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
message.setValueS32("x", x);
message.setValueS32("y", y);
message.setValue("modifiers", translateModifiers(modifiers));
-
+
sendMessage(message);
}
-
+
bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
@@ -664,9 +664,9 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD
message.setValue("text", text);
message.setValue("modifiers", translateModifiers(modifiers));
message.setValueLLSD("native_key_data", native_key_data);
-
+
sendMessage(message);
-
+
return true;
}
@@ -688,7 +688,7 @@ void LLPluginClassMedia::loadURI(const std::string &uri)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
message.setValue("uri", uri);
-
+
sendMessage(message);
}
@@ -705,7 +705,7 @@ const char* LLPluginClassMedia::priorityToString(EPriority priority)
case PRIORITY_NORMAL: result = "normal"; break;
case PRIORITY_HIGH: result = "high"; break;
}
-
+
return result;
}
@@ -716,44 +716,44 @@ void LLPluginClassMedia::setPriority(EPriority priority)
mPriority = priority;
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
-
+
std::string priority_string = priorityToString(priority);
switch(priority)
{
- case PRIORITY_UNLOADED:
+ case PRIORITY_UNLOADED:
mSleepTime = 1.0f;
break;
- case PRIORITY_STOPPED:
+ case PRIORITY_STOPPED:
mSleepTime = 1.0f;
break;
- case PRIORITY_HIDDEN:
+ case PRIORITY_HIDDEN:
mSleepTime = 1.0f;
break;
case PRIORITY_SLIDESHOW:
mSleepTime = 1.0f;
break;
- case PRIORITY_LOW:
+ case PRIORITY_LOW:
mSleepTime = 1.0f / 25.0f;
break;
- case PRIORITY_NORMAL:
+ case PRIORITY_NORMAL:
mSleepTime = 1.0f / 50.0f;
break;
- case PRIORITY_HIGH:
+ case PRIORITY_HIGH:
mSleepTime = 1.0f / 100.0f;
break;
}
-
+
message.setValue("priority", priority_string);
sendMessage(message);
-
+
if(mPlugin)
{
mPlugin->setSleepTime(mSleepTime);
}
-
+
LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
-
+
// This may affect the calculated size, so recalculate it here.
setSizeInternal();
}
@@ -774,12 +774,12 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
F64 LLPluginClassMedia::getCPUUsage()
{
F64 result = 0.0f;
-
+
if(mPlugin)
{
result = mPlugin->getCPUUsage();
}
-
+
return result;
}
@@ -843,14 +843,14 @@ void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "plugins_enabled");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
message.setValueBoolean("enable", enabled);
sendMessage(message);
}
void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "javascript_enabled");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
message.setValueBoolean("enable", enabled);
sendMessage(message);
}
@@ -868,11 +868,11 @@ void LLPluginClassMedia::setTarget(const std::string &target)
mTarget = target;
}
-/* virtual */
+/* virtual */
void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
std::string message_class = message.getClass();
-
+
if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
std::string message_name = message.getName();
@@ -883,21 +883,21 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mRequestedTextureFormat = message.getValueU32("format");
mRequestedTextureType = message.getValueU32("type");
mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
- mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");
-
+ mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");
+
// These two are optional, and will default to 0 if they're not specified.
mDefaultMediaWidth = message.getValueS32("default_width");
mDefaultMediaHeight = message.getValueS32("default_height");
-
+
mAllowDownsample = message.getValueBoolean("allow_downsample");
mPadding = message.getValueS32("padding");
setSizeInternal();
-
+
mTextureParamsReceived = true;
}
else if(message_name == "updated")
- {
+ {
if(message.hasValue("left"))
{
LLRect newDirtyRect;
@@ -905,7 +905,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
newDirtyRect.mTop = message.getValueS32("top");
newDirtyRect.mRight = message.getValueS32("right");
newDirtyRect.mBottom = message.getValueS32("bottom");
-
+
// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
// If they're backwards, swap them.
if(newDirtyRect.mTop < newDirtyRect.mBottom)
@@ -914,7 +914,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
newDirtyRect.mTop = newDirtyRect.mBottom;
newDirtyRect.mBottom = temp;
}
-
+
if(mDirtyRect.isEmpty())
{
mDirtyRect = newDirtyRect;
@@ -924,7 +924,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mDirtyRect.unionWith(newDirtyRect);
}
- LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("
+ LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("
<< newDirtyRect.mLeft << ", "
<< newDirtyRect.mTop << ", "
<< newDirtyRect.mRight << ", "
@@ -934,10 +934,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
<< mDirtyRect.mRight << ", "
<< mDirtyRect.mBottom << ")"
<< LL_ENDL;
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
- }
-
+ }
+
bool time_duration_updated = false;
int previous_percent = mProgressPercent;
@@ -957,7 +957,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mCurrentRate = message.getValueReal("current_rate");
}
-
+
if(message.hasValue("loaded_duration"))
{
mLoadedDuration = message.getValueReal("loaded_duration");
@@ -968,7 +968,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
// If the message doesn't contain a loaded_duration param, assume it's equal to duration
mLoadedDuration = mDuration;
}
-
+
// Calculate a percentage based on the loaded duration and total duration.
if(mDuration != 0.0f) // Don't divide by zero.
{
@@ -979,7 +979,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
}
-
+
if(previous_percent != mProgressPercent)
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
@@ -988,9 +988,9 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
else if(message_name == "media_status")
{
std::string status = message.getValue("status");
-
+
LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
-
+
if(status == "loading")
{
mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
@@ -1030,24 +1030,24 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
// TODO: check that name matches?
mNaturalMediaWidth = width;
mNaturalMediaHeight = height;
-
+
setSizeInternal();
}
else if(message_name == "size_change_response")
{
std::string name = message.getValue("name");
-
+
// TODO: check that name matches?
-
+
mTextureWidth = message.getValueS32("texture_width");
mTextureHeight = message.getValueS32("texture_height");
mMediaWidth = message.getValueS32("width");
mMediaHeight = message.getValueS32("height");
-
+
// This invalidates any existing dirty rect.
resetDirty();
-
- // TODO: should we verify that the plugin sent back the right values?
+
+ // TODO: should we verify that the plugin sent back the right values?
// Two size changes in a row may cause them to not match, due to queueing, etc.
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
@@ -1114,7 +1114,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mNavigateResultString = message.getValue("result_string");
mHistoryBackAvailable = message.getValueBoolean("history_back_available");
mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
}
else if(message_name == "progress")
@@ -1136,7 +1136,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mClickURL = message.getValue("uri");
mClickTarget = message.getValue("target");
- //mClickUUID = message.getValue("uuid");
+ mClickUUID = message.getValue("uuid");
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
}
else if(message_name == "click_nofollow")
@@ -1169,7 +1169,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mGeometryY = message.getValueS32("y");
mGeometryWidth = message.getValueS32("width");
mGeometryHeight = message.getValueS32("height");
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
}
else if(message_name == "link_hovered")
@@ -1178,7 +1178,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mHoverLink = message.getValue("link");
mHoverText = message.getValue("title");
// message.getValue("text");
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
}
else
@@ -1194,7 +1194,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
// if(message_name == "message_name")
// {
// }
-// else
+// else
{
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
}
@@ -1202,13 +1202,13 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
}
-/* virtual */
+/* virtual */
void LLPluginClassMedia::pluginLaunchFailed()
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
}
-/* virtual */
+/* virtual */
void LLPluginClassMedia::pluginDied()
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
@@ -1248,7 +1248,7 @@ void LLPluginClassMedia::focus(bool focused)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
message.setValueBoolean("focused", focused);
-
+
sendMessage(message);
}
@@ -1275,13 +1275,13 @@ void LLPluginClassMedia::clear_cookies()
void LLPluginClassMedia::set_cookies(const std::string &cookies)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
- message.setValue("cookies", cookies);
+ message.setValue("cookies", cookies);
sendMessage(message);
}
void LLPluginClassMedia::enable_cookies(bool enable)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookies_enabled");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
message.setValueBoolean("enable", enable);
sendMessage(message);
}
@@ -1308,7 +1308,7 @@ void LLPluginClassMedia::browse_reload(bool ignore_cache)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
message.setValueBoolean("ignore_cache", ignore_cache);
-
+
sendMessage(message);
}
@@ -1373,6 +1373,12 @@ void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
sendMessage(message);
}
+void LLPluginClassMedia::setOverrideClickTarget(const std::string &target)
+{
+ mClickEnforceTarget = true;
+ mOverrideClickTarget = target;
+}
+
void LLPluginClassMedia::crashPlugin()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
@@ -1422,7 +1428,7 @@ void LLPluginClassMedia::seek(float time)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
message.setValueReal("time", time);
-
+
sendMessage(message);
}
@@ -1440,11 +1446,11 @@ void LLPluginClassMedia::setVolume(float volume)
if(volume != mRequestedVolume)
{
mRequestedVolume = volume;
-
+
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
message.setValueReal("volume", volume);
-
+
sendMessage(message);
}
}
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 3f53551b90..255fb0e2f1 100755
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -251,6 +251,13 @@ public:
// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
std::string getClickUUID() const { return mClickUUID; };
+ // mClickTarget is received from message and governs how link will be opened
+ // use this to enforce your own way of opening links inside plugins
+ void setOverrideClickTarget(const std::string &target);
+ void resetOverrideClickTarget() { mClickEnforceTarget = false; };
+ bool isOverrideClickTarget() const { return mClickEnforceTarget; }
+ std::string getOverrideClickTarget() const { return mOverrideClickTarget; };
+
// These are valid during MEDIA_EVENT_DEBUG_MESSAGE
std::string getDebugMessageText() const { return mDebugMessageText; };
std::string getDebugMessageLevel() const { return mDebugMessageLevel; };
@@ -406,6 +413,8 @@ protected:
std::string mClickNavType;
std::string mClickTarget;
std::string mClickUUID;
+ bool mClickEnforceTarget;
+ std::string mOverrideClickTarget;
std::string mDebugMessageText;
std::string mDebugMessageLevel;
S32 mGeometryX;
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 29747cb09c..9eff74f1e8 100755
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp