common/Session.cpp                    |   16 ++
 common/Session.hpp                    |   11 +
 kit/ChildSession.hpp                  |    2 
 kit/Kit.cpp                           |  204 ++++------------------------------
 kit/Watermark.hpp                     |  180 ++++++++++++++++++++++++++++++
 loleaflet/src/control/Parts.js        |    2 
 loleaflet/src/core/Socket.js          |    3 
 loleaflet/src/layer/tile/GridLayer.js |    2 
 loleaflet/src/layer/tile/TileLayer.js |    2 
 test/TileCacheTests.cpp               |   85 +++++++-------
 test/TileQueueTests.cpp               |   58 ++++-----
 test/WhiteBoxTests.cpp                |   21 +--
 test/httpwstest.cpp                   |    6 -
 wsd/ClientSession.cpp                 |   12 +-
 wsd/DocumentBroker.cpp                |   13 +-
 wsd/DocumentBroker.hpp                |    2 
 wsd/TileCache.cpp                     |   25 ++--
 wsd/TileCache.hpp                     |    8 -
 wsd/TileDesc.hpp                      |   41 +++++-
 19 files changed, 398 insertions(+), 295 deletions(-)

New commits:
commit eb6064816b2f31e1bbc83f47162ae7ff632e53ca
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Mon Oct 14 00:45:59 2019 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Mon Oct 14 12:12:56 2019 +0300

    Include nviewid to tests with tile messages
    
    Change-Id: I8af803bd57cc0e3d0af510dcf6013c1658658678

diff --git a/test/TileCacheTests.cpp b/test/TileCacheTests.cpp
index b4ec0fa8d..7e2e6c9dd 100644
--- a/test/TileCacheTests.cpp
+++ b/test/TileCacheTests.cpp
@@ -185,6 +185,7 @@ void TileCacheTests::testSimple()
     // now, so it discards the cached data.
     TileCache tc("doc.ods", Poco::Timestamp());
 
+    int nviewid=0;
     int part = 0;
     int width = 256;
     int height = 256;
@@ -192,7 +193,7 @@ void TileCacheTests::testSimple()
     int tilePosY = 0;
     int tileWidth = 3840;
     int tileHeight = 3840;
-    TileDesc tile(part, width, height, tilePosX, tilePosY, tileWidth, 
tileHeight, -1, 0, -1, false);
+    TileDesc tile(nviewid, part, width, height, tilePosX, tilePosY, tileWidth, 
tileHeight, -1, 0, -1, false);
 
     // No Cache
     TileCache::Tile tileData = tc.lookupTile(tile);
@@ -209,7 +210,7 @@ void TileCacheTests::testSimple()
     CPPUNIT_ASSERT_MESSAGE("cached tile corrupted", data == *tileData);
 
     // Invalidate Tiles
-    tc.invalidateTiles("invalidatetiles: EMPTY");
+    tc.invalidateTiles("invalidatetiles: EMPTY", nviewid);
 
     // No Cache
     tileData = tc.lookupTile(tile);
@@ -225,13 +226,13 @@ void TileCacheTests::testSimpleCombine()
     // First.
     std::shared_ptr<LOOLWebSocket> socket1 = loadDocAndGetSocket(_uri, 
documentURL, "simpleCombine-1 ");
 
-    sendTextFrame(socket1, "tilecombine part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
+    sendTextFrame(socket1, "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
 
     std::vector<char> tile1a = getResponseMessage(socket1, "tile:", testname);
     CPPUNIT_ASSERT_MESSAGE("did not receive a tile: message as expected", 
!tile1a.empty());
     std::vector<char> tile1b = getResponseMessage(socket1, "tile:", testname);
     CPPUNIT_ASSERT_MESSAGE("did not receive a tile: message as expected", 
!tile1b.empty());
-    sendTextFrame(socket1, "tilecombine part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
+    sendTextFrame(socket1, "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
 
     tile1a = getResponseMessage(socket1, "tile:", testname);
     CPPUNIT_ASSERT_MESSAGE("did not receive a tile: message as expected", 
!tile1a.empty());
@@ -242,7 +243,7 @@ void TileCacheTests::testSimpleCombine()
     std::cerr << "Connecting second client." << std::endl;
     std::shared_ptr<LOOLWebSocket> socket2 = loadDocAndGetSocket(_uri, 
documentURL, "simpleCombine-2 ", true);
 
-    sendTextFrame(socket2, "tilecombine part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
+    sendTextFrame(socket2, "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
 
     std::vector<char> tile2a = getResponseMessage(socket2, "tile:", testname);
     CPPUNIT_ASSERT_MESSAGE("did not receive a tile: message as expected", 
!tile2a.empty());
@@ -267,7 +268,7 @@ void TileCacheTests::testCancelTiles()
         std::shared_ptr<LOOLWebSocket> socket = 
loadDocAndGetSocket("setclientpart.ods", _uri, testName);
 
         // Request a huge tile, and cancel immediately.
-        sendTextFrame(socket, "tilecombine part=0 width=2560 height=2560 
tileposx=0 tileposy=0 tilewidth=38400 tileheight=38400");
+        sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=2560 
height=2560 tileposx=0 tileposy=0 tilewidth=38400 tileheight=38400");
         sendTextFrame(socket, "canceltiles");
 
         const auto res = getResponseString(socket, "tile:", testName, 1000);
@@ -306,8 +307,8 @@ void TileCacheTests::testCancelTilesMultiView()
         std::shared_ptr<LOOLWebSocket> socket1 = loadDocAndGetSocket(_uri, 
documentURL, "cancelTilesMultiView-1 ");
         std::shared_ptr<LOOLWebSocket> socket2 = loadDocAndGetSocket(_uri, 
documentURL, "cancelTilesMultiView-2 ", true);
 
-        sendTextFrame(socket1, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840", 
"cancelTilesMultiView-1 ");
-        sendTextFrame(socket2, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680,0 tileposy=0,0,0,22520 tilewidth=3840 tileheight=3840", 
"cancelTilesMultiView-2 ");
+        sendTextFrame(socket1, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840", 
"cancelTilesMultiView-1 ");
+        sendTextFrame(socket2, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680,0 tileposy=0,0,0,22520 tilewidth=3840 
tileheight=3840", "cancelTilesMultiView-2 ");
 
         sendTextFrame(socket1, "canceltiles");
         const auto res1 = getResponseString(socket1, "tile:", 
"cancelTilesMultiView-1 ", 500);
@@ -367,8 +368,8 @@ void TileCacheTests::testDisconnectMultiView()
         std::shared_ptr<LOOLWebSocket> socket1 = loadDocAndGetSocket(_uri, 
documentURL, "disconnectMultiView-1 ");
         std::shared_ptr<LOOLWebSocket> socket2 = loadDocAndGetSocket(_uri, 
documentURL, "disconnectMultiView-2 ", true);
 
-        sendTextFrame(socket1, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840", 
"cancelTilesMultiView-1 ");
-        sendTextFrame(socket2, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680,0 tileposy=0,0,0,22520 tilewidth=3840 tileheight=3840", 
"cancelTilesMultiView-2 ");
+        sendTextFrame(socket1, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840", 
"cancelTilesMultiView-1 ");
+        sendTextFrame(socket2, "tilecombine nviewid=0  part=0 width=256 
height=256 tileposx=0,3840,7680,0 tileposy=0,0,0,22520 tilewidth=3840 
tileheight=3840", "cancelTilesMultiView-2 ");
 
         socket1->shutdown();
 
@@ -414,10 +415,10 @@ void TileCacheTests::testUnresponsiveClient()
         assertResponseString(socket2, "invalidatetiles:", "client2 ");
 
         // Ask for tiles and don't read!
-        sendTextFrame(socket1, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840");
+        sendTextFrame(socket1, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840");
 
         // Verify that we get all 8 tiles.
-        sendTextFrame(socket2, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840");
+        sendTextFrame(socket2, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680,11520,0,3840,7680,11520 
tileposy=0,0,0,0,3840,3840,3840,3840 tilewidth=3840 tileheight=3840");
         for (int i = 0; i < 8; ++i)
         {
             std::vector<char> tile = getResponseMessage(socket2, "tile:", 
"client2 ");
@@ -435,7 +436,7 @@ void TileCacheTests::testImpressTiles()
         const std::string testName = "impressTiles ";
         std::shared_ptr<LOOLWebSocket> socket = 
loadDocAndGetSocket("setclientpart.odp", _uri, testName);
 
-        sendTextFrame(socket, "tile part=0 width=180 height=135 tileposx=0 
tileposy=0 tilewidth=15875 tileheight=11906 id=0", testName);
+        sendTextFrame(socket, "tile nviewid=0 part=0 width=180 height=135 
tileposx=0 tileposy=0 tilewidth=15875 tileheight=11906 id=0", testName);
         getTileMessage(*socket, testName);
     }
     catch (const Poco::Exception& exc)
@@ -500,7 +501,7 @@ void TileCacheTests::testTilesRenderedJustOnce()
         assertResponseString(socket, "invalidatetiles:", testname);
 
         // Get 3 tiles.
-        sendTextFrame(socket, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname);
+        sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname);
         assertResponseString(socket, "tile:", testname);
         assertResponseString(socket, "tile:", testname);
         assertResponseString(socket, "tile:", testname);
@@ -513,7 +514,7 @@ void TileCacheTests::testTilesRenderedJustOnce()
         CPPUNIT_ASSERT_EQUAL((i+1) * 3, renderCount2);
 
         // Get same 3 tiles.
-        sendTextFrame(socket, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname);
+        sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname);
         const auto tile1 = assertResponseString(socket, "tile:", testname);
         std::string renderId1;
         LOOLProtocol::getTokenStringFromMessage(tile1, "renderid", renderId1);
@@ -578,25 +579,25 @@ void 
TileCacheTests::testTilesRenderedJustOnceMultiClient()
         assertResponseString(socket, "invalidatetiles:", testname1);
 
         // Get 3 tiles.
-        sendTextFrame(socket, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname1);
+        sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname1);
         assertResponseString(socket, "tile:", testname1);
         assertResponseString(socket, "tile:", testname1);
         assertResponseString(socket, "tile:", testname1);
 
         assertResponseString(socket2, "invalidatetiles:", testname2);
-        sendTextFrame(socket2, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname2);
+        sendTextFrame(socket2, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname2);
         assertResponseString(socket2, "tile:", testname2);
         assertResponseString(socket2, "tile:", testname2);
         assertResponseString(socket2, "tile:", testname2);
 
         assertResponseString(socket3, "invalidatetiles:", testname3);
-        sendTextFrame(socket3, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname3);
+        sendTextFrame(socket3, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname3);
         assertResponseString(socket3, "tile:", testname3);
         assertResponseString(socket3, "tile:", testname3);
         assertResponseString(socket3, "tile:", testname3);
 
         assertResponseString(socket4, "invalidatetiles:", testname4);
-        sendTextFrame(socket4, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname4);
+        sendTextFrame(socket4, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname4);
         assertResponseString(socket4, "tile:", testname4);
         assertResponseString(socket4, "tile:", testname4);
         assertResponseString(socket4, "tile:", testname4);
@@ -609,7 +610,7 @@ void TileCacheTests::testTilesRenderedJustOnceMultiClient()
         CPPUNIT_ASSERT_EQUAL((i+1) * 3, renderCount2);
 
         // Get same 3 tiles.
-        sendTextFrame(socket, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", testname1);
+        sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840", 
testname1);
         const auto tile1 = assertResponseString(socket, "tile:", testname1);
         std::string renderId1;
         LOOLProtocol::getTokenStringFromMessage(tile1, "renderid", renderId1);
@@ -649,8 +650,8 @@ void TileCacheTests::testSimultaneousTilesRenderedJustOnce()
     assertResponseString(socket1, "statechanged:", "client1 ");
     assertResponseString(socket2, "statechanged:", "client2 ");
 
-    sendTextFrame(socket1, "tile part=42 width=400 height=400 tileposx=1000 
tileposy=2000 tilewidth=3000 tileheight=3000");
-    sendTextFrame(socket2, "tile part=42 width=400 height=400 tileposx=1000 
tileposy=2000 tilewidth=3000 tileheight=3000");
+    sendTextFrame(socket1, "tile nviewid=0 part=42 width=400 height=400 
tileposx=1000 tileposy=2000 tilewidth=3000 tileheight=3000");
+    sendTextFrame(socket2, "tile nviewid=0 part=42 width=400 height=400 
tileposx=1000 tileposy=2000 tilewidth=3000 tileheight=3000");
 
     const auto response1 = assertResponseString(socket1, "tile:", "client1 ");
     const auto response2 = assertResponseString(socket2, "tile:", "client2 ");
@@ -737,7 +738,7 @@ void 
TileCacheTests::checkBlackTiles(std::shared_ptr<LOOLWebSocket>& socket, con
     // render correctly and there are no black tiles.
     // Current cap of table size ends at 257280 twips (for load12.ods),
     // otherwise 2035200 should be rendered successfully.
-    const char* req = "tile part=0 width=256 height=256 tileposx=0 
tileposy=253440 tilewidth=3840 tileheight=3840";
+    const char* req = "tile nviewid=0 part=0 width=256 height=256 tileposx=0 
tileposy=253440 tilewidth=3840 tileheight=3840";
     sendTextFrame(socket, req);
 
     const std::vector<char> tile = getResponseMessage(socket, "tile:", name);
@@ -1124,21 +1125,22 @@ void 
TileCacheTests::requestTiles(std::shared_ptr<LOOLWebSocket>& socket, const
             tileHeight = tileSize;
             tileX = tileSize * itCol;
             tileY = tileSize * itRow;
-            text = Poco::format("tile part=%d width=%d height=%d tileposx=%d 
tileposy=%d tilewidth=%d tileheight=%d",
-                                part, pixTileSize, pixTileSize, tileX, tileY, 
tileWidth, tileHeight);
+            text = Poco::format("tile nviewid=%d part=%d width=%d height=%d 
tileposx=%d tileposy=%d tilewidth=%d tileheight=%d",
+                                0, part, pixTileSize, pixTileSize, tileX, 
tileY, tileWidth, tileHeight);
 
             sendTextFrame(socket, text, name);
             tile = assertResponseString(socket, "tile:", name);
-            // expected tile: part= width= height= tileposx= tileposy= 
tilewidth= tileheight=
+            // expected tile: nviewid= part= width= height= tileposx= 
tileposy= tilewidth= tileheight=
             Poco::StringTokenizer tokens(tile, " ", 
Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
             CPPUNIT_ASSERT_EQUAL(std::string("tile:"), tokens[0]);
-            CPPUNIT_ASSERT_EQUAL(part, 
std::stoi(tokens[1].substr(std::string("part=").size())));
-            CPPUNIT_ASSERT_EQUAL(pixTileSize, 
std::stoi(tokens[2].substr(std::string("width=").size())));
-            CPPUNIT_ASSERT_EQUAL(pixTileSize, 
std::stoi(tokens[3].substr(std::string("height=").size())));
-            CPPUNIT_ASSERT_EQUAL(tileX, 
std::stoi(tokens[4].substr(std::string("tileposx=").size())));
-            CPPUNIT_ASSERT_EQUAL(tileY, 
std::stoi(tokens[5].substr(std::string("tileposy=").size())));
-            CPPUNIT_ASSERT_EQUAL(tileWidth, 
std::stoi(tokens[6].substr(std::string("tileWidth=").size())));
-            CPPUNIT_ASSERT_EQUAL(tileHeight, 
std::stoi(tokens[7].substr(std::string("tileHeight=").size())));
+            CPPUNIT_ASSERT_EQUAL(0, 
std::stoi(tokens[1].substr(std::string("nviewid=").size())));
+            CPPUNIT_ASSERT_EQUAL(part, 
std::stoi(tokens[2].substr(std::string("part=").size())));
+            CPPUNIT_ASSERT_EQUAL(pixTileSize, 
std::stoi(tokens[3].substr(std::string("width=").size())));
+            CPPUNIT_ASSERT_EQUAL(pixTileSize, 
std::stoi(tokens[4].substr(std::string("height=").size())));
+            CPPUNIT_ASSERT_EQUAL(tileX, 
std::stoi(tokens[5].substr(std::string("tileposx=").size())));
+            CPPUNIT_ASSERT_EQUAL(tileY, 
std::stoi(tokens[6].substr(std::string("tileposy=").size())));
+            CPPUNIT_ASSERT_EQUAL(tileWidth, 
std::stoi(tokens[7].substr(std::string("tileWidth=").size())));
+            CPPUNIT_ASSERT_EQUAL(tileHeight, 
std::stoi(tokens[8].substr(std::string("tileHeight=").size())));
         }
     }
 }
@@ -1193,7 +1195,7 @@ void TileCacheTests::testTileRequestByZoom()
     sendTextFrame(socket, "clientzoom tilepixelwidth=256 tilepixelheight=256 
tiletwipwidth=3200 tiletwipheight=3200");
 
     // Request all tile of the visible area (it happens by zoom)
-    sendTextFrame(socket, "tilecombine part=0 width=256 height=256 
tileposx=0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800
 
tileposy=0,0,0,0,0,3200,3200,3200,3200,3200,6400,6400,6400,6400,6400,9600,9600,9600,9600,9600
 tilewidth=3200 tileheight=3200");
+    sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800
 
tileposy=0,0,0,0,0,3200,3200,3200,3200,3200,6400,6400,6400,6400,6400,9600,9600,9600,9600,9600
 tilewidth=3200 tileheight=3200");
 
     // Check that we get all the tiles without we send back the tileprocessed 
message
     for (int i = 0; i < 20; ++i)
@@ -1265,7 +1267,7 @@ void TileCacheTests::testTileProcessed()
     sendTextFrame(socket, "clientzoom tilepixelwidth=256 tilepixelheight=256 
tiletwipwidth=3200 tiletwipheight=3200");
 
     // Request a lots of tiles (more than wsd can send once)
-    sendTextFrame(socket, "tilecombine part=0 width=256 height=256 
tileposx=0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800
 
tileposy=0,0,0,0,0,3200,3200,3200,3200,3200,6400,6400,6400,6400,6400,9600,9600,9600,9600,9600,12800,12800,12800,12800,12800
 tilewidth=3200 tileheight=3200");
+    sendTextFrame(socket, "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800,0,3200,6400,9600,12800
 
tileposy=0,0,0,0,0,3200,3200,3200,3200,3200,6400,6400,6400,6400,6400,9600,9600,9600,9600,9600,12800,12800,12800,12800,12800
 tilewidth=3200 tileheight=3200");
 
     std::vector<std::string> tileIDs;
     int arrivedTile = 0;
@@ -1280,11 +1282,12 @@ void TileCacheTests::testTileProcessed()
 
             // Store tileID, so we can send it back
             Poco::StringTokenizer tokens(tile, " ", 
Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-            std::string tileID = tokens[1].substr(std::string("part=").size()) 
+ ":" +
-                                 
tokens[4].substr(std::string("tileposx=").size()) + ":" +
-                                 
tokens[5].substr(std::string("tileposy=").size()) + ":" +
-                                 
tokens[6].substr(std::string("tileWidth=").size()) + ":" +
-                                 
tokens[7].substr(std::string("tileHeight=").size());
+            std::string tileID = tokens[2].substr(std::string("part=").size()) 
+ ":" +
+                                 
tokens[5].substr(std::string("tileposx=").size()) + ":" +
+                                 
tokens[6].substr(std::string("tileposy=").size()) + ":" +
+                                 
tokens[7].substr(std::string("tileWidth=").size()) + ":" +
+                                 
tokens[8].substr(std::string("tileHeight=").size()) + ":" +
+                                 
tokens[1].substr(std::string("nviewid=").size());
             tileIDs.push_back(tileID);
         }
 
@@ -1460,7 +1463,7 @@ void TileCacheTests::testWireIDFilteringOnWSDSide()
 
     //2. Now request the same tiles by the other client (e.g. scroll to the 
same view)
 
-    sendTextFrame(socket2, "tilecombine part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840");
+    sendTextFrame(socket2, "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840");
 
     // We expect three tiles sent to the second client
     arrivedTiles = 0;
diff --git a/test/TileQueueTests.cpp b/test/TileQueueTests.cpp
index 6ca1bf22f..395c131dc 100644
--- a/test/TileQueueTests.cpp
+++ b/test/TileQueueTests.cpp
@@ -70,11 +70,11 @@ class TileQueueTests : public CPPUNIT_NS::TestFixture
 
 void TileQueueTests::testTileQueuePriority()
 {
-    const std::string reqHigh = "tile part=0 width=256 height=256 tileposx=0 
tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0";
-    const std::string resHigh = "tile part=0 width=256 height=256 tileposx=0 
tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1";
+    const std::string reqHigh = "tile nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0";
+    const std::string resHigh = "tile nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1";
     const TileQueue::Payload payloadHigh(resHigh.data(), resHigh.data() + 
resHigh.size());
-    const std::string reqLow = "tile part=0 width=256 height=256 tileposx=0 
tileposy=253440 tilewidth=3840 tileheight=3840 oldwid=0 wid=0";
-    const std::string resLow = "tile part=0 width=256 height=256 tileposx=0 
tileposy=253440 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1";
+    const std::string reqLow = "tile nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840 oldwid=0 wid=0";
+    const std::string resLow = "tile nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 
ver=-1";
     const TileQueue::Payload payloadLow(resLow.data(), resLow.data() + 
resLow.size());
 
     TileQueue queue;
@@ -116,15 +116,15 @@ void TileQueueTests::testTileQueuePriority()
 
 void TileQueueTests::testTileCombinedRendering()
 {
-    const std::string req1 = "tile part=0 width=256 height=256 tileposx=0 
tileposy=0 tilewidth=3840 tileheight=3840";
-    const std::string req2 = "tile part=0 width=256 height=256 tileposx=3840 
tileposy=0 tilewidth=3840 tileheight=3840";
-    const std::string req3 = "tile part=0 width=256 height=256 tileposx=0 
tileposy=3840 tilewidth=3840 tileheight=3840";
+    const std::string req1 = "tile nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840";
+    const std::string req2 = "tile nviewid=0 part=0 width=256 height=256 
tileposx=3840 tileposy=0 tilewidth=3840 tileheight=3840";
+    const std::string req3 = "tile nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=3840 tilewidth=3840 tileheight=3840";
 
-    const std::string resHor = "tilecombine part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 imgsize=0,0 tilewidth=3840 tileheight=3840 
ver=-1,-1 oldwid=0,0 wid=0,0";
+    const std::string resHor = "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840 tileposy=0,0 imgsize=0,0 tilewidth=3840 
tileheight=3840 ver=-1,-1 oldwid=0,0 wid=0,0";
     const TileQueue::Payload payloadHor(resHor.data(), resHor.data() + 
resHor.size());
-    const std::string resVer = "tilecombine part=0 width=256 height=256 
tileposx=0,0 tileposy=0,3840 imgsize=0,0 tilewidth=3840 tileheight=3840 
ver=-1,-1 oldwid=0,0 wid=0,0";
+    const std::string resVer = "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,0 tileposy=0,3840 imgsize=0,0 tilewidth=3840 
tileheight=3840 ver=-1,-1 oldwid=0,0 wid=0,0";
     const TileQueue::Payload payloadVer(resVer.data(), resVer.data() + 
resVer.size());
-    const std::string resFull = "tilecombine part=0 width=256 height=256 
tileposx=0,3840,0 tileposy=0,0,3840 imgsize=0,0,0 tilewidth=3840 
tileheight=3840 ver=-1,-1,-1 oldwid=0,0,0 wid=0,0,0";
+    const std::string resFull = "tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=0,3840,0 tileposy=0,0,3840 imgsize=0,0,0 tilewidth=3840 
tileheight=3840 ver=-1,-1,-1 oldwid=0,0,0 wid=0,0,0";
     const TileQueue::Payload payloadFull(resFull.data(), resFull.data() + 
resFull.size());
 
     TileQueue queue;
@@ -159,8 +159,8 @@ void TileQueueTests::testTileRecombining()
 {
     TileQueue queue;
 
-    queue.put("tilecombine part=0 width=256 height=256 tileposx=0,3840,7680 
tileposy=0,0,0 tilewidth=3840 tileheight=3840");
-    queue.put("tilecombine part=0 width=256 height=256 tileposx=0,3840 
tileposy=0,0 tilewidth=3840 tileheight=3840");
+    queue.put("tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840");
+    queue.put("tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0,3840 tileposy=0,0 tilewidth=3840 tileheight=3840");
 
     // the tilecombine's get merged, resulting in 3 "tile" messages
     CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(queue.getQueue().size()));
@@ -168,7 +168,7 @@ void TileQueueTests::testTileRecombining()
     // but when we later extract that, it is just one "tilecombine" message
     std::string message(payloadAsString(queue.get()));
 
-    CPPUNIT_ASSERT_EQUAL(std::string("tilecombine part=0 width=256 height=256 
tileposx=7680,0,3840 tileposy=0,0,0 imgsize=0,0,0 tilewidth=3840 
tileheight=3840 ver=-1,-1,-1 oldwid=0,0,0 wid=0,0,0"), message);
+    CPPUNIT_ASSERT_EQUAL(std::string("tilecombine nviewid=0 part=0 width=256 
height=256 tileposx=7680,0,3840 tileposy=0,0,0 imgsize=0,0,0 tilewidth=3840 
tileheight=3840 ver=-1,-1,-1 oldwid=0,0,0 wid=0,0,0"), message);
 
     // and nothing remains in the queue
     CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(queue.getQueue().size()));
@@ -188,10 +188,10 @@ void TileQueueTests::testViewOrder()
 
     const std::vector<std::string> tiles =
     {
-        "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 
tileheight=3840 oldwid=0 wid=0 ver=-1",
-        "tile part=0 width=256 height=256 tileposx=0 tileposy=7680 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1",
-        "tile part=0 width=256 height=256 tileposx=0 tileposy=15360 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1",
-        "tile part=0 width=256 height=256 tileposx=0 tileposy=23040 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1"
+        "tile nviewid=0 part=0 width=256 height=256 tileposx=0 tileposy=0 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1",
+        "tile nviewid=0 part=0 width=256 height=256 tileposx=0 tileposy=7680 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1",
+        "tile nviewid=0 part=0 width=256 height=256 tileposx=0 tileposy=15360 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1",
+        "tile nviewid=0 part=0 width=256 height=256 tileposx=0 tileposy=23040 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1"
     };
 
     for (auto &tile : tiles)
@@ -214,10 +214,10 @@ void TileQueueTests::testPreviewsDeprioritization()
     // simple case - put previews to the queue and get everything back again
     const std::vector<std::string> previews =
     {
-        "tile part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=0",
-        "tile part=1 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=1",
-        "tile part=2 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=2",
-        "tile part=3 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=3"
+        "tile nviewid=0 part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=0",
+        "tile nviewid=0 part=1 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=1",
+        "tile nviewid=0 part=2 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=2",
+        "tile nviewid=0part=3 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1 id=3"
     };
 
     for (auto &preview : previews)
@@ -236,8 +236,8 @@ void TileQueueTests::testPreviewsDeprioritization()
     // the previews
     const std::vector<std::string> tiles =
     {
-        "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 
tileheight=3840 oldwid=0 wid=0 ver=-1",
-        "tile part=0 width=256 height=256 tileposx=0 tileposy=7680 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1"
+        "tile nviewid=0 part=0 width=256 height=256 tileposx=0 tileposy=0 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1",
+        "tile nviewid=0 part=0 width=256 height=256 tileposx=0 tileposy=7680 
tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1"
     };
 
     for (auto &preview : previews)
@@ -323,9 +323,9 @@ void TileQueueTests::testSenderQueueTileDeduplication()
 
     const std::vector<std::string> part_messages =
     {
-        "tile: part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=0",
-        "tile: part=1 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=1",
-        "tile: part=2 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1"
+        "tile: nviewid=0 part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=0",
+        "tile: nviewid=0 part=1 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=1",
+        "tile: nviewid=0 part=2 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1"
     };
 
     for (const auto& msg : part_messages)
@@ -342,9 +342,9 @@ void TileQueueTests::testSenderQueueTileDeduplication()
 
     const std::vector<std::string> dup_messages =
     {
-        "tile: part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1",
-        "tile: part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=1",
-        "tile: part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=1"
+        "tile: nviewid=0 part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=-1",
+        "tile: nviewid=0 part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=1",
+        "tile: nviewid=0 part=0 width=180 height=135 tileposx=0 tileposy=0 
tilewidth=15875 tileheight=11906 ver=1"
     };
 
     for (const auto& msg : dup_messages)
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index a3b6f47de..96a11efa7 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -353,17 +353,18 @@ void WhiteBoxTests::testTokenizer()
     CPPUNIT_ASSERT_EQUAL(std::string("A"), tokens[0]);
     CPPUNIT_ASSERT_EQUAL(std::string("Z"), tokens[1]);
 
-    tokens = LOOLProtocol::tokenize("tile part=0 width=256 height=256 
tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 ver=-1");
-    CPPUNIT_ASSERT_EQUAL(9UL, tokens.size());
+    tokens = LOOLProtocol::tokenize("tile nviewid=0 part=0 width=256 
height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 ver=-1");
+    CPPUNIT_ASSERT_EQUAL(10UL, tokens.size());
     CPPUNIT_ASSERT_EQUAL(std::string("tile"), tokens[0]);
-    CPPUNIT_ASSERT_EQUAL(std::string("part=0"), tokens[1]);
-    CPPUNIT_ASSERT_EQUAL(std::string("width=256"), tokens[2]);
-    CPPUNIT_ASSERT_EQUAL(std::string("height=256"), tokens[3]);
-    CPPUNIT_ASSERT_EQUAL(std::string("tileposx=0"), tokens[4]);
-    CPPUNIT_ASSERT_EQUAL(std::string("tileposy=0"), tokens[5]);
-    CPPUNIT_ASSERT_EQUAL(std::string("tilewidth=3840"), tokens[6]);
-    CPPUNIT_ASSERT_EQUAL(std::string("tileheight=3840"), tokens[7]);
-    CPPUNIT_ASSERT_EQUAL(std::string("ver=-1"), tokens[8]);
+    CPPUNIT_ASSERT_EQUAL(std::string("nviewid=0"), tokens[1]);
+    CPPUNIT_ASSERT_EQUAL(std::string("part=0"), tokens[2]);
+    CPPUNIT_ASSERT_EQUAL(std::string("width=256"), tokens[3]);
+    CPPUNIT_ASSERT_EQUAL(std::string("height=256"), tokens[4]);
+    CPPUNIT_ASSERT_EQUAL(std::string("tileposx=0"), tokens[5]);
+    CPPUNIT_ASSERT_EQUAL(std::string("tileposy=0"), tokens[6]);
+    CPPUNIT_ASSERT_EQUAL(std::string("tilewidth=3840"), tokens[7]);
+    CPPUNIT_ASSERT_EQUAL(std::string("tileheight=3840"), tokens[8]);
+    CPPUNIT_ASSERT_EQUAL(std::string("ver=-1"), tokens[9]);
 
     // With custom delimeters
     tokens = LOOLProtocol::tokenize(std::string("ABC:DEF"), ':');
diff --git a/test/httpwstest.cpp b/test/httpwstest.cpp
index 8e2beaae5..07a27aa1a 100644
--- a/test/httpwstest.cpp
+++ b/test/httpwstest.cpp
@@ -1792,7 +1792,7 @@ void HTTPWSTest::testCalcEditRendering()
 
     assertResponseString(socket, "cellformula: abc", testname);
 
-    const char* req = "tilecombine part=0 width=512 height=512 tileposx=3840 
tileposy=0 tilewidth=7680 tileheight=7680";
+    const char* req = "tilecombine nviewid=0 part=0 width=512 height=512 
tileposx=3840 tileposy=0 tilewidth=7680 tileheight=7680";
     sendTextFrame(socket, req, testname);
 
     const std::vector<char> tile = getResponseMessage(socket, "tile:", 
testname);
@@ -1876,7 +1876,7 @@ void HTTPWSTest::testCalcRenderAfterNewView51()
     // Wait for status due to doc resize.
     assertResponseString(socket, "status:", testname);
 
-    const char* req = "tilecombine part=0 width=256 height=256 tileposx=0 
tileposy=253440 tilewidth=3840 tileheight=3840";
+    const char* req = "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840";
 
     // Get tile.
     const std::vector<char> tile1 = getTileAndSave(socket, req, 
"/tmp/calc_render_51_orig.png", testname);
@@ -1922,7 +1922,7 @@ void HTTPWSTest::testCalcRenderAfterNewView53()
     sendTextFrame(socket, "key type=input char=0 key=1031", testname);
 
     // Get tile.
-    const char* req = "tilecombine part=0 width=256 height=256 tileposx=0 
tileposy=291840 tilewidth=3840 tileheight=3840 oldwid=0";
+    const char* req = "tilecombine nviewid=0 part=0 width=256 height=256 
tileposx=0 tileposy=291840 tilewidth=3840 tileheight=3840 oldwid=0";
     const std::vector<char> tile1 = getTileAndSave(socket, req, 
"/tmp/calc_render_53_orig.png", testname);
 
 
commit 03d59187530f62375457eea41d5237ffca580d80
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Mon Oct 14 00:10:37 2019 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Mon Oct 14 00:15:09 2019 +0300

    Adjust TileCache to normalizedViewId

diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index c72bec66b..fe71f4917 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -980,7 +980,7 @@ public:
 
         if (it == _sessions.end())
         {
-            LOG_ERR("Session is not found. Maybe exited after rendering 
request.");
+            LOG_ERR("Session is not found. Maybe exited after tile rendering 
request. " << nViewId);
             return;
         }
 
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index 5467fdd03..969d74af3 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -977,6 +977,9 @@ L.Socket = L.Class.extend({
                        else if (tokens[i].substring(0, 7) === 'viewid=') {
                                command.viewid = tokens[i].substring(7);
                        }
+                       else if (tokens[i].substring(0, 8) === 'nviewid=') {
+                               command.nviewid = tokens[i].substring(8);
+                       }
                        else if (tokens[i].substring(0, 7) === 'params=') {
                                command.params = 
tokens[i].substring(7).split(',');
                        }
diff --git a/loleaflet/src/layer/tile/TileLayer.js 
b/loleaflet/src/layer/tile/TileLayer.js
index 8b60f8ef4..84828a4af 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -1603,7 +1603,7 @@ L.TileLayer = L.GridLayer.extend({
                L.Log.log(textMsg, L.INCOMING, key);
 
                // Send acknowledgment, that the tile message arrived
-               var tileID = command.part + ':' + command.x + ':' + command.y + 
':' + command.tileWidth + ':' + command.tileHeight;
+               var tileID = command.part + ':' + command.x + ':' + command.y + 
':' + command.tileWidth + ':' + command.tileHeight + ':' + command.nviewid;
                this._map._socket.sendMessage('tileprocessed tile=' + tileID);
        },
 
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 87594c4c4..d7f32428f 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -1157,6 +1157,7 @@ void ClientSession::enqueueSendMessage(const 
std::shared_ptr<Message>& data)
     // Track sent tile
     if (tile)
     {
+        tile->setNormalizedViewId(getHash());
         traceTileBySend(*tile, sizeBefore == newSize);
     }
 }
@@ -1321,7 +1322,7 @@ void ClientSession::dumpState(std::ostream& os)
 void ClientSession::handleTileInvalidation(const std::string& message,
     const std::shared_ptr<DocumentBroker>& docBroker)
 {
-    docBroker->invalidateTiles(message);
+    docBroker->invalidateTiles(message, getHash());
 
     // Skip requesting new tiles if we don't have client visible area data yet.
     if(!_clientVisibleArea.hasSurface() ||
@@ -1454,7 +1455,7 @@ std::string ClientSession::generateTileID(const TileDesc& 
tile) const
 {
     std::ostringstream tileID;
     tileID << tile.getPart() << ":" << tile.getTilePosX() << ":" << 
tile.getTilePosY() << ":"
-           << tile.getTileWidth() << ":" << tile.getTileHeight();
+           << tile.getTileWidth() << ":" << tile.getTileHeight() << ":" << 
tile.getNormalizedViewId();
     return tileID.str();
 }
 
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 2d1ea7e53..f7e34f5fa 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1387,10 +1387,10 @@ bool DocumentBroker::handleInput(const 
std::vector<char>& payload)
     return true;
 }
 
-void DocumentBroker::invalidateTiles(const std::string& tiles)
+void DocumentBroker::invalidateTiles(const std::string& tiles, int 
normalizedViewId)
 {
     // Remove from cache.
-    _tileCache->invalidateTiles(tiles);
+    _tileCache->invalidateTiles(tiles, normalizedViewId);
 }
 
 void DocumentBroker::handleTileRequest(TileDesc& tile,
@@ -1461,7 +1461,6 @@ void 
DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined,
     if (!tilesNeedsRendering.empty())
     {
         TileCombined newTileCombined = 
TileCombined::create(tilesNeedsRendering);
-
         // Forward to child to render.
         const std::string req = newTileCombined.serialize("tilecombine");
         LOG_TRC("Sending uncached residual tilecombine request to Kit: " << 
req);
@@ -1494,7 +1493,8 @@ void 
DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined,
             for (auto& oldTile : requestedTiles)
             {
                 if(oldTile.getTilePosX() == newTile.getTilePosX() &&
-                   oldTile.getTilePosY() == newTile.getTilePosY() )
+                   oldTile.getTilePosY() == newTile.getTilePosY()  &&
+                   oldTile.getNormalizedViewId() == 
newTile.getNormalizedViewId())
                 {
                     oldTile.setVersion(newTile.getVersion());
                     oldTile.setOldWireId(newTile.getOldWireId());
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index f3016fbcf..6c2e4e3c6 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -303,7 +303,7 @@ public:
         _cursorHeight = h;
     }
 
-    void invalidateTiles(const std::string& tiles);
+    void invalidateTiles(const std::string& tiles, int normalizedViewId);
     void handleTileRequest(TileDesc& tile,
                            const std::shared_ptr<ClientSession>& session);
     void handleDialogRequest(const std::string& dialogCmd);
diff --git a/wsd/TileCache.cpp b/wsd/TileCache.cpp
index 8ea86a235..17743b265 100644
--- a/wsd/TileCache.cpp
+++ b/wsd/TileCache.cpp
@@ -306,7 +306,7 @@ TileCache::Tile TileCache::lookupCachedTile(const 
std::string& name, const std::
     return loadTile(dir + "/" + name);
 }
 
-void TileCache::invalidateTiles(int part, int x, int y, int width, int height)
+void TileCache::invalidateTiles(int part, int x, int y, int width, int height, 
int normalizedViewId)
 {
     LOG_TRC("Removing invalidated tiles: part: " << part <<
             ", x: " << x << ", y: " << y <<
@@ -318,7 +318,7 @@ void TileCache::invalidateTiles(int part, int x, int y, int 
width, int height)
     for (auto it = _cache.begin(); it != _cache.end();)
     {
         const std::string fileName = it->first;
-        if (intersectsTile(fileName, part, x, y, width, height))
+        if (intersectsTile(fileName, part, x, y, width, height, 
normalizedViewId))
         {
             LOG_DBG("Removing tile: " << it->first);
             it = _cache.erase(it);
@@ -328,11 +328,11 @@ void TileCache::invalidateTiles(int part, int x, int y, 
int width, int height)
     }
 }
 
-void TileCache::invalidateTiles(const std::string& tiles)
+void TileCache::invalidateTiles(const std::string& tiles, const int 
normalizedViewId)
 {
     std::pair<int, Util::Rectangle> result = 
TileCache::parseInvalidateMsg(tiles);
     Util::Rectangle& invalidateRect = result.second;
-    invalidateTiles(result.first, invalidateRect.getLeft(), 
invalidateRect.getTop(), invalidateRect.getWidth(), invalidateRect.getHeight());
+    invalidateTiles(result.first, invalidateRect.getLeft(), 
invalidateRect.getTop(), invalidateRect.getWidth(), invalidateRect.getHeight(), 
normalizedViewId);
 }
 
 std::pair<int, Util::Rectangle> TileCache::parseInvalidateMsg(const 
std::string& tiles)
@@ -385,25 +385,28 @@ void TileCache::removeFile(const std::string& fileName)
 std::string TileCache::cacheFileName(const TileDesc& tile)
 {
     std::ostringstream oss;
-    oss << tile.getPart() << '_' << tile.getWidth() << 'x' << tile.getHeight() 
<< '.'
+    oss << tile.getNormalizedViewId() << '_' << tile.getPart() << '_' << 
tile.getWidth() << 'x' << tile.getHeight() << '.'
         << tile.getTilePosX() << ',' << tile.getTilePosY() << '.'
         << tile.getTileWidth() << 'x' << tile.getTileHeight() << ".png";
     return oss.str();
 }
 
-bool TileCache::parseCacheFileName(const std::string& fileName, int& part, 
int& width, int& height, int& tilePosX, int& tilePosY, int& tileWidth, int& 
tileHeight)
+bool TileCache::parseCacheFileName(const std::string& fileName, int& part, 
int& width, int& height, int& tilePosX, int& tilePosY, int& tileWidth, int& 
tileHeight, int& normalizedViewId)
 {
-    return std::sscanf(fileName.c_str(), "%d_%dx%d.%d,%d.%dx%d.png", &part, 
&width, &height, &tilePosX, &tilePosY, &tileWidth, &tileHeight) == 7;
+    return std::sscanf(fileName.c_str(), "%d_%d_%dx%d.%d,%d.%dx%d.png", 
&normalizedViewId, &part, &width, &height, &tilePosX, &tilePosY, &tileWidth, 
&tileHeight) == 8;
 }
 
-bool TileCache::intersectsTile(const std::string& fileName, int part, int x, 
int y, int width, int height)
+bool TileCache::intersectsTile(const std::string& fileName, int part, int x, 
int y, int width, int height, int normalizedViewId)
 {
-    int tilePart, tilePixelWidth, tilePixelHeight, tilePosX, tilePosY, 
tileWidth, tileHeight;
-    if (parseCacheFileName(fileName, tilePart, tilePixelWidth, 
tilePixelHeight, tilePosX, tilePosY, tileWidth, tileHeight))
+    int tilePart, tilePixelWidth, tilePixelHeight, tilePosX, tilePosY, 
tileWidth, tileHeight, nViewId;
+    if (parseCacheFileName(fileName, tilePart, tilePixelWidth, 
tilePixelHeight, tilePosX, tilePosY, tileWidth, tileHeight, nViewId))
     {
         if (part != -1 && tilePart != part)
             return false;
 
+        if (normalizedViewId != nViewId)
+            return false;
+
         const int left = std::max(x, tilePosX);
         const int right = std::min(x + width, tilePosX + tileWidth);
         const int top = std::max(y, tilePosY);
@@ -420,7 +423,7 @@ bool TileCache::intersectsTile(const std::string& fileName, 
int part, int x, int
 void TileCache::subscribeToTileRendering(const TileDesc& tile, const 
std::shared_ptr<ClientSession>& subscriber)
 {
     std::ostringstream oss;
-    oss << '(' << tile.getPart() << ',' << tile.getTilePosX() << ',' << 
tile.getTilePosY() << ')';
+    oss << '(' << tile.getNormalizedViewId() << ',' << tile.getPart() << ',' 
<< tile.getTilePosX() << ',' << tile.getTilePosY() << ')';
     const std::string name = oss.str();
 
     assertCorrectThread();
diff --git a/wsd/TileCache.hpp b/wsd/TileCache.hpp
index fe5a7ca34..01713d3da 100644
--- a/wsd/TileCache.hpp
+++ b/wsd/TileCache.hpp
@@ -80,7 +80,7 @@ public:
     Tile lookupCachedTile(const std::string& name, const std::string& dir);
 
     // The tiles parameter is an invalidatetiles: message as sent by the child 
process
-    void invalidateTiles(const std::string& tiles);
+    void invalidateTiles(const std::string& tiles, int normalizedViewId);
 
     /// Parse invalidateTiles message to a part number and a rectangle of the 
invalidated area
     static std::pair<int, Util::Rectangle> parseInvalidateMsg(const 
std::string& tiles);
@@ -97,7 +97,7 @@ public:
     void assertCorrectThread();
 
 private:
-    void invalidateTiles(int part, int x, int y, int width, int height);
+    void invalidateTiles(int part, int x, int y, int width, int height, int 
normalizedViewId);
 
     /// Lookup tile in our cache.
     TileCache::Tile loadTile(const std::string &fileName);
@@ -106,10 +106,10 @@ private:
     void removeFile(const std::string& fileName);
 
     static std::string cacheFileName(const TileDesc& tile);
-    static bool parseCacheFileName(const std::string& fileName, int& part, 
int& width, int& height, int& tilePosX, int& tilePosY, int& tileWidth, int& 
tileHeight);
+    static bool parseCacheFileName(const std::string& fileName, int& part, 
int& width, int& height, int& tilePosX, int& tilePosY, int& tileWidth, int& 
tileHeight, int& normalizedViewId);
 
     /// Extract location from fileName, and check if it intersects with [x, y, 
width, height].
-    static bool intersectsTile(const std::string& fileName, int part, int x, 
int y, int width, int height);
+    static bool intersectsTile(const std::string& fileName, int part, int x, 
int y, int width, int height, int normalizedViewId);
 
     void saveDataToCache(const std::string &fileName, const char *data, const 
size_t size);
 
diff --git a/wsd/TileDesc.hpp b/wsd/TileDesc.hpp
index 50668a41e..6d0ed408e 100644
--- a/wsd/TileDesc.hpp
+++ b/wsd/TileDesc.hpp
@@ -545,6 +545,7 @@ public:
         _height = desc.getHeight();
         _tileWidth = desc.getTileWidth();
         _tileHeight = desc.getTileHeight();
+        _normalizedViewId = desc.getNormalizedViewId();
         _tiles.push_back(desc);
     }
 
commit 917036a5851344079d905ada50709baf247ceabe
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Fri Oct 11 15:22:12 2019 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Mon Oct 14 00:15:09 2019 +0300

    Moved class Watermark to a seperate file
    
    Watermark class is moved to another file
    and included in ChildSession and
    each session will have its own Watermark objects
    to render its own Watermark texts
    Added hash method for watermark texts
    and use it as normalizedViewId to find correct
    sessions with their watermark texts for rendering it
    to correct tile

diff --git a/common/Session.cpp b/common/Session.cpp
index e5a70c081..8822b1973 100644
--- a/common/Session.cpp
+++ b/common/Session.cpp
@@ -256,6 +256,22 @@ void Session::getIOStats(uint64_t &sent, uint64_t &recv)
     }
 }
 
+void Session::setHash(const std::string& text)
+{
+    int hash = 0x811C9DC5;
+    int prime = 0x1000193;
+
+    if (!text.empty())
+    {
+       for (unsigned int i = 0; i < text.length(); ++i)
+       {
+           hash += hash ^ text[i];
+           hash *= prime;
+       }
+    }
+    _hash = abs(hash);
+}
+
 void Session::dumpState(std::ostream& os)
 {
     WebSocketHandler::dumpState(os);
diff --git a/common/Session.hpp b/common/Session.hpp
index 6955b1e66..623a9d3c7 100644
--- a/common/Session.hpp
+++ b/common/Session.hpp
@@ -122,6 +122,12 @@ public:
 
     const std::string& getJailedFilePathAnonym() const { return 
_jailedFilePathAnonym; }
 
+    int getHash() { return _hash; }
+
+    void setHash(const std::string& text);
+
+    void setHash(const int hash) { _hash = hash; };
+
 protected:
     Session(const std::string& name, const std::string& id, bool readonly);
     virtual ~Session();
@@ -212,6 +218,11 @@ private:
 
     /// Language for the document based on what the user has in the UI.
     std::string _lang;
+
+    /// Hash for normalizedViewId which is basically an identity for the tile 
to
+    /// choose what to render on and send it to its subscribers
+    /// it is the close-to-unique integer representation of a string like 
Watermarks etc.
+    int _hash;
 };
 
 #endif
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index b97cdcc9e..b390537de 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -24,6 +24,7 @@
 #include "Kit.hpp"
 #include "Session.hpp"
 
+class Watermark;
 class ChildSession;
 
 enum class LokEventTargetEnum
@@ -237,6 +238,7 @@ public:
     }
 
     using Session::sendTextFrame;
+    std::shared_ptr<Watermark> _docWatermark;
 
 private:
     bool loadDocument(const char* buffer, int length, const 
std::vector<std::string>& tokens);
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 9fda917e4..c72bec66b 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -54,6 +54,7 @@
 #include <Poco/URI.h>
 #include <Poco/Util/Application.h>
 
+#include "Watermark.hpp"
 #include "ChildSession.hpp"
 #include <Common.hpp>
 #include <IoUtil.hpp>
@@ -585,171 +586,6 @@ public:
     }
 };
 
-class Watermark
-{
-public:
-    Watermark(const std::shared_ptr<lok::Document>& loKitDoc, const 
std::string& text,
-    const std::shared_ptr<ChildSession> & session)
-        : _loKitDoc(loKitDoc)
-        , _text(text)
-        , _font("Liberation Sans")
-        , _width(0)
-        , _height(0)
-        , _alphaLevel(session->getWatermarkOpacity())
-    {
-    }
-
-    ~Watermark()
-    {
-    }
-
-    void blending(unsigned char* tilePixmap,
-                   int offsetX, int offsetY,
-                   int tilesPixmapWidth, int tilesPixmapHeight,
-                   int tileWidth, int tileHeight,
-                   LibreOfficeKitTileMode /*mode*/)
-    {
-        // set requested watermark size a little bit smaller than tile size
-        int width = tileWidth * 0.9;
-        int height = tileHeight * 0.9;
-
-        const std::vector<unsigned char>* pixmap = getPixmap(width, height);
-
-        if (pixmap && tilePixmap)
-        {
-            // center watermark
-            const int maxX = std::min(tileWidth, _width);
-            const int maxY = std::min(tileHeight, _height);
-            offsetX += (tileWidth - maxX) / 2;
-            offsetY += (tileHeight - maxY) / 2;
-
-            alphaBlend(*pixmap, _width, _height, offsetX, offsetY, tilePixmap, 
tilesPixmapWidth, tilesPixmapHeight);
-        }
-    }
-
-private:
-    /// Alpha blend pixels from 'from' over the 'to'.
-    void alphaBlend(const std::vector<unsigned char>& from, int from_width, 
int from_height, int from_offset_x, int from_offset_y,
-            unsigned char* to, int to_width, int to_height)
-    {
-        for (int to_y = from_offset_y, from_y = 0; (to_y < to_height) && 
(from_y < from_height) ; ++to_y, ++from_y)
-            for (int to_x = from_offset_x, from_x = 0; (to_x < to_width) && 
(from_x < from_width); ++to_x, ++from_x)
-            {
-                const unsigned char* f = from.data() + 4 * (from_y * 
from_width + from_x);
-                double src_r = f[0];
-                double src_g = f[1];
-                double src_b = f[2];
-                double src_a = f[3] / 255.0;
-
-                unsigned char* t = to + 4 * (to_y * to_width + to_x);
-                double dst_r = t[0];
-                double dst_g = t[1];
-                double dst_b = t[2];
-                double dst_a = t[3] / 255.0;
-
-                double out_a = src_a + dst_a * (1.0 - src_a);
-                unsigned char out_r = src_r + dst_r * (1.0 - src_a);
-                unsigned char out_g = src_g + dst_g * (1.0 - src_a);
-                unsigned char out_b = src_b + dst_b * (1.0 - src_a);
-
-                t[0] = out_r;
-                t[1] = out_g;
-                t[2] = out_b;
-                t[3] = static_cast<unsigned char>(out_a * 255.0);
-            }
-    }
-
-    /// Create bitmap that we later use as the watermark for every tile.
-    const std::vector<unsigned char>* getPixmap(int width, int height)
-    {
-        if (!_pixmap.empty() && width == _width && height == _height)
-            return &_pixmap;
-
-        _pixmap.clear();
-
-        _width = width;
-        _height = height;
-
-        if (!_loKitDoc)
-        {
-            LOG_ERR("Watermark rendering requested without a valid document.");
-            return nullptr;
-        }
-
-        // renderFont returns a buffer based on RGBA mode, where r, g, b
-        // are always set to 0 (black) and the alpha level is 0 everywhere
-        // except on the text area; the alpha level take into account of
-        // performing anti-aliasing over the text edges.
-        unsigned char* textPixels = _loKitDoc->renderFont(_font.c_str(), 
_text.c_str(), &_width, &_height);
-
-        if (!textPixels)
-        {
-            LOG_ERR("Watermark: rendering failed.");
-        }
-
-        const unsigned int pixel_count = width * height * 4;
-
-        std::vector<unsigned char> text(textPixels, textPixels + pixel_count);
-        // No longer needed.
-        std::free(textPixels);
-
-        _pixmap.reserve(pixel_count);
-
-        // Create the white blurred background
-        // Use box blur, it's enough for our purposes
-        const int r = 2;
-        const double weight = (r+1) * (r+1);
-        for (int y = 0; y < height; ++y)
-        {
-            for (int x = 0; x < width; ++x)
-            {
-                double t = 0;
-                for (int ky = std::max(y - r, 0); ky <= std::min(y + r, height 
- 1); ++ky)
-                {
-                    for (int kx = std::max(x - r, 0); kx <= std::min(x + r, 
width - 1); ++kx)
-                    {
-                        // Pre-multiplied alpha; the text is black, so all the
-                        // information is only in the alpha channel
-                        t += text[4 * (ky * width + kx) + 3];
-                    }
-                }
-
-                // Clamp the result.
-                double avg = t / weight;
-                if (avg > 255.0)
-                    avg = 255.0;
-
-                // Pre-multiplied alpha, but use white for the resulting color
-                const double alpha = avg / 255.0;
-                _pixmap[4 * (y * width + x) + 0] = 0xff * alpha;
-                _pixmap[4 * (y * width + x) + 1] = 0xff * alpha;
-                _pixmap[4 * (y * width + x) + 2] = 0xff * alpha;
-                _pixmap[4 * (y * width + x) + 3] = avg;
-            }
-        }
-
-        // Now copy the (black) text over the (white) blur
-        alphaBlend(text, _width, _height, 0, 0, _pixmap.data(), _width, 
_height);
-
-        // Make the resulting pixmap semi-transparent
-        for (unsigned char* p = _pixmap.data(); p < _pixmap.data() + 
pixel_count; p++)
-        {
-            *p = static_cast<unsigned char>(*p * _alphaLevel);
-        }
-
-        return &_pixmap;
-    }
-
-private:
-    std::shared_ptr<lok::Document> _loKitDoc;
-    std::string _text;
-    std::string _font;
-    int _width;
-    int _height;
-    double _alphaLevel;
-    std::vector<unsigned char> _pixmap;
-};
-
 #if !MOBILEAPP
 static FILE* ProcSMapsFile = nullptr;
 #endif
@@ -1138,6 +974,16 @@ public:
         const int pixelWidth = tileCombined.getWidth();
         const int pixelHeight = tileCombined.getHeight();
 
+        int nViewId = tileCombined.getNormalizedViewId();
+        const auto it = std::find_if(_sessions.begin(), _sessions.end(), 
[nViewId](const std::pair<std::string, std::shared_ptr<ChildSession>>& val){ 
return (val.second)->getHash() == nViewId; });
+        const auto& session = it->second;
+
+        if (it == _sessions.end())
+        {
+            LOG_ERR("Session is not found. Maybe exited after rendering 
request.");
+            return;
+        }
+
         std::vector<TileDesc> renderedTiles;
         std::vector<TileDesc> duplicateTiles;
         std::vector<TileBinaryHash> duplicateHashes;
@@ -1152,6 +998,12 @@ public:
             const int offsetX = positionX * pixelWidth;
             const int offsetY = positionY * pixelHeight;
 
+            if (session->_docWatermark)
+                session->_docWatermark->blending(pixmap.data(), offsetX, 
offsetY,
+                                        pixmapWidth, pixmapHeight,
+                                        pixelWidth, pixelHeight,
+                                        mode);
+
             const uint64_t hash = Png::hashSubBuffer(pixmap.data(), offsetX, 
offsetY,
                                                      pixelWidth, pixelHeight, 
pixmapWidth, pixmapHeight);
 
@@ -1195,12 +1047,6 @@ public:
             if (!skipCompress)
             {
                 renderingIds.push_back(wireId);
-                if (_docWatermark)
-                    _docWatermark->blending(pixmap.data(), offsetX, offsetY,
-                                            pixmapWidth, pixmapHeight,
-                                            pixelWidth, pixelHeight,
-                                            mode);
-
                 // Queue to be executed later in parallel inside 'run'
                 
_pngPool.pushWorkUnlocked([=,&output,&pixmap,&tiles,&renderedTiles](){
                         PngCache::CacheData data(new std::vector< char >() );
@@ -1815,9 +1661,6 @@ private:
             // Only save the options on opening the document.
             // No support for changing them after opening a document.
             _renderOpts = renderOpts;
-
-            if (!watermarkText.empty())
-                _docWatermark.reset(new Watermark(_loKitDocument, 
watermarkText, session));
         }
         else
         {
@@ -1873,6 +1716,16 @@ private:
                 sessionId << "] loaded view [" << viewId << "]. Have " <<
                 viewCount << " view" << (viewCount != 1 ? "s." : "."));
 
+        if (!watermarkText.empty())
+        {
+            session->_docWatermark.reset(new Watermark(_loKitDocument, 
watermarkText, session));
+            session->setHash(watermarkText);
+        }
+        else
+        {
+            session->setHash(0);
+        }
+
         return _loKitDocument;
     }
 
@@ -2173,9 +2026,6 @@ private:
     // Whether password is required to view the document, or modify it
     PasswordType _docPasswordType;
 
-    // Document watermark
-    std::unique_ptr<Watermark> _docWatermark;
-
     std::atomic<bool> _stop;
     mutable std::mutex _mutex;
 
diff --git a/kit/Watermark.hpp b/kit/Watermark.hpp
new file mode 100644
index 000000000..04d18a1ea
--- /dev/null
+++ b/kit/Watermark.hpp
@@ -0,0 +1,180 @@
+#ifndef INCLUDED_WATERMARK_HPP
+#define INCLUDED_WATERMARK_HPP
+
+#define LOK_USE_UNSTABLE_API
+#include <LibreOfficeKit/LibreOfficeKitInit.h>
+#include <LibreOfficeKit/LibreOfficeKit.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <vector>
+#include <Log.hpp>
+#include <cstdlib>
+#include <string>
+#include "ChildSession.hpp"
+
+
+class Watermark
+{
+public:
+    Watermark(const std::shared_ptr<lok::Document>& loKitDoc, const 
std::string& text,
+    const std::shared_ptr<ChildSession> & session)
+        : _loKitDoc(loKitDoc)
+        , _text(text)
+        , _font("Liberation Sans")
+        , _width(0)
+        , _height(0)
+        , _alphaLevel(session->getWatermarkOpacity())
+    {
+    }
+
+    ~Watermark()
+    {
+    }
+
+    void blending(unsigned char* tilePixmap,
+                   int offsetX, int offsetY,
+                   int tilesPixmapWidth, int tilesPixmapHeight,
+                   int tileWidth, int tileHeight,
+                   LibreOfficeKitTileMode /*mode*/)
+    {
+        // set requested watermark size a little bit smaller than tile size
+        int width = tileWidth * 0.9;
+        int height = tileHeight * 0.9;
+
+        const std::vector<unsigned char>* pixmap = getPixmap(width, height);
+
+        if (pixmap && tilePixmap)
+        {
+            // center watermark
+            const int maxX = std::min(tileWidth, _width);
+            const int maxY = std::min(tileHeight, _height);
+            offsetX += (tileWidth - maxX) / 2;
+            offsetY += (tileHeight - maxY) / 2;
+
+            alphaBlend(*pixmap, _width, _height, offsetX, offsetY, tilePixmap, 
tilesPixmapWidth, tilesPixmapHeight);
+        }
+    }
+
+private:
+    /// Alpha blend pixels from 'from' over the 'to'.
+    void alphaBlend(const std::vector<unsigned char>& from, int from_width, 
int from_height, int from_offset_x, int from_offset_y,
+            unsigned char* to, int to_width, int to_height)
+    {
+        for (int to_y = from_offset_y, from_y = 0; (to_y < to_height) && 
(from_y < from_height) ; ++to_y, ++from_y)
+            for (int to_x = from_offset_x, from_x = 0; (to_x < to_width) && 
(from_x < from_width); ++to_x, ++from_x)
+            {
+                const unsigned char* f = from.data() + 4 * (from_y * 
from_width + from_x);
+                double src_r = f[0];
+                double src_g = f[1];
+                double src_b = f[2];
+                double src_a = f[3] / 255.0;
+
+                unsigned char* t = to + 4 * (to_y * to_width + to_x);
+                double dst_r = t[0];
+                double dst_g = t[1];
+                double dst_b = t[2];
+                double dst_a = t[3] / 255.0;
+
+                double out_a = src_a + dst_a * (1.0 - src_a);
+                unsigned char out_r = src_r + dst_r * (1.0 - src_a);
+                unsigned char out_g = src_g + dst_g * (1.0 - src_a);
+                unsigned char out_b = src_b + dst_b * (1.0 - src_a);
+
+                t[0] = out_r;
+                t[1] = out_g;
+                t[2] = out_b;
+                t[3] = static_cast<unsigned char>(out_a * 255.0);
+            }
+    }
+
+    /// Create bitmap that we later use as the watermark for every tile.
+    const std::vector<unsigned char>* getPixmap(int width, int height)
+    {
+        if (!_pixmap.empty() && width == _width && height == _height)
+            return &_pixmap;
+
+        _pixmap.clear();
+
+        _width = width;
+        _height = height;
+
+        if (!_loKitDoc)
+        {
+            LOG_ERR("Watermark rendering requested without a valid document.");
+            return nullptr;
+        }
+
+        // renderFont returns a buffer based on RGBA mode, where r, g, b
+        // are always set to 0 (black) and the alpha level is 0 everywhere
+        // except on the text area; the alpha level take into account of
+        // performing anti-aliasing over the text edges.
+        unsigned char* textPixels = _loKitDoc->renderFont(_font.c_str(), 
_text.c_str(), &_width, &_height);
+
+        if (!textPixels)
+        {
+            LOG_ERR("Watermark: rendering failed.");
+        }
+
+        const unsigned int pixel_count = width * height * 4;
+
+        std::vector<unsigned char> text(textPixels, textPixels + pixel_count);
+        // No longer needed.
+        std::free(textPixels);
+
+        _pixmap.reserve(pixel_count);
+
+        // Create the white blurred background
+        // Use box blur, it's enough for our purposes
+        const int r = 2;
+        const double weight = (r+1) * (r+1);
+        for (int y = 0; y < height; ++y)
+        {
+            for (int x = 0; x < width; ++x)
+            {
+                double t = 0;
+                for (int ky = std::max(y - r, 0); ky <= std::min(y + r, height 
- 1); ++ky)
+                {
+                    for (int kx = std::max(x - r, 0); kx <= std::min(x + r, 
width - 1); ++kx)
+                    {
+                        // Pre-multiplied alpha; the text is black, so all the
+                        // information is only in the alpha channel
+                        t += text[4 * (ky * width + kx) + 3];
+                    }
+                }
+
+                // Clamp the result.
+                double avg = t / weight;
+                if (avg > 255.0)
+                    avg = 255.0;
+
+                // Pre-multiplied alpha, but use white for the resulting color
+                const double alpha = avg / 255.0;
+                _pixmap[4 * (y * width + x) + 0] = 0xff * alpha;
+                _pixmap[4 * (y * width + x) + 1] = 0xff * alpha;
+                _pixmap[4 * (y * width + x) + 2] = 0xff * alpha;
+                _pixmap[4 * (y * width + x) + 3] = avg;
+            }
+        }
+
+        // Now copy the (black) text over the (white) blur
+        alphaBlend(text, _width, _height, 0, 0, _pixmap.data(), _width, 
_height);
+
+        // Make the resulting pixmap semi-transparent
+        for (unsigned char* p = _pixmap.data(); p < _pixmap.data() + 
pixel_count; p++)
+        {
+            *p = static_cast<unsigned char>(*p * _alphaLevel);
+        }
+
+        return &_pixmap;
+    }
+
+private:
+    std::shared_ptr<lok::Document> _loKitDoc;
+    std::string _text;
+    std::string _font;
+    int _width;
+    int _height;
+    double _alphaLevel;
+    std::vector<unsigned char> _pixmap;
+};
+
+#endif
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 3322464e5..87594c4c4 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -588,6 +588,7 @@ bool ClientSession::sendTile(const char * /*buffer*/, int 
/*length*/, const std:
     try
     {
         TileDesc tileDesc = TileDesc::parse(tokens);
+        tileDesc.setNormalizedViewId(getHash());
         docBroker->handleTileRequest(tileDesc, shared_from_this());
     }
     catch (const std::exception& exc)
@@ -605,6 +606,7 @@ bool ClientSession::sendCombinedTiles(const char* 
/*buffer*/, int /*length*/, co
     try
     {
         TileCombined tileCombined = TileCombined::parse(tokens);
+        tileCombined.setNormalizedViewId(getHash());
         docBroker->handleTileCombinedRequest(tileCombined, shared_from_this());
     }
     catch (const std::exception& exc)
@@ -1344,7 +1346,7 @@ void ClientSession::handleTileInvalidation(const 
std::string& message,
     if( part == -1 ) // If no part is specifed we use the part used by the 
client
         part = _clientSelectedPart;
 
-    int normalizedViewId = 0;
+    int normalizedViewId = getHash();
 
     std::vector<TileDesc> invalidTiles;
     if(part == _clientSelectedPart || _isTextDocument)
@@ -1377,6 +1379,7 @@ void ClientSession::handleTileInvalidation(const 
std::string& message,
     if(!invalidTiles.empty())
     {
         TileCombined tileCombined = TileCombined::create(invalidTiles);
+        tileCombined.setNormalizedViewId(normalizedViewId);
         docBroker->handleTileCombinedRequest(tileCombined, shared_from_this());
     }
 }
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 8b0011fcd..2d1ea7e53 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -637,6 +637,11 @@ bool DocumentBroker::load(const 
std::shared_ptr<ClientSession>& session, const s
     session->setUserExtraInfo(userExtraInfo);
     session->setWatermarkText(watermarkText);
 
+    if(!watermarkText.empty())
+        session->setHash(watermarkText);
+    else
+        session->setHash(0);
+
     // Basic file information was stored by the above getWOPIFileInfo() or 
getLocalFileInfo() calls
     const StorageBase::FileInfo fileInfo = _storage->getFileInfo();
     if (!fileInfo.isValid())
commit 8c70a1687b021ff6a9f03c3163123f6f7f6b98de
Author:     Mert Tumer <mert.tu...@collabora.com>
AuthorDate: Fri Oct 11 12:17:07 2019 +0300
Commit:     Mert Tumer <mert.tu...@collabora.com>
CommitDate: Mon Oct 14 00:15:09 2019 +0300

    Extended TileDesc with normalizedViewId

diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js
index 95e5bc2a0..775654312 100644
--- a/loleaflet/src/control/Parts.js
+++ b/loleaflet/src/control/Parts.js
@@ -124,6 +124,7 @@ L.Map.include({
                }
 
                this._socket.sendMessage('tile ' +
+                                                       'nviewid=0' + ' ' +
                                                        'part=' + part + ' ' +
                                                        'width=' + maxWidth * 
dpiscale + ' ' +
                                                        'height=' + maxHeight * 
dpiscale + ' ' +
@@ -148,6 +149,7 @@ L.Map.include({
                var dpiscale = L.getDpiScaleFactor();
 
                this._socket.sendMessage('tile ' +
+                                                       'nviewid=0' + ' ' +
                                                        'part=' + part + ' ' +
                                                        'width=' + width * 
dpiscale + ' ' +
                                                        'height=' + height * 
dpiscale + ' ' +
diff --git a/loleaflet/src/layer/tile/GridLayer.js 
b/loleaflet/src/layer/tile/GridLayer.js
index 3fcbbbac5..dbb850054 100644
--- a/loleaflet/src/layer/tile/GridLayer.js
+++ b/loleaflet/src/layer/tile/GridLayer.js
@@ -688,6 +688,7 @@ L.GridLayer = L.Layer.extend({
 
                        if (tilePositionsX !== '' && tilePositionsY !== '') {
                                var message = 'tilecombine ' +
+                                       'nviewid=0 ' +
                                        'part=' + this._selectedPart + ' ' +
                                        'width=' + this._tileWidthPx + ' ' +
                                        'height=' + this._tileHeightPx + ' ' +
@@ -1022,6 +1023,7 @@ L.GridLayer = L.Layer.extend({
 
                        twips = this._coordsToTwips(coords);
                        msg = 'tilecombine ' +
+                               'nviewid=0 ' +
                                'part=' + coords.part + ' ' +
                                'width=' + this._tileWidthPx + ' ' +
                                'height=' + this._tileHeightPx + ' ' +
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 36c0c5965..3322464e5 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -1344,6 +1344,8 @@ void ClientSession::handleTileInvalidation(const 
std::string& message,
     if( part == -1 ) // If no part is specifed we use the part used by the 
client
         part = _clientSelectedPart;
 
+    int normalizedViewId = 0;
+
     std::vector<TileDesc> invalidTiles;
     if(part == _clientSelectedPart || _isTextDocument)
     {
@@ -1358,7 +1360,7 @@ void ClientSession::handleTileInvalidation(const 
std::string& message,
                 Util::Rectangle tileRect (j * _tileWidthTwips, i * 
_tileHeightTwips, _tileWidthTwips, _tileHeightTwips);
                 if(invalidateRect.intersects(tileRect))
                 {
-                    invalidTiles.emplace_back(part, _tileWidthPixel, 
_tileHeightPixel, j * _tileWidthTwips, i * _tileHeightTwips, _tileWidthTwips, 
_tileHeightTwips, -1, 0, -1, false);
+                    invalidTiles.emplace_back(normalizedViewId, part, 
_tileWidthPixel, _tileHeightPixel, j * _tileWidthTwips, i * _tileHeightTwips, 
_tileWidthTwips, _tileHeightTwips, -1, 0, -1, false);
 
                     TileWireId oldWireId = 0;
                     auto iter = 
_oldWireIds.find(generateTileID(invalidTiles.back()));
diff --git a/wsd/TileDesc.hpp b/wsd/TileDesc.hpp
index 6170cc7e7..50668a41e 100644
--- a/wsd/TileDesc.hpp
+++ b/wsd/TileDesc.hpp
@@ -29,9 +29,10 @@ typedef uint64_t TileBinaryHash;
 class TileDesc
 {
 public:
-    TileDesc(int part, int width, int height, int tilePosX, int tilePosY, int 
tileWidth,
+    TileDesc(int normalizedViewId, int part, int width, int height, int 
tilePosX, int tilePosY, int tileWidth,
              int tileHeight, int ver, int imgSize, int id, bool broadcast)
-        : _part(part)
+        : _normalizedViewId(normalizedViewId)
+        , _part(part)
         , _width(width)
         , _height(height)
         , _tilePosX(tilePosX)
@@ -45,7 +46,8 @@ public:
         , _oldWireId(0)
         , _wireId(0)
     {
-        if (_part < 0 ||
+        if (_normalizedViewId < 0 ||
+            _part < 0 ||
             _width <= 0 ||
             _height <= 0 ||
             _tilePosX < 0 ||
@@ -57,7 +59,8 @@ public:
             throw BadArgumentException("Invalid tile descriptor.");
         }
     }
-
+    int getNormalizedViewId() const { return _normalizedViewId; }
+    void setNormalizedViewId(const int normalizedViewId) { _normalizedViewId = 
normalizedViewId; }
     int getPart() const { return _part; }
     int getWidth() const { return _width; }
     int getHeight() const { return _height; }
@@ -128,7 +131,8 @@ public:
             other.getWidth() != getWidth() ||
             other.getHeight() != getHeight() ||
             other.getTileWidth() != getTileWidth() ||
-            other.getTileHeight() != getTileHeight())
+            other.getTileHeight() != getTileHeight() ||
+            other.getNormalizedViewId() != getNormalizedViewId())
         {
             return false;
         }
@@ -158,6 +162,7 @@ public:
     {
         std::ostringstream oss;
         oss << prefix
+            << " nviewid=" << _normalizedViewId
             << " part=" << _part
             << " width=" << _width
             << " height=" << _height
@@ -225,7 +230,7 @@ public:
         const bool broadcast = (LOOLProtocol::getTokenString(tokens, 
"broadcast", s) &&
                                 s == "yes");
 
-        TileDesc result(pairs["part"], pairs["width"], pairs["height"],
+        TileDesc result(pairs["nviewid"], pairs["part"], pairs["width"], 
pairs["height"],
                         pairs["tileposx"], pairs["tileposy"],
                         pairs["tilewidth"], pairs["tileheight"],
                         pairs["ver"],
@@ -243,6 +248,7 @@ public:
     }
 
 private:
+    int _normalizedViewId;
     int _part;
     int _width;
     int _height;
@@ -264,19 +270,21 @@ private:
 class TileCombined
 {
 private:
-    TileCombined(int part, int width, int height,
+    TileCombined(int normalizedViewId, int part, int width, int height,
                  const std::string& tilePositionsX, const std::string& 
tilePositionsY,
                  int tileWidth, int tileHeight, const std::string& vers,
                  const std::string& imgSizes,
                  const std::string& oldWireIds,
                  const std::string& wireIds) :
+        _normalizedViewId(normalizedViewId),
         _part(part),
         _width(width),
         _height(height),
         _tileWidth(tileWidth),
         _tileHeight(tileHeight)
     {
-        if (_part < 0 ||
+        if (_normalizedViewId < 0 ||
+            _part < 0 ||
             _width <= 0 ||
             _height <= 0 ||
             _tileWidth <= 0 ||
@@ -342,13 +350,14 @@ private:
                 throw BadArgumentException("Invalid tilecombine descriptor.");
             }
 
-            _tiles.emplace_back(_part, _width, _height, x, y, _tileWidth, 
_tileHeight, ver, imgSize, -1, false);
+            _tiles.emplace_back(_normalizedViewId, _part, _width, _height, x, 
y, _tileWidth, _tileHeight, ver, imgSize, -1, false);
             _tiles.back().setOldWireId(oldWireId);
             _tiles.back().setWireId(wireId);
         }
     }
 
 public:
+    int getNormalizedViewId() const { return _normalizedViewId; }
     int getPart() const { return _part; }
     int getWidth() const { return _width; }
     int getHeight() const { return _height; }
@@ -358,6 +367,13 @@ public:
     const std::vector<TileDesc>& getTiles() const { return _tiles; }
     std::vector<TileDesc>& getTiles() { return _tiles; }
 
+    void setNormalizedViewId(int nViewId)
+    {
+        for (auto& tile : getTiles())
+            tile.setNormalizedViewId(nViewId);
+
+        _normalizedViewId = nViewId;
+    }
     /// Serialize this instance into a string.
     /// Optionally prepend a prefix.
     std::string serialize(const std::string& prefix = std::string(),
@@ -371,6 +387,7 @@ public:
     {
         std::ostringstream oss;
         oss << prefix
+            << " nviewid=" << _normalizedViewId
             << " part=" << _part
             << " width=" << _width
             << " height=" << _height
@@ -483,7 +500,7 @@ public:
             }
         }
 
-        return TileCombined(pairs["part"], pairs["width"], pairs["height"],
+        return TileCombined(pairs["nviewid"], pairs["part"], pairs["width"], 
pairs["height"],
                             tilePositionsX, tilePositionsY,
                             pairs["tilewidth"], pairs["tileheight"],
                             versions, imgSizes, oldwireIds, wireIds);
@@ -515,7 +532,7 @@ public:
         }
 
         vers.seekp(-1, std::ios_base::cur); // Remove last comma.
-        return TileCombined(tiles[0].getPart(), tiles[0].getWidth(), 
tiles[0].getHeight(),
+        return TileCombined(tiles[0].getNormalizedViewId(), 
tiles[0].getPart(), tiles[0].getWidth(), tiles[0].getHeight(),
                             xs.str(), ys.str(), tiles[0].getTileWidth(), 
tiles[0].getTileHeight(),
                             vers.str(), "", oldhs.str(), hs.str());
     }
@@ -533,6 +550,7 @@ public:
 
 private:
     std::vector<TileDesc> _tiles;
+    int _normalizedViewId;
     int _part;
     int _width;
     int _height;
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to