loleaflet/src/control/Parts.js        |    2 
 loleaflet/src/layer/tile/GridLayer.js |  133 ++++++++++++++++++++++++++++++++++
 loolwsd/MasterProcessSession.cpp      |  113 ++++++++++++++++++++++++++++
 3 files changed, 244 insertions(+), 4 deletions(-)

New commits:
commit 424a5aee42d0ad8d8b14c22134b971606220a632
Author: Tomaž Vajngerl <tomaz.vajng...@collabora.com>
Date:   Wed Jan 20 23:09:41 2016 +0100

    loleaflet: specific tile update function when changing parts
    
    _updateOnChangePart includes duplicated and changed _update and
    _addTile functions. Deduplication will be done later..

diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js
index 8e2d5c3..189f2d5 100644
--- a/loleaflet/src/control/Parts.js
+++ b/loleaflet/src/control/Parts.js
@@ -32,7 +32,7 @@ L.Map.include({
                });
                this._socket.sendMessage('setclientpart part=' + 
docLayer._selectedPart);
                docLayer._clearSelections();
-               docLayer._update();
+               docLayer._updateOnChangePart();
                docLayer._pruneTiles();
                docLayer._prevSelectedPartNeedsUpdate = true;
                if (docLayer._invalidatePreview) {
diff --git a/loleaflet/src/layer/tile/GridLayer.js 
b/loleaflet/src/layer/tile/GridLayer.js
index 8e3be8f..60ed36a 100644
--- a/loleaflet/src/layer/tile/GridLayer.js
+++ b/loleaflet/src/layer/tile/GridLayer.js
@@ -558,6 +558,139 @@ L.GridLayer = L.Layer.extend({
                }
        },
 
+       _updateOnChangePart: function () {
+               var map = this._map;
+               if (!map || this._documentInfo === '') {
+                       return;
+               }
+
+               var center = map.getCenter();
+               var zoom = Math.round(map.getZoom());
+
+               var pixelBounds = map.getPixelBounds(center, zoom),
+                       tileRange = this._pxBoundsToTileRange(pixelBounds),
+                       queue = [];
+
+               for (var key in this._tiles) {
+                       if (this._keyToTileCoords(key).z !== zoom ||
+                                       this._keyToTileCoords(key).part !== 
this._selectedPart) {
+                               this._tiles[key].current = false;
+                       }
+               }
+
+               // if there is no exiting tile in the current view
+               var newView = true;
+               // create a queue of coordinates to load tiles from
+               for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
+                       for (var i = tileRange.min.x; i <= tileRange.max.x; 
i++) {
+                               var coords = new L.Point(i, j);
+                               coords.z = zoom;
+                               coords.part = this._selectedPart;
+
+                               if (!this._isValidTile(coords)) { continue; }
+
+                               key = this._tileCoordsToKey(coords);
+                               var tile = this._tiles[key];
+                               if (tile) {
+                                       tile.current = true;
+                                       newView = false;
+                               } else {
+                                       queue.push(coords);
+                               }
+                       }
+               }
+
+               if (queue.length !== 0) {
+                       if (newView) {
+                               // we know that a new set of tiles that cover 
the whole view has been requested
+                               // so we're able to cancel the previous 
requests that are being processed
+                               this._map._socket.sendMessage('canceltiles');
+                               for (key in this._tiles) {
+                                       var tile = this._tiles[key];
+                                       if (!tile.loaded) {
+                                               L.DomUtil.remove(tile.el);
+                                               delete this._tiles[key];
+                                       }
+                               }
+                               this._emptyTilesCount = 0;
+                       }
+
+                       // if its the first batch of tiles to load
+                       if (this._noTilesToLoad()) {
+                               this.fire('loading');
+                       }
+
+                       // create DOM fragment to append tiles in one batch
+                       var fragment = document.createDocumentFragment();
+                       var tilePositionsX = '';
+                       var tilePositionsY = '';
+
+                       for (i = 0; i < queue.length; i++) {
+                               var coords = queue[i];
+                               var tilePos = this._getTilePos(coords),
+                               key = this._tileCoordsToKey(coords);
+
+                               if (coords.part === this._selectedPart) {
+                                       var tile = 
this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, 
coords));
+
+                                       this._initTile(tile);
+
+                                       // if createTile is defined with a 
second argument ("done" callback),
+                                       // we know that tile is async and will 
be ready later; otherwise
+                                       if (this.createTile.length < 2) {
+                                               // mark tile as ready, but 
delay one frame for opacity animation to happen
+                                               
setTimeout(L.bind(this._tileReady, this, coords, null, tile), 0);
+                                       }
+
+                                       // we prefer top/left over translate3d 
so that we don't create a HW-accelerated layer from each tile
+                                       // which is slow, and it also fixes 
gaps between tiles in Safari
+                                       L.DomUtil.setPosition(tile, tilePos, 
true);
+
+                                       // save tile in cache
+                                       this._tiles[key] = {
+                                               el: tile,
+                                               coords: coords,
+                                               current: true
+                                       };
+
+                                       fragment.appendChild(tile);
+
+                                       this.fire('tileloadstart', {
+                                               tile: tile,
+                                               coords: coords
+                                       });
+                               }
+                               if (!this._tileCache[key]) {
+                                       var twips = this._coordsToTwips(coords);
+                                       if (tilePositionsX !== '')
+                                               tilePositionsX += ',';
+                                       tilePositionsX += twips.x;
+                                       if (tilePositionsY !== '')
+                                               tilePositionsY += ',';
+                                       tilePositionsY += twips.y;
+                               }
+                               else {
+                                       tile.src = this._tileCache[key];
+                               }
+                       }
+
+                       if (tilePositionsX !== '' && tilePositionsY !== '') {
+                               var message = 'tilecombine ' +
+                                       'part=' + this._selectedPart + ' ' +
+                                       'width=' + this._tileSize + ' ' +
+                                       'height=' + this._tileSize + ' ' +
+                                       'tileposx=' + tilePositionsX + ' ' +
+                                       'tileposy=' + tilePositionsY + ' ' +
+                                       'tilewidth=' + this._tileWidthTwips + ' 
' +
+                                       'tileheight=' + this._tileHeightTwips;
+
+                               this._map._socket.sendMessage(message, "");
+                       }
+
+                       this._level.el.appendChild(fragment);
+               }
+       },
+
        _isValidTile: function (coords) {
                if (coords.x < 0 || coords.y < 0) {
                        return false;
commit 21121e2f55e95310fe436ce51f86f9897924b09e
Author: Tomaž Vajngerl <tomaz.vajng...@collabora.com>
Date:   Wed Jan 20 23:04:41 2016 +0100

    Support returning cached tiles for "tilecombine"

diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp
index d3b3fd9..d41820d 100644
--- a/loolwsd/MasterProcessSession.cpp
+++ b/loolwsd/MasterProcessSession.cpp
@@ -20,6 +20,7 @@
 #include "LOOLWSD.hpp"
 #include "MasterProcessSession.hpp"
 #include "Util.hpp"
+#include "Rectangle.hpp"
 
 using namespace LOOLProtocol;
 
@@ -575,12 +576,118 @@ void MasterProcessSession::sendTile(const char *buffer, 
int length, StringTokeni
     forwardToPeer(buffer, length);
 }
 
-void MasterProcessSession::sendCombinedTiles(const char *buffer, int length, 
StringTokenizer& /*tokens*/)
+
+void MasterProcessSession::sendCombinedTiles(const char* /*buffer*/, int 
/*length*/, StringTokenizer& tokens)
 {
-    // This is for invalidation - we should not have cached tiles
+    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::string forwardTileX;
+    std::string forwardTileY;
+
+    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;
+        }
+
+        std::unique_ptr<std::fstream> cachedTile = 
_tileCache->lookupTile(part, pixelWidth, pixelHeight, x, y, tileWidth, 
tileHeight);
+
+        if (cachedTile && cachedTile->is_open())
+        {
+            std::string response = "tile: part=" + std::to_string(part) +
+                               " width=" + std::to_string(pixelWidth) +
+                               " height=" + std::to_string(pixelHeight) +
+                               " tileposx=" + std::to_string(x) +
+                               " tileposy=" + std::to_string(y) +
+                               " tilewidth=" + std::to_string(tileWidth) +
+                               " tileheight=" + std::to_string(tileHeight) + 
"\n";
+
+            std::vector<char> output;
+            output.reserve(4 * pixelWidth * pixelHeight);
+            output.resize(response.size());
+            std::memcpy(output.data(), response.data(), response.size());
+            cachedTile->seekg(0, std::ios_base::end);
+            size_t pos = output.size();
+            std::streamsize size = cachedTile->tellg();
+            output.resize(pos + size);
+            cachedTile->seekg(0, std::ios_base::beg);
+            cachedTile->read(output.data() + pos, size);
+            cachedTile->close();
+
+            sendBinaryFrame(output.data(), output.size());
+        }
+        else
+        {
+            if (!forwardTileX.empty())
+                forwardTileX += ",";
+            forwardTileX += std::to_string(x);
+
+            if (!forwardTileY.empty())
+                forwardTileY += ",";
+            forwardTileY += std::to_string(y);
+        }
+    }
+
+    if (forwardTileX.empty() && forwardTileY.empty())
+        return;
+
     if (_peer.expired())
         dispatchChild();
-    forwardToPeer(buffer, length);
+
+    std::string forward = "tilecombine part=" + std::to_string(part) +
+                               " width=" + std::to_string(pixelWidth) +
+                               " height=" + std::to_string(pixelHeight) +
+                               " tileposx=" + forwardTileX +
+                               " tileposy=" + forwardTileY +
+                               " tilewidth=" + std::to_string(tileWidth) +
+                               " tileheight=" + std::to_string(tileHeight);
+
+    forwardToPeer(forward.c_str(), forward.size());
 }
 
 void MasterProcessSession::dispatchChild()
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to