ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj  |   28 
 ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift   |    4 
 ios/LibreOfficeLight/LibreOfficeLight/DocumentTiledView.swift    |   65 +
 ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift |  327 
+++++++++
 ios/LibreOfficeLight/LibreOfficeLight/LOKit/LOKitThread.swift    |  350 
----------
 ios/LibreOfficeLight/LibreOfficeLight/LOKit/RenderCache.swift    |   78 ++
 6 files changed, 489 insertions(+), 363 deletions(-)

New commits:
commit a468fef9ac977e812e83e3cce462b75d8d24c64d
Author: Jon Nermut <jon.ner...@gmail.com>
Date:   Sat Jan 20 17:08:43 2018 +1100

    iOS: keep track of doc part
    
    - implement swipe left/right and tap gestures for presentations
    - move some classes to their own files
    
    Change-Id: I3ddd3e17ec809c87097d5515f08038bbc969764f
    Reviewed-on: https://gerrit.libreoffice.org/48231
    Reviewed-by: jan iversen <j...@libreoffice.org>
    Tested-by: jan iversen <j...@libreoffice.org>

diff --git a/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj 
b/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj
index 48174b80e271..315d4d18151b 100644
--- a/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj
+++ b/ios/LibreOfficeLight/LibreOfficeLight.xcodeproj/project.pbxproj
@@ -33,6 +33,8 @@
                39B091CE1E5F0BB800682A59 /* unorc in Resources */ = {isa = 
PBXBuildFile; fileRef = 39B08B9C1E5F0BB600682A59 /* unorc */; };
                39E950531FC9842000D82C49 /* source in Resources */ = {isa = 
PBXBuildFile; fileRef = 39E950521FC9842000D82C49 /* source */; };
                39EF4E2F1FA500C9001914AC /* PropertiesController.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = 39EF4E2E1FA500C9001914AC /* 
PropertiesController.swift */; };
+               FC31D01E2012F65500E7F402 /* DocumentHolder.swift in Sources */ 
= {isa = PBXBuildFile; fileRef = FC31D01D2012F65500E7F402 /* 
DocumentHolder.swift */; };
+               FC31D0202012F6D300E7F402 /* RenderCache.swift in Sources */ = 
{isa = PBXBuildFile; fileRef = FC31D01F2012F6D300E7F402 /* RenderCache.swift 
*/; };
                FCAB1CB82009DB6900F1CC34 /* DocumentOverlaysView.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = FCAB1CB72009DB6900F1CC34 /* 
DocumentOverlaysView.swift */; };
                FCC2E3FA2004A01500CEB504 /* Document.swift in Sources */ = {isa 
= PBXBuildFile; fileRef = FCC2E3F62004A01400CEB504 /* Document.swift */; };
                FCC2E3FC2004A01500CEB504 /* LibreOfficeKitWrapper.swift in 
Sources */ = {isa = PBXBuildFile; fileRef = FCC2E3F82004A01400CEB504 /* 
LibreOfficeKitWrapper.swift */; };
@@ -77,6 +79,14 @@
                39E950521FC9842000D82C49 /* source */ = {isa = 
PBXFileReference; lastKnownFileType = folder; name = source; path = ../source; 
sourceTree = "<group>"; };
                39EE81531FA644E800B73AB8 /* Info.plist */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = 
Info.plist; sourceTree = "<group>"; };
                39EF4E2E1FA500C9001914AC /* PropertiesController.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = PropertiesController.swift; sourceTree = "<group>"; };
+               FC31D00E2012EE4A00E7F402 /* LibreOfficeKit.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
LibreOfficeKit.h; sourceTree = "<group>"; };
+               FC31D00F2012EE4A00E7F402 /* LibreOfficeKit.hxx */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path 
= LibreOfficeKit.hxx; sourceTree = "<group>"; };
+               FC31D0102012EE4A00E7F402 /* LibreOfficeKitEnums.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
LibreOfficeKitEnums.h; sourceTree = "<group>"; };
+               FC31D0112012EE4A00E7F402 /* LibreOfficeKitGtk.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
LibreOfficeKitGtk.h; sourceTree = "<group>"; };
+               FC31D0122012EE4A00E7F402 /* LibreOfficeKitInit.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
LibreOfficeKitInit.h; sourceTree = "<group>"; };
+               FC31D0132012EE4A00E7F402 /* LibreOfficeKitTypes.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
LibreOfficeKitTypes.h; sourceTree = "<group>"; };
+               FC31D01D2012F65500E7F402 /* DocumentHolder.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
DocumentHolder.swift; sourceTree = "<group>"; };
+               FC31D01F2012F6D300E7F402 /* RenderCache.swift */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
RenderCache.swift; sourceTree = "<group>"; };
                FCAB1CB72009DB6900F1CC34 /* DocumentOverlaysView.swift */ = 
{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = 
DocumentOverlaysView.swift; sourceTree = "<group>"; };
                FCC2E3F62004A01400CEB504 /* Document.swift */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path 
= Document.swift; sourceTree = "<group>"; };
                FCC2E3F82004A01400CEB504 /* LibreOfficeKitWrapper.swift */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.swift; path = LibreOfficeKitWrapper.swift; sourceTree = "<group>"; };
@@ -194,13 +204,29 @@
                        name = Resources;
                        sourceTree = SOURCE_ROOT;
                };
+               FC31D00D2012EE4A00E7F402 /* LibreOfficeKit */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FC31D00E2012EE4A00E7F402 /* LibreOfficeKit.h */,
+                               FC31D00F2012EE4A00E7F402 /* LibreOfficeKit.hxx 
*/,
+                               FC31D0102012EE4A00E7F402 /* 
LibreOfficeKitEnums.h */,
+                               FC31D0112012EE4A00E7F402 /* LibreOfficeKitGtk.h 
*/,
+                               FC31D0122012EE4A00E7F402 /* 
LibreOfficeKitInit.h */,
+                               FC31D0132012EE4A00E7F402 /* 
LibreOfficeKitTypes.h */,
+                       );
+                       name = LibreOfficeKit;
+                       path = ../../include/LibreOfficeKit;
+                       sourceTree = "<group>";
+               };
                FCC2E3F52004A01400CEB504 /* LOKit */ = {
                        isa = PBXGroup;
                        children = (
                                FCC2E4042004B74000CEB504 /* AsyncUtil.swift */,
                                FCC2E3F62004A01400CEB504 /* Document.swift */,
+                               FC31D01D2012F65500E7F402 /* 
DocumentHolder.swift */,
                                FCC2E3F82004A01400CEB504 /* 
LibreOfficeKitWrapper.swift */,
                                FCC2E3F92004A01400CEB504 /* LOKitThread.swift 
*/,
+                               FC31D01F2012F6D300E7F402 /* RenderCache.swift 
*/,
                                FCC2E4022004B72700CEB504 /* Util.swift */,
                        );
                        path = LOKit;
@@ -306,7 +332,9 @@
                        files = (
                                FCC2E4032004B72700CEB504 /* Util.swift in 
Sources */,
                                392ED9B31E5E4B03005C8435 /* 
ViewPrintManager.swift in Sources */,
+                               FC31D01E2012F65500E7F402 /* 
DocumentHolder.swift in Sources */,
                                FCAB1CB82009DB6900F1CC34 /* 
DocumentOverlaysView.swift in Sources */,
+                               FC31D0202012F6D300E7F402 /* RenderCache.swift 
in Sources */,
                                399648471E5B87DC00E73E83 /* 
ViewProperties.swift in Sources */,
                                FCC2E3FC2004A01500CEB504 /* 
LibreOfficeKitWrapper.swift in Sources */,
                                39284DB31FA5F207006F43E4 /* 
DocumentActions.swift in Sources */,
diff --git a/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift 
b/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift
index a15889985f31..3decec85410a 100755
--- a/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift
+++ b/ios/LibreOfficeLight/LibreOfficeLight/DocumentController.swift
@@ -61,9 +61,11 @@ class DocumentController: UIViewController, MenuDelegate, 
UIDocumentBrowserViewC
     override func viewDidAppear(_ animated: Bool)
     {
         super.viewDidAppear(animated)
-        let res = Bundle.main.url(forResource: "example", withExtension: "odt")
+        //let res = Bundle.main.url(forResource: "example", withExtension: 
"odt")
         //let res = Bundle.main.url(forResource: "example2", withExtension: 
"docx")
 
+        let res = Bundle.main.url(forResource: "testdata/1", withExtension: 
"pptx")
+
         if let exampleDoc = res
         {
             self.doOpen(exampleDoc)
diff --git a/ios/LibreOfficeLight/LibreOfficeLight/DocumentTiledView.swift 
b/ios/LibreOfficeLight/LibreOfficeLight/DocumentTiledView.swift
index 20ca23178f5c..f0a36878c4b3 100644
--- a/ios/LibreOfficeLight/LibreOfficeLight/DocumentTiledView.swift
+++ b/ios/LibreOfficeLight/LibreOfficeLight/DocumentTiledView.swift
@@ -18,9 +18,7 @@ class DocumentTiledLayer : CATiledLayer
     }
 }
 
-
-
-
+/// The main tiled view, which sits inside the scroll view
 public class DocumentTiledView: UIView
 {
     var myScale: CGFloat
@@ -33,16 +31,11 @@ public class DocumentTiledView: UIView
 
     var drawCount = 0
 
-
-
     // Create a new view with the desired frame and scale.
     public init(frame: CGRect, document: DocumentHolder, scale: CGFloat)
     {
-
-
         self.document = document
 
-
         myScale = scale
         initialSize = frame.size
         var size = document.sync { $0.getDocumentSizeAsCGSize() }
@@ -67,12 +60,28 @@ public class DocumentTiledView: UIView
 
         if let tiledLayer = self.layer as? CATiledLayer
         {
+            // these are all tweakable parameters, that give different 
behaviour to the tiled view
             tiledLayer.levelsOfDetail = 4
             tiledLayer.levelsOfDetailBias = 7
             tiledLayer.tileSize = CGSize(width: 1024.0, height: 1024.0)
             //tiledLayer.tileSize = CGSize(width: 512.0, height: 512.0)
         }
 
+        let tap = UITapGestureRecognizer(target: self, action: 
#selector(onTap) )
+        tap.numberOfTapsRequired = 1
+        self.addGestureRecognizer(tap)
+
+        if (document.isPresentation) // only for preso atm
+        {
+            // add swipe left/right gestures on a preso
+            let swipeRight = UISwipeGestureRecognizer(target: self, action: 
#selector(onSwipeRight))
+            swipeRight.direction = .right
+            self.addGestureRecognizer(swipeRight)
+
+            let swipeLeft = UISwipeGestureRecognizer(target: self, action: 
#selector(onSwipeLeft))
+            swipeLeft.direction = .left
+            self.addGestureRecognizer(swipeLeft)
+        }
     }
 
     required public init?(coder aDecoder: NSCoder)
@@ -80,6 +89,14 @@ public class DocumentTiledView: UIView
         fatalError("init(coder:) has not been implemented")
     }
 
+    func incrementPart(amount: Int)
+    {
+        document?.incrementPart(amount: Int32(amount))
+        document?.async { _ in
+            runOnMain { self.setNeedsDisplay() }
+        }
+    }
+
     public func twipsToPixels(rect: CGRect) -> CGRect
     {
         return rect.applying(CGAffineTransform(scaleX: 1.0/initialScaleFactor, 
y: 1.0/initialScaleFactor ))
@@ -196,8 +213,32 @@ public class DocumentTiledView: UIView
     }
 
 
-//    override func pressesBegan
-//    {
-//
-//    }
+}
+
+/// Gesture handlers
+public extension DocumentTiledView
+{
+    @objc func onTap(_ sender: UITapGestureRecognizer)
+    {
+        if (document?.isPresentation ?? false)
+        {
+            incrementPart(amount: 1)
+        }
+    }
+
+    @objc func onSwipeRight(_ sender: UISwipeGestureRecognizer)
+    {
+        if (document?.isPresentation ?? false)
+        {
+            incrementPart(amount: -1)
+        }
+    }
+
+    @objc func onSwipeLeft(_ sender: UISwipeGestureRecognizer)
+    {
+        if (document?.isPresentation ?? false)
+        {
+            incrementPart(amount: 1)
+        }
+    }
 }
diff --git a/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift 
b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift
new file mode 100644
index 000000000000..a380cc45edd0
--- /dev/null
+++ b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/DocumentHolder.swift
@@ -0,0 +1,327 @@
+//
+// 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/.
+//
+
+import Foundation
+import UIKit
+import QuartzCore
+
+/**
+ * Holds the document object so to enforce access in a thread safe way.
+ */
+public class DocumentHolder
+{
+    private let doc: Document
+
+    public weak var delegate: DocumentUIDelegate? = nil
+    public weak var searchDelegate: SearchDelegate? = nil
+
+    private let cache = RenderCache()
+
+    public let documentType: LibreOfficeKitDocumentType
+    public let documentSize: CGSize
+    public let views: Int32
+    public let parts: Int32
+
+    public private(set) var currentPart: Int32 = 0
+
+    init(doc: Document)
+    {
+        self.doc = doc
+        self.documentType = doc.getDocumentType()
+        documentSize = doc.getDocumentSizeAsCGSize()
+        views = doc.getViewsCount()
+        parts = doc.getParts()
+
+        doc.registerCallback() {
+            [weak self] typ, payload in
+            self?.onDocumentEvent(type: typ, payload: payload)
+        }
+    }
+
+    public var isPresentation: Bool
+    {
+        return documentType == LOK_DOCTYPE_PRESENTATION
+    }
+    public var isText: Bool
+    {
+        return documentType == LOK_DOCTYPE_TEXT
+    }
+    public var isDrawing: Bool
+    {
+        return documentType == LOK_DOCTYPE_DRAWING
+    }
+    public var isSpeadsheet: Bool
+    {
+        return documentType == LOK_DOCTYPE_SPREADSHEET
+    }
+
+    /// Gives async access to the document
+    public func async(_ closure: @escaping (Document) -> ())
+    {
+        LOKitThread.instance.async
+        {
+            closure(self.doc)
+        }
+        self.invokeHandlers()
+    }
+
+    public func invokeHandlers()
+    {
+        LOKitThread.instance.async
+        {
+            self.doc.invokeHandlers()
+        }
+    }
+
+    /// Gives sync access to the document - blocks until the closure runs.
+    /// Careful of deadlocks.
+    public func sync<R>( _ closure: @escaping (Document) -> R ) -> R
+    {
+        return LOKitThread.instance.sync
+        {
+            self.invokeHandlers()
+            return closure(self.doc)
+        }
+    }
+
+    /// Paints a tile and return synchronously, using a cached version if it 
can
+    public func paintTileToImage(canvasSize: CGSize,
+                                 tileRect: CGRect) -> UIImage?
+    {
+        if let cached = cache.get(part: currentPart, canvasSize: canvasSize, 
tileRect: tileRect)
+        {
+            return cached
+        }
+
+        let img = sync {
+            $0.paintTileToImage(canvasSize: canvasSize, tileRect: tileRect)
+        }
+        if let image = img
+        {
+            cache.add(cachedRender: CachedRender(part: currentPart, 
canvasSize: canvasSize, tileRect: tileRect, image: image))
+        }
+
+        return img
+    }
+
+    private func onDocumentEvent(type: LibreOfficeKitCallbackType, payload: 
String?)
+    {
+        print("onDocumentEvent type:\(type) payload:\(payload ?? "")")
+
+        switch type
+        {
+        case LOK_CALLBACK_INVALIDATE_TILES:
+            runOnMain {
+                self.delegate?.invalidateTiles( rects: decodeRects(payload) )
+            }
+        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+            runOnMain {
+                self.delegate?.invalidateVisibleCursor( rects: 
decodeRects(payload) )
+            }
+        case LOK_CALLBACK_TEXT_SELECTION:
+            runOnMain {
+                self.delegate?.textSelection( rects: decodeRects(payload) )
+            }
+        case LOK_CALLBACK_TEXT_SELECTION_START:
+            runOnMain {
+                self.delegate?.textSelectionStart( rects: decodeRects(payload) 
)
+            }
+        case LOK_CALLBACK_TEXT_SELECTION_END:
+            runOnMain {
+                self.delegate?.textSelectionEnd( rects: decodeRects(payload) )
+            }
+
+        case LOK_CALLBACK_SEARCH_NOT_FOUND:
+            runOnMain {
+                self.searchDelegate?.searchNotFound()
+            }
+        case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
+            runOnMain {
+                self.searchResults(payload: payload)
+            }
+
+        case LOK_CALLBACK_SET_PART:
+            if let p = payload, let newPart = Int32(p)
+            {
+                self.currentPart = newPart
+                // TODO: callback?
+            }
+
+        default:
+            print("onDocumentEvent type:\(type) not handled!")
+        }
+    }
+
+    private func searchResults(payload: String?)
+    {
+        if let d = payload, let data = d.data(using: .utf8)
+        {
+            let decoder = JSONDecoder()
+            do
+            {
+                let searchResults = try decoder.decode(SearchResults.self, 
from: data )
+                self.searchDelegate?.searchResultSelection(searchResults: 
searchResults)
+            }
+            catch
+            {
+                print("Error decoding payload: \(error)")
+            }
+        }
+    }
+
+    public func search(searchString: String, forwardDirection: Bool = true, 
from: CGPoint)
+    {
+        var rootJson = JSONObject()
+        addProperty(&rootJson, "SearchItem.SearchString", "string", 
searchString);
+        addProperty(&rootJson, "SearchItem.Backward", "boolean", 
String(!forwardDirection) );
+        addProperty(&rootJson, "SearchItem.SearchStartPointX", "long", 
String(describing: from.x) );
+        addProperty(&rootJson, "SearchItem.SearchStartPointY", "long", 
String(describing: from.y) );
+        addProperty(&rootJson, "SearchItem.Command", "long", "0") // 
String.valueOf(0)); // search all == 1
+
+        if let jsonStr = encode(json: rootJson)
+        {
+            async {
+                $0.postUnoCommand(command: ".uno:ExecuteSearch", arguments: 
jsonStr, notifyWhenFinished: true)
+            }
+        }
+    }
+
+    public func incrementPart(amount: Int32)
+    {
+        async {
+            document in
+            let currentPart = document.getPart()
+            let numParts = document.getParts()
+            let newPart = currentPart + amount
+            if (newPart < numParts && newPart > 0)
+            {
+                document.setPart(nPart: newPart)
+            }
+        }
+    }
+}
+
+public typealias JSONObject = Dictionary<String, AnyObject>
+public func addProperty( _ json: inout JSONObject, _ parentValue: String, _ 
type: String, _ value: String)
+{
+    var child = JSONObject();
+    child["type"] = type as AnyObject
+    child["value"] = value as AnyObject
+    json[parentValue] = child as AnyObject
+}
+
+func encode(json: JSONObject) -> String?
+{
+    if let data = try? JSONSerialization.data(withJSONObject: json, options: 
.prettyPrinted)
+    {
+        return String(data: data, encoding: String.Encoding.utf8)
+    }
+    return nil
+}
+
+/// Decodes a series of rectangles in the form: "x, y, width, height; x, y, 
width, height"
+public func decodeRects(_ payload: String?) -> [CGRect]?
+{
+    guard var pl = payload else { return nil }
+    pl = pl.trimmingCharacters(in: .whitespacesAndNewlines )
+    if pl == "EMPTY" || pl.count == 0
+    {
+        return nil
+    }
+    var ret = [CGRect]()
+    for rectStr in pl.split(separator: ";")
+    {
+        let coords = rectStr.split(separator: ",").flatMap { 
Double($0.trimmingCharacters(in: .whitespacesAndNewlines)) }
+        if coords.count == 4
+        {
+            let rect = CGRect(x: coords[0],
+                              y: coords[1],
+                              width: coords[2],
+                              height: coords[3])
+            ret.append( rect )
+        }
+    }
+    return ret
+}
+
+// MARK :- Delegates
+
+public protocol DocumentUIDelegate: class
+{
+    func invalidateTiles(rects: [CGRect]? )
+    func invalidateVisibleCursor(rects: [CGRect]? )
+
+    func textSelection(rects: [CGRect]? )
+    func textSelectionStart(rects: [CGRect]? )
+    func textSelectionEnd(rects: [CGRect]? )
+}
+
+public protocol SearchDelegate: class
+{
+    func searchNotFound()
+    func searchResultSelection(searchResults: SearchResults)
+}
+
+/**
+ Encodes this example json:
+ {
+ "searchString": "Office",
+ "highlightAll": "true",
+ "searchResultSelection": [
+ {
+ "part": "0",
+ "rectangles": "1951, 10743, 627, 239"
+ },
+ {
+ "part": "0",
+ "rectangles": "5343, 9496, 627, 287"
+ },
+ {
+ "part": "0",
+ "rectangles": "1951, 9256, 627, 239"
+ },
+ {
+ "part": "0",
+ "rectangles": "6502, 5946, 626, 287"
+ },
+ {
+ "part": "0",
+ "rectangles": "6686, 5658, 627, 287"
+ },
+ {
+ "part": "0",
+ "rectangles": "4103, 5418, 573, 239"
+ },
+ {
+ "part": "0",
+ "rectangles": "1951, 5418, 627, 239"
+ },
+ {
+ "part": "0",
+ "rectangles": "4934, 1658, 1586, 559"
+ }
+ ]
+ }
+ */
+public struct SearchResults: Codable
+{
+    public var searchString: String?
+    public var highlightAll: String?
+    public var searchResultSelection: Array<PartAndRectangles>?
+}
+
+public struct PartAndRectangles: Codable
+{
+    public var part: String?
+    public var rectangles: String?
+
+    public var rectsAsCGRects: [CGRect]? {
+        return decodeRects(self.rectangles)
+    }
+}
+
diff --git a/ios/LibreOfficeLight/LibreOfficeLight/LOKit/LOKitThread.swift 
b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/LOKitThread.swift
index e8f60e0f2119..8e3607612a6b 100644
--- a/ios/LibreOfficeLight/LibreOfficeLight/LOKit/LOKitThread.swift
+++ b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/LOKitThread.swift
@@ -119,280 +119,6 @@ public class LOKitThread
     }
 }
 
-
-open class CachedRender
-{
-    open let canvasSize: CGSize
-    open let tileRect: CGRect
-    open let image: UIImage
-
-    public init(canvasSize: CGSize, tileRect: CGRect, image: UIImage)
-    {
-        self.canvasSize = canvasSize
-        self.tileRect = tileRect
-        self.image = image
-    }
-}
-
-class RenderCache
-{
-    let CACHE_LOWMEM = 4
-    let CACHE_NORMAL = 20
-
-    var cachedRenders: [CachedRender] = []
-    var hasReceivedMemoryWarning = false
-
-    let lock = NSRecursiveLock()
-
-    func emptyCache()
-    {
-        lock.lock(); defer { lock.unlock() }
-
-        cachedRenders.removeAll()
-
-    }
-
-    func pruneCache()
-    {
-        lock.lock(); defer { lock.unlock() }
-
-        let max = hasReceivedMemoryWarning ? CACHE_LOWMEM : CACHE_NORMAL
-        while cachedRenders.count > max
-        {
-            cachedRenders.remove(at: 0)
-        }
-    }
-
-    func add(cachedRender: CachedRender)
-    {
-        lock.lock(); defer { lock.unlock() }
-
-        cachedRenders.append(cachedRender)
-        pruneCache()
-    }
-
-    func get(canvasSize: CGSize, tileRect: CGRect) -> UIImage?
-    {
-        lock.lock(); defer { lock.unlock() }
-
-        if let cr = cachedRenders.first(where: { $0.canvasSize == canvasSize 
&& $0.tileRect == tileRect })
-        {
-            return cr.image
-        }
-        return nil
-    }
-
-}
-
-/**
- * Holds the document object so to enforce access in a thread safe way.
- */
-public class DocumentHolder
-{
-    private let doc: Document
-
-    public weak var delegate: DocumentUIDelegate? = nil
-    public weak var searchDelegate: SearchDelegate? = nil
-
-    private let cache = RenderCache()
-
-    init(doc: Document)
-    {
-        self.doc = doc
-        doc.registerCallback() {
-            [weak self] typ, payload in
-            self?.onDocumentEvent(type: typ, payload: payload)
-        }
-    }
-
-    /// Gives async access to the document
-    public func async(_ closure: @escaping (Document) -> ())
-    {
-        LOKitThread.instance.async
-        {
-            closure(self.doc)
-        }
-        self.invokeHandlers()
-    }
-
-    public func invokeHandlers()
-    {
-        LOKitThread.instance.async
-        {
-            self.doc.invokeHandlers()
-        }
-    }
-
-    /// Gives sync access to the document - blocks until the closure runs.
-    /// Careful of deadlocks.
-    public func sync<R>( _ closure: @escaping (Document) -> R ) -> R
-    {
-        return LOKitThread.instance.sync
-        {
-            self.invokeHandlers()
-            return closure(self.doc)
-        }
-    }
-
-    /// Paints a tile and return synchronously, using a cached version if it 
can
-    public func paintTileToImage(canvasSize: CGSize,
-                                 tileRect: CGRect) -> UIImage?
-    {
-        if let cached = cache.get(canvasSize: canvasSize, tileRect: tileRect)
-        {
-            return cached
-        }
-
-        let img = sync {
-            $0.paintTileToImage(canvasSize: canvasSize, tileRect: tileRect)
-        }
-        if let image = img
-        {
-            cache.add(cachedRender: CachedRender(canvasSize: canvasSize, 
tileRect: tileRect, image: image))
-        }
-
-        return img
-    }
-
-
-    private func onDocumentEvent(type: LibreOfficeKitCallbackType, payload: 
String?)
-    {
-        print("onDocumentEvent type:\(type) payload:\(payload ?? "")")
-
-        switch type
-        {
-        case LOK_CALLBACK_INVALIDATE_TILES:
-            runOnMain {
-                self.delegate?.invalidateTiles( rects: decodeRects(payload) )
-            }
-        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
-            runOnMain {
-                self.delegate?.invalidateVisibleCursor( rects: 
decodeRects(payload) )
-            }
-        case LOK_CALLBACK_TEXT_SELECTION:
-            runOnMain {
-                self.delegate?.textSelection( rects: decodeRects(payload) )
-            }
-        case LOK_CALLBACK_TEXT_SELECTION_START:
-            runOnMain {
-                self.delegate?.textSelectionStart( rects: decodeRects(payload) 
)
-            }
-        case LOK_CALLBACK_TEXT_SELECTION_END:
-            runOnMain {
-                self.delegate?.textSelectionEnd( rects: decodeRects(payload) )
-            }
-
-        case LOK_CALLBACK_SEARCH_NOT_FOUND:
-            runOnMain {
-                self.searchDelegate?.searchNotFound()
-            }
-        case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
-            runOnMain {
-                self.searchResults(payload: payload)
-            }
-
-
-        default:
-            print("onDocumentEvent type:\(type) not handled!")
-        }
-    }
-
-    private func searchResults(payload: String?)
-    {
-        if let d = payload, let data = d.data(using: .utf8)
-        {
-            let decoder = JSONDecoder()
-
-            do
-            {
-                let searchResults = try decoder.decode(SearchResults.self, 
from: data )
-
-                /*
-                if let srs = searchResults.searchResultSelection
-                {
-                    for par in srs
-                    {
-                        print("\(par.rectsAsCGRects)")
-                    }
-                }
-                */
-
-                self.searchDelegate?.searchResultSelection(searchResults: 
searchResults)
-            }
-            catch
-            {
-                print("Error decoding payload: \(error)")
-            }
-
-        }
-    }
-
-    public func search(searchString: String, forwardDirection: Bool = true, 
from: CGPoint)
-    {
-        var rootJson = JSONObject()
-
-        addProperty(&rootJson, "SearchItem.SearchString", "string", 
searchString);
-        addProperty(&rootJson, "SearchItem.Backward", "boolean", 
String(!forwardDirection) );
-        addProperty(&rootJson, "SearchItem.SearchStartPointX", "long", 
String(describing: from.x) );
-        addProperty(&rootJson, "SearchItem.SearchStartPointY", "long", 
String(describing: from.y) );
-        addProperty(&rootJson, "SearchItem.Command", "long", "0") // 
String.valueOf(0)); // search all == 1
-
-        if let jsonStr = encode(json: rootJson)
-        {
-            async {
-                $0.postUnoCommand(command: ".uno:ExecuteSearch", arguments: 
jsonStr, notifyWhenFinished: true)
-            }
-        }
-    }
-
-
-}
-
-public typealias JSONObject = Dictionary<String, AnyObject>
-public func addProperty( _ json: inout JSONObject, _ parentValue: String, _ 
type: String, _ value: String)
-{
-    var child = JSONObject();
-    child["type"] = type as AnyObject
-    child["value"] = value as AnyObject
-    json[parentValue] = child as AnyObject
-}
-
-func encode(json: JSONObject) -> String?
-{
-    //let encoder = JSONEncoder()
-
-    if let data = try? JSONSerialization.data(withJSONObject: json, options: 
.prettyPrinted)
-    {
-        return String(data: data, encoding: String.Encoding.utf8)
-    }
-    return nil
-}
-
-/// Decodes a series of rectangles in the form: "x, y, width, height; x, y, 
width, height"
-public func decodeRects(_ payload: String?) -> [CGRect]?
-{
-    guard var pl = payload else { return nil }
-    pl = pl.trimmingCharacters(in: .whitespacesAndNewlines )
-    if pl == "EMPTY" || pl.count == 0
-    {
-        return nil
-    }
-    var ret = [CGRect]()
-    for rectStr in pl.split(separator: ";")
-    {
-        let coords = rectStr.split(separator: ",").flatMap { 
Double($0.trimmingCharacters(in: .whitespacesAndNewlines)) }
-        if coords.count == 4
-        {
-            let rect = CGRect(x: coords[0],
-                              y: coords[1],
-                              width: coords[2],
-                              height: coords[3])
-            ret.append( rect )
-        }
-    }
-    return ret
-}
-
 /**
  * Delegate methods for global events emitted from LOKit.
  * Mostly dispatched on the main thread unless noted.
@@ -405,85 +131,9 @@ public protocol LOKitUIDelegate: class
 public protocol ProgressDelegate: class
 {
     func statusIndicatorStart()
-
     func statusIndicatorFinish()
-
     func statusIndicatorSetValue(value: Double)
 }
 
 
-public protocol DocumentUIDelegate: class
-{
-    func invalidateTiles(rects: [CGRect]? )
-
-    func invalidateVisibleCursor(rects: [CGRect]? )
-
-    func textSelection(rects: [CGRect]? )
-    func textSelectionStart(rects: [CGRect]? )
-    func textSelectionEnd(rects: [CGRect]? )
-}
 
-public protocol SearchDelegate: class
-{
-    func searchNotFound()
-
-    func searchResultSelection(searchResults: SearchResults)
-}
-
-/**
- Encodes this example json:
- {
- "searchString": "Office",
- "highlightAll": "true",
- "searchResultSelection": [
- {
- "part": "0",
- "rectangles": "1951, 10743, 627, 239"
- },
- {
- "part": "0",
- "rectangles": "5343, 9496, 627, 287"
- },
- {
- "part": "0",
- "rectangles": "1951, 9256, 627, 239"
- },
- {
- "part": "0",
- "rectangles": "6502, 5946, 626, 287"
- },
- {
- "part": "0",
- "rectangles": "6686, 5658, 627, 287"
- },
- {
- "part": "0",
- "rectangles": "4103, 5418, 573, 239"
- },
- {
- "part": "0",
- "rectangles": "1951, 5418, 627, 239"
- },
- {
- "part": "0",
- "rectangles": "4934, 1658, 1586, 559"
- }
- ]
- }
-*/
-public struct SearchResults: Codable
-{
-    public var searchString: String?
-    public var highlightAll: String?
-    public var searchResultSelection: Array<PartAndRectangles>?
-}
-
-public struct PartAndRectangles: Codable
-{
-    public var part: String?
-    public var rectangles: String?
-
-    public var rectsAsCGRects: [CGRect]? {
-        return decodeRects(self.rectangles)
-    }
-}
diff --git a/ios/LibreOfficeLight/LibreOfficeLight/LOKit/RenderCache.swift 
b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/RenderCache.swift
new file mode 100644
index 000000000000..f217db0414a6
--- /dev/null
+++ b/ios/LibreOfficeLight/LibreOfficeLight/LOKit/RenderCache.swift
@@ -0,0 +1,78 @@
+//
+// 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/.
+//
+
+import Foundation
+import UIKit
+
+
+open class CachedRender
+{
+    open let part: Int32
+    open let canvasSize: CGSize
+    open let tileRect: CGRect
+    open let image: UIImage
+
+    public init(part: Int32, canvasSize: CGSize, tileRect: CGRect, image: 
UIImage)
+    {
+        self.canvasSize = canvasSize
+        self.tileRect = tileRect
+        self.image = image
+        self.part = part
+    }
+}
+
+class RenderCache
+{
+    let CACHE_LOWMEM = 4
+    let CACHE_NORMAL = 20
+
+    var cachedRenders: [CachedRender] = []
+    var hasReceivedMemoryWarning = false
+
+    let lock = NSRecursiveLock()
+
+    func emptyCache()
+    {
+        lock.lock(); defer { lock.unlock() }
+        cachedRenders.removeAll()
+    }
+
+    func pruneCache()
+    {
+        lock.lock(); defer { lock.unlock() }
+
+        let max = hasReceivedMemoryWarning ? CACHE_LOWMEM : CACHE_NORMAL
+        while cachedRenders.count > max
+        {
+            cachedRenders.remove(at: 0)
+        }
+    }
+
+    func add(cachedRender: CachedRender)
+    {
+        lock.lock(); defer { lock.unlock() }
+
+        cachedRenders.append(cachedRender)
+        pruneCache()
+    }
+
+    func get(part: Int32, canvasSize: CGSize, tileRect: CGRect) -> UIImage?
+    {
+        lock.lock(); defer { lock.unlock() }
+
+        if let cr = cachedRenders.first(where: {
+                $0.canvasSize == canvasSize
+                && $0.tileRect == tileRect
+                && $0.part == part
+        })
+        {
+            return cr.image
+        }
+        return nil
+    }
+}
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to