Revision: 15178
http://sourceforge.net/p/skim-app/code/15178
Author: hofman
Date: 2025-05-10 15:51:27 +0000 (Sat, 10 May 2025)
Log Message:
-----------
Draw page in presentation view async in bitmap. Delay transition animation
until the image is drawn and set.
Modified Paths:
--------------
trunk/SKPresentationOptionsSheetController.m
trunk/SKPresentationView.m
trunk/SKTransitionController.h
trunk/SKTransitionController.m
Modified: trunk/SKPresentationOptionsSheetController.m
===================================================================
--- trunk/SKPresentationOptionsSheetController.m 2025-05-09 22:02:52 UTC
(rev 15177)
+++ trunk/SKPresentationOptionsSheetController.m 2025-05-10 15:51:27 UTC
(rev 15178)
@@ -320,7 +320,7 @@
rect.size.height = round(0.5 * NSHeight(rect)) + 34.0;
if (previewWindow == nil) {
- previewWindow = [[NSPanel alloc] initWithContentRect:rect
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView
backing:NSBackingStoreBuffered defer:NO];
+ previewWindow = [[NSPanel alloc] initWithContentRect:rect
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView
backing:NSBackingStoreBuffered defer:NO screen:[[self window] screen]];
[previewWindow setReleasedWhenClosed:NO];
[previewWindow setTitlebarAppearsTransparent:YES];
[previewWindow setHidesOnDeactivate:NO];
@@ -363,6 +363,7 @@
CGFloat titleHeight = NSHeight([previewWindow frame]) -
NSHeight([previewWindow contentLayoutRect]);
rect.size.height += titleHeight - 28.0;
[previewWindow setFrame:rect display:NO];
+ [previewWindow layoutIfNeeded];
[previewWindow center];
[previewView setPage:[[controller pdfDocument] pageAtIndex:idx]];
Modified: trunk/SKPresentationView.m
===================================================================
--- trunk/SKPresentationView.m 2025-05-09 22:02:52 UTC (rev 15177)
+++ trunk/SKPresentationView.m 2025-05-10 15:51:27 UTC (rev 15178)
@@ -80,6 +80,7 @@
static NSInteger navigationMode = SKNavigationBottom;
@interface SKPDFPageView () <CALayerDelegate>
+- (void)displayPage:(void (^)(void))completionHandler;
@end
@implementation SKPDFPageView
@@ -101,7 +102,7 @@
CALayer *layer = [CALayer layer];
[layer setMasksToBounds:YES];
[layer setFrame:NSRectToCGRect([self bounds])];
- [layer setDelegate:self];
+ [layer setActions:@{@"contents": [NSNull null]}];
pageView = [[NSView alloc] initWithFrame:[self bounds]];
[pageView setLayer:layer];
[pageView setWantsLayer:YES];
@@ -145,7 +146,7 @@
- (void)setPage:(PDFPage *)newPage {
if (newPage != page) {
page = newPage;
- [[pageView layer] setNeedsDisplay];
+ [self displayPage:nil];
[[NSNotificationCenter defaultCenter]
postNotificationName:SKPresentationViewPageChangedNotification object:self];
}
}
@@ -171,7 +172,11 @@
if ([transitionController pageTransitions] == nil &&
([[transitionController transition] style] == SKNoTransition ||
equalStrings([page label], [toPage label])))
return NO;
- [transitionController animateView:self forRect:[self pageRect:page]
toRect:[self pageRect:toPage] atIndex:idx forward:forward change:^{ [self
setPage:toPage]; }];
+ [transitionController animateView:self forRect:[self pageRect:page]
toRect:[self pageRect:toPage] atIndex:idx forward:forward change:^(void
(^done)(void)){
+ page = toPage;
+ [self displayPage:done];
+ [[NSNotificationCenter defaultCenter]
postNotificationName:SKPresentationViewPageChangedNotification object:self];
+ }];
return YES;
}
@@ -195,31 +200,77 @@
}
}
-#pragma mark CALayer delegate
+#pragma mark Drawing
-- (void)drawLayer:(CALayer *)aLayer inContext:(CGContextRef)context {
- if (page == nil)
+- (void)displayPage:(void (^)(void))completionHandler {
+ if (page == nil) {
+ [[pageView layer] setContents:nil];
+ if (completionHandler)
+ completionHandler();
return;
+ }
+
+ static dispatch_queue_t drawingQueue = nil;
+ if (drawingQueue == nil) {
+ dispatch_queue_attr_t queuePriority =
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT,
QOS_CLASS_UTILITY, 0);
+ drawingQueue =
dispatch_queue_create("net.sourceforge.skim-app.skim.pageView", queuePriority);
+ }
+
NSRect bounds = [self bounds];
- NSRect pageRect = [page boundsForBox:kPDFDisplayBoxCropBox];
- if (([page rotation] % 180) != 0)
- pageRect = NSMakeRect(0.0, 0.0, NSHeight(pageRect), NSWidth(pageRect));
- CGFloat scale = [self autoScales] ? fmin(NSHeight(bounds) /
NSHeight(pageRect), NSWidth(bounds) / NSWidth(pageRect)) : 1.0;
- pageRect = NSInsetRect(bounds, 0.5 * (NSWidth(bounds) - scale *
NSWidth(pageRect)), 0.5 * (NSHeight(bounds) - scale * NSHeight(pageRect)));
- CGContextSaveGState(context);
- CGContextSetFillColorWithColor(context,
CGColorGetConstantColor(kCGColorWhite));
- CGContextFillRect(context, SKPixelAlignedRect(NSRectToCGRect(pageRect),
context));
- CGContextRestoreGState(context);
- CGContextSaveGState(context);
- CGContextSetInterpolationQuality(context, [[NSUserDefaults
standardUserDefaults] integerForKey:SKInterpolationQualityKey] + 1);
- CGContextTranslateCTM(context, NSMinX(pageRect), NSMinY(pageRect));
- CGContextScaleCTM(context, scale, scale);
- [page drawWithBox:kPDFDisplayBoxCropBox toContext:context];
- CGContextRestoreGState(context);
+ NSBitmapImageRep *imageRep = [self
bitmapImageRepForCachingDisplayInRect:bounds];
+
+ if (imageRep == nil) {
+ if (completionHandler)
+ completionHandler();
+ return;
+ }
+
+ PDFPage *thePage = page;
+ BOOL autoScales = [self autoScales];
+
+ dispatch_async(drawingQueue, ^{
+
+ NSRect pageRect = [thePage boundsForBox:kPDFDisplayBoxCropBox];
+ if (([thePage rotation] % 180) != 0)
+ pageRect = NSMakeRect(0.0, 0.0, NSHeight(pageRect),
NSWidth(pageRect));
+ CGFloat scale = autoScales ? fmin(NSHeight(bounds) /
NSHeight(pageRect), NSWidth(bounds) / NSWidth(pageRect)) : 1.0;
+ pageRect = NSInsetRect(bounds, 0.5 * (NSWidth(bounds) - scale *
NSWidth(pageRect)), 0.5 * (NSHeight(bounds) - scale * NSHeight(pageRect)));
+ CGContextRef context = [[NSGraphicsContext
graphicsContextWithBitmapImageRep:imageRep] CGContext];
+
+ CGContextSaveGState(context);
+ CGContextSetFillColorWithColor(context,
CGColorGetConstantColor(kCGColorWhite));
+ CGContextFillRect(context,
SKPixelAlignedRect(NSRectToCGRect(pageRect), context));
+ CGContextRestoreGState(context);
+ CGContextSaveGState(context);
+ CGContextSetInterpolationQuality(context, [[NSUserDefaults
standardUserDefaults] integerForKey:SKInterpolationQualityKey] + 1);
+ CGContextTranslateCTM(context, NSMinX(pageRect), NSMinY(pageRect));
+ CGContextScaleCTM(context, scale, scale);
+ [thePage drawWithBox:kPDFDisplayBoxCropBox toContext:context];
+ CGContextRestoreGState(context);
+
+ NSImage *image = [[NSImage alloc] initWithSize:bounds.size];
+ [image addRepresentation:imageRep];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ if (thePage == page)
+ [[pageView layer] setContents:image];
+ if (completionHandler)
+ completionHandler();
+
+ });
+
+ });
}
-- (BOOL)layer:(CALayer *)aLayer shouldInheritContentsScale:(CGFloat)newScale
fromWindow:(NSWindow *)window {
- return YES;
+- (NSBitmapImageRep *)bitmapImageRepCachingDisplay {
+ NSImage *image = [[pageView layer] contents];
+ if ([image isKindOfClass:[NSImage class]]) {
+ NSImageRep *imageRep = [[image representations] firstObject];
+ if ([imageRep isKindOfClass:[NSBitmapImageRep class]])
+ return (NSBitmapImageRep *)imageRep;
+ }
+ return [super bitmapImageRepCachingDisplay];
}
@end
@@ -267,12 +318,12 @@
- (void)viewDidEndLiveResize {
[super viewDidEndLiveResize];
- [[pageView layer] setNeedsDisplay];
+ [self displayPage:nil];
}
- (void)updatedAnnotationOnPage:(PDFPage *)aPage {
if (page == aPage)
- [[pageView layer] setNeedsDisplay];
+ [self displayPage:nil];
}
#pragma mark Accessors
@@ -289,7 +340,7 @@
if (flag != pvFlags.autoScales) {
pvFlags.autoScales = flag;
[pageView setLayerContentsPlacement:flag ?
NSViewLayerContentsPlacementScaleProportionallyToFill :
NSViewLayerContentsPlacementCenter];
- [[pageView layer] setNeedsDisplay];
+ [self displayPage:nil];
[[NSNotificationCenter defaultCenter]
postNotificationName:SKPresentationViewAutoScalesChangedNotification
object:self];
}
}
Modified: trunk/SKTransitionController.h
===================================================================
--- trunk/SKTransitionController.h 2025-05-09 22:02:52 UTC (rev 15177)
+++ trunk/SKTransitionController.h 2025-05-10 15:51:27 UTC (rev 15178)
@@ -56,7 +56,7 @@
@property (nonatomic) BOOL shouldScale;
-- (void)animateView:(NSView *)view forRect:(NSRect)rect toRect:(NSRect)toRect
atIndex:(NSUInteger)anIndex forward:(BOOL)forward change:(void (^)(void))change;
+- (void)animateView:(NSView *)view forRect:(NSRect)rect toRect:(NSRect)toRect
atIndex:(NSUInteger)anIndex forward:(BOOL)forward change:(void (^)(void (^
_Nullable done)(void)))change;
@end
Modified: trunk/SKTransitionController.m
===================================================================
--- trunk/SKTransitionController.m 2025-05-09 22:02:52 UTC (rev 15177)
+++ trunk/SKTransitionController.m 2025-05-10 15:51:27 UTC (rev 15178)
@@ -171,9 +171,9 @@
return image;
}
-- (void)animateView:(NSView *)view forRect:(NSRect)rect toRect:(NSRect)toRect
atIndex:(NSUInteger)idx forward:(BOOL)forward change:(void (^)(void))change {
+- (void)animateView:(NSView *)view forRect:(NSRect)rect toRect:(NSRect)toRect
atIndex:(NSUInteger)idx forward:(BOOL)forward change:(void (^)(void
(^done)(void)))change {
if (animating) {
- change();
+ change(nil);
return;
}
@@ -183,7 +183,7 @@
if ([currentTransition style] == SKNoTransition) {
- change();
+ change(nil);
} else {
@@ -191,44 +191,46 @@
CIImage *initialImage = [self currentImageForRect:rect inView:view
scale:NULL];
- change();
+ change(^{
+
+ NSRect bounds = [view bounds];
+ CGFloat imageScale = 1.0;
+ CIImage *finalImage = [self currentImageForRect:toRect inView:view
scale:&imageScale];
+ CGRect cgRect =
CGRectIntegral(scaleRect(NSIntersectionRect(NSUnionRect(rect, toRect), bounds),
imageScale));
+ CGRect cgBounds = scaleRect(bounds, imageScale);
+ CGRect extent = [currentTransition shouldRestrict] ? cgRect :
cgBounds;
+ NSString *filterName = [currentTransition styleName];
+ CGFloat scale = shouldScale ? imageScale * NSHeight(bounds) /
NSHeight([[[view window] screen] frame]) : imageScale;
+ CIFilter *transitionFilter = [self
transitionFilterWithName:filterName
+ rect:cgRect
+ extent:extent
+ scale:scale
+ forward:forward
+
initialImage:initialImage
+
finalImage:finalImage];
+
+ if (transitionView == nil)
+ transitionView = [[SKTransitionView alloc]
initWithFrame:bounds];
+ else
+ [transitionView setFrame:bounds];
+ [transitionView setExtent:cgBounds];
+ [transitionView setFilter:transitionFilter];
+ [view addSubview:transitionView positioned:NSWindowAbove
relativeTo:nil];
- NSRect bounds = [view bounds];
- CGFloat imageScale = 1.0;
- CIImage *finalImage = [self currentImageForRect:toRect inView:view
scale:&imageScale];
- CGRect cgRect =
CGRectIntegral(scaleRect(NSIntersectionRect(NSUnionRect(rect, toRect), bounds),
imageScale));
- CGRect cgBounds = scaleRect(bounds, imageScale);
- CGRect extent = [currentTransition shouldRestrict] ? cgRect : cgBounds;
- NSString *filterName = [currentTransition styleName];
- CGFloat scale = shouldScale ? imageScale * NSHeight(bounds) /
NSHeight([[[view window] screen] frame]) : imageScale;
- CIFilter *transitionFilter = [self transitionFilterWithName:filterName
- rect:cgRect
- extent:extent
- scale:scale
- forward:forward
-
initialImage:initialImage
-
finalImage:finalImage];
+ // Update the view and its window, so it shows the correct state
when it is shown.
+ [view display];
+
+ [NSAnimationContext runAnimationGroup:^(NSAnimationContext
*context){
+ [context setDuration:[currentTransition duration]];
+ [[transitionView animator] setProgress:1.0];
+ } completionHandler:^{
+ [transitionView removeFromSuperview];
+ [transitionView setFilter:nil];
+ animating = NO;
+ }];
+
+ });
- if (transitionView == nil)
- transitionView = [[SKTransitionView alloc] initWithFrame:bounds];
- else
- [transitionView setFrame:bounds];
- [transitionView setExtent:cgBounds];
- [transitionView setFilter:transitionFilter];
- [view addSubview:transitionView positioned:NSWindowAbove
relativeTo:nil];
-
- // Update the view and its window, so it shows the correct state when
it is shown.
- [view display];
-
- [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
- [context setDuration:[currentTransition duration]];
- [[transitionView animator] setProgress:1.0];
- } completionHandler:^{
- [transitionView removeFromSuperview];
- [transitionView setFilter:nil];
- animating = NO;
- }];
-
}
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit