[Libreoffice-commits] online.git: Branch 'distro/collabora/milestone-7' - 5 commits - loleaflet/src loolwsd/LOKitClient.cpp loolwsd/LOOLProtocol.cpp loolwsd/LOOLProtocol.hpp loolwsd/LOOLSession.cpp loolwsd/LOOLSession.hpp loolwsd/Rectangle.hpp loolwsd/Util.cpp loolwsd/Util.hpp

Tomaž Vajngerl tomaz.vajngerl at collabora.com
Tue Jan 12 04:47:09 PST 2016


 loleaflet/src/layer/tile/CalcTileLayer.js    |   40 ++++---
 loleaflet/src/layer/tile/ImpressTileLayer.js |   40 ++++---
 loleaflet/src/layer/tile/WriterTileLayer.js  |   40 ++++---
 loolwsd/LOKitClient.cpp                      |    3 
 loolwsd/LOOLProtocol.cpp                     |   14 ++
 loolwsd/LOOLProtocol.hpp                     |    1 
 loolwsd/LOOLSession.cpp                      |  149 ++++++++++++++++++++++++++-
 loolwsd/LOOLSession.hpp                      |    6 +
 loolwsd/Rectangle.hpp                        |   81 ++++++++++++++
 loolwsd/Util.cpp                             |   25 ++--
 loolwsd/Util.hpp                             |    6 -
 11 files changed, 344 insertions(+), 61 deletions(-)

New commits:
commit 2f58be7613f2bd663693b7022f7ca5e38f5c1f41
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Tue Jan 12 12:20:53 2016 +0100

    Send tilcombine command when invalidating tiles

diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js
index 6364345..58303f3 100644
--- a/loleaflet/src/layer/tile/CalcTileLayer.js
+++ b/loleaflet/src/layer/tile/CalcTileLayer.js
@@ -30,7 +30,10 @@ L.CalcTileLayer = L.TileLayer.extend({
 		var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest());
 		var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast());
 		var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight);
-		var toRequest = [];
+
+                var tilePositionsX = "";
+		var tilePositionsY = "";
+		var needsNewTiles = false;
 
 		for (var key in this._tiles) {
 			var coords = this._tiles[key].coords;
@@ -45,15 +48,14 @@ L.CalcTileLayer = L.TileLayer.extend({
 					this._tiles[key]._invalidCount = 1;
 				}
 				if (visibleArea.intersects(bounds)) {
-					var msg = 'tile ' +
-							'part=' + coords.part + ' ' +
-							'width=' + this._tileSize + ' ' +
-							'height=' + this._tileSize + ' ' +
-							'tileposx=' + tileTopLeft.x + ' '    +
-							'tileposy=' + tileTopLeft.y + ' ' +
-							'tilewidth=' + this._tileWidthTwips + ' ' +
-							'tileheight=' + this._tileHeightTwips;
-					toRequest.push({msg: msg, key: key, coords: coords});
+					if (tilePositionsX !== "")
+						tilePositionsX += ',';
+					tilePositionsX += tileTopLeft.x;
+
+					if (tilePositionsY !== "")
+						tilePositionsY += ',';
+					tilePositionsY += tileTopLeft.y;
+					needsNewTiles = true;
 				}
 				else {
 					// tile outside of the visible area, just remove it
@@ -63,12 +65,18 @@ L.CalcTileLayer = L.TileLayer.extend({
 			}
 		}
 
-		// Sort tiles so that we request those closer to the cursor first
-		var cursorPos = this._map.project(this._visibleCursor.getNorthWest());
-		cursorPos = cursorPos.divideBy(this._tileSize);
-		toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);});
-		for (var i = 0; i < toRequest.length; i++) {
-			L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key);
+		if (needsNewTiles)
+		{
+			var message = 'tilecombine ' +
+				'part=' + command.part + ' ' +
+				'width=' + this._tileSize + ' ' +
+				'height=' + this._tileSize + ' ' +
+				'tileposx=' + tilePositionsX + ' ' +
+				'tileposy=' + tilePositionsY + ' ' +
+				'tilewidth=' + this._tileWidthTwips + ' ' +
+				'tileheight=' + this._tileHeightTwips;
+
+			L.Socket.sendMessage(message, "");
 		}
 
 		for (key in this._tileCache) {
diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js
index 0868c43..ec7b27c 100644
--- a/loleaflet/src/layer/tile/ImpressTileLayer.js
+++ b/loleaflet/src/layer/tile/ImpressTileLayer.js
@@ -21,7 +21,10 @@ L.ImpressTileLayer = L.TileLayer.extend({
 		var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest());
 		var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast());
 		var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight);
-		var toRequest = [];
+
+		var tilePositionsX = "";
+		var tilePositionsY = "";
+		var needsNewTiles = false;
 
 		for (var key in this._tiles) {
 			var coords = this._tiles[key].coords;
@@ -36,15 +39,14 @@ L.ImpressTileLayer = L.TileLayer.extend({
 					this._tiles[key]._invalidCount = 1;
 				}
 				if (visibleArea.intersects(bounds)) {
-					var msg = 'tile ' +
-							'part=' + coords.part + ' ' +
-							'width=' + this._tileSize + ' ' +
-							'height=' + this._tileSize + ' ' +
-							'tileposx=' + tileTopLeft.x + ' '    +
-							'tileposy=' + tileTopLeft.y + ' ' +
-							'tilewidth=' + this._tileWidthTwips + ' ' +
-							'tileheight=' + this._tileHeightTwips;
-					toRequest.push({msg: msg, key: key, coords: coords});
+					if (tilePositionsX !== "")
+						tilePositionsX += ',';
+					tilePositionsX += tileTopLeft.x;
+
+					if (tilePositionsY !== "")
+						tilePositionsY += ',';
+					tilePositionsY += tileTopLeft.y;
+					needsNewTiles = true;
 				}
 				else {
 					// tile outside of the visible area, just remove it
@@ -54,12 +56,18 @@ L.ImpressTileLayer = L.TileLayer.extend({
 			}
 		}
 
-		// Sort tiles so that we request those closer to the cursor first
-		var cursorPos = this._map.project(this._visibleCursor.getNorthWest());
-		cursorPos = cursorPos.divideBy(this._tileSize);
-		toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);});
-		for (var i = 0; i < toRequest.length; i++) {
-			L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key);
+		if (needsNewTiles)
+		{
+			var message = 'tilecombine ' +
+				'part=' + command.part + ' ' +
+				'width=' + this._tileSize + ' ' +
+				'height=' + this._tileSize + ' ' +
+				'tileposx=' + tilePositionsX + ' ' +
+				'tileposy=' + tilePositionsY + ' ' +
+				'tilewidth=' + this._tileWidthTwips + ' ' +
+				'tileheight=' + this._tileHeightTwips;
+
+			L.Socket.sendMessage(message, "");
 		}
 
 		for (key in this._tileCache) {
diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js
index dd04890..71aeb4a 100644
--- a/loleaflet/src/layer/tile/WriterTileLayer.js
+++ b/loleaflet/src/layer/tile/WriterTileLayer.js
@@ -22,7 +22,10 @@ L.WriterTileLayer = L.TileLayer.extend({
 		var visibleTopLeft = this._latLngToTwips(this._map.getBounds().getNorthWest());
 		var visibleBottomRight = this._latLngToTwips(this._map.getBounds().getSouthEast());
 		var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight);
-		var toRequest = [];
+
+		var tilePositionsX = "";
+		var tilePositionsY = "";
+		var needsNewTiles = false;
 
 		for (var key in this._tiles) {
 			var coords = this._tiles[key].coords;
@@ -37,15 +40,14 @@ L.WriterTileLayer = L.TileLayer.extend({
 					this._tiles[key]._invalidCount = 1;
 				}
 				if (visibleArea.intersects(bounds)) {
-					var msg = 'tile ' +
-							'part=' + coords.part + ' ' +
-							'width=' + this._tileSize + ' ' +
-							'height=' + this._tileSize + ' ' +
-							'tileposx=' + tileTopLeft.x + ' '    +
-							'tileposy=' + tileTopLeft.y + ' ' +
-							'tilewidth=' + this._tileWidthTwips + ' ' +
-							'tileheight=' + this._tileHeightTwips;
-					toRequest.push({msg: msg, key: key, coords: coords});
+					if (tilePositionsX !== "")
+						tilePositionsX += ',';
+					tilePositionsX += tileTopLeft.x;
+
+					if (tilePositionsY !== "")
+						tilePositionsY += ',';
+					tilePositionsY += tileTopLeft.y;
+					needsNewTiles = true;
 				}
 				else {
 					// tile outside of the visible area, just remove it
@@ -55,12 +57,18 @@ L.WriterTileLayer = L.TileLayer.extend({
 			}
 		}
 
-		// Sort tiles so that we request those closer to the cursor first
-		var cursorPos = this._map.project(this._visibleCursor.getNorthWest());
-		cursorPos = cursorPos.divideBy(this._tileSize);
-		toRequest.sort(function(x, y) {return x.coords.distanceTo(cursorPos) - y.coords.distanceTo(cursorPos);});
-		for (var i = 0; i < toRequest.length; i++) {
-			L.Socket.sendMessage(toRequest[i].msg, toRequest[i].key);
+		if (needsNewTiles)
+		{
+			var message = 'tilecombine ' +
+				'part=' + command.part + ' ' +
+				'width=' + this._tileSize + ' ' +
+				'height=' + this._tileSize + ' ' +
+				'tileposx=' + tilePositionsX + ' ' +
+				'tileposy=' + tilePositionsY + ' ' +
+				'tilewidth=' + this._tileWidthTwips + ' ' +
+				'tileheight=' + this._tileHeightTwips;
+
+			L.Socket.sendMessage(message, "");
 		}
 
 		for (key in this._tileCache) {
commit 251f431138bfde1a29b78b11421cc16d68e89f30
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Tue Jan 12 12:20:09 2016 +0100

    Add "tilecombine" command to render more tiles in one call
    
    When invalidating we need to rerender more tiles at once.
    This change optimizes that with a new command which rerenders a
    larger area once and then separates the rendered buffer into more
    tiles. This generally decreases the invalidation time by 2-4 times
    and in some cases (when invalidating images in document) up to 9
    times.

diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 3216eb8..85e6f0e 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -57,6 +57,7 @@
 #include "LOOLWSD.hpp"
 #include "TileCache.hpp"
 #include "Util.hpp"
+#include "Rectangle.hpp"
 
 using namespace LOOLProtocol;
 
@@ -392,6 +393,7 @@ bool MasterProcessSession::handleInput(const char *buffer, int length)
              tokens[0] != "setpage" &&
              tokens[0] != "status" &&
              tokens[0] != "tile" &&
+             tokens[0] != "tilecombine" &&
              tokens[0] != "uno")
     {
         sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown");
@@ -431,6 +433,10 @@ bool MasterProcessSession::handleInput(const char *buffer, int length)
     {
         sendTile(buffer, length, tokens);
     }
+    else if (tokens[0] == "tilecombine")
+    {
+        sendCombinedTiles(buffer, length, tokens);
+    }
     else
     {
         // All other commands are such that they always require a
@@ -664,6 +670,14 @@ void MasterProcessSession::sendTile(const char *buffer, int length, StringTokeni
     forwardToPeer(buffer, length);
 }
 
+void MasterProcessSession::sendCombinedTiles(const char *buffer, int length, StringTokenizer& /*tokens*/)
+{
+    // This is for invalidation - we should not have cached tiles
+    if (_peer.expired())
+        dispatchChild();
+    forwardToPeer(buffer, length);
+}
+
 void MasterProcessSession::dispatchChild()
 {
     // Copy document into jail using the fixed name
@@ -836,6 +850,10 @@ bool ChildProcessSession::handleInput(const char *buffer, int length)
     {
         sendTile(buffer, length, tokens);
     }
+    else if (tokens[0] == "tilecombine")
+    {
+        sendCombinedTiles(buffer, length, tokens);
+    }
     else
     {
         // All other commands are such that they always require a LibreOfficeKitDocument session,
@@ -1230,6 +1248,133 @@ void ChildProcessSession::sendTile(const char* /*buffer*/, int /*length*/, Strin
     sendBinaryFrame(output.data(), output.size());
 }
 
+void ChildProcessSession::sendCombinedTiles(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
+{
+    int part, pixelWidth, pixelHeight, tileWidth, tileHeight;
+    std::string tilePositionsX, tilePositionsY;
+
+    if (tokens.count() < 8 ||
+        !getTokenInteger(tokens[1], "part", part) ||
+        !getTokenInteger(tokens[2], "width", pixelWidth) ||
+        !getTokenInteger(tokens[3], "height", pixelHeight) ||
+        !getTokenString (tokens[4], "tileposx", tilePositionsX) ||
+        !getTokenString (tokens[5], "tileposy", tilePositionsY) ||
+        !getTokenInteger(tokens[6], "tilewidth", tileWidth) ||
+        !getTokenInteger(tokens[7], "tileheight", tileHeight))
+    {
+        sendTextFrame("error: cmd=tilecombine kind=syntax");
+        return;
+    }
+
+    if (part < 0 || pixelWidth <= 0 || pixelHeight <= 0
+       || tileWidth <= 0 || tileHeight <= 0
+       || tilePositionsX.empty() || tilePositionsY.empty())
+    {
+        sendTextFrame("error: cmd=tilecombine kind=invalid");
+        return;
+    }
+
+    Util::Rectangle renderArea;
+
+    StringTokenizer positionXtokens(tilePositionsX, ",", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+    StringTokenizer positionYtokens(tilePositionsY, ",", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+    size_t numberOfPositions = positionYtokens.count();
+
+    // check that number of positions for X and Y is the same
+    if (numberOfPositions != positionYtokens.count())
+    {
+        sendTextFrame("error: cmd=tilecombine kind=invalid");
+        return;
+    }
+
+    std::vector<Util::Rectangle> tiles;
+    tiles.reserve(numberOfPositions);
+
+    for (size_t i = 0; i < numberOfPositions; i++)
+    {
+        int x, y;
+
+        if (!stringToInteger(positionXtokens[i], x))
+        {
+            sendTextFrame("error: cmd=tilecombine kind=syntax");
+            return;
+        }
+        if (!stringToInteger(positionYtokens[i], y))
+        {
+            sendTextFrame("error: cmd=tilecombine kind=syntax");
+            return;
+        }
+
+        Util::Rectangle rectangle(x, y, tileWidth, tileHeight);
+
+        if (tiles.empty())
+        {
+            renderArea = rectangle;
+        }
+        else
+        {
+            renderArea.extend(rectangle);
+        }
+
+        tiles.push_back(rectangle);
+    }
+
+    if (_docType != "text" && part != _loKitDocument->pClass->getPart(_loKitDocument))
+    {
+        _loKitDocument->pClass->setPart(_loKitDocument, part);
+    }
+
+    LibreOfficeKitTileMode mode = static_cast<LibreOfficeKitTileMode>(_loKitDocument->pClass->getTileMode(_loKitDocument));
+
+    int tilesByX = renderArea.getWidth() / tileWidth;
+    int tilesByY = renderArea.getHeight() / tileHeight;
+
+    int pixmapWidth = tilesByX * pixelWidth;
+    int pixmapHeight = tilesByY * pixelHeight;
+
+    const size_t pixmapSize = 4 * pixmapWidth * pixmapHeight;
+
+    std::vector<unsigned char> pixmap(pixmapSize, 0);
+
+    Poco::Timestamp timestamp;
+    _loKitDocument->pClass->paintTile(_loKitDocument, pixmap.data(), pixmapWidth, pixmapHeight,
+                                      renderArea.getLeft(), renderArea.getTop(),
+                                      renderArea.getWidth(), renderArea.getHeight());
+
+    std::cout << Util::logPrefix() << "paintTile (Multiple) called, tile at [" << renderArea.getLeft() << ", " << renderArea.getTop() << "]"
+                << " (" << renderArea.getWidth() << ", " << renderArea.getHeight() << ") rendered in "
+                << double(timestamp.elapsed())/1000 <<  "ms" << std::endl;
+
+    for (Util::Rectangle& tileRect : tiles)
+    {
+        std::string response = "tile: part=" + std::to_string(part) +
+                               " width=" + std::to_string(pixelWidth) +
+                               " height=" + std::to_string(pixelHeight) +
+                               " tileposx=" + std::to_string(tileRect.getLeft()) +
+                               " tileposy=" + std::to_string(tileRect.getTop()) +
+                               " tilewidth=" + std::to_string(tileWidth) +
+                               " tileheight=" + std::to_string(tileHeight) + "\n";
+
+        std::vector<char> output;
+        output.reserve(pixelWidth * pixelHeight * 4 + response.size());
+        output.resize(response.size());
+
+        std::copy(response.begin(), response.end(), output.begin());
+
+        int positionX = (tileRect.getLeft() - renderArea.getLeft()) / tileWidth;
+        int positionY = (tileRect.getTop() - renderArea.getTop())  / tileHeight;
+
+        if (!Util::encodeSubBufferToPNG(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight, pixelWidth, pixelHeight, pixmapWidth, pixmapHeight, output, mode))
+        {
+            sendTextFrame("error: cmd=tile kind=failure");
+            return;
+        }
+
+        sendBinaryFrame(output.data(), output.size());
+    }
+}
+
 bool ChildProcessSession::clientZoom(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
 {
     int tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight;
diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp
index 5f81fed..9413544 100644
--- a/loolwsd/LOOLSession.hpp
+++ b/loolwsd/LOOLSession.hpp
@@ -71,6 +71,8 @@ protected:
 
     virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens) = 0;
 
+    virtual void sendCombinedTiles(const char *buffer, int length, Poco::StringTokenizer& tokens) = 0;
+
     virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens) = 0;
 
     // Fields common to sessions in master and jailed processes:
@@ -143,6 +145,8 @@ public:
 
     virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens);
 
+    virtual void sendCombinedTiles(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
+
     virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens);
 
     void dispatchChild();
@@ -197,6 +201,8 @@ public:
 
     virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens);
 
+    virtual void sendCombinedTiles(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
+
     virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens);
 
     bool clientZoom(const char *buffer, int length, Poco::StringTokenizer& tokens);
commit 5c25dd61cb6a27da47c6e3776024cd7d622082b8
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Tue Jan 12 12:11:49 2016 +0100

    add simple Rectangle struct implementation

diff --git a/loolwsd/Rectangle.hpp b/loolwsd/Rectangle.hpp
new file mode 100644
index 0000000..bac02b4
--- /dev/null
+++ b/loolwsd/Rectangle.hpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_RECTANGLE_HPP
+#define INCLUDED_RECTANGLE_HPP
+
+#include <limits>
+
+namespace Util
+{
+
+struct Rectangle
+{
+    int _x1;
+    int _y1;
+    int _x2;
+    int _y2;
+
+    Rectangle()
+        : _x1(std::numeric_limits<int>::max())
+        , _y1(std::numeric_limits<int>::max())
+        , _x2(std::numeric_limits<int>::min())
+        , _y2(std::numeric_limits<int>::min())
+    {}
+
+    Rectangle(int x, int y, int width, int height)
+        : _x1(x)
+        , _y1(y)
+        , _x2(x + width)
+        , _y2(y + height)
+    {}
+
+    void extend(Rectangle& rectangle)
+    {
+        if (rectangle._x1 < _x1)
+            _x1 = rectangle._x1;
+        if (rectangle._x2 > _x2)
+            _x2 = rectangle._x2;
+        if (rectangle._y1 < _y1)
+            _y1 = rectangle._y1;
+        if (rectangle._y2 > _y2)
+            _y2 = rectangle._y2;
+    }
+
+    int getLeft()
+    {
+        return _x1;
+    }
+
+    int getTop()
+    {
+        return _y1;
+    }
+
+    int getWidth()
+    {
+        return _x2 - _x1;
+    }
+
+    int getHeight()
+    {
+        return _y2 - _y1;
+    }
+
+    bool isValid()
+    {
+        return _x1 <= _x2 && _y1 <= _y2;
+    }
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit f7acce6f20bf362b741542d66e2879c1638bab7c
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Tue Jan 12 12:07:13 2016 +0100

    add function to convert string to integer

diff --git a/loolwsd/LOOLProtocol.cpp b/loolwsd/LOOLProtocol.cpp
index c831abc..3871889 100644
--- a/loolwsd/LOOLProtocol.cpp
+++ b/loolwsd/LOOLProtocol.cpp
@@ -23,6 +23,20 @@ using Poco::StringTokenizer;
 
 namespace LOOLProtocol
 {
+    bool stringToInteger(const std::string& input, int& value)
+    {
+        try
+        {
+            value = std::stoi(input);
+        }
+        catch (std::invalid_argument&)
+        {
+            return false;
+        }
+
+        return true;
+    }
+
     bool getTokenInteger(const std::string& token, const std::string& name, int& value)
     {
         size_t nextIdx;
diff --git a/loolwsd/LOOLProtocol.hpp b/loolwsd/LOOLProtocol.hpp
index 42e82df..b5ad6fc 100644
--- a/loolwsd/LOOLProtocol.hpp
+++ b/loolwsd/LOOLProtocol.hpp
@@ -62,6 +62,7 @@ namespace LOOLProtocol
         TILE,
     };
 
+    bool stringToInteger(const std::string& input, int& value);
     bool getTokenInteger(const std::string& token, const std::string& name, int& value);
     bool getTokenString(const std::string& token, const std::string& name, std::string& value);
     bool getTokenKeyword(const std::string& token, const std::string& name, const std::map<std::string, int>& map, int& value);
commit 10937bf29806f6a7ede245748e0048e00ca4b3ab
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Tue Jan 12 12:00:42 2016 +0100

    encode PNG from buffer at arbitrary buffer position
    
    This commit add 2 methods to encode a buffer to PNG: the "old"
    method which encodes the whole buffer to a PNG, and a new method
    to encode a part of a buffer (sub image) to PNG. The first method
    is only added for convenience.

diff --git a/loolwsd/LOKitClient.cpp b/loolwsd/LOKitClient.cpp
index afbc62d..931ea11 100644
--- a/loolwsd/LOKitClient.cpp
+++ b/loolwsd/LOKitClient.cpp
@@ -167,7 +167,8 @@ protected:
 
                 std::vector<char> png;
                 LibreOfficeKitTileMode mode = static_cast<LibreOfficeKitTileMode>(loKitDocument->pClass->getTileMode(loKitDocument));
-                Util::encodePNGAndAppendToBuffer(pixmap.data(), canvasWidth, canvasHeight, png, mode);
+
+                Util::encodeBufferToPNG(pixmap.data(), canvasWidth, canvasHeight, png, mode);
 
                 TemporaryFile pngFile;
                 std::ofstream pngStream(pngFile.path(), std::ios::binary);
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index f5299aa..3216eb8 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -1127,7 +1127,7 @@ void ChildProcessSession::sendFontRendering(const char* /*buffer*/, int /*length
     std::cout << Util::logPrefix() << "renderFont called, font[" << font << "] rendered in " << double(timestamp.elapsed())/1000 <<  "ms" << std::endl;
 
     if (pixmap != nullptr) {
-        if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, LOK_TILEMODE_RGBA))
+        if (!Util::encodeBufferToPNG(pixmap, width, height, output, LOK_TILEMODE_RGBA))
         {
             sendTextFrame("error: cmd=renderfont kind=failure");
             delete[] pixmap;
@@ -1219,7 +1219,7 @@ void ChildProcessSession::sendTile(const char* /*buffer*/, int /*length*/, Strin
     std::cout << Util::logPrefix() << "paintTile called, tile at [" << tilePosX << ", " << tilePosY << "] rendered in " << double(timestamp.elapsed())/1000 <<  "ms" << std::endl;
 
     LibreOfficeKitTileMode mode = static_cast<LibreOfficeKitTileMode>(_loKitDocument->pClass->getTileMode(_loKitDocument));
-    if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, mode))
+    if (!Util::encodeBufferToPNG(pixmap, width, height, output, mode))
     {
         sendTextFrame("error: cmd=tile kind=failure");
         return;
diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp
index 232e425..faf7518 100644
--- a/loolwsd/Util.cpp
+++ b/loolwsd/Util.cpp
@@ -82,8 +82,18 @@ namespace Util
         return false;
     }
 
-    bool encodePNGAndAppendToBuffer(unsigned char *pixmap, int width, int height, std::vector<char>& output, LibreOfficeKitTileMode mode)
+    bool encodeBufferToPNG(unsigned char *pixmap, int width, int height, std::vector<char>& output, LibreOfficeKitTileMode mode)
     {
+       
+        return encodeSubBufferToPNG(pixmap, 0, 0, width, height, width, height, output, mode);
+    }
+
+    bool encodeSubBufferToPNG(unsigned char *pixmap, int startX, int startY, int width, int height,
+                              int bufferWidth, int bufferHeight, std::vector<char>& output, LibreOfficeKitTileMode mode)
+    {
+        if (bufferWidth < width || bufferHeight < height)
+            return false;
+
         png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
         png_infop info_ptr = png_create_info_struct(png_ptr);
@@ -101,19 +111,16 @@ namespace Util
 
         png_write_info(png_ptr, info_ptr);
 
-        switch (mode)
+        if (mode == LOK_TILEMODE_BGRA)
         {
-        case LOK_TILEMODE_RGBA:
-            break;
-        case LOK_TILEMODE_BGRA:
             png_set_write_user_transform_fn (png_ptr, unpremultiply_data);
-            break;
-        default:
-            assert(false);
         }
 
         for (int y = 0; y < height; ++y)
-            png_write_row(png_ptr, pixmap + y * width * 4);
+        {
+            size_t position = ((startY + y) * bufferWidth * 4) + (startX * 4);
+            png_write_row(png_ptr, pixmap + position);
+        }
 
         png_write_end(png_ptr, info_ptr);
 
diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp
index 02a21d6..e4f3d55 100644
--- a/loolwsd/Util.hpp
+++ b/loolwsd/Util.hpp
@@ -25,7 +25,11 @@ namespace Util
 
     // Sadly, older libpng headers don't use const for the pixmap pointer parameter to
     // png_write_row(), so can't use const here for pixmap.
-    bool encodePNGAndAppendToBuffer(unsigned char *pixmap, int width, int height, std::vector<char>& output, LibreOfficeKitTileMode mode);
+    bool encodeBufferToPNG(unsigned char* pixmap, int width, int height,
+                           std::vector<char>& output, LibreOfficeKitTileMode mode);
+    bool encodeSubBufferToPNG(unsigned char* pixmap, int startX, int startY, int width, int height,
+                              int bufferWidth, int bufferHeight,
+                              std::vector<char>& output, LibreOfficeKitTileMode mode);
 
     // Call WebSocket::shutdown() ignoring Poco::IOException
     void shutdownWebSocket(Poco::Net::WebSocket& ws);


More information about the Libreoffice-commits mailing list