Revision: 25435
http://sourceforge.net/p/bibdesk/svn/25435
Author: hofman
Date: 2021-01-18 17:20:06 +0000 (Mon, 18 Jan 2021)
Log Message:
-----------
Make FVTextIcon a subclass of FVImageIcon to avoid repeating a lot of code,
main difference is drawing the source image. Remove unused old QTKit code from
FVMovieIcon, mostly commented out anyway.
Modified Paths:
--------------
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVImageIcon.m
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.h
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.m
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.h
trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.m
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVImageIcon.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVImageIcon.m 2021-01-18
16:48:31 UTC (rev 25434)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVImageIcon.m 2021-01-18
17:20:06 UTC (rev 25435)
@@ -115,6 +115,9 @@
[self releaseResources];
}
+// this is overridden by FVTextIcon, which uses a default page size
+- (NSSize)_defaultSize { return FVDefaultThumbnailSize(); }
+
// only guaranteed to have _thumbnailSize; returning NSZeroSize causes
_drawingRectWithRect: to return garbage
- (NSSize)size {
if (NO == NSEqualSizes(_fullSize, NSZeroSize))
@@ -122,7 +125,7 @@
else if (NO == NSEqualSizes(_thumbnailSize, NSZeroSize))
return _thumbnailSize;
else
- return FVDefaultThumbnailSize();
+ return [self _defaultSize];
}
- (BOOL)needsRenderForSize:(NSSize)size
@@ -142,16 +145,11 @@
return needsRender;
}
-// FVMovieIcon overrides this to provide its TIFF data
-- (CFDataRef)_copyDataForImageSourceWhileLocked
-{
- return (CFDataRef)[[NSData allocWithZone:FVDefaultZone()]
initWithContentsOfURL:_fileURL options:NSUncachedRead error:NULL];
-}
+// Overridden by subclasses to provide their own source image
+- (CGImageRef)_copySourceImageAtFullSize:(BOOL *)isFullSize {
+ CGImageRef image = NULL;
+ CFDataRef imageData = (CFDataRef)[[NSData allocWithZone:FVDefaultZone()]
initWithContentsOfURL:_fileURL options:NSUncachedRead error:NULL];
-- (CGImageRef)_copyImageWhileLocked {
- CGImageRef image = NULL;
- CFDataRef imageData = [self _copyDataForImageSourceWhileLocked];
-
if (imageData) {
CGImageSourceRef src = CGImageSourceCreateWithData(imageData,
_imsrcOptions);
CFRelease(imageData);
@@ -162,6 +160,8 @@
}
}
+ *isFullSize = NO;
+
return image;
}
@@ -221,13 +221,17 @@
// local references for disk caching so we can unlock and draw earlier
CGImageRef fullImage = NULL, thumbnail = NULL;
- CGImageRef sourceImage = [self _copyImageWhileLocked];
+ BOOL isFullSize = NO;
+ CGImageRef sourceImage = [self _copySourceImageAtFullSize:&isFullSize];
// Now we have a thumbnail, create the full image so we have both of them
in the cache. Originally only the large image was cached to disk, and then
only if it was actually resampled. ImageIO is fast, in general, so
FVCGImageCache doesn't really benefit us significantly. The problem is
FVMovieIcon, which hits the main thread to get image data. To avoid hiccups in
the subclass, then, we'll just cache both images for consistency.
if (sourceImage) {
- // limit the size for better drawing/memory performance
- _fullImage = FVCreateResampledFullImage(sourceImage);
+ // limit the size for better drawing/memory performance if it's not
yet ok
+ if (isFullSize)
+ _fullImage = CGImageRetain(sourceImage);
+ else
+ _fullImage = FVCreateResampledFullImage(sourceImage);
fullImage = CGImageRetain(_fullImage);
// resample the original image for better quality
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.h
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.h 2021-01-18
16:48:31 UTC (rev 25434)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.h 2021-01-18
17:20:06 UTC (rev 25435)
@@ -38,7 +38,6 @@
#import <Cocoa/Cocoa.h>
#import "FVImageIcon.h"
-#import "FVIcon_Private.h"
@interface FVMovieIcon : FVImageIcon
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.m 2021-01-18
16:48:31 UTC (rev 25434)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVMovieIcon.m 2021-01-18
17:20:06 UTC (rev 25435)
@@ -37,74 +37,19 @@
*/
#import "FVMovieIcon.h"
+#import "FVIcon_Private.h"
#import "FVFinderIcon.h"
-#import "FVAllocator.h"
-#import "FVOperationQueue.h"
-#import "FVInvocationOperation.h"
#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >=
MAC_OS_X_VERSION_10_7
#import <AVFoundation/AVFoundation.h>
#endif
-/* @@ QTKit
-#import <QTKit/QTKit.h>
- */
-
@interface FVImageIcon (Private)
-- (CFDataRef)_copyDataForImageSourceWhileLocked;
-- (CGImageRef)_copyImageWhileLocked;
+- (CGImageRef)_copySourceImageAtFullSize:(BOOL *)isFullSize;
@end
@implementation FVMovieIcon
-/*
- QTMovie can't be used from multiple threads simultaneously, since the
underlying C functions apparently aren't thread safe. Deallocation in
particular seems to crash. In addition, Christiaan found a case where a QT
component tried to display a window and ended up trying to run NSApp in a modal
session from a thread. While modal windows are supposed to work from a thread,
it appeared to cause a crash in some Carbon window drawing code.
-
- If performance problems are evident, we could just use Quick Look for
thumbnailing movies, but I don't see any problems dropping ~200 movies on the
test program window.
-
- Note: QTKit on 10.5 has enterQTKitOnThread/exitQTKitOnThread, which might be
worth investigating as well. Another note: enterQTKitOnThread does not seem to
help, even locking beforehand so multiple threads aren't calling it
simultaneously. Trying to load certain wmv files causes it to crash very
reliably.
-
- */
-
-- (NSData *)_copyTIFFDataFromMovie
-{
- NSAssert2(pthread_main_np() != 0, @"*** threading violation *** +[%@ %@]
requires main thread", self, NSStringFromSelector(_cmd));
- NSData *data = nil;
-/* @@ QTKit
- NSMutableDictionary *attributes = [NSMutableDictionary new];
- [attributes setObject:_fileURL forKey:QTMovieURLAttribute];
-
- // Loading
/DevTools/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/QuickTime/REF/Effects/gradwip2.mov
puts up a stupid modal dialog about searching for resources /after/ blocking
for a long time.
- [attributes setObject:[NSNumber numberWithBool:NO]
forKey:QTMovieResolveDataRefsAttribute];
-
- // QTMovieResolveDataRefsAttribute = NO probably implies
QTMovieAskUnresolvedDataRefsAttribute = NO ...
- [attributes setObject:[NSNumber numberWithBool:NO]
forKey:QTMovieAskUnresolvedDataRefsAttribute];
-
- // failed atttempt to stop Flip4Mac from putting up a progress bar during
loads
- [attributes setObject:[NSNumber numberWithBool:YES]
forKey:QTMovieDontInteractWithUserAttribute];
-
- QTMovie *movie = [[QTMovie alloc] initWithAttributes:attributes
error:NULL];
- [attributes release];
-
- // Is poster time something the movie producer sets? Always zero on my
tests, which is typically a black screen. Quick Look uses some non-zero time,
but it doesn't seem to be a fixed percentage.
- QTTime movieTime = [[movie attributeForKey:QTMovieDurationAttribute]
QTTimeValue];
- NSValue *timeValue = [movie attributeForKey:QTMovieCurrentTimeAttribute];
- if (nil == timeValue || QTTimeCompare(QTZeroTime, [timeValue QTTimeValue])
== NSOrderedSame)
- timeValue = [movie attributeForKey:QTMoviePosterTimeAttribute];
-
- QTTime timeToGet = QTZeroTime;
- if (timeValue && QTTimeCompare(QTZeroTime, [timeValue QTTimeValue]) ==
NSOrderedSame) {
- // 4% or 10 seconds, whichever is smaller
- NSTimeInterval frameTime = MIN((movieTime.timeValue /
movieTime.timeScale) * 0.04, 10);
- timeToGet = QTMakeTimeWithTimeInterval(frameTime);
- }
- data = [[[movie frameImageAtTime:timeToGet] TIFFRepresentation] retain];
- [movie release];
- */
-
- return data;
-}
-
+ (BOOL)canInitWithURL:(NSURL *)aURL withType:(NSString *)type
{
if (false == UTTypeConformsTo((CFStringRef)type, kUTTypeMovie))
@@ -118,9 +63,6 @@
if (UTTypeEqual((CFStringRef)type,
FVSTR("com.microsoft.windows-media-wmv")))
return NO;
-/* @@ QTKit
- return [QTMovie canInitWithURL:aURL];
- */
#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7
return NO;
#else
@@ -140,36 +82,12 @@
#endif
}
-- (BOOL)canReleaseResources;
-{
- return NULL != _fullImage;
-}
-
-// object is locked while this is called, so we can manipulate ivars
-- (CFDataRef)_copyDataForImageSourceWhileLocked
-{
- NSAssert2([self tryLock] == NO, @"*** threading violation *** -[%@ %@]
requires caller to lock self", [self class], NSStringFromSelector(_cmd));
-
- FVInvocationOperation *op;
- op = [[FVInvocationOperation alloc] initWithTarget:self
selector:@selector(_copyTIFFDataFromMovie) object:nil];
- [op setConcurrent:NO];
- [[FVOperationQueue mainQueue] addOperation:op];
- while (NO == [op isFinished])
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, TRUE);
-
- CFDataRef data = (CFDataRef)[op copyResult];
- // result isn't owned by the operation, but the containing invocation is
- [op release];
-
- // superclass will cache the resulting images to disk unconditionally, in
order to avoid hitting the main thread again
- return data;
-}
-
#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >=
MAC_OS_X_VERSION_10_7
-- (CGImageRef)_copyImageWhileLocked {
+// overridden from FVImageIcon to provide a movie frame rather than an image
from an image source
+- (CGImageRef)_copySourceImageAtFullSize:(BOOL *)isFullSize {
if ([AVAsset self] == Nil)
- return [super _copyImageWhileLocked];
+ return [super _copySourceImageAtFullSize:isFullSize];
AVAsset *asset = [[AVURLAsset alloc] initWithURL:_fileURL options:nil];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc]
initWithAsset:asset];
CMTime time = [asset duration];
@@ -178,6 +96,9 @@
CGImageRef image = [imageGenerator copyCGImageAtTime:time actualTime:NULL
error:NULL];
[imageGenerator release];
[asset release];
+
+ *isFullSize = NO;
+
return image;
}
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.h
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.h 2021-01-18
16:48:31 UTC (rev 25434)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.h 2021-01-18
17:20:06 UTC (rev 25435)
@@ -37,15 +37,11 @@
*/
#import <Cocoa/Cocoa.h>
-#import "FVBaseIcon.h"
+#import "FVImageIcon.h"
-@interface FVTextIcon : FVBaseIcon
+@interface FVTextIcon : FVImageIcon
{
@protected
- CGImageRef _fullImage;
- NSSize _fullSize;
- CGImageRef _thumbnail;
- NSSize _thumbnailSize;
BOOL _isPlainText;
}
Modified: trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.m
===================================================================
--- trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.m 2021-01-18
16:48:31 UTC (rev 25434)
+++ trunk/bibdesk_vendorsrc/amaxwell/FileView/FVTextIcon.m 2021-01-18
17:20:06 UTC (rev 25435)
@@ -38,8 +38,6 @@
#import "FVTextIcon.h"
#import "FVIcon_Private.h"
-#import "FVOperation.h"
-#import "FVOperationQueue.h"
@implementation FVTextIcon
@@ -77,10 +75,6 @@
{
self = [super initWithURL:aURL drawsLinkBadge:drawsLinkBadge];
if (self) {
- _fullSize = NSZeroSize;
- _thumbnailSize = NSZeroSize;
- _fullImage = NULL;
- _thumbnail = NULL;
_isPlainText = isPlainText;
}
return self;
@@ -91,118 +85,11 @@
return [self initWithURL:aURL drawsLinkBadge:drawsLinkBadge
isPlainText:NO];
}
-- (void)dealloc
-{
- CGImageRelease(_fullImage);
- CGImageRelease(_thumbnail);
- [super dealloc];
+// overridden from FVImageIcon, we use default page size by default
+- (NSSize)_defaultSize {
+ return NSMakeSize(FVDefaultPaperWidth * FVDefaultScale,
FVDefaultPaperHeight * FVDefaultScale);
}
-// _fullSize can be NSZeroSize when only _thumbnail was retrieved from cache;
returning NSZeroSize causes _drawingRectWithRect: to return garbage
-- (NSSize)size {
- if (NO == NSEqualSizes(_fullSize, NSZeroSize))
- return _fullSize;
- else if (NO == NSEqualSizes(_thumbnailSize, NSZeroSize))
- return _thumbnailSize;
- else
- return NSMakeSize(FVDefaultPaperWidth * FVDefaultScale,
FVDefaultPaperHeight * FVDefaultScale);
-}
-
-- (BOOL)needsRenderForSize:(NSSize)size {
- BOOL needsRender = NO;
- // if we can't lock we're already rendering, which will give us both icons
(so no render required)
- if ([self tryLock]) {
- if (FVShouldDrawFullImageWithThumbnailSize(size, _thumbnailSize))
- needsRender = (NULL == _fullImage);
- else
- needsRender = (NULL == _thumbnail);
- [self unlock];
- }
- return needsRender;
-}
-
-// It turns out to be fairly important to draw small text icons if possible,
since the bitmaps have a pretty huge memory footprint (if we draw _fullImage
all the time, dragging in the view is unbearably slow if there are more than a
couple of text icons). Using trylock for drawing to avoid stalling the main
thread while rendering; there are some degenerate cases where rendering is
really slow (e.g. a huge ASCII grid file).
-- (void)fastDrawInRect:(NSRect)dstRect ofContext:(CGContextRef)context;
-{
- // draw thumbnail if present, regardless of the size requested
- if (NO == [self tryLock]) {
- // no lock, so just draw the blank page and bail out
- [self _drawPlaceholderInRect:dstRect ofContext:context];
- }
- else if (NULL == _thumbnail) {
- [self unlock];
- [self _drawPlaceholderInRect:dstRect ofContext:context];
- }
- else if (_thumbnail) {
- CGContextDrawImage(context, [self _drawingRectWithRect:dstRect],
_thumbnail);
- [self unlock];
- if (_drawsLinkBadge) {
- // get rid of any shadow, or we may draw a text shadow if the page
is transparent
- CGContextSaveGState(context);
- CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
- [self _badgeIconInRect:dstRect ofContext:context];
- CGContextSaveGState(context);
- }
- }
- else {
- [self unlock];
- // let drawInRect: handle the rect conversion
- [self drawInRect:dstRect ofContext:context];
- }
-}
-
-- (void)drawInRect:(NSRect)dstRect ofContext:(CGContextRef)context;
-{
- if (NO == [self tryLock]) {
- [self _drawPlaceholderInRect:dstRect ofContext:context];
- }
- else {
- CGRect drawRect = [self _drawingRectWithRect:dstRect];
- CGImageRef toDraw = _thumbnail;
-
- if
(FVShouldDrawFullImageWithThumbnailSize(FVSizeForRectInContext(dstRect,
context), _thumbnailSize))
- toDraw = _fullImage;
-
- // draw the image if it's been created, or just draw a dummy icon
- if (toDraw) {
- CGContextDrawImage(context, drawRect, toDraw);
- [self unlock];
- if (_drawsLinkBadge) {
- // get rid of any shadow, or we may draw a text shadow if the
page is transparent
- CGContextSaveGState(context);
- CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
- [self _badgeIconInRect:dstRect ofContext:context];
- CGContextSaveGState(context);
- }
- }
- else {
- [self unlock];
- [self _drawPlaceholderInRect:dstRect ofContext:context];
- }
- }
-}
-
-- (BOOL)canReleaseResources;
-{
- return (NULL != _fullImage || NULL != _thumbnail);
-}
-
-- (void)releaseResources
-{
- [self lock];
- CGImageRelease(_fullImage);
- _fullImage = NULL;
- CGImageRelease(_thumbnail);
- _thumbnail = NULL;
- [self unlock];
-}
-
-- (void)recache;
-{
- [FVCGImageCache invalidateCachesForKey:_cacheKey];
- [self releaseResources];
-}
-
- (CGImageRef)_newImageWithAttributedString:(NSMutableAttributedString
*)attrString documentAttributes:(NSDictionary *)documentAttributes
{
NSParameterAssert(attrString);
@@ -286,67 +173,17 @@
return image;
}
-- (void)renderForSize:(NSSize)size
-{
- [[self class] _startRenderingForKey:_cacheKey];
-
- // hold the lock to let needsRenderForSize: know that this icon doesn't
need rendering
- [self lock];
-
- if ([NSThread instancesRespondToSelector:@selector(setName:)] &&
pthread_main_np() == 0)
- [[NSThread currentThread] setName:[_fileURL path]];
-
- // !!! two early returns here after a cache check
-
- if (NULL != _fullImage) {
- // note that _fullImage may be non-NULL if we were added to the
FVOperationQueue multiple times before renderForSize: was called
- [self unlock];
- [[self class] _stopRenderingForKey:_cacheKey];
- return;
- }
- else {
-
- if (NULL == _thumbnail) {
- _thumbnail = [FVCGImageCache newThumbnailForKey:_cacheKey];
- _thumbnailSize = FVCGImageSize(_thumbnail);
- }
-
- if (NULL != _thumbnail) {
-
- if (FVShouldDrawFullImageWithThumbnailSize(size, _thumbnailSize)) {
- _fullImage = [FVCGImageCache newImageForKey:_cacheKey];
- if (NULL != _fullImage) {
- _fullSize = FVCGImageSize(_fullImage);
- [self unlock];
- [[self class] _stopRenderingForKey:_cacheKey];
- return;
- }
- }
- else {
- [self unlock];
- [[self class] _stopRenderingForKey:_cacheKey];
- return;
- }
- }
- }
-
- /*
- At this point, neither icon should be present, unless ImageIO failed
previously or caching failed.
- However, if multiple views are caching icons at the same time, we can end
up here with a thumbnail
- but no full image.
- */
- NSParameterAssert(NULL == _fullImage);
-
+// overridden from FVImageIcon to get an image based on an attributed string
+- (CGImageRef)_copySourceImageAtFullSize:(BOOL *)isFullSize {
// originally kept the attributed string as an ivar, but it's not worth it
in most cases
- // no need to lock for -fileURL since it's invariant
NSDictionary *documentAttributes = nil;
NSMutableAttributedString *attrString = nil;
- /*
- This is a minor optimization: NSAttributedString creates a bunch of
temporary objects for pasteboard
- translation when reading a file, but we avoid that by loading with
NSString directly. Interestingly,
- this also appears to be at least a partial workaround for
rdar://problem/5775728 (CoreGraphics memory leaks),
+ /*
+ This is a minor optimization: NSAttributedString creates a bunch of
temporary objects for pasteboard
+ translation when reading a file, but we avoid that by loading with
NSString directly. Interestingly,
+ this also appears to be at least a partial workaround for
rdar://problem/5775728 (CoreGraphics memory leaks),
since Instruments shows I'm only leaking a single
NSConcreteAttributedString here now.
*/
if (_isPlainText) {
@@ -364,7 +201,7 @@
// not plain text, so try to load with NSAttributedString
if (nil == attrString) {
/*
- Occasionally NSAttributedString might end up calling
NSHTMLReader/WebKit to load a file, which raises
+ Occasionally NSAttributedString might end up calling
NSHTMLReader/WebKit to load a file, which raises
an exception and crashes on 10.4. The workaround is to always load
on the main thread on 10.4.
*/
attrString = [[NSMutableAttributedString allocWithZone:[self zone]]
initWithURL:_fileURL documentAttributes:&documentAttributes];
@@ -372,47 +209,18 @@
// plain text failed and so did NSAttributedString, so display a mildly
unhelpful error message
if (nil == attrString) {
- NSBundle *bundle = [NSBundle bundleForClass:[FVTextIcon class]];
+ NSBundle *bundle = [NSBundle bundleForClass:[FVTextIcon class]];
NSString *err = [NSLocalizedStringFromTableInBundle(@"Unable to read
text file ", @"FileView", bundle, @"error message with single trailing space")
stringByAppendingString:[_fileURL path]];
attrString = [[NSMutableAttributedString alloc] initWithString:err];
}
FVAPIParameterAssert(nil != attrString);
- CGImageRelease(_fullImage);
- _fullImage = [self _newImageWithAttributedString:attrString
documentAttributes:documentAttributes];
- [attrString release];
-
- if (NULL != _fullImage) {
- // reset size while we have the lock, since it may be different now
that we've read the string
- _fullSize = FVCGImageSize(_fullImage);
- }
-
- // resample the existing bitmap to create a thumbnail image
- if (NULL == _thumbnail)
- _thumbnail = FVCreateResampledThumbnail(_fullImage);
-
- // local copies for caching
- CGImageRef fullImage = CGImageRetain(_fullImage), thumbnail =
CGImageRetain(_thumbnail);
-
- if (NULL != _thumbnail)
- _thumbnailSize = FVCGImageSize(_thumbnail);
+ CGImageRef image = [self _newImageWithAttributedString:attrString
documentAttributes:documentAttributes];
- // get rid of this to save memory if we aren't drawing it right away
- if (FVShouldDrawFullImageWithThumbnailSize(size, _thumbnailSize) == NO) {
- CGImageRelease(_fullImage);
- _fullImage = NULL;
- }
+ // don't need to resample for _fullImage
+ *isFullSize = YES;
- // can draw now
- [self unlock];
-
- // cache and release
- if (fullImage) [FVCGImageCache cacheImage:fullImage forKey:_cacheKey];
- CGImageRelease(fullImage);
- if (thumbnail) [FVCGImageCache cacheThumbnail:thumbnail forKey:_cacheKey];
- CGImageRelease(thumbnail);
-
- [[self class] _stopRenderingForKey:_cacheKey];
+ return image;
}
@end
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Bibdesk-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bibdesk-commit