fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / ios / shared / ios_sharedlo / objective_c / render / MLORenderManager.m
blobea7abe662289b623cd16c1a53ab0d7870ecac579
1 // -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 //
3 // This file is part of the LibreOffice project.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 #import "MLOCommon.h"
11 #import <UIKit/UIKit.h>
13 #import "MLOMainViewController.h"
14 #import "MLORenderManager_Impl.h"
15 #import "MLORenderBuffer.h"
16 #import "MLOScalingBuffer.h"
17 #import "MLOGestureLimiter.h"
18 #import "MLOGestureEngine_Impl.h"
19 #import "MLOSelectionViewController.h"
20 #import "NSObject+MLOUtils.h"
21 #import "MLOPostRenderManager.h"
22 #import "mlo_utils.h"
23 #import <QuartzCore/QuartzCore.h>
25 #include <touch/touch.h>
27 static MLORenderManager * instance = nil;
29 static const CGFloat
30     HORIZONAL_BUFFER_SCALE=1.0f,
31     VERTICAL_BUFFER_SCALE=1.0f,
32     BUFFER_SCALE_BIAS =1.0f,
34     RENDERING_BIAS_RATIO = 1.0f/(BUFFER_SCALE_BIAS*HORIZONAL_BUFFER_SCALE *VERTICAL_BUFFER_SCALE),
36     MAX_RENDER_PER_SECOND_ON_DEFAULT_ZOOM =4 * RENDERING_BIAS_RATIO,
37     MAX_RENDER_PER_SECOND_ON_MAX_ZOOM_IN=3 * RENDERING_BIAS_RATIO;
39 static const NSTimeInterval    
40     LO_PAN_RENDER_MAX_DURATION = 0.3f,
41     LO_PINCH_RENDER_MAX_DURATION = 0.5f,
42     RESET_TRANSFORM_ANIMATION_DURATION=0.1f,
43     LO_RENDER_BACKOFF_MIN = 1.0f / MAX_RENDER_PER_SECOND_ON_DEFAULT_ZOOM,
44     LO_RENDER_BACKOFF_MAX = 1.0f / MAX_RENDER_PER_SECOND_ON_MAX_ZOOM_IN,
45     LO_RENDER_BACK_OFF_MAX_DELTA = LO_RENDER_BACKOFF_MAX - LO_RENDER_BACKOFF_MIN;
49 static const NSInteger BUFFER_COUNT=2;
51 #define MLOGestureDirectionString(enum) [@[@"X",@"Y",@"Z"] objectAtIndex:enum]
53 @interface MLORenderManager ()
54 @property MLOGestureEngine * gestureEngine;
55 @property MLOPostRenderManager * post;
56 @property NSArray * buffers;
57 @property NSInteger activeBufferIndex,nextBufferIndex,frameIdCounter;
58 @property NSTimeInterval bufferTransfromResetDeadline,renderBlockReleaseTime;
59 @property CGFloat inRenderTiltX,inRenderTiltY, inRenderTiltScale;
60 @end
62 @implementation MLORenderManager 
64 +(MLORenderManager *) getInstance{
65     if(instance == nil){
66         instance = [MLORenderManager new];
67     }
68     return instance;
71 -(MLORenderBuffer *)getBufferAtIndex:(NSInteger) index{
72     return [_buffers objectAtIndex:index];
75 -(id)init{
76     self = [super init];
77     if(self){
78         self.gestureEngine = nil;
79         [self createBufffers];
80         self.renderBlockReleaseTime = 0;
81         self.activeBufferIndex = 0;
82         self.nextBufferIndex = _activeBufferIndex + 1;
83         [self loRenderWillBegin];
84         self.view.backgroundColor = [UIColor whiteColor];
85         self.currentGesture = NO_GESTURE;
86     }
87     return self;
90 -(void) createBufffers{
91     NSMutableArray * array = [NSMutableArray new];
92     
93     for (NSInteger i = 0 ; i < BUFFER_COUNT; i++) {
94         
95         [array addObject:[[MLORenderBuffer alloc] initWithArrayIndex: i renderManager:self]];
96     }
97     
98     self.buffers = [NSArray arrayWithArray:array];
99     
100     for (NSInteger i = 0 ; i < BUFFER_COUNT; i++) {
101         
102         MLORenderBuffer * buffer = [_buffers objectAtIndex:i];
103         
104         NSInteger previousIndex = BUFFER_COUNT -1;
105         if(i !=0){
106             previousIndex = i-1;
107         }
108         buffer.previous = [_buffers objectAtIndex:previousIndex];
109         [self.view addSubview:buffer];
110     }
113 -(void)showLibreOffice:(MLOGestureEngine *) gestureEngine{
114     self.gestureEngine = gestureEngine;
117 -(void)hideLibreOffice{
118     self.currentGesture = NO_GESTURE;
119     [self.scaler hide];
120     self.gestureEngine = nil;
123 -(void) panDeltaX:(CGFloat) deltaX deltaY:(CGFloat) deltaY{
124     
125     self.currentGesture = PAN;
126         
127     if(deltaX || deltaY){
128         [[self getActiveBuffer] moveDeltaX:deltaX deltaY:deltaY];
129        
130         self.inRenderTiltX+=deltaX;
131         self.inRenderTiltY+=deltaY;
132     }
135 -(void) pinchDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY scale:(CGFloat)scale{
136     
137     if(ENABLE_PINCH_RENDERING_VIA_IOS){
138                
139         self.currentGesture = PINCH;
140         
141         if(self.scaler ==nil){
142             self.scaler = [[MLOScalingBuffer alloc] initWithRenderManager:self];
143         }
144         
145         [self.scaler scale:scale deltaX:deltaX deltaY:deltaY];
146     
147         self.inRenderTiltScale*=scale;
148         self.inRenderTiltX = self.inRenderTiltX*scale +deltaX;
149         self.inRenderTiltY = self.inRenderTiltY*scale +deltaY;
150         
151     }
154 -(void)endGestures{
155     self.currentGesture = NO_GESTURE;
156     NSLog(@"RenderManager: self.currentGesture = NO_GESTURE");
159 -(CGPoint) getShiftFromCanvasCenter{
160     
161     CGPoint bufferCenter= [self currentBufferCenter];
162     CGPoint canvasCenter = _gestureEngine.mainViewController.canvas.center;
163     
164     return CGPointMake(bufferCenter.x - canvasCenter.x,
165                        bufferCenter.y - canvasCenter.y);
168 -(CGPoint) currentBufferCenter{
169     if(self.currentGesture ==PINCH){
170         return self.scaler.center;
171     }
172     return [self getActiveBuffer].center;
175 -(void)loRenderWillBegin{
176     self.inRenderTiltX = NO_MOVE_DELTA;
177     self.inRenderTiltY = NO_MOVE_DELTA;
178     self.inRenderTiltScale = NO_SCALE;
181 -(void)setWidth:(NSInteger) width height:(NSInteger) height{
182         
183     self.view.frame = CGRectMake(0,0, width,height);
184     
185     CGFloat bufferWidth = width*HORIZONAL_BUFFER_SCALE;
186     CGFloat bufferHeight = height*VERTICAL_BUFFER_SCALE;
187     self.bufferFrame = CGRectMake(0,0, bufferWidth,bufferHeight);
188     
189     for (MLORenderBuffer * buffer in _buffers) {
190         buffer.frame = self.bufferFrame;
191     }
192     
193     touch_lo_set_view_size(bufferWidth,bufferHeight);
195 -(MLORenderBuffer *) getActiveBuffer{
196     return[_buffers objectAtIndex:self.activeBufferIndex];
199 -(MLORenderBuffer *) getNextBuffer{
200     return[_buffers objectAtIndex:self.nextBufferIndex];
203 -(void) renderInContext:(CGContextRef) context{
204     // used for magnification
205      [[self getActiveBuffer].layer renderInContext:context];
208 -(void)swapIndexes{
209     self.nextBufferIndex = (self.nextBufferIndex +1)% BUFFER_COUNT;
210     self.activeBufferIndex = (self.activeBufferIndex +1)% BUFFER_COUNT;
213 -(void)swapPreviousBuffer:(MLORenderingUIView*) previous withNextBuffer:(MLORenderBuffer *) next{
214     
215     NSTimeInterval bufferTransformResetDelay = [self getBufferTransformResetDelay];
216     NSTimeInterval bufferTransformResetDeadline =CACurrentMediaTime() + bufferTransformResetDelay;
217     
218     self.bufferTransfromResetDeadline = bufferTransformResetDeadline;
219     
220     if(self.scaler && self.scaler.didRender){
221         previous = self.scaler;
222     }
223      
224     [self showBuffer:next];
225     
226     [self swapIndexes];
227    
228     [previous hide];
229     
232 -(NSTimeInterval) getBufferTransformResetDelay{
233    
234     switch(self.currentGesture){
235         case PAN: return LO_PAN_RENDER_MAX_DURATION;
236         case PINCH: return LO_PINCH_RENDER_MAX_DURATION;
237         case NO_GESTURE: return 0;
238     }
241 -(void)showBuffer:(MLORenderBuffer *) buffer{
243     buffer.alpha = 1.0f;
246 -(CGFloat) currentZoomRatio{
247     return [_gestureEngine.limiter zoom] / MAX_ZOOM;
250 -(void) renderWithRect:(CGRect) rect{
252     if(ENABLE_LO_DESKTOP){
253     
254         switch(self.currentGesture){
255             case PAN:
256                 {
257                     NSTimeInterval now = CACurrentMediaTime();
258                     
259                     NSTimeInterval delta =  LO_RENDER_BACKOFF_MIN +
260                                             LO_RENDER_BACK_OFF_MAX_DELTA * [self currentZoomRatio];
261                     
262                     NSTimeInterval releaseTime = now + delta;
263                     
264                     NSTimeInterval currentReleaseTime = self.renderBlockReleaseTime;
265                     
266                     NSInteger currentFrameId = self.frameIdCounter++;
267                     
268                     if(now > currentReleaseTime){
269                    
270                         [self pereodicRender:rect releaseTime:releaseTime];
271                    
272                     }else{
273                         
274                         [self performBlock:^{
275                             
276                             if((self.renderBlockReleaseTime == currentReleaseTime)
277                                && (currentFrameId==0)){
278                                
279                                 [self pereodicRender:rect releaseTime:releaseTime];
280                             }
281                         }afterDelay:delta];
282                     }
283                 }
284                 break;
285             case PINCH:
286             case NO_GESTURE:
287                 [[self getNextBuffer] setNeedsDisplayInRect:rect];
288             break;
289         }
290     }
293 -(void)renderNow{
294     [[self getNextBuffer] setNeedsDisplayInRect:self.bufferFrame];
297 -(void)pereodicRender:(CGRect) rect releaseTime:(NSTimeInterval) releaseTime{
298     
299     static NSTimeInterval lastRender = 0;
300     
301     [[self getNextBuffer] setNeedsDisplayInRect:rect];
302     
303     self.frameIdCounter = 0;
304         
305     self.renderBlockReleaseTime =releaseTime;
306     
307     NSTimeInterval now = CACurrentMediaTime();
308     NSLog(@"Render interval %f",now - lastRender);
309     
310     lastRender = now;
314 // C functions
315 // ===========
317 // Functions called in the LO thread, which thus need to dispatch any
318 // CocoaTouch activity to happen on the GUI thread. Use
319 // dispatch_async() consistently.
322 void touch_ui_damaged(int minX, int minY, int width, int height)
324     CGRect rect = CGRectMake(minX, minY, width, height);
326     dispatch_async(dispatch_get_main_queue(), ^{
327         
328         [[MLORenderManager getInstance] renderWithRect:rect];
329         
330     });
331     // NSLog(@"lo_damaged: %dx%d@(%d,%d)", (int)rect.size.width, (int)rect.size.height, (int)rect.origin.x, (int)rect.origin.y);
334 @end
336 // vim:set shiftwidth=4 softtabstop=4 expandtab: