From eaa4e977d687abbfb28687c66cb0b92e66deb484 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Wed, 11 Dec 2019 22:48:46 +0200
Subject: [PATCH] SL-12334 [Copypaste] Texture is not copied to clipboard from
 a full-perms object

---
 indra/newview/llpanelface.cpp   | 69 ++++++++++++++++++++-------------
 indra/newview/llpanelobject.cpp | 42 ++++++++++++--------
 indra/newview/llpanelobject.h   |  6 +++
 3 files changed, 73 insertions(+), 44 deletions(-)

diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 3a48db0a1ae..914863ccc04 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -2922,15 +2922,24 @@ void LLPanelFace::onCopyFaces()
 
                 if (te_data["te"].has("imageid"))
                 {
+                    LLUUID item_id;
                     LLUUID id = te_data["te"]["imageid"].asUUID();
-                    // Doesn't support local images!
-                    if (id.isNull() || !LLPanelObject::canCopyTexture(id))
+                    bool full_perm = LLPanelObject::isLibraryTexture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify());
+
+                    // todo: fix this, we are often searching same tuxture multiple times (equal to number of faces)
+                    if (id.notNull() && !full_perm)
                     {
-                        if (LLLocalBitmapMgr::getInstance()->isLocalBitmap(id))
-                        {
-                            te_data["te"]["imageid"] = id;
-                        }
-                        else
+                        // What this does is simply searches inventory for item with same asset id,
+                        // as result it is Hightly unreliable, leaves little control to user, borderline hack
+                        // but there are little options to preserve permissions - multiple inventory
+                        // items might reference same asset and inventory search is expensive.
+                        item_id = LLPanelObject::getCopyPermInventoryTextureId(id);
+                    }
+
+                    if (id.isNull()
+                        || (!full_perm && item_id.isNull()))
+                    {
+                        if (!LLLocalBitmapMgr::getInstance()->isLocalBitmap(id))
                         {
                             te_data["te"].erase("imageid");
                             te_data["te"]["imageid"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
@@ -2939,23 +2948,30 @@ void LLPanelFace::onCopyFaces()
                     }
                     else
                     {
-                        te_data["te"]["itemfullperm"] = false; // if item is not in inventory, we won't get here
-                        LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control");
-                        LLUUID item_id = texture_ctrl->getImageItemID();
-                        if (item_id.notNull())
+                        te_data["te"]["itemfullperm"] = full_perm;
+                        // If full permission object, texture is free to copy,
+                        // but otherwise we need to check inventory and extract permissions
+                        //
+                        // Normally we care only about restrictions for current user and objects
+                        // don't inherit any 'next owner' permissions from texture, so there is
+                        // no need to record item id if full_perm==true
+                        if (!full_perm && item_id.notNull())
                         {
-                            // Texture control should have the id (otherwise canCopyTexture == false),
-                            // use it for consistency.
-                            te_data["te"]["imageitemid"] = item_id;
-
                             LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
                             if (itemp)
                             {
-                                te_data["te"]["itemfullperm"] = itemp->getIsFullPerm();
-                                if (!itemp->isFinished())
+                                LLPermissions item_permissions = itemp->getPermissions();
+                                if (item_permissions.allowOperationBy(PERM_COPY,
+                                    gAgent.getID(),
+                                    gAgent.getGroupID()))
                                 {
-                                    // needed for dropTextureAllFaces
-                                    LLInventoryModelBackgroundFetch::instance().start(item_id, false);
+                                    te_data["te"]["imageitemid"] = item_id;
+                                    te_data["te"]["itemfullperm"] = itemp->getIsFullPerm();
+                                    if (!itemp->isFinished())
+                                    {
+                                        // needed for dropTextureAllFaces
+                                        LLInventoryModelBackgroundFetch::instance().start(item_id, false);
+                                    }
                                 }
                             }
                         }
@@ -3041,6 +3057,7 @@ void LLPanelFace::pasteFace(LLViewerObject* objectp, S32 te)
         if (te_data.has("te"))
         {
             // Texture
+            bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
             if (mPasteDiffuse && te_data["te"].has("imageid"))
             {
                 const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id
@@ -3061,8 +3078,9 @@ void LLPanelFace::pasteFace(LLViewerObject* objectp, S32 te)
                 }
 
                 // for case when item got removed from inventory after we pressed 'copy'
-                if (!itemp_res)
+                if (!itemp_res && !full_perm)
                 {
+                    // todo: fix this, we are often searching same tuxter multiple times (equal to number of faces)
                     LLViewerInventoryCategory::cat_array_t cats;
                     LLViewerInventoryItem::item_array_t items;
                     LLAssetIDMatches asset_id_matches(imageid);
@@ -3111,14 +3129,11 @@ void LLPanelFace::pasteFace(LLViewerObject* objectp, S32 te)
                     }
                 }
                 // not an inventory item or no complete items
-                else if (te_data["te"].has("itemfullperm"))
+                else if (full_perm)
                 {
-                    if (te_data["te"]["itemfullperm"].asBoolean())
-                    {
-                        // when user clicked copy, item existed in inventory as fullperm (also can be used for local images)
-                        LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
-                        objectp->setTEImage(U8(te), image);
-                    }
+                    // Either library, local or existed as fullperm when user made a copy
+                    LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+                    objectp->setTEImage(U8(te), image);
                 }
             }
 
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index b99c77fb795..b179b1be53d 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -2503,32 +2503,31 @@ bool LLPanelObject::pasteEnabletMenuItem(const LLSD& userdata)
     return true;
 }
 
-// Static
-bool LLPanelObject::canCopyTexture(LLUUID image_id)
+//static
+bool LLPanelObject::isLibraryTexture(LLUUID image_id)
 {
-    // User is allowed to copy a texture if:
-    // library asset or default texture,
-    // or copy perm asset exists in user's inventory
-
-    // Library asset or default texture
     if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID())
-        || image_id == LLUUID(gSavedSettings.getString( "DefaultObjectTexture" ))
-        || image_id == LLUUID(gSavedSettings.getString( "UIImgWhiteUUID" ))
-        || image_id == LLUUID(gSavedSettings.getString( "UIImgInvisibleUUID" ))
+        || image_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture"))
+        || image_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID"))
+        || image_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID"))
         || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE))
     {
         return true;
     }
+    return false;
+}
 
-    // Search for a copy perm asset
+//static
+LLUUID LLPanelObject::getCopyPermInventoryTextureId(LLUUID image_id)
+{
     LLViewerInventoryCategory::cat_array_t cats;
     LLViewerInventoryItem::item_array_t items;
     LLAssetIDMatches asset_id_matches(image_id);
     gInventory.collectDescendentsIf(LLUUID::null,
-                                    cats,
-                                    items,
-                                    LLInventoryModel::INCLUDE_TRASH,
-                                    asset_id_matches);
+        cats,
+        items,
+        LLInventoryModel::INCLUDE_TRASH,
+        asset_id_matches);
     if (items.size())
     {
         for (S32 i = 0; i < items.size(); i++)
@@ -2541,11 +2540,20 @@ bool LLPanelObject::canCopyTexture(LLUUID image_id)
                     gAgent.getID(),
                     gAgent.getGroupID()))
                 {
-                    return true;
+                    return itemp->getUUID();
                 }
             }
         }
     }
+    return LLUUID::null;
+}
 
-    return false;
+// Static
+bool LLPanelObject::canCopyTexture(LLUUID image_id)
+{
+    // User is allowed to copy a texture if:
+    // library asset or default texture,
+    // or copy perm asset exists in user's inventory
+
+    return isLibraryTexture(image_id) || getCopyPermInventoryTextureId(image_id).notNull();
 }
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index 0c37e837ad0..65f46a8ed39 100644
--- a/indra/newview/llpanelobject.h
+++ b/indra/newview/llpanelobject.h
@@ -88,6 +88,12 @@ class LLPanelObject : public LLPanel
     bool            pasteCheckMenuItem(const LLSD& userdata);
     void            pasteDoMenuItem(const LLSD& userdata);
     bool            pasteEnabletMenuItem(const LLSD& userdata);
+    static bool     isLibraryTexture(LLUUID image_id);
+
+    // Finds copy-enabled texture with specified asset from inventory
+    // This can be performance unfriendly and doesn't warranty that
+    // the texture is original source of asset
+    static LLUUID   getCopyPermInventoryTextureId(LLUUID image_id);
     static bool     canCopyTexture(LLUUID image_id);
 
 protected:
-- 
GitLab