diff options
author | Tor Lillqvist <tml@collabora.com> | 2019-03-22 15:49:47 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2019-05-09 13:44:53 +0200 |
commit | fce8094f0848ee2b52998d0a61af20449aab9fc9 (patch) | |
tree | d0a98357703e1ec2e80bf413dd465cb296136d33 | |
parent | fb162606ea6e518a48bb04738235a5953d894d7f (diff) |
For iOS, generate the data: URLs for the PNG tiles already in the Online codecd-4.0.4-1
(What we cache is also the textual data: URLs even if we store them
using .png file names.)
This avoids the current back-and-forth-encoding: First we
base64-encode the complete binary "tile:" message (one text line
followed by a newline and the binary PNG) to pass to WebKit, then in
the JavaScript snippet passed to WebKit we decode the base64 and turn
it into an ArrayBuffer, and then we unpack the ArrayBuffer and encode
the PNG part to use as a data: URL.
-rw-r--r-- | common/Png.hpp | 18 | ||||
-rw-r--r-- | ios/Mobile/Document.mm | 92 | ||||
-rw-r--r-- | loleaflet/src/core/Socket.js | 12 |
3 files changed, 59 insertions, 63 deletions
diff --git a/common/Png.hpp b/common/Png.hpp index 84861fc48..0d40a37a0 100644 --- a/common/Png.hpp +++ b/common/Png.hpp @@ -52,6 +52,10 @@ #include <cassert> #include <chrono> +#ifdef IOS +#include <Foundation/Foundation.h> +#endif + #include "Log.hpp" #include "SpookyV2.h" @@ -134,6 +138,10 @@ bool encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY, png_set_compression_level(png_ptr, Z_BEST_SPEED); #endif +#ifdef IOS + auto initialSize = output.size(); +#endif + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_write_fn(png_ptr, &output, user_write_fn, user_flush_fn); @@ -169,6 +177,16 @@ bool encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY, png_destroy_write_struct(&png_ptr, &info_ptr); +#ifdef IOS + auto base64 = [[NSData dataWithBytesNoCopy:output.data() + initialSize length:(output.size() - initialSize) freeWhenDone:NO] base64EncodedDataWithOptions:0]; + + const char dataURLStart[] = "data:image/png;base64,"; + + output.resize(initialSize); + output.insert(output.end(), dataURLStart, dataURLStart + sizeof(dataURLStart)-1); + output.insert(output.end(), (char*)base64.bytes, (char*)base64.bytes + base64.length); +#endif + return true; } diff --git a/ios/Mobile/Document.mm b/ios/Mobile/Document.mm index 8550bc3e8..5473ef081 100644 --- a/ios/Mobile/Document.mm +++ b/ios/Mobile/Document.mm @@ -84,69 +84,39 @@ NSString *js; - // Check if the message is binary. We say that any message that isn't just a single line is - // "binary" even if that strictly speaking isn't the case; for instance the commandvalues: - // message has a long bunch of non-binary JSON on multiple lines. But _onMessage() in Socket.js - // handles it fine even if such a message, too, comes in as an ArrayBuffer. (Look for the - // "textMsg = String.fromCharCode.apply(null, imgBytes);".) - - const char *newline = (const char *)memchr(buffer, '\n', length); - if (newline != nullptr) { - // The data needs to be an ArrayBuffer - js = @"window.TheFakeWebSocket.onmessage({'data': Base64ToArrayBuffer('"; - js = [js stringByAppendingString: [[NSData dataWithBytes:buffer length:length] base64EncodedStringWithOptions:0]]; - js = [js stringByAppendingString:@"')});"]; - NSString *subjs = [js substringToIndex:std::min(100ul, js.length)]; - if (subjs.length < js.length) - subjs = [subjs stringByAppendingString:@"..."]; - - // LOG_TRC("Evaluating JavaScript: " << [subjs UTF8String]); - - dispatch_async(dispatch_get_main_queue(), ^{ - [self.viewController.webView evaluateJavaScript:js - completionHandler:^(id _Nullable obj, NSError * _Nullable error) - { - if (error) { - LOG_ERR("Error after " << [subjs UTF8String] << ": " << [error.localizedDescription UTF8String]); - } - } - ]; - }); - } else { - const unsigned char *ubufp = (const unsigned char *)buffer; - std::vector<char> data; - for (int i = 0; i < length; i++) { - if (ubufp[i] < ' ' || ubufp[i] == '\'' || ubufp[i] == '\\') { - data.push_back('\\'); - data.push_back('x'); - data.push_back("0123456789abcdef"[(ubufp[i] >> 4) & 0x0F]); - data.push_back("0123456789abcdef"[ubufp[i] & 0x0F]); - } else { - data.push_back(ubufp[i]); - } + const unsigned char *ubufp = (const unsigned char *)buffer; + std::vector<char> data; + for (int i = 0; i < length; i++) { + if (ubufp[i] < ' ' || ubufp[i] == '\'' || ubufp[i] == '\\') { + data.push_back('\\'); + data.push_back('x'); + data.push_back("0123456789abcdef"[(ubufp[i] >> 4) & 0x0F]); + data.push_back("0123456789abcdef"[ubufp[i] & 0x0F]); + } else { + data.push_back(ubufp[i]); } - data.push_back(0); - - js = @"window.TheFakeWebSocket.onmessage({'data': '"; - js = [js stringByAppendingString:[NSString stringWithUTF8String:data.data()]]; - js = [js stringByAppendingString:@"'});"]; - - // LOG_TRC("Evaluating JavaScript: " << [js UTF8String]); - - dispatch_async(dispatch_get_main_queue(), ^{ - [self.viewController.webView evaluateJavaScript:js - completionHandler:^(id _Nullable obj, NSError * _Nullable error) - { - if (error) { - LOG_ERR("Error after " << [js UTF8String] << ": " << [[error localizedDescription] UTF8String]); - NSString *jsException = error.userInfo[@"WKJavaScriptExceptionMessage"]; - if (jsException != nil) - LOG_ERR("JavaScript exception: " << [jsException UTF8String]); - } - } - ]; - }); } + data.push_back(0); + + js = @"window.TheFakeWebSocket.onmessage({'data': '"; + js = [js stringByAppendingString:[NSString stringWithUTF8String:data.data()]]; + js = [js stringByAppendingString:@"'});"]; + + // LOG_TRC("Evaluating JavaScript: " << [js UTF8String]); + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.viewController.webView evaluateJavaScript:js + completionHandler:^(id _Nullable obj, NSError * _Nullable error) + { + if (error) { + LOG_ERR("Error after " << [js UTF8String] << ": " << [[error localizedDescription] UTF8String]); + NSString *jsException = error.userInfo[@"WKJavaScriptExceptionMessage"]; + if (jsException != nil) + LOG_ERR("JavaScript exception: " << [jsException UTF8String]); + } + } + ]; + }); } @end diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index f7dc49dda..78d8a00d7 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -239,7 +239,7 @@ L.Socket = L.Class.extend({ }, _onMessage: function (e) { - var imgBytes, index, textMsg; + var imgBytes, index, textMsg, img; if (typeof (e.data) === 'string') { textMsg = e.data; @@ -749,13 +749,21 @@ L.Socket = L.Class.extend({ textMsg = decodeURIComponent(window.escape(textMsg)); } } + else if (window.ThisIsTheiOSApp) { + // In the iOS app, the native code sends us the PNG tile already as a data: URL after the newline + var newlineIndex = textMsg.indexOf('\n'); + if (newlineIndex > 0) { + img = textMsg.substring(newlineIndex+1); + textMsg = textMsg.substring(0, newlineIndex); + } + } else { var data = imgBytes.subarray(index + 1); if (data.length > 0 && data[0] == 68 /* D */) { console.log('Socket: got a delta !'); - var img = data; + img = data; } else { |