[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