loleaflet/reference.html | 47 ++++++++ loleaflet/src/control/Toolbar.js | 8 + loleaflet/src/core/Socket.js | 5 loleaflet/src/layer/tile/TileLayer.js | 11 + loolwsd/LOOLSession.cpp | 93 ++++++++++++++++ loolwsd/LOOLSession.hpp | 6 + loolwsd/TileCache.cpp | 29 ++++ loolwsd/TileCache.hpp | 6 + loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h | 6 + loolwsd/protocol.txt | 5 10 files changed, 213 insertions(+), 3 deletions(-)
New commits: commit 5b1471aaf05d60164bc0016955cca1c1063c6427 Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Nov 30 12:59:37 2015 +0200 loolwsd: update the bundled headers diff --git a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h index 5189cca..a78c0aa 100644 --- a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h +++ b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h @@ -202,6 +202,12 @@ struct _LibreOfficeKitDocumentClass int (*getView) (LibreOfficeKitDocument* pThis); /// @see lok::Document::getViews(). int (*getViews) (LibreOfficeKitDocument* pThis); + + /// @see lok::Document::renderFont(). + unsigned char* (*renderFont) (LibreOfficeKitDocument* pThis, + const char* pFontName, + int* pFontWidth, + int* pFontHeight); #endif // LOK_USE_UNSTABLE_API }; commit e1b0e3dce92d66a258570c011ed171454119e4b3 Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Nov 30 12:58:41 2015 +0200 loolwsd: update renderFont png encoding diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index b0ef846..9708131 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -1117,17 +1117,16 @@ void ChildProcessSession::sendFontRendering(const char* /*buffer*/, int /*length pixmap = _loKitDocument->pClass->renderFont(_loKitDocument, decodedFont.c_str(), &width, &height); std::cout << Util::logPrefix() << "renderFont called, font[" << font << "] rendered in " << double(timestamp.elapsed())/1000 << "ms" << std::endl; - if (pixmap != NULL) { - if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output)) + if (pixmap != nullptr) { + if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output, LOK_TILEMODE_RGBA)) { sendTextFrame("error: cmd=renderfont kind=failure"); delete[] pixmap; return; } + delete[] pixmap; } - delete[] pixmap; - sendBinaryFrame(output.data(), output.size()); } commit b78fd2c68a635250db44c636220854a7b1bfdf68 Author: Mihai Varga <mihai.va...@collabora.com> Date: Fri Nov 27 16:16:27 2015 +0200 loleaflet: renderfont command handler diff --git a/loleaflet/reference.html b/loleaflet/reference.html index 9996b4c..9c80699 100644 --- a/loleaflet/reference.html +++ b/loleaflet/reference.html @@ -1636,6 +1636,12 @@ var map = L.map('map', { <td><code>undefined</code></td> <td>Applies a style from a style family.</td> </tr> + <tr> + <td><code><b>renderFont</b>( + <nobr><String><i>fontName</i>)</nobr> + <td><code>undefined</code></td> + <td>Renders the given font in the smallest rectangle it can fit in.</td> + </tr> </table> <h2 id="loleaflet-page">Page oriented</h2> @@ -1752,6 +1758,11 @@ var map = L.map('map', { <td>Fired when the url for the pdf export is ready.</td> </tr> <tr> + <td><code><b>renderfont</b></code></td> + <td><code><a href="#renderfont-event">RenderFontEvent</a></code></td> + <td>Fired when the font rendering is ready.</td> + </tr> + <tr> <td><code><b>search</b></code></td> <td><code><a href="#search-event">SearchEvent</a></code></td> <td>Fired when the search result is ready.</td> @@ -1976,6 +1987,26 @@ var map = L.map('map', { </tr> </table> +<h3 id="renderfont-event">RenderFontEvent</h3> + +<table data-id='events'> + <tr> + <th class="width100">property</th> + <th>type</th> + <th>description</th> + </tr> + <tr> + <td><code><b>font</b></code></td> + <td><code>String</code></td> + <td>Font name.</td> + </tr> + <tr> + <td><code><b>img</b></code></td> + <td><code>String</code></td> + <td>The image data URL.</td> + </tr> +</table> + <h3 id="search-event">SearchEvent</h3> <table data-id='events'> diff --git a/loleaflet/src/control/Toolbar.js b/loleaflet/src/control/Toolbar.js index 4ff4d17..4f05b43 100644 --- a/loleaflet/src/control/Toolbar.js +++ b/loleaflet/src/control/Toolbar.js @@ -104,5 +104,9 @@ L.Map.include({ } }; L.Socket.sendMessage('uno .uno:EnterString ' + JSON.stringify(command)); + }, + + renderFont: function (fontName) { + L.Socket.sendMessage('renderfont font=' + window.encodeURIComponent(fontName)); } }); diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index fe47c65..744ca6f 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -85,7 +85,7 @@ L.Socket = { textMsg = String.fromCharCode.apply(null, imgBytes.subarray(0, index)); } - if (!textMsg.startsWith('tile:')) { + if (!textMsg.startsWith('tile:') && !textMsg.startsWith('renderfont:')) { // log the tile msg separately as we need the tile coordinates L.Log.log(textMsg, L.INCOMING); if (imgBytes !== undefined) { @@ -222,6 +222,9 @@ L.Socket = { else if (tokens[i].substring(0, 5) === 'port=') { command.port = tokens[i].substring(5); } + else if (tokens[i].substring(0, 5) === 'font=') { + command.font = window.decodeURIComponent(tokens[i].substring(5)); + } } if (command.tileWidth && command.tileHeight && this._map._docLayer) { var scale = command.tileWidth / this._map._docLayer.options.tileWidthTwips; diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 94f32bb..1810ca3 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -257,6 +257,9 @@ L.TileLayer = L.GridLayer.extend({ else if (textMsg.startsWith('partpagerectangles:')) { this._onPartPageRectanglesMsg(textMsg); } + else if (textMsg.startsWith('renderfont:')) { + this._onRenderFontMsg(textMsg, img); + } else if (textMsg.startsWith('searchnotfound:')) { this._onSearchNotFoundMsg(textMsg); } @@ -445,6 +448,14 @@ L.TileLayer = L.GridLayer.extend({ this._onCurrentPageUpdate(); }, + _onRenderFontMsg: function (textMsg, img) { + var command = L.Socket.parseServerCmd(textMsg); + this._map.fire('renderfont', { + font: command.font, + img: img + }); + }, + _onSearchNotFoundMsg: function (textMsg) { var originalPhrase = textMsg.substring(16); this._map.fire('search', {originalPhrase: originalPhrase, count: 0}); commit 862cfe29a021f653b3292d9b78deb6be2345d78a Author: Mihai Varga <mihai.va...@collabora.com> Date: Fri Nov 27 16:13:25 2015 +0200 loolwsd: `renderfont` command handler Renders the requested font and sends it back to the client as a png image diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index 1bac381..b0ef846 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -295,6 +295,16 @@ bool MasterProcessSession::handleInput(const char *buffer, int length) assert(firstLine.size() == static_cast<std::string::size_type>(length)); peer->_tileCache->invalidateTiles(firstLine); } + else if (tokens[0] == "renderfont:") + { + std::string font; + if (tokens.count() < 2 || + !getTokenString(tokens[1], "font", font)) + assert(false); + + assert(firstLine.size() < static_cast<std::string::size_type>(length)); + peer->_tileCache->saveRendering(font, "font", buffer + firstLine.size() + 1, length - firstLine.size() - 1); + } } forwardToPeer(buffer, length); @@ -365,6 +375,7 @@ bool MasterProcessSession::handleInput(const char *buffer, int length) tokens[0] != "key" && tokens[0] != "mouse" && tokens[0] != "partpagerectangles" && + tokens[0] != "renderfont" && tokens[0] != "requestloksession" && tokens[0] != "resetselection" && tokens[0] != "saveas" && @@ -401,6 +412,10 @@ bool MasterProcessSession::handleInput(const char *buffer, int length) { return invalidateTiles(buffer, length, tokens); } + else if (tokens[0] == "renderfont") + { + sendFontRendering(buffer, length, tokens); + } else if (tokens[0] == "status") { return getStatus(buffer, length); @@ -548,6 +563,43 @@ std::string MasterProcessSession::getSaveAs() return _saveAsQueue.get(); } +void MasterProcessSession::sendFontRendering(const char *buffer, int length, StringTokenizer& tokens) +{ + std::string font; + + if (tokens.count() < 2 || + !getTokenString(tokens[1], "font", font)) + { + sendTextFrame("error: cmd=renderfont kind=syntax"); + return; + } + + std::string response = "renderfont: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n"; + + std::vector<char> output; + output.resize(response.size()); + std::memcpy(output.data(), response.data(), response.size()); + + std::unique_ptr<std::fstream> cachedRendering = _tileCache->lookupRendering(font, "font"); + if (cachedRendering && cachedRendering->is_open()) + { + cachedRendering->seekg(0, std::ios_base::end); + size_t pos = output.size(); + std::streamsize size = cachedRendering->tellg(); + output.resize(pos + size); + cachedRendering->seekg(0, std::ios_base::beg); + cachedRendering->read(output.data() + pos, size); + cachedRendering->close(); + + sendBinaryFrame(output.data(), output.size()); + return; + } + + if (_peer.expired()) + dispatchChild(); + forwardToPeer(buffer, length); +} + void MasterProcessSession::sendTile(const char *buffer, int length, StringTokenizer& tokens) { int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight; @@ -756,6 +808,10 @@ bool ChildProcessSession::handleInput(const char *buffer, int length) sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded"); return false; } + else if (tokens[0] == "renderfont") + { + sendFontRendering(buffer, length, tokens); + } else if (tokens[0] == "setclientpart") { return setClientPart(buffer, length, tokens); @@ -1037,6 +1093,44 @@ bool ChildProcessSession::loadDocument(const char *buffer, int length, StringTok return true; } +void ChildProcessSession::sendFontRendering(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) +{ + std::string font, decodedFont; + int width, height; + unsigned char *pixmap; + + if (tokens.count() < 2 || + !getTokenString(tokens[1], "font", font)) + { + sendTextFrame("error: cmd=renderfont kind=syntax"); + return; + } + + URI::decode(font, decodedFont); + std::string response = "renderfont: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n"; + + std::vector<char> output; + output.resize(response.size()); + std::memcpy(output.data(), response.data(), response.size()); + + Poco::Timestamp timestamp; + pixmap = _loKitDocument->pClass->renderFont(_loKitDocument, decodedFont.c_str(), &width, &height); + std::cout << Util::logPrefix() << "renderFont called, font[" << font << "] rendered in " << double(timestamp.elapsed())/1000 << "ms" << std::endl; + + if (pixmap != NULL) { + if (!Util::encodePNGAndAppendToBuffer(pixmap, width, height, output)) + { + sendTextFrame("error: cmd=renderfont kind=failure"); + delete[] pixmap; + return; + } + } + + delete[] pixmap; + + sendBinaryFrame(output.data(), output.size()); +} + bool ChildProcessSession::getStatus(const char* /*buffer*/, int /*length*/) { std::string status = "status: " + LOKitHelper::documentStatus(_loKitDocument); diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp index b807cab..3fe471a 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 sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens) = 0; + // Fields common to sessions in master and jailed processes: // In the master process, the websocket to the LOOL client or the jailed child process. In a @@ -137,6 +139,8 @@ public: virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens); + virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens); + void dispatchChild(); void forwardToPeer(const char *buffer, int length); @@ -190,6 +194,8 @@ public: virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens); + virtual void sendFontRendering(const char *buffer, int length, Poco::StringTokenizer& tokens); + bool clientZoom(const char *buffer, int length, Poco::StringTokenizer& tokens); bool downloadAs(const char *buffer, int length, Poco::StringTokenizer& tokens); bool getChildId(); diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt index 2f98f31..e9cce86 100644 --- a/loolwsd/protocol.txt +++ b/loolwsd/protocol.txt @@ -65,6 +65,11 @@ mouse type=<type> x=<x> y=<y> count=<count> <type> is 'buttondown', 'buttonup' or 'move', others are numbers. +renderfont font=<font> + + requests the rendering of the given font. + The font parameter is URL encoded + requestloksession requests the initialization of a LOK process in an attempt to predict the user's commit aa405d383691f72b748dbcea5390412497927c8f Author: Mihai Varga <mihai.va...@collabora.com> Date: Fri Nov 27 16:12:44 2015 +0200 loolwsd: cache rendered fonts diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp index cbd0278..d978bd2 100644 --- a/loolwsd/TileCache.cpp +++ b/loolwsd/TileCache.cpp @@ -188,6 +188,35 @@ void TileCache::saveTextFile(const std::string& text, std::string fileName) textStream.close(); } +void TileCache::saveRendering(const std::string& name, const std::string& dir, const char *data, size_t size) +{ + // can fonts be invalidated? + std::string dirName = cacheDirName(false) + "/" + dir; + + File(dirName).createDirectories(); + + std::string fileName = dirName + "/" + name; + + std::fstream outStream(fileName, std::ios::out); + outStream.write(data, size); + outStream.close(); +} + +std::unique_ptr<std::fstream> TileCache::lookupRendering(const std::string& name, const std::string& dir) +{ + std::string dirName = cacheDirName(false) + "/" + dir; + std::string fileName = dirName + "/" + name; + File directory(dirName); + + if (directory.exists() && directory.isDirectory() && File(fileName).exists()) + { + std::unique_ptr<std::fstream> result(new std::fstream(fileName, std::ios::in)); + return result; + } + + return nullptr; +} + void TileCache::invalidateTiles(int part, int x, int y, int width, int height) { // in the Editing cache, remove immediately diff --git a/loolwsd/TileCache.hpp b/loolwsd/TileCache.hpp index 8294784..316f85f 100644 --- a/loolwsd/TileCache.hpp +++ b/loolwsd/TileCache.hpp @@ -51,6 +51,12 @@ public: // The parameter is a message void saveTextFile(const std::string& text, std::string fileName); + // Saves a font / style / etc rendering + // The dir parameter should be the type of rendering, like "font", "style", etc + void saveRendering(const std::string& name, const std::string& dir, const char *data, size_t size); + + std::unique_ptr<std::fstream> lookupRendering(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); commit 46a726c22e68640bad8ea6dffc38fc8d0efd762e Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Nov 23 20:08:04 2015 +0200 loleaflet: tested and document .uno:SetHyperlink' diff --git a/loleaflet/reference.html b/loleaflet/reference.html index f8ad51f..9996b4c 100644 --- a/loleaflet/reference.html +++ b/loleaflet/reference.html @@ -8140,6 +8140,22 @@ var unoCommands = [ }, { + uno: '.uno:SetHyperlink', + parameter: { + 'Hyperlink.Text': { + type: 'string', + value: 'some text' + }, + 'Hyperlink.URL': { + type: 'string', + value: 'url' + } + }, + description: 'Creates a hyperlink. If Hyperlink.Text is not specified, the hyperlink will be set for the current ' + + 'selection. Hyperlink.URL can be a web URL or a bookmark from the document.' +}, + +{ uno: '.uno:Shadowed', parameter: null, description: 'Shadowed.' commit 4aafd56654e94ca660ec20d0b310e2c0a028537a Author: Mihai Varga <mihai.va...@collabora.com> Date: Mon Nov 23 19:57:27 2015 +0200 loleaflet: add a JSON parameter to sendUnoCommand() diff --git a/loleaflet/src/control/Toolbar.js b/loleaflet/src/control/Toolbar.js index 1644947..4ff4d17 100644 --- a/loleaflet/src/control/Toolbar.js +++ b/loleaflet/src/control/Toolbar.js @@ -77,9 +77,9 @@ L.Map.include({ } }, - sendUnoCommand: function (command) { + sendUnoCommand: function (command, json) { if (this._docLayer._permission === 'edit') { - L.Socket.sendMessage('uno ' + command); + L.Socket.sendMessage('uno ' + command + (json ? ' ' + JSON.stringify(json) : '')); } }, _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits