Files
loongoffice/ios/shared/ios_sharedlo/objective_c/render/MLORenderManager.m
Tor Lillqvist ab5b6e3de4 The Emacs mode for Objective-C is called "ObjC"
Change-Id: I78428758aff0f0fb7e25ae8724ac32db824e10a6
2013-10-17 21:18:10 +03:00

338 lines
9.6 KiB
Objective-C

// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
//
// 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 "MLOCommon.h"
#import <UIKit/UIKit.h>
#import "MLOMainViewController.h"
#import "MLORenderManager_Impl.h"
#import "MLORenderBuffer.h"
#import "MLOScalingBuffer.h"
#import "MLOGestureLimiter.h"
#import "MLOGestureEngine_Impl.h"
#import "MLOSelectionViewController.h"
#import "NSObject+MLOUtils.h"
#import "MLOPostRenderManager.h"
#import "mlo_utils.h"
#import <QuartzCore/QuartzCore.h>
#include <touch/touch.h>
static MLORenderManager * instance = nil;
static const CGFloat
HORIZONAL_BUFFER_SCALE=1.0f,
VERTICAL_BUFFER_SCALE=1.0f,
BUFFER_SCALE_BIAS =1.0f,
RENDERING_BIAS_RATIO = 1.0f/(BUFFER_SCALE_BIAS*HORIZONAL_BUFFER_SCALE *VERTICAL_BUFFER_SCALE),
MAX_RENDER_PER_SECOND_ON_DEFAULT_ZOOM =4 * RENDERING_BIAS_RATIO,
MAX_RENDER_PER_SECOND_ON_MAX_ZOOM_IN=3 * RENDERING_BIAS_RATIO;
static const NSTimeInterval
LO_PAN_RENDER_MAX_DURATION = 0.3f,
LO_PINCH_RENDER_MAX_DURATION = 0.5f,
RESET_TRANSFORM_ANIMATION_DURATION=0.1f,
LO_RENDER_BACKOFF_MIN = 1.0f / MAX_RENDER_PER_SECOND_ON_DEFAULT_ZOOM,
LO_RENDER_BACKOFF_MAX = 1.0f / MAX_RENDER_PER_SECOND_ON_MAX_ZOOM_IN,
LO_RENDER_BACK_OFF_MAX_DELTA = LO_RENDER_BACKOFF_MAX - LO_RENDER_BACKOFF_MIN;
static const NSInteger BUFFER_COUNT=2;
typedef enum {X,Y,Z} MLOGestureDirection;
#define MLOGestureDirectionString(enum) [@[@"X",@"Y",@"Z"] objectAtIndex:enum]
@interface MLORenderManager ()
@property MLOGestureEngine * gestureEngine;
@property MLOPostRenderManager * post;
@property NSArray * buffers;
@property NSInteger activeBufferIndex,nextBufferIndex,frameIdCounter;
@property NSTimeInterval bufferTransfromResetDeadline,renderBlockReleaseTime;
@property CGFloat inRenderTiltX,inRenderTiltY, inRenderTiltScale;
@end
@implementation MLORenderManager
+(MLORenderManager *) getInstance{
if(instance == nil){
instance = [MLORenderManager new];
}
return instance;
}
-(MLORenderBuffer *)getBufferAtIndex:(NSInteger) index{
return [_buffers objectAtIndex:index];
}
-(id)init{
self = [super init];
if(self){
self.gestureEngine = nil;
[self createBufffers];
self.renderBlockReleaseTime = 0;
self.activeBufferIndex = 0;
self.nextBufferIndex = _activeBufferIndex + 1;
[self loRenderWillBegin];
self.view.backgroundColor = [UIColor whiteColor];
self.currentGesture = NO_GESTURE;
}
return self;
}
-(void) createBufffers{
NSMutableArray * array = [NSMutableArray new];
for (NSInteger i = 0 ; i < BUFFER_COUNT; i++) {
[array addObject:[[MLORenderBuffer alloc] initWithArrayIndex: i renderManager:self]];
}
self.buffers = [NSArray arrayWithArray:array];
for (NSInteger i = 0 ; i < BUFFER_COUNT; i++) {
MLORenderBuffer * buffer = [_buffers objectAtIndex:i];
NSInteger previousIndex = BUFFER_COUNT -1;
if(i !=0){
previousIndex = i-1;
}
buffer.previous = [_buffers objectAtIndex:previousIndex];
[self.view addSubview:buffer];
}
}
-(void)showLibreOffice:(MLOGestureEngine *) gestureEngine{
self.gestureEngine = gestureEngine;
}
-(void)hideLibreOffice{
self.currentGesture = NO_GESTURE;
[self.scaler hide];
self.gestureEngine = nil;
}
-(void) panDeltaX:(CGFloat) deltaX deltaY:(CGFloat) deltaY{
self.currentGesture = PAN;
if(deltaX || deltaY){
[[self getActiveBuffer] moveDeltaX:deltaX deltaY:deltaY];
self.inRenderTiltX+=deltaX;
self.inRenderTiltY+=deltaY;
}
}
-(void) pinchDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY scale:(CGFloat)scale{
if(ENABLE_PINCH_RENDERING_VIA_IOS){
self.currentGesture = PINCH;
if(self.scaler ==nil){
self.scaler = [[MLOScalingBuffer alloc] initWithRenderManager:self];
}
[self.scaler scale:scale deltaX:deltaX deltaY:deltaY];
self.inRenderTiltScale*=scale;
self.inRenderTiltX = self.inRenderTiltX*scale +deltaX;
self.inRenderTiltY = self.inRenderTiltY*scale +deltaY;
}
}
-(void)endGestures{
self.currentGesture = NO_GESTURE;
NSLog(@"RenderManager: self.currentGesture = NO_GESTURE");
}
-(CGPoint) getShiftFromCanvasCenter{
CGPoint bufferCenter= [self currentBufferCenter];
CGPoint canvasCenter = _gestureEngine.mainViewController.canvas.center;
return CGPointMake(bufferCenter.x - canvasCenter.x,
bufferCenter.y - canvasCenter.y);
}
-(CGPoint) currentBufferCenter{
if(self.currentGesture ==PINCH){
return self.scaler.center;
}
return [self getActiveBuffer].center;
}
-(void)loRenderWillBegin{
self.inRenderTiltX = NO_MOVE_DELTA;
self.inRenderTiltY = NO_MOVE_DELTA;
self.inRenderTiltScale = NO_SCALE;
}
-(void)setWidth:(NSInteger) width height:(NSInteger) height{
self.view.frame = CGRectMake(0,0, width,height);
CGFloat bufferWidth = width*HORIZONAL_BUFFER_SCALE;
CGFloat bufferHeight = height*VERTICAL_BUFFER_SCALE;
self.bufferFrame = CGRectMake(0,0, bufferWidth,bufferHeight);
for (MLORenderBuffer * buffer in _buffers) {
buffer.frame = self.bufferFrame;
}
touch_lo_set_view_size(bufferWidth,bufferHeight);
}
-(MLORenderBuffer *) getActiveBuffer{
return[_buffers objectAtIndex:self.activeBufferIndex];
}
-(MLORenderBuffer *) getNextBuffer{
return[_buffers objectAtIndex:self.nextBufferIndex];
}
-(void) renderInContext:(CGContextRef) context{
// used for magnification
[[self getActiveBuffer].layer renderInContext:context];
}
-(void)swapIndexes{
self.nextBufferIndex = (self.nextBufferIndex +1)% BUFFER_COUNT;
self.activeBufferIndex = (self.activeBufferIndex +1)% BUFFER_COUNT;
}
-(void)swapPreviousBuffer:(MLORenderingUIView*) previous withNextBuffer:(MLORenderBuffer *) next{
NSTimeInterval bufferTransformResetDelay = [self getBufferTransformResetDelay];
NSTimeInterval bufferTransformResetDeadline =CACurrentMediaTime() + bufferTransformResetDelay;
self.bufferTransfromResetDeadline = bufferTransformResetDeadline;
if(self.scaler && self.scaler.didRender){
previous = self.scaler;
}
[self showBuffer:next];
[self swapIndexes];
[previous hide];
}
-(NSTimeInterval) getBufferTransformResetDelay{
switch(self.currentGesture){
case PAN: return LO_PAN_RENDER_MAX_DURATION;
case PINCH: return LO_PINCH_RENDER_MAX_DURATION;
case NO_GESTURE: return 0;
}
}
-(void)showBuffer:(MLORenderBuffer *) buffer{
buffer.alpha = 1.0f;
}
-(CGFloat) currentZoomRatio{
return [_gestureEngine.limiter zoom] / MAX_ZOOM;
}
-(void) renderWithRect:(CGRect) rect{
if(ENABLE_LO_DESKTOP){
switch(self.currentGesture){
case PAN:
{
NSTimeInterval now = CACurrentMediaTime();
NSTimeInterval delta = LO_RENDER_BACKOFF_MIN +
LO_RENDER_BACK_OFF_MAX_DELTA * [self currentZoomRatio];
NSTimeInterval releaseTime = now + delta;
NSTimeInterval currentReleaseTime = self.renderBlockReleaseTime;
NSInteger currentFrameId = self.frameIdCounter++;
if(now > currentReleaseTime){
[self pereodicRender:rect releaseTime:releaseTime];
}else{
[self performBlock:^{
if((self.renderBlockReleaseTime == currentReleaseTime)
&& (currentFrameId==0)){
[self pereodicRender:rect releaseTime:releaseTime];
}
}afterDelay:delta];
}
}
break;
case PINCH:
case NO_GESTURE:
[[self getNextBuffer] setNeedsDisplayInRect:rect];
break;
}
}
}
-(void)renderNow{
[[self getNextBuffer] setNeedsDisplayInRect:self.bufferFrame];
}
-(void)pereodicRender:(CGRect) rect releaseTime:(NSTimeInterval) releaseTime{
static NSTimeInterval lastRender = 0;
[[self getNextBuffer] setNeedsDisplayInRect:rect];
self.frameIdCounter = 0;
self.renderBlockReleaseTime =releaseTime;
NSTimeInterval now = CACurrentMediaTime();
NSLog(@"Render interval %f",now - lastRender);
lastRender = now;
}
// C functions
// ===========
//
// Functions called in the LO thread, which thus need to dispatch any
// CocoaTouch activity to happen on the GUI thread. Use
// dispatch_async() consistently.
void touch_ui_damaged(int minX, int minY, int width, int height)
{
CGRect rect = CGRectMake(minX, minY, width, height);
dispatch_async(dispatch_get_main_queue(), ^{
[[MLORenderManager getInstance] renderWithRect:rect];
});
// NSLog(@"lo_damaged: %dx%d@(%d,%d)", (int)rect.size.width, (int)rect.size.height, (int)rect.origin.x, (int)rect.origin.y);
}
@end
// vim:set shiftwidth=4 softtabstop=4 expandtab: