2001-12-17 16:51:51 +00:00
|
|
|
/** <title>NSImage</title>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
<abstract>Load, manipulate and display images</abstract>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
Copyright (C) 1996, 2005 Free Software Foundation, Inc.
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
Author: Adam Fedor <fedor@colorado.edu>
|
1996-08-22 18:51:08 +00:00
|
|
|
Date: Feb 1996
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
This library is free software; you can redistribute it and/or
|
2007-10-29 21:16:17 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1996-05-30 20:03:15 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-10 04:01:49 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2007-10-29 21:16:17 +00:00
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2007-10-29 21:16:17 +00:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1996-10-18 17:14:13 +00:00
|
|
|
License along with this library; see the file COPYING.LIB.
|
2007-10-29 21:16:17 +00:00
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2003-07-31 23:52:10 +00:00
|
|
|
#include "config.h"
|
1997-02-18 00:29:25 +00:00
|
|
|
#include <string.h>
|
2005-01-24 23:28:07 +00:00
|
|
|
#include <math.h>
|
1997-02-18 00:29:25 +00:00
|
|
|
|
2009-09-27 08:54:03 +00:00
|
|
|
#import <Foundation/NSArray.h>
|
|
|
|
#import <Foundation/NSBundle.h>
|
|
|
|
#import <Foundation/NSDebug.h>
|
|
|
|
#import <Foundation/NSDictionary.h>
|
|
|
|
#import <Foundation/NSException.h>
|
|
|
|
#import <Foundation/NSFileManager.h>
|
|
|
|
#import <Foundation/NSLock.h>
|
|
|
|
#import <Foundation/NSKeyedArchiver.h>
|
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
|
|
|
|
#import "AppKit/NSImage.h"
|
|
|
|
|
|
|
|
#import "AppKit/AppKitExceptions.h"
|
|
|
|
#import "AppKit/NSAffineTransform.h"
|
|
|
|
#import "AppKit/NSBitmapImageRep.h"
|
|
|
|
#import "AppKit/NSCachedImageRep.h"
|
|
|
|
#import "AppKit/NSColor.h"
|
|
|
|
#import "AppKit/NSPasteboard.h"
|
|
|
|
#import "AppKit/NSPrintOperation.h"
|
|
|
|
#import "AppKit/NSScreen.h"
|
|
|
|
#import "AppKit/NSView.h"
|
|
|
|
#import "AppKit/NSWindow.h"
|
|
|
|
#import "AppKit/PSOperators.h"
|
|
|
|
#import "GNUstepGUI/GSDisplayServer.h"
|
|
|
|
#import "GSThemePrivate.h"
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
/* Helpers. Would be nicer to use the C99 fmin/fmax functions, but that
|
|
|
|
isn't currently possible. */
|
2005-02-03 09:47:38 +00:00
|
|
|
static double gs_min(double x, double y)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
|
|
|
if (x > y)
|
|
|
|
return y;
|
|
|
|
else
|
|
|
|
return x;
|
|
|
|
}
|
2005-02-03 09:47:38 +00:00
|
|
|
static double gs_max(double x, double y)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
|
|
|
if (x < y)
|
|
|
|
return y;
|
|
|
|
else
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
BOOL NSImageForceCaching = NO; /* use on missmatch */
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2002-09-25 22:55:44 +00:00
|
|
|
@implementation NSBundle (NSImageAdditions)
|
|
|
|
|
|
|
|
- (NSString*) pathForImageResource: (NSString*)name
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSString *ext = [name pathExtension];
|
|
|
|
NSString *path = nil;
|
2002-09-25 22:55:44 +00:00
|
|
|
|
|
|
|
if ((ext == nil) || [ext isEqualToString:@""])
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSArray *types = [NSImage imageUnfilteredFileTypes];
|
|
|
|
unsigned c = [types count];
|
|
|
|
unsigned i;
|
2002-09-25 22:55:44 +00:00
|
|
|
|
|
|
|
for (i = 0; path == nil && i < c; i++)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
ext = [types objectAtIndex: i];
|
|
|
|
path = [self pathForResource: name ofType: ext];
|
|
|
|
}
|
2002-09-25 22:55:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = [name stringByDeletingPathExtension];
|
|
|
|
path = [self pathForResource: name ofType: ext];
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
@interface GSRepData : NSObject
|
1999-04-28 11:16:26 +00:00
|
|
|
{
|
|
|
|
@public
|
2008-12-15 17:14:30 +00:00
|
|
|
NSImageRep *rep;
|
|
|
|
NSImageRep *original;
|
|
|
|
NSColor *bg;
|
1999-04-28 11:16:26 +00:00
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
@implementation GSRepData
|
1999-04-28 11:16:26 +00:00
|
|
|
- (id) copyWithZone: (NSZone*)z
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
GSRepData *c = (GSRepData*)NSCopyObject(self, 0, z);
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
|
|
if (c->rep)
|
2000-12-23 14:19:23 +00:00
|
|
|
c->rep = [c->rep copyWithZone: z];
|
1999-04-28 11:16:26 +00:00
|
|
|
if (c->bg)
|
2000-12-23 14:19:23 +00:00
|
|
|
c->bg = [c->bg copyWithZone: z];
|
1999-04-28 11:16:26 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
TEST_RELEASE(rep);
|
|
|
|
TEST_RELEASE(bg);
|
2009-10-10 14:10:52 +00:00
|
|
|
[super dealloc];
|
1999-04-28 11:16:26 +00:00
|
|
|
}
|
|
|
|
@end
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
/* Class variables and functions for class methods */
|
2009-09-27 08:54:03 +00:00
|
|
|
static NSRecursiveLock *imageLock = nil;
|
|
|
|
static NSMutableDictionary *nameDict = nil;
|
|
|
|
static NSDictionary *nsmapping = nil;
|
|
|
|
static NSColor *clearColor = nil;
|
2008-12-15 17:14:30 +00:00
|
|
|
static Class cachedClass = 0;
|
|
|
|
static Class bitmapClass = 0;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2003-10-30 00:23:23 +00:00
|
|
|
static NSArray *iterate_reps_for_types(NSArray *imageReps, SEL method);
|
1996-08-22 18:51:08 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
/* Find the GSRepData object holding a representation */
|
2003-10-30 00:23:23 +00:00
|
|
|
static GSRepData*
|
1996-08-22 18:51:08 +00:00
|
|
|
repd_for_rep(NSArray *_reps, NSImageRep *rep)
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSEnumerator *enumerator = [_reps objectEnumerator];
|
|
|
|
IMP nextImp = [enumerator methodForSelector: @selector(nextObject)];
|
|
|
|
GSRepData *repd;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
1999-12-02 10:35:07 +00:00
|
|
|
while ((repd = (*nextImp)(enumerator, @selector(nextObject))) != nil)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
if (repd->rep == rep)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
|
|
|
return repd;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
2008-12-15 17:14:30 +00:00
|
|
|
format: @"Cannot find stored representation"];
|
1996-08-22 18:51:08 +00:00
|
|
|
/* NOT REACHED */
|
1999-04-28 11:16:26 +00:00
|
|
|
return nil;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@interface NSImage (Private)
|
2000-12-23 14:19:23 +00:00
|
|
|
- (BOOL) _useFromFile: (NSString *)fileName;
|
|
|
|
- (BOOL) _loadFromData: (NSData *)data;
|
|
|
|
- (BOOL) _loadFromFile: (NSString *)fileName;
|
2008-12-13 19:32:54 +00:00
|
|
|
- (GSRepData*) _cacheForRep: (NSImageRep*)rep;
|
|
|
|
- (NSCachedImageRep*) _doImageCache: (NSImageRep *)rep;
|
1996-08-22 18:51:08 +00:00
|
|
|
@end
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
@implementation NSImage
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
+ (void) initialize
|
1997-03-05 01:11:17 +00:00
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
if (imageLock == nil)
|
1997-03-05 01:11:17 +00:00
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
imageLock = [NSRecursiveLock new];
|
|
|
|
[imageLock lock];
|
2001-12-02 11:45:01 +00:00
|
|
|
|
1997-03-05 01:11:17 +00:00
|
|
|
// Initial version
|
1999-03-30 13:59:35 +00:00
|
|
|
[self setVersion: 1];
|
1997-03-05 01:11:17 +00:00
|
|
|
|
|
|
|
// initialize the class variables
|
|
|
|
nameDict = [[NSMutableDictionary alloc] initWithCapacity: 10];
|
2009-09-27 08:54:03 +00:00
|
|
|
path = [NSBundle pathForLibraryResource: @"nsmapping"
|
|
|
|
ofType: @"strings"
|
|
|
|
inDirectory: @"Images"];
|
1997-12-04 01:58:57 +00:00
|
|
|
if (path)
|
2008-12-15 17:14:30 +00:00
|
|
|
nsmapping = RETAIN([[NSString stringWithContentsOfFile: path]
|
|
|
|
propertyListFromStringsFileFormat]);
|
1999-12-01 13:49:47 +00:00
|
|
|
clearColor = RETAIN([NSColor clearColor]);
|
2000-12-23 14:19:23 +00:00
|
|
|
cachedClass = [NSCachedImageRep class];
|
|
|
|
bitmapClass = [NSBitmapImageRep class];
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
1997-03-05 01:11:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
+ (id) imageNamed: (NSString *)aName
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
NSImage *image;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2009-09-10 11:02:17 +00:00
|
|
|
/* 2009-09-10 changed operation of nsmapping so that the loaded
|
|
|
|
* image is stored under the key 'aName', not under the mapped
|
|
|
|
* name. That way the image is created with the correct name and
|
|
|
|
* a later call to -setName: will work properly.
|
|
|
|
*/
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock lock];
|
|
|
|
image = (NSImage*)[nameDict objectForKey: aName];
|
2009-08-28 05:02:24 +00:00
|
|
|
if (image == nil || [(id)image _resource] == nil)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2009-09-10 11:02:17 +00:00
|
|
|
NSString *realName = [nsmapping objectForKey: aName];
|
|
|
|
NSString *ext;
|
|
|
|
NSString *path = nil;
|
|
|
|
NSBundle *main_bundle;
|
|
|
|
NSArray *array;
|
|
|
|
|
|
|
|
if (realName == nil)
|
|
|
|
{
|
|
|
|
realName = aName;
|
|
|
|
}
|
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
// FIXME: This should use [NSBundle pathForImageResource], but this will
|
|
|
|
// only allow imageUnfilteredFileTypes.
|
2000-12-23 14:19:23 +00:00
|
|
|
/* If there is no image with that name, search in the main bundle */
|
1999-10-29 18:43:48 +00:00
|
|
|
main_bundle = [NSBundle mainBundle];
|
2009-09-10 11:02:17 +00:00
|
|
|
ext = [realName pathExtension];
|
2000-10-20 04:19:22 +00:00
|
|
|
if (ext != nil && [ext length] == 0)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
ext = nil;
|
|
|
|
}
|
1997-03-20 19:23:21 +00:00
|
|
|
|
|
|
|
/* Check if extension is one of the image types */
|
|
|
|
array = [self imageFileTypes];
|
2009-09-10 11:02:17 +00:00
|
|
|
if (ext != nil && [array indexOfObject: ext] != NSNotFound)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
/* Extension is one of the image types
|
|
|
|
So remove from the name */
|
2009-09-10 11:02:17 +00:00
|
|
|
realName = [realName stringByDeletingPathExtension];
|
2008-12-15 17:14:30 +00:00
|
|
|
}
|
1997-03-20 19:23:21 +00:00
|
|
|
else
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
/* Otherwise extension is not an image type
|
|
|
|
So leave it alone */
|
|
|
|
ext = nil;
|
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
|
|
|
|
/* First search locally */
|
1996-08-22 18:51:08 +00:00
|
|
|
if (ext)
|
2009-09-10 11:02:17 +00:00
|
|
|
path = [main_bundle pathForResource: realName ofType: ext];
|
1996-08-22 18:51:08 +00:00
|
|
|
else
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
id o, e;
|
|
|
|
|
|
|
|
e = [array objectEnumerator];
|
|
|
|
while ((o = [e nextObject]))
|
|
|
|
{
|
2009-09-10 11:02:17 +00:00
|
|
|
path = [main_bundle pathForResource: realName
|
|
|
|
ofType: o];
|
2008-12-15 17:14:30 +00:00
|
|
|
if (path != nil && [path length] != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
|
2010-01-16 05:22:02 +00:00
|
|
|
/* Second search on theme bundle */
|
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
if (ext)
|
|
|
|
path = [[[GSTheme theme] bundle] pathForResource: realName ofType: ext];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id o, e;
|
|
|
|
|
|
|
|
e = [array objectEnumerator];
|
|
|
|
while ((o = [e nextObject]))
|
|
|
|
{
|
|
|
|
path = [[[GSTheme theme] bundle] pathForResource: realName
|
|
|
|
ofType: o];
|
|
|
|
if (path != nil && [path length] != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-01-31 13:40:15 +00:00
|
|
|
/* If not found then search in system */
|
|
|
|
if (!path)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
if (ext)
|
|
|
|
{
|
2009-09-10 11:02:17 +00:00
|
|
|
path = [NSBundle pathForLibraryResource: realName
|
2008-12-15 17:14:30 +00:00
|
|
|
ofType: ext
|
|
|
|
inDirectory: @"Images"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id o, e;
|
|
|
|
|
|
|
|
e = [array objectEnumerator];
|
|
|
|
while ((o = [e nextObject]))
|
|
|
|
{
|
2009-09-10 11:02:17 +00:00
|
|
|
path = [NSBundle pathForLibraryResource: realName
|
|
|
|
ofType: o
|
2008-12-15 17:14:30 +00:00
|
|
|
inDirectory: @"Images"];
|
|
|
|
if (path != nil && [path length] != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1997-01-31 13:40:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
if ([path length] != 0)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
image = [[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initByReferencingFile: path];
|
|
|
|
if (image != nil)
|
|
|
|
{
|
|
|
|
[image setName: aName];
|
|
|
|
AUTORELEASE(image);
|
|
|
|
image->_flags.archiveByName = YES;
|
|
|
|
}
|
2009-08-28 13:04:15 +00:00
|
|
|
image = (NSImage*)[nameDict objectForKey: aName];
|
2008-12-15 17:14:30 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
2009-09-27 08:54:03 +00:00
|
|
|
IF_NO_GC([[image retain] autorelease]);
|
|
|
|
[imageLock unlock];
|
2000-12-23 14:19:23 +00:00
|
|
|
return image;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
2004-10-30 11:19:07 +00:00
|
|
|
+ (NSImage *) _standardImageWithName: (NSString *)name
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSImage *image = nil;
|
2004-10-30 11:19:07 +00:00
|
|
|
|
|
|
|
image = [NSImage imageNamed: name];
|
|
|
|
if (image == nil)
|
|
|
|
image = [NSImage imageNamed: [@"common_" stringByAppendingString: name]];
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
return [self initWithSize: NSMakeSize(0, 0)];
|
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (id) initWithSize: (NSSize)aSize
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
if (!(self = [super init]))
|
|
|
|
return nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
//_flags.archiveByName = NO;
|
|
|
|
//_flags.scalable = NO;
|
|
|
|
//_flags.dataRetained = NO;
|
|
|
|
//_flags.flipDraw = NO;
|
1996-08-22 18:51:08 +00:00
|
|
|
if (aSize.width && aSize.height)
|
|
|
|
{
|
2002-02-25 17:39:11 +00:00
|
|
|
_size = aSize;
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.sizeWasExplicitlySet = YES;
|
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
//_flags.usesEPSOnResolutionMismatch = NO;
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.colorMatchPreferred = YES;
|
|
|
|
_flags.multipleResolutionMatching = YES;
|
2001-08-11 18:34:22 +00:00
|
|
|
//_flags.cacheSeparately = NO;
|
|
|
|
//_flags.unboundedCacheDepth = NO;
|
|
|
|
//_flags.syncLoad = NO;
|
|
|
|
_reps = [[NSMutableArray alloc] initWithCapacity: 2];
|
|
|
|
ASSIGN(_color, clearColor);
|
2003-01-21 05:08:26 +00:00
|
|
|
_cacheMode = NSImageCacheDefault;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1999-03-26 15:59:01 +00:00
|
|
|
- (id) initByReferencingFile: (NSString *)fileName
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
if (!(self = [self init]))
|
|
|
|
return nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
if (![self _useFromFile: fileName])
|
1999-03-26 15:59:01 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
1999-03-26 15:59:01 +00:00
|
|
|
}
|
2001-09-16 19:44:11 +00:00
|
|
|
_flags.archiveByName = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-03-26 15:59:01 +00:00
|
|
|
- (id) initWithContentsOfFile: (NSString *)fileName
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
if (!(self = [self init]))
|
2005-11-24 13:48:41 +00:00
|
|
|
return nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
_flags.dataRetained = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
if (![self _loadFromFile: fileName])
|
1999-03-26 15:59:01 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
1999-03-26 15:59:01 +00:00
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
- (id) initWithData: (NSData *)data
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
if (!(self = [self init]))
|
2005-11-24 13:48:41 +00:00
|
|
|
return nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
_flags.dataRetained = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
if (![self _loadFromData: data])
|
1999-03-26 15:59:01 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
1999-03-26 15:59:01 +00:00
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
- (id) initWithBitmapHandle: (void *)bitmap
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2010-09-12 16:34:22 +00:00
|
|
|
NSImageRep *rep;
|
2000-12-24 14:05:12 +00:00
|
|
|
|
2010-09-12 16:34:22 +00:00
|
|
|
if (!(self = [self init]))
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
rep = [[NSBitmapImageRep alloc] initWithBitmapHandle: bitmap];
|
2000-12-24 14:05:12 +00:00
|
|
|
if (rep == nil)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
|
2000-12-24 14:05:12 +00:00
|
|
|
[self addRepresentation: rep];
|
2003-07-25 22:14:40 +00:00
|
|
|
RELEASE(rep);
|
2000-12-24 14:05:12 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (id)initWithIconHandle:(void *)icon
|
|
|
|
{
|
|
|
|
// Only needed on MS Windows
|
2010-09-12 16:34:22 +00:00
|
|
|
NSImageRep *rep;
|
2000-12-24 14:05:12 +00:00
|
|
|
|
2010-09-12 16:34:22 +00:00
|
|
|
if (!(self = [self init]))
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
rep = [[NSBitmapImageRep alloc] initWithIconHandle: icon];
|
2000-12-24 14:05:12 +00:00
|
|
|
if (rep == nil)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
|
2000-12-24 14:05:12 +00:00
|
|
|
[self addRepresentation: rep];
|
2003-07-25 22:14:40 +00:00
|
|
|
RELEASE(rep);
|
2000-12-24 14:05:12 +00:00
|
|
|
return self;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 07:51:58 +00:00
|
|
|
- (id) initWithContentsOfURL: (NSURL *)anURL
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2010-09-12 16:34:22 +00:00
|
|
|
NSArray *array;
|
2000-12-24 14:05:12 +00:00
|
|
|
|
2010-09-12 16:34:22 +00:00
|
|
|
if (!(self = [self init]))
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
array = [NSImageRep imageRepsWithContentsOfURL: anURL];
|
2000-12-24 14:05:12 +00:00
|
|
|
if (!array)
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.dataRetained = YES;
|
2000-12-24 14:05:12 +00:00
|
|
|
[self addRepresentations: array];
|
|
|
|
return self;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithPasteboard: (NSPasteboard *)pasteboard
|
|
|
|
{
|
2005-11-24 13:48:41 +00:00
|
|
|
NSArray *reps;
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
if (!(self = [self init]))
|
2005-11-24 13:48:41 +00:00
|
|
|
return nil;
|
|
|
|
|
|
|
|
reps = [NSImageRep imageRepsWithPasteboard: pasteboard];
|
2000-12-23 14:19:23 +00:00
|
|
|
if (reps != nil)
|
|
|
|
[self addRepresentations: reps];
|
|
|
|
else
|
|
|
|
{
|
2003-06-24 22:57:12 +00:00
|
|
|
NSArray *array = [pasteboard propertyListForType: NSFilenamesPboardType];
|
|
|
|
NSString* file;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2003-06-24 22:57:12 +00:00
|
|
|
if ((array == nil) || ([array count] == 0) ||
|
2008-12-15 17:14:30 +00:00
|
|
|
(file = [array objectAtIndex: 0]) == nil ||
|
|
|
|
![self _loadFromFile: file])
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
RELEASE(self);
|
|
|
|
return nil;
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.dataRetained = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) dealloc
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2009-11-12 12:44:40 +00:00
|
|
|
if (_name == nil)
|
|
|
|
{
|
|
|
|
RELEASE(_reps);
|
|
|
|
TEST_RELEASE(_fileName);
|
|
|
|
RELEASE(_color);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self retain];
|
|
|
|
NSLog(@"Warning ... attempt to deallocate image with name: %@", _name);
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (id) copyWithZone: (NSZone *)zone
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSImage *copy;
|
2000-12-24 14:05:12 +00:00
|
|
|
NSArray *reps = [self representations];
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
NSImageRep *rep;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1997-07-07 16:56:52 +00:00
|
|
|
copy = (NSImage*)NSCopyObject (self, 0, zone);
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2009-11-13 07:51:58 +00:00
|
|
|
copy->_name = nil;
|
2000-12-23 14:19:23 +00:00
|
|
|
RETAIN(_fileName);
|
1999-12-01 13:49:47 +00:00
|
|
|
RETAIN(_color);
|
2000-12-23 14:19:23 +00:00
|
|
|
copy->_lockedView = nil;
|
2001-08-11 18:34:22 +00:00
|
|
|
// FIXME: maybe we should retain if _flags.dataRetained = NO
|
2000-12-24 14:05:12 +00:00
|
|
|
copy->_reps = [[NSMutableArray alloc] initWithCapacity: [_reps count]];
|
|
|
|
|
|
|
|
// Only copy non-cached reps.
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if (![rep isKindOfClass: cachedClass])
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
[copy addRepresentation: rep];
|
|
|
|
}
|
2000-12-24 14:05:12 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2010-05-09 06:55:33 +00:00
|
|
|
/* This methd sets the name of an image, updating the global name dictionary
|
|
|
|
* to point to the image (or removing an image from the dictionary if the
|
|
|
|
* new name is nil).
|
2009-08-27 06:03:16 +00:00
|
|
|
* The images are actually accessed via proxy objects, so that when a
|
2010-05-09 06:55:33 +00:00
|
|
|
* new system image is set (using [NSImage+_setImage:name:]), the proxy
|
|
|
|
* for that image just starts using the new version.
|
2009-08-27 06:03:16 +00:00
|
|
|
*/
|
2002-04-03 16:59:43 +00:00
|
|
|
- (BOOL) setName: (NSString *)aName
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2009-02-10 14:32:08 +00:00
|
|
|
GSThemeProxy *proxy = nil;
|
2001-08-13 11:07:39 +00:00
|
|
|
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock lock];
|
|
|
|
|
2009-08-27 06:03:16 +00:00
|
|
|
/* The name is already set... nothing to do.
|
|
|
|
*/
|
|
|
|
if (aName == _name || [aName isEqual: _name] == YES)
|
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
2009-08-27 06:03:16 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the new name is already in use by another image,
|
|
|
|
* we must do nothing.
|
|
|
|
*/
|
|
|
|
if (aName != nil && [[nameDict objectForKey: aName] _resource] != nil)
|
2001-08-13 11:07:39 +00:00
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
2009-02-10 14:32:08 +00:00
|
|
|
return NO;
|
|
|
|
}
|
2009-08-27 06:03:16 +00:00
|
|
|
|
|
|
|
/* If this image had another name, we remove it.
|
|
|
|
*/
|
2009-09-27 08:54:03 +00:00
|
|
|
if (_name != nil)
|
2009-02-10 14:32:08 +00:00
|
|
|
{
|
|
|
|
/* We retain self in case removing from the dictionary releases us */
|
|
|
|
IF_NO_GC([[self retain] autorelease]);
|
2009-09-27 08:54:03 +00:00
|
|
|
[nameDict removeObjectForKey: _name];
|
2009-08-27 06:03:16 +00:00
|
|
|
DESTROY(_name);
|
2001-08-13 11:07:39 +00:00
|
|
|
}
|
|
|
|
|
2009-08-27 06:03:16 +00:00
|
|
|
/* If the new name is null, there is nothing more to do.
|
|
|
|
*/
|
|
|
|
if (aName == nil)
|
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
2009-08-27 06:03:16 +00:00
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2002-04-03 16:59:43 +00:00
|
|
|
ASSIGN(_name, aName);
|
2001-08-13 11:07:39 +00:00
|
|
|
|
2009-02-08 11:02:57 +00:00
|
|
|
if ((proxy = [nameDict objectForKey: _name]) == nil)
|
|
|
|
{
|
2009-02-10 14:32:08 +00:00
|
|
|
proxy = [GSThemeProxy alloc];
|
2009-02-08 11:02:57 +00:00
|
|
|
[nameDict setObject: proxy forKey: _name];
|
|
|
|
[proxy release];
|
|
|
|
}
|
2009-02-10 14:32:08 +00:00
|
|
|
[proxy _setResource: self];
|
2001-08-13 11:07:39 +00:00
|
|
|
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
1996-08-22 18:51:08 +00:00
|
|
|
return YES;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (NSString *) name
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2009-09-27 08:54:03 +00:00
|
|
|
NSString *name;
|
|
|
|
|
|
|
|
[imageLock lock];
|
|
|
|
name = [[_name retain] autorelease];
|
|
|
|
[imageLock unlock];
|
|
|
|
return name;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
- (void) setSize: (NSSize)aSize
|
|
|
|
{
|
2002-02-26 14:37:55 +00:00
|
|
|
// Optimized as this is called very often from NSImageCell
|
|
|
|
if (NSEqualSizes(_size, aSize))
|
|
|
|
return;
|
|
|
|
|
2002-02-25 17:39:11 +00:00
|
|
|
_size = aSize;
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.sizeWasExplicitlySet = YES;
|
2002-02-26 14:37:55 +00:00
|
|
|
|
|
|
|
[self recache];
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSSize) size
|
|
|
|
{
|
|
|
|
if (_size.width == 0)
|
|
|
|
{
|
|
|
|
NSImageRep *rep = [self bestRepresentationForDevice: nil];
|
|
|
|
|
2004-05-26 23:42:48 +00:00
|
|
|
if (rep)
|
2008-12-15 17:14:30 +00:00
|
|
|
_size = [rep size];
|
2004-05-26 23:42:48 +00:00
|
|
|
else
|
2008-12-15 17:14:30 +00:00
|
|
|
_size = NSZeroSize;
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
return _size;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isFlipped
|
|
|
|
{
|
|
|
|
return _flags.flipDraw;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setFlipped: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.flipDraw = flag;
|
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
// Choosing Which Image Representation to Use
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setUsesEPSOnResolutionMismatch: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.useEPSOnResolutionMismatch = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (BOOL) usesEPSOnResolutionMismatch
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.useEPSOnResolutionMismatch;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setPrefersColorMatch: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.colorMatchPreferred = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (BOOL) prefersColorMatch
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.colorMatchPreferred;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setMatchesOnMultipleResolution: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
_flags.multipleResolutionMatching = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
- (BOOL) matchesOnMultipleResolution
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
|
|
|
return _flags.multipleResolutionMatching;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
|
|
// Determining How the Image is Stored
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setCachedSeparately: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.cacheSeparately = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) isCachedSeparately
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.cacheSeparately;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setDataRetained: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.dataRetained = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) isDataRetained
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.dataRetained;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setCacheDepthMatchesImageDepth: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.unboundedCacheDepth = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) cacheDepthMatchesImageDepth
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.unboundedCacheDepth;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (void) setCacheMode: (NSImageCacheMode)mode
|
|
|
|
{
|
|
|
|
_cacheMode = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSImageCacheMode) cacheMode
|
|
|
|
{
|
|
|
|
return _cacheMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
// Determining How the Image is Drawn
|
1996-08-22 18:51:08 +00:00
|
|
|
- (BOOL) isValid
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
BOOL valid = NO;
|
|
|
|
unsigned i, count;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
if (_flags.syncLoad)
|
|
|
|
{
|
|
|
|
/* Make sure any images that were added with _useFromFile: are loaded
|
|
|
|
in and added to the representation list. */
|
|
|
|
if (![self _loadFromFile: _fileName])
|
|
|
|
return NO;
|
|
|
|
_flags.syncLoad = NO;
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
/* Go through all our representations and determine if at least one
|
|
|
|
is a valid cache */
|
|
|
|
// FIXME: Not sure if this is correct
|
|
|
|
count = [_reps count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
GSRepData *repd = (GSRepData*)[_reps objectAtIndex: i];
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
if (repd->bg != nil || [repd->rep isKindOfClass: cachedClass] == NO)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
|
|
|
valid = YES;
|
|
|
|
break;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
2008-12-13 19:32:54 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) recache
|
|
|
|
{
|
2002-03-28 03:53:18 +00:00
|
|
|
unsigned i;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2002-02-26 14:37:55 +00:00
|
|
|
i = [_reps count];
|
2005-11-16 11:34:25 +00:00
|
|
|
while (i--)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
GSRepData *repd;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
|
|
repd = (GSRepData*)[_reps objectAtIndex: i];
|
2002-02-26 14:37:55 +00:00
|
|
|
if (repd->original != nil)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
|
|
|
[_reps removeObjectAtIndex: i];
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setScalesWhenResized: (BOOL)flag
|
|
|
|
{
|
|
|
|
_flags.scalable = flag;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
- (BOOL) scalesWhenResized
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _flags.scalable;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setBackgroundColor: (NSColor *)aColor
|
|
|
|
{
|
1999-12-02 10:35:07 +00:00
|
|
|
if (aColor == nil)
|
|
|
|
{
|
|
|
|
aColor = clearColor;
|
|
|
|
}
|
1999-12-01 13:49:47 +00:00
|
|
|
ASSIGN(_color, aColor);
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
- (NSColor *) backgroundColor
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1996-08-22 18:51:08 +00:00
|
|
|
return _color;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Using the Image
|
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
2008-12-15 17:14:30 +00:00
|
|
|
operation: (NSCompositingOperation)op
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
// Might not be computed up to now
|
|
|
|
NSSize size = [self size];
|
2009-11-01 22:43:20 +00:00
|
|
|
NSRect rect = NSMakeRect(0, 0, size.width, size.height);
|
1999-04-28 11:16:26 +00:00
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
[self compositeToPoint: aPoint fromRect: rect operation: op];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
2008-12-13 19:32:54 +00:00
|
|
|
fromRect: (NSRect)aRect
|
|
|
|
operation: (NSCompositingOperation)op
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2010-06-01 11:04:36 +00:00
|
|
|
[self compositeToPoint: aPoint
|
|
|
|
fromRect: aRect
|
2008-12-13 19:32:54 +00:00
|
|
|
operation: op
|
|
|
|
fraction: 1.0];
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
2008-12-13 19:32:54 +00:00
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
|
|
|
NSSize size = [self size];
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
[self compositeToPoint: aPoint
|
|
|
|
fromRect: NSMakeRect(0, 0, size.width, size.height)
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) compositeToPoint: (NSPoint)aPoint
|
2008-12-13 19:32:54 +00:00
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2005-07-08 23:51:49 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
NSImageRep *rep = [self bestRepresentationForDevice: nil];
|
|
|
|
NSCachedImageRep *cache = nil;
|
|
|
|
|
|
|
|
if (rep == nil)
|
2009-01-20 20:18:22 +00:00
|
|
|
NS_VOIDRETURN;
|
2008-12-13 19:32:54 +00:00
|
|
|
|
|
|
|
if (([GSCurrentContext() isDrawingToScreen] == YES)
|
|
|
|
&& _cacheMode != NSImageCacheNever)
|
|
|
|
cache = [self _doImageCache: rep];
|
|
|
|
|
|
|
|
if (cache != nil)
|
2005-07-08 23:51:49 +00:00
|
|
|
{
|
2010-06-01 11:04:36 +00:00
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
2009-11-01 22:43:20 +00:00
|
|
|
NSRect rect = [cache rect];
|
2008-12-13 19:32:54 +00:00
|
|
|
|
|
|
|
NSDebugLLog(@"NSImage", @"composite rect %@ in %@",
|
|
|
|
NSStringFromRect(rect), NSStringFromRect(srcRect));
|
2010-06-01 11:04:36 +00:00
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
// Move the drawing rectangle to the origin of the image rep
|
|
|
|
// and intersect the two rects.
|
|
|
|
srcRect.origin.x += rect.origin.x;
|
|
|
|
srcRect.origin.y += rect.origin.y;
|
|
|
|
rect = NSIntersectionRect(srcRect, rect);
|
|
|
|
|
2010-06-01 11:04:36 +00:00
|
|
|
[ctxt GScomposite: [[cache window] gState]
|
|
|
|
toPoint: aPoint
|
|
|
|
fromRect: rect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
else
|
2005-07-08 23:51:49 +00:00
|
|
|
{
|
2010-06-01 11:04:36 +00:00
|
|
|
NSRect rect = NSMakeRect(aPoint.x, aPoint.y, _size.width, _size.height);
|
2008-12-13 19:32:54 +00:00
|
|
|
[self drawRepresentation: rep inRect: rect];
|
|
|
|
}
|
2005-07-08 23:51:49 +00:00
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
2006-11-06 13:58:37 +00:00
|
|
|
NSLog(@"NSImage: compositeToPoint:fromRect:operation:fraction:"
|
|
|
|
@"failed due to %@: %@",
|
|
|
|
[localException name], [localException reason]);
|
2005-07-08 23:51:49 +00:00
|
|
|
if ([_delegate respondsToSelector: @selector(imageDidNotDraw:inRect:)])
|
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
NSImage *image = [_delegate imageDidNotDraw: self inRect: srcRect];
|
|
|
|
|
|
|
|
if (image != nil)
|
|
|
|
[image compositeToPoint: aPoint
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
|
|
|
}
|
2005-07-08 23:51:49 +00:00
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2001-12-17 16:51:51 +00:00
|
|
|
- (void) dissolveToPoint: (NSPoint)aPoint fraction: (float)aFloat
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
NSSize size = [self size];
|
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
[self dissolveToPoint: aPoint
|
|
|
|
fromRect: NSMakeRect(0, 0, size.width, size.height)
|
|
|
|
fraction: aFloat];
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
- (void) dissolveToPoint: (NSPoint)aPoint
|
2008-12-15 17:14:30 +00:00
|
|
|
fromRect: (NSRect)aRect
|
|
|
|
fraction: (float)aFloat
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-07-08 23:51:49 +00:00
|
|
|
[self compositeToPoint: aPoint
|
2008-12-15 17:14:30 +00:00
|
|
|
fromRect: aRect
|
|
|
|
operation: NSCompositeSourceOver
|
|
|
|
fraction: aFloat];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2001-02-19 20:50:49 +00:00
|
|
|
- (BOOL) drawRepresentation: (NSImageRep *)imageRep inRect: (NSRect)aRect
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-01-24 23:28:07 +00:00
|
|
|
BOOL r;
|
|
|
|
|
|
|
|
PSgsave();
|
|
|
|
|
2008-12-16 08:00:29 +00:00
|
|
|
if (_color != nil)
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
NSRect fillrect = aRect;
|
2008-12-15 17:14:30 +00:00
|
|
|
|
|
|
|
[_color set];
|
2003-01-21 05:08:26 +00:00
|
|
|
NSRectFill(fillrect);
|
2008-12-15 17:14:30 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == NO)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
/* Reset alpha for image drawing. */
|
|
|
|
[[NSColor colorWithCalibratedWhite: 1.0 alpha: 1.0] set];
|
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
if (!_flags.scalable)
|
|
|
|
r = [imageRep drawAtPoint: aRect.origin];
|
|
|
|
else
|
|
|
|
r = [imageRep drawInRect: aRect];
|
|
|
|
|
|
|
|
PSgrestore();
|
|
|
|
|
|
|
|
return r;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
- (void) drawAtPoint: (NSPoint)point
|
2008-12-15 17:14:30 +00:00
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2005-01-24 23:28:07 +00:00
|
|
|
[self drawInRect: NSMakeRect(point.x, point.y, srcRect.size.width,
|
2007-11-30 19:52:26 +00:00
|
|
|
srcRect.size.height)
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2010-06-01 11:04:36 +00:00
|
|
|
/* New code path that delegates as much as possible to the backend and whose
|
|
|
|
behavior precisely matches Cocoa. */
|
|
|
|
- (void) nativeDrawInRect: (NSRect)dstRect
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
|
|
|
{
|
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
|
|
|
NSSize imgSize = [self size];
|
|
|
|
float widthScaleFactor;
|
|
|
|
float heightScaleFactor;
|
|
|
|
|
|
|
|
if (NSEqualRects(srcRect, NSZeroRect))
|
|
|
|
{
|
|
|
|
srcRect.size = imgSize;
|
|
|
|
/* For -drawAtPoint:fromRect:operation:fraction: used with a zero rect */
|
|
|
|
if (NSEqualSizes(dstRect.size, NSZeroSize))
|
|
|
|
{
|
|
|
|
dstRect.size = imgSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dstRect.size.width || !dstRect.size.height
|
|
|
|
|| !srcRect.size.width || !srcRect.size.height)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Clip to image bounds
|
|
|
|
if (srcRect.origin.x < 0)
|
|
|
|
srcRect.origin.x = 0;
|
|
|
|
if (srcRect.origin.y < 0)
|
|
|
|
srcRect.origin.y = 0;
|
|
|
|
if (NSMaxX(srcRect) > imgSize.width)
|
|
|
|
srcRect.size.width = imgSize.width - srcRect.origin.x;
|
|
|
|
if (NSMaxY(srcRect) > imgSize.height)
|
|
|
|
srcRect.size.height = imgSize.height - srcRect.origin.y;
|
|
|
|
|
|
|
|
widthScaleFactor = dstRect.size.width / srcRect.size.width;
|
|
|
|
heightScaleFactor = dstRect.size.height / srcRect.size.height;
|
|
|
|
|
|
|
|
if (![ctxt isDrawingToScreen])
|
|
|
|
{
|
|
|
|
/* We can't composite or dissolve if we aren't drawing to a screen,
|
|
|
|
so we'll just draw the right part of the image in the right
|
|
|
|
place. */
|
|
|
|
NSPoint p;
|
|
|
|
|
|
|
|
p.x = dstRect.origin.x / widthScaleFactor - srcRect.origin.x;
|
|
|
|
p.y = dstRect.origin.y / heightScaleFactor - srcRect.origin.y;
|
|
|
|
|
|
|
|
DPSgsave(ctxt);
|
|
|
|
DPSrectclip(ctxt, dstRect.origin.x, dstRect.origin.y,
|
|
|
|
dstRect.size.width, dstRect.size.height);
|
|
|
|
DPSscale(ctxt, widthScaleFactor, heightScaleFactor);
|
|
|
|
[self drawRepresentation: [self bestRepresentationForDevice: nil]
|
|
|
|
inRect: NSMakeRect(p.x, p.y, imgSize.width, imgSize.height)];
|
|
|
|
DPSgrestore(ctxt);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We cannot ask the backend to draw the image directly when the source rect
|
|
|
|
doesn't cover the whole image.
|
|
|
|
Cairo doesn't support to specify a source rect for a surface used as a
|
|
|
|
source, see cairo_set_source_surface()).
|
|
|
|
CoreGraphics is similarly limited, see CGContextDrawImage().
|
|
|
|
For now, we always use a two step process:
|
|
|
|
- draw the image data in a cache to apply the srcRect to inRect scaling
|
|
|
|
- draw the cache into the destination context
|
|
|
|
It might be worth to move the first step to the backend, so we don't have
|
|
|
|
to create a cache window but just an intermediate surface.
|
|
|
|
We create a cache every time but otherwise we are more efficient than the
|
|
|
|
old code path since the cache size is limited to what we actually draw
|
|
|
|
and doesn't involve drawing the whole image. */
|
|
|
|
{
|
|
|
|
/* An intermediate image used to scale the image to be drawn as needed */
|
|
|
|
NSCachedImageRep *cache;
|
|
|
|
/* The scaled image graphics state we used as the source from which we
|
|
|
|
draw into the destination (the current graphics context)*/
|
|
|
|
int gState;
|
|
|
|
/* The context of the cache window */
|
|
|
|
NSGraphicsContext *cacheCtxt;
|
|
|
|
/* The size of the cache window that will hold the scaled image */
|
|
|
|
NSSize cacheSize = NSMakeSize(imgSize.width * widthScaleFactor,
|
|
|
|
imgSize.height * heightScaleFactor);
|
|
|
|
NSRect srcRectInCache = NSMakeRect(srcRect.origin.x * widthScaleFactor,
|
|
|
|
srcRect.origin.y * heightScaleFactor,
|
|
|
|
srcRect.size.width * widthScaleFactor,
|
|
|
|
srcRect.size.height * heightScaleFactor);
|
|
|
|
|
|
|
|
cache = [[NSCachedImageRep alloc]
|
|
|
|
initWithSize: cacheSize
|
|
|
|
depth: [[NSScreen mainScreen] depth]
|
|
|
|
separate: YES
|
|
|
|
alpha: YES];
|
|
|
|
|
|
|
|
[[[cache window] contentView] lockFocus];
|
|
|
|
cacheCtxt = GSCurrentContext();
|
|
|
|
|
|
|
|
/* Clear the cache window surface */
|
|
|
|
DPScompositerect(cacheCtxt, 0, 0, cacheSize.width, cacheSize.height, NSCompositeClear);
|
|
|
|
gState = [cacheCtxt GSDefineGState];
|
|
|
|
|
|
|
|
//NSLog(@"Draw in cache size %@", NSStringFromSize(cacheSize));
|
|
|
|
|
|
|
|
/* We must not use -drawRepresentation:inRect: because the image must drawn
|
|
|
|
scaled even when -scalesWhenResized is NO */
|
|
|
|
[[self bestRepresentationForDevice: nil]
|
|
|
|
drawInRect: NSMakeRect(0, 0, cacheSize.width, cacheSize.height)];
|
|
|
|
/* If we're doing a dissolve, use a DestinationIn composite to lower
|
|
|
|
the alpha of the pixels. */
|
|
|
|
if (delta != 1.0)
|
|
|
|
{
|
|
|
|
DPSsetalpha(cacheCtxt, delta);
|
|
|
|
DPScompositerect(cacheCtxt, 0, 0, cacheSize.width, cacheSize.height,
|
|
|
|
NSCompositeDestinationIn);
|
|
|
|
}
|
|
|
|
|
|
|
|
[[[cache window] contentView] unlockFocus];
|
|
|
|
|
|
|
|
//NSLog(@"Draw in %@ from %@ from cache rect %@", NSStringFromRect(dstRect),
|
|
|
|
// NSStringFromRect(srcRect), NSStringFromRect(srcRectInCache));
|
|
|
|
|
|
|
|
[ctxt GSdraw: gState
|
|
|
|
toPoint: dstRect.origin
|
|
|
|
fromRect: srcRectInCache
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
|
|
|
|
|
|
|
[ctxt GSUndefineGState: gState];
|
|
|
|
DESTROY(cache);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Old code path that can probably partially be merged with the new native implementation.
|
|
|
|
Fallback for backends other than Cairo. */
|
|
|
|
- (void) guiDrawInRect: (NSRect)dstRect
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2005-01-24 23:28:07 +00:00
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
|
|
|
NSAffineTransform *transform;
|
2007-11-30 19:52:26 +00:00
|
|
|
NSSize s;
|
|
|
|
|
|
|
|
s = [self size];
|
|
|
|
|
|
|
|
if (NSEqualRects(srcRect, NSZeroRect))
|
|
|
|
srcRect = NSMakeRect(0, 0, s.width, s.height);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
if (!dstRect.size.width || !dstRect.size.height
|
2006-11-19 11:32:51 +00:00
|
|
|
|| !srcRect.size.width || !srcRect.size.height)
|
2005-01-24 23:28:07 +00:00
|
|
|
return;
|
|
|
|
|
2007-11-30 19:52:26 +00:00
|
|
|
// CLip to image bounds
|
|
|
|
if (srcRect.origin.x < 0)
|
|
|
|
srcRect.origin.x = 0;
|
|
|
|
if (srcRect.origin.y < 0)
|
|
|
|
srcRect.origin.y = 0;
|
|
|
|
if (NSMaxX(srcRect) > s.width)
|
|
|
|
srcRect.size.width = s.width - srcRect.origin.x;
|
|
|
|
if (NSMaxY(srcRect) > s.height)
|
|
|
|
srcRect.size.height = s.height - srcRect.origin.y;
|
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
if (![ctxt isDrawingToScreen])
|
|
|
|
{
|
|
|
|
/* We can't composite or dissolve if we aren't drawing to a screen,
|
2007-11-30 19:52:26 +00:00
|
|
|
so we'll just draw the right part of the image in the right
|
|
|
|
place. */
|
2005-01-24 23:28:07 +00:00
|
|
|
NSPoint p;
|
|
|
|
double fx, fy;
|
2007-11-30 19:52:26 +00:00
|
|
|
|
2005-01-24 23:28:07 +00:00
|
|
|
fx = dstRect.size.width / srcRect.size.width;
|
|
|
|
fy = dstRect.size.height / srcRect.size.height;
|
|
|
|
|
|
|
|
p.x = dstRect.origin.x / fx - srcRect.origin.x;
|
|
|
|
p.y = dstRect.origin.y / fy - srcRect.origin.y;
|
|
|
|
|
|
|
|
DPSgsave(ctxt);
|
|
|
|
DPSrectclip(ctxt, dstRect.origin.x, dstRect.origin.y,
|
2007-11-30 19:52:26 +00:00
|
|
|
dstRect.size.width, dstRect.size.height);
|
2005-01-24 23:28:07 +00:00
|
|
|
DPSscale(ctxt, fx, fy);
|
|
|
|
[self drawRepresentation: [self bestRepresentationForDevice: nil]
|
2007-11-30 19:52:26 +00:00
|
|
|
inRect: NSMakeRect(p.x, p.y, s.width, s.height)];
|
2005-01-24 23:28:07 +00:00
|
|
|
DPSgrestore(ctxt);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out what the effective transform from image space to
|
|
|
|
'window space' is. */
|
|
|
|
transform = [ctxt GSCurrentCTM];
|
|
|
|
|
|
|
|
[transform scaleXBy: dstRect.size.width / srcRect.size.width
|
2008-12-15 17:14:30 +00:00
|
|
|
yBy: dstRect.size.height / srcRect.size.height];
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* If the effective transform is the identity transform and there's
|
|
|
|
no dissolve, we can composite from our cache. */
|
2006-11-19 11:32:51 +00:00
|
|
|
|
|
|
|
if (delta == 1.0)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
2006-11-19 11:32:51 +00:00
|
|
|
NSAffineTransformStruct ts = [transform transformStruct];
|
|
|
|
|
|
|
|
if (fabs(ts.m11 - 1.0) < 0.01 && fabs(ts.m12) < 0.01
|
2007-11-30 19:52:26 +00:00
|
|
|
&& fabs(ts.m21) < 0.01 && fabs(ts.m22 - 1.0) < 0.01)
|
|
|
|
{
|
|
|
|
[self compositeToPoint: dstRect.origin
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op];
|
|
|
|
return;
|
|
|
|
}
|
2005-01-24 23:28:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We can't composite or dissolve directly from the image reps, so we
|
|
|
|
create a temporary off-screen window large enough to hold the
|
|
|
|
transformed image, draw the image rep there, and composite from there
|
|
|
|
to the destination.
|
|
|
|
|
|
|
|
Optimization: Since we do the entire image at once, we might need a
|
|
|
|
huge buffer. If this starts hurting too much, there are a couple of
|
|
|
|
things we could do to:
|
|
|
|
|
|
|
|
1. Take srcRect into account and only process the parts of the image
|
2007-11-30 19:52:26 +00:00
|
|
|
we really need.
|
2005-01-24 23:28:07 +00:00
|
|
|
2. Take the clipping path into account. Desirable, especially if we're
|
2007-11-30 19:52:26 +00:00
|
|
|
being drawn as lots of small strips in a scrollview. We don't have
|
|
|
|
the clipping path here, though.
|
2005-01-24 23:28:07 +00:00
|
|
|
3. Allocate a permanent but small buffer and process the image
|
2007-11-30 19:52:26 +00:00
|
|
|
piecewise.
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
NSCachedImageRep *cache;
|
2006-11-19 11:32:51 +00:00
|
|
|
NSAffineTransformStruct ts;
|
2005-01-24 23:28:07 +00:00
|
|
|
NSPoint p;
|
|
|
|
double x0, y0, x1, y1, w, h;
|
|
|
|
int gState;
|
2007-04-04 14:33:39 +00:00
|
|
|
NSGraphicsContext *ctxt1;
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
/* Figure out how big we need to make the window that'll hold the
|
|
|
|
transformed image. */
|
|
|
|
p = [transform transformPoint: NSMakePoint(0, s.height)];
|
|
|
|
x0 = x1 = p.x;
|
|
|
|
y0 = y1 = p.y;
|
|
|
|
|
|
|
|
p = [transform transformPoint: NSMakePoint(s.width, 0)];
|
2005-02-03 09:47:38 +00:00
|
|
|
x0 = gs_min(x0, p.x);
|
|
|
|
y0 = gs_min(y0, p.y);
|
|
|
|
x1 = gs_max(x1, p.x);
|
|
|
|
y1 = gs_max(y1, p.y);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
p = [transform transformPoint: NSMakePoint(s.width, s.height)];
|
2005-02-03 09:47:38 +00:00
|
|
|
x0 = gs_min(x0, p.x);
|
|
|
|
y0 = gs_min(y0, p.y);
|
|
|
|
x1 = gs_max(x1, p.x);
|
|
|
|
y1 = gs_max(y1, p.y);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
p = [transform transformPoint: NSMakePoint(0, 0)];
|
2005-02-03 09:47:38 +00:00
|
|
|
x0 = gs_min(x0, p.x);
|
|
|
|
y0 = gs_min(y0, p.y);
|
|
|
|
x1 = gs_max(x1, p.x);
|
|
|
|
y1 = gs_max(y1, p.y);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
x0 = floor(x0);
|
|
|
|
y0 = floor(y0);
|
|
|
|
x1 = ceil(x1);
|
|
|
|
y1 = ceil(y1);
|
|
|
|
|
|
|
|
w = x1 - x0;
|
|
|
|
h = y1 - y0;
|
|
|
|
|
|
|
|
/* This is where we want the origin of image space to be in our
|
|
|
|
window. */
|
|
|
|
p.x -= x0;
|
|
|
|
p.y -= y0;
|
|
|
|
|
|
|
|
cache = [[NSCachedImageRep alloc]
|
2008-12-15 17:14:30 +00:00
|
|
|
initWithSize: NSMakeSize(w, h)
|
|
|
|
depth: [[NSScreen mainScreen] depth]
|
|
|
|
separate: YES
|
|
|
|
alpha: YES];
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
[[[cache window] contentView] lockFocus];
|
2007-04-04 14:33:39 +00:00
|
|
|
// The context of the cache window
|
|
|
|
ctxt1 = GSCurrentContext();
|
|
|
|
DPScompositerect(ctxt1, 0, 0, w, h, NSCompositeClear);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
/* Set up the effective transform. We also save a gState with this
|
|
|
|
transform to make it easier to do the final composite. */
|
2006-11-19 11:32:51 +00:00
|
|
|
ts = [transform transformStruct];
|
|
|
|
ts.tX = p.x;
|
|
|
|
ts.tY = p.y;
|
|
|
|
[transform setTransformStruct: ts];
|
2007-04-04 14:33:39 +00:00
|
|
|
[ctxt1 GSSetCTM: transform];
|
|
|
|
gState = [ctxt1 GSDefineGState];
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
[self drawRepresentation: [self bestRepresentationForDevice: nil]
|
2008-12-15 17:14:30 +00:00
|
|
|
inRect: NSMakeRect(0, 0, s.width, s.height)];
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
/* If we're doing a dissolve, use a DestinationIn composite to lower
|
|
|
|
the alpha of the pixels. */
|
2006-11-06 13:58:37 +00:00
|
|
|
if (delta != 1.0)
|
2005-01-24 23:28:07 +00:00
|
|
|
{
|
2007-04-04 14:33:39 +00:00
|
|
|
DPSsetalpha(ctxt1, delta);
|
|
|
|
DPScompositerect(ctxt1, 0, 0, s.width, s.height,
|
|
|
|
NSCompositeDestinationIn);
|
2005-01-24 23:28:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[[[cache window] contentView] unlockFocus];
|
|
|
|
|
|
|
|
|
|
|
|
DPScomposite(ctxt, srcRect.origin.x, srcRect.origin.y,
|
2007-04-04 14:33:39 +00:00
|
|
|
srcRect.size.width, srcRect.size.height, gState,
|
|
|
|
dstRect.origin.x, dstRect.origin.y, op);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
[ctxt GSUndefineGState: gState];
|
|
|
|
|
|
|
|
DESTROY(cache);
|
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2010-06-01 11:04:36 +00:00
|
|
|
- (void) drawInRect: (NSRect)dstRect
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
|
|
|
fraction: (float)delta
|
|
|
|
{
|
|
|
|
if ([GSCurrentContext() supportsDrawGState])
|
|
|
|
{
|
|
|
|
[self nativeDrawInRect: dstRect fromRect: srcRect operation: op fraction: delta];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self guiDrawInRect: dstRect fromRect: srcRect operation: op fraction: delta];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
- (void) addRepresentation: (NSImageRep *)imageRep
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
GSRepData *repd;
|
1999-03-26 15:59:01 +00:00
|
|
|
|
1999-04-28 11:16:26 +00:00
|
|
|
repd = [GSRepData new];
|
2000-12-23 14:19:23 +00:00
|
|
|
repd->rep = RETAIN(imageRep);
|
|
|
|
[_reps addObject: repd];
|
1999-12-01 13:49:47 +00:00
|
|
|
RELEASE(repd);
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addRepresentations: (NSArray *)imageRepArray
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
unsigned i, count;
|
|
|
|
GSRepData *repd;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
count = [imageRepArray count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
repd = [GSRepData new];
|
1999-12-01 13:49:47 +00:00
|
|
|
repd->rep = RETAIN([imageRepArray objectAtIndex: i]);
|
1999-04-28 11:16:26 +00:00
|
|
|
[_reps addObject: repd];
|
1999-12-01 13:49:47 +00:00
|
|
|
RELEASE(repd);
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeRepresentation: (NSImageRep *)imageRep
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
unsigned i;
|
|
|
|
GSRepData *repd;
|
1999-04-28 11:16:26 +00:00
|
|
|
|
|
|
|
i = [_reps count];
|
|
|
|
while (i-- > 0)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
1999-04-28 11:16:26 +00:00
|
|
|
repd = (GSRepData*)[_reps objectAtIndex: i];
|
|
|
|
if (repd->rep == imageRep)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
|
|
|
[_reps removeObjectAtIndex: i];
|
|
|
|
}
|
1999-04-28 11:16:26 +00:00
|
|
|
else if (repd->original == imageRep)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
// Remove cached representations for this representation
|
|
|
|
// instead of turning them into real ones
|
|
|
|
//repd->original = nil;
|
|
|
|
[_reps removeObjectAtIndex: i];
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) lockFocus
|
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
[self lockFocusOnRepresentation: nil];
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) lockFocusOnRepresentation: (NSImageRep *)imageRep
|
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
if (_cacheMode != NSImageCacheNever)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSWindow *window;
|
2002-08-03 03:32:19 +00:00
|
|
|
GSRepData *repd;
|
1999-12-01 13:49:47 +00:00
|
|
|
|
2001-08-11 18:34:22 +00:00
|
|
|
if (imageRep == nil)
|
2008-11-16 23:21:58 +00:00
|
|
|
imageRep = [self bestRepresentationForDevice: nil];
|
2001-08-11 18:34:22 +00:00
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
repd = [self _cacheForRep: imageRep];
|
|
|
|
imageRep = repd->rep;
|
2002-08-03 03:32:19 +00:00
|
|
|
|
1999-12-01 13:49:47 +00:00
|
|
|
window = [(NSCachedImageRep *)imageRep window];
|
|
|
|
_lockedView = [window contentView];
|
2000-12-23 14:19:23 +00:00
|
|
|
if (_lockedView == nil)
|
2008-11-16 23:21:58 +00:00
|
|
|
[NSException raise: NSImageCacheException
|
|
|
|
format: @"Cannot lock focus on nil rep"];
|
1999-12-01 13:49:47 +00:00
|
|
|
[_lockedView lockFocus];
|
2008-12-15 17:14:30 +00:00
|
|
|
if (repd->bg == nil)
|
2008-11-16 23:21:58 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
// Clear the background of the cached image, as it is not valid
|
|
|
|
if ([_color alphaComponent] < 1.0)
|
2008-11-16 23:21:58 +00:00
|
|
|
{
|
|
|
|
/* With a Quartz-like alpha model, alpha can't be cleared
|
|
|
|
with a rectfill, so we need to clear the alpha channel
|
|
|
|
explictly. (A compositerect with NSCompositeCopy would
|
|
|
|
be more efficient, but it doesn't seem like it's
|
|
|
|
implemented correctly in all backends yet (as of
|
|
|
|
2002-08-23). Also, this will work with both the Quartz-
|
|
|
|
and DPS-model.) */
|
|
|
|
PScompositerect(0, 0, _size.width, _size.height,
|
|
|
|
NSCompositeClear);
|
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
|
|
|
|
repd->bg = [_color copy];
|
2008-12-16 08:00:29 +00:00
|
|
|
if (_color != nil)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
// Won't be needed when drawRepresentation: gets called,
|
|
|
|
// but we never know.
|
|
|
|
[_color set];
|
|
|
|
NSRectFill(NSMakeRect(0, 0, _size.width, _size.height));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([repd->bg alphaComponent] == 1.0)
|
|
|
|
{
|
|
|
|
[imageRep setOpaque: YES];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[imageRep setOpaque: [repd->original isOpaque]];
|
|
|
|
}
|
|
|
|
|
2008-11-16 23:21:58 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) unlockFocus
|
|
|
|
{
|
1999-12-01 13:49:47 +00:00
|
|
|
if (_lockedView != nil)
|
|
|
|
{
|
|
|
|
[_lockedView unlockFocus];
|
|
|
|
_lockedView = nil;
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
/* Determine if the device is color or gray scale and find the reps of
|
|
|
|
the same type
|
|
|
|
*/
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
2008-12-15 17:14:30 +00:00
|
|
|
withColorMatch: (NSDictionary*)deviceDescription
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
int colors = 3;
|
|
|
|
NSImageRep* rep;
|
|
|
|
NSMutableArray *breps;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
NSString *colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
|
|
|
|
|
|
|
|
if (colorSpace != nil)
|
|
|
|
colors = NSNumberOfColorComponents(colorSpace);
|
|
|
|
|
|
|
|
breps = [NSMutableArray array];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([rep colorSpaceName] || abs(NSNumberOfColorComponents([rep colorSpaceName]) - colors) <= 1)
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
|
|
|
return (NSMutableArray *)reps;
|
|
|
|
return breps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find reps that match the resolution of the device or return the rep
|
|
|
|
that has the highest resolution */
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
2008-12-15 17:14:30 +00:00
|
|
|
withResolutionMatch: (NSDictionary*)deviceDescription
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
|
|
|
NSImageRep* rep;
|
|
|
|
NSMutableArray *breps;
|
2000-12-24 14:05:12 +00:00
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
2011-02-09 22:20:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
NSSize dres;
|
2003-01-21 05:08:26 +00:00
|
|
|
NSValue *resolution = [deviceDescription objectForKey: NSDeviceResolution];
|
|
|
|
|
|
|
|
if (resolution)
|
|
|
|
dres = [resolution sizeValue];
|
|
|
|
else
|
|
|
|
dres = NSMakeSize(0, 0);
|
2011-02-09 22:20:00 +00:00
|
|
|
*/
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
breps = [NSMutableArray array];
|
2000-12-24 14:05:12 +00:00
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
/* FIXME: Not sure about checking resolution */
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
|
|
|
return (NSMutableArray *)reps;
|
|
|
|
return breps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find reps that match the bps of the device or return the rep that
|
|
|
|
has the highest bps */
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
2008-12-15 17:14:30 +00:00
|
|
|
withBpsMatch: (NSDictionary*)deviceDescription
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
|
|
|
NSImageRep* rep, *max_rep;
|
|
|
|
NSMutableArray *breps;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
int bps = [[deviceDescription objectForKey: NSDeviceBitsPerSample] intValue];
|
|
|
|
int max_bps;
|
|
|
|
|
|
|
|
breps = [NSMutableArray array];
|
|
|
|
max_bps = 0;
|
|
|
|
max_rep = nil;
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
2003-01-30 04:29:00 +00:00
|
|
|
int rep_bps = 0;
|
2003-01-21 05:08:26 +00:00
|
|
|
if ([rep respondsToSelector: @selector(bitsPerPixel)])
|
|
|
|
rep_bps = [(NSBitmapImageRep *)rep bitsPerPixel];
|
|
|
|
if (rep_bps > max_bps)
|
|
|
|
{
|
|
|
|
max_bps = rep_bps;
|
|
|
|
max_rep = rep;
|
|
|
|
}
|
|
|
|
if (rep_bps == bps)
|
|
|
|
[breps addObject: rep];
|
1999-12-01 13:49:47 +00:00
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
if ([breps count] == 0 && max_rep != nil)
|
|
|
|
[breps addObject: max_rep];
|
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
|
|
|
return (NSMutableArray *)reps;
|
|
|
|
return breps;
|
1999-12-01 13:49:47 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (NSMutableArray *) _representationsWithCachedImages: (BOOL)flag
|
1999-12-01 13:49:47 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
unsigned count;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
if (_flags.syncLoad)
|
1999-12-01 13:49:47 +00:00
|
|
|
{
|
2000-12-24 14:05:12 +00:00
|
|
|
/* Make sure any images that were added with _useFromFile: are loaded
|
2008-12-13 19:32:54 +00:00
|
|
|
in and added to the representation list. */
|
2000-12-24 14:05:12 +00:00
|
|
|
[self _loadFromFile: _fileName];
|
|
|
|
_flags.syncLoad = NO;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
2000-12-24 14:05:12 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
count = [_reps count];
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
return [NSArray array];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
id repList[count];
|
|
|
|
unsigned i, j;
|
1999-12-01 13:49:47 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
[_reps getObjects: repList];
|
2003-01-21 05:08:26 +00:00
|
|
|
j = 0;
|
2000-12-23 14:19:23 +00:00
|
|
|
for (i = 0; i < count; i++)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
2003-01-21 05:08:26 +00:00
|
|
|
if (flag || ((GSRepData*)repList[i])->original == nil)
|
|
|
|
{
|
|
|
|
repList[j] = ((GSRepData*)repList[i])->rep;
|
|
|
|
j++;
|
|
|
|
}
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
return [NSArray arrayWithObjects: repList count: j];
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (NSImageRep*) bestRepresentationForDevice: (NSDictionary*)deviceDescription
|
|
|
|
{
|
|
|
|
NSMutableArray *reps = [self _representationsWithCachedImages: NO];
|
|
|
|
|
|
|
|
if (deviceDescription == nil)
|
|
|
|
{
|
|
|
|
if ([GSCurrentContext() isDrawingToScreen] == YES)
|
|
|
|
{
|
2008-11-16 23:21:58 +00:00
|
|
|
// Take the device description from the current context.
|
|
|
|
deviceDescription = [[[GSCurrentContext() attributes] objectForKey:
|
|
|
|
NSGraphicsContextDestinationAttributeName]
|
|
|
|
deviceDescription];
|
2003-01-21 05:08:26 +00:00
|
|
|
}
|
|
|
|
else if ([NSPrintOperation currentOperation])
|
|
|
|
{
|
|
|
|
/* FIXME: We could try to use the current printer,
|
2008-11-16 23:21:58 +00:00
|
|
|
but there are many cases where might
|
2003-01-21 05:08:26 +00:00
|
|
|
not be printing (EPS, PDF, etc) to a specific device */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_flags.colorMatchPreferred == YES)
|
|
|
|
{
|
|
|
|
reps = [self _bestRep: reps withColorMatch: deviceDescription];
|
|
|
|
reps = [self _bestRep: reps withResolutionMatch: deviceDescription];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reps = [self _bestRep: reps withResolutionMatch: deviceDescription];
|
|
|
|
reps = [self _bestRep: reps withColorMatch: deviceDescription];
|
|
|
|
}
|
|
|
|
reps = [self _bestRep: reps withBpsMatch: deviceDescription];
|
|
|
|
/* Pick an arbitrary representation if there is more than one */
|
|
|
|
return [reps lastObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) representations
|
|
|
|
{
|
|
|
|
return [self _representationsWithCachedImages: YES];
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (void) setDelegate: anObject
|
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
_delegate = anObject;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
1999-03-30 13:59:35 +00:00
|
|
|
- (id) delegate
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
return _delegate;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
// Producing TIFF Data for the Image
|
2000-12-23 14:19:23 +00:00
|
|
|
- (NSData *) TIFFRepresentation
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2007-03-08 09:35:09 +00:00
|
|
|
NSData *data;
|
|
|
|
|
|
|
|
// As a result of using bitmap representations, new drawing wont show on the tiff data.
|
|
|
|
data = [bitmapClass TIFFRepresentationOfImageRepsInArray: [self representations]];
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
NSBitmapImageRep *rep;
|
|
|
|
NSSize size = [self size];
|
|
|
|
|
|
|
|
// If there isn't a bitmap representation to output, create one and store it.
|
|
|
|
[self lockFocus];
|
|
|
|
rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:
|
2008-12-15 17:14:30 +00:00
|
|
|
NSMakeRect(0.0, 0.0, size.width, size.height)];
|
2007-03-08 09:35:09 +00:00
|
|
|
[self unlockFocus];
|
|
|
|
[self addRepresentation: rep];
|
|
|
|
data = [rep TIFFRepresentation];
|
|
|
|
RELEASE(rep);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (NSData *) TIFFRepresentationUsingCompression: (NSTIFFCompression)comp
|
2008-11-16 23:21:58 +00:00
|
|
|
factor: (float)aFloat
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2007-03-08 09:35:09 +00:00
|
|
|
NSData *data;
|
|
|
|
|
|
|
|
// As a result of using bitmap representations, new drawing wont show on the tiff data.
|
|
|
|
data = [bitmapClass TIFFRepresentationOfImageRepsInArray: [self representations]
|
2008-12-15 17:14:30 +00:00
|
|
|
usingCompression: comp
|
|
|
|
factor: aFloat];
|
2007-03-08 09:35:09 +00:00
|
|
|
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
NSBitmapImageRep *rep;
|
|
|
|
NSSize size = [self size];
|
|
|
|
|
|
|
|
// If there isn't a bitmap representation to output, create one and store it.
|
|
|
|
[self lockFocus];
|
|
|
|
rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:
|
2008-12-15 17:14:30 +00:00
|
|
|
NSMakeRect(0.0, 0.0, size.width, size.height)];
|
2007-03-08 09:35:09 +00:00
|
|
|
[self unlockFocus];
|
|
|
|
[self addRepresentation: rep];
|
|
|
|
data = [rep TIFFRepresentationUsingCompression: comp factor: aFloat];
|
|
|
|
RELEASE(rep);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
// NSCoding
|
1999-03-02 08:58:30 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder*)coder
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
BOOL flag;
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2006-10-15 08:34:47 +00:00
|
|
|
if ([coder allowsKeyedCoding])
|
1999-12-28 16:02:01 +00:00
|
|
|
{
|
2006-08-09 01:37:32 +00:00
|
|
|
// FIXME: Not sure this is the way it goes...
|
2006-08-09 05:48:54 +00:00
|
|
|
/*
|
2006-10-15 08:34:47 +00:00
|
|
|
if (_flags.archiveByName == NO)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *container = [NSMutableArray array];
|
|
|
|
NSMutableArray *reps = [NSMutableArray array];
|
|
|
|
NSEnumerator *en = [_reps objectEnumerator];
|
|
|
|
GSRepData *rd = nil;
|
|
|
|
|
|
|
|
// add the reps to the container...
|
|
|
|
[container addObject: reps];
|
|
|
|
while ((rd = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[reps addObject: rd->rep];
|
|
|
|
}
|
|
|
|
[coder encodeObject: container forKey: @"NSReps"];
|
|
|
|
}
|
2006-08-09 01:37:32 +00:00
|
|
|
else
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
[coder encodeObject: _name forKey: @"NSImageName"];
|
|
|
|
}
|
2006-08-09 05:48:54 +00:00
|
|
|
*/
|
2006-08-09 01:37:32 +00:00
|
|
|
|
|
|
|
// encode the rest...
|
|
|
|
[coder encodeObject: _color forKey: @"NSColor"];
|
|
|
|
[coder encodeInt: 0 forKey: @"NSImageFlags"]; // zero...
|
|
|
|
[coder encodeSize: _size forKey: @"NSSize"];
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-09 01:37:32 +00:00
|
|
|
flag = _flags.archiveByName;
|
1999-12-28 16:02:01 +00:00
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2006-08-09 01:37:32 +00:00
|
|
|
if (flag == YES)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* System image - just encode the name.
|
|
|
|
*/
|
|
|
|
[coder encodeValueOfObjCType: @encode(id) at: &_name];
|
|
|
|
}
|
2006-08-09 01:37:32 +00:00
|
|
|
else
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *a;
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSImageRep *r;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Normal image - encode the ivars
|
|
|
|
*/
|
|
|
|
[coder encodeValueOfObjCType: @encode(NSSize) at: &_size];
|
|
|
|
[coder encodeValueOfObjCType: @encode(id) at: &_color];
|
|
|
|
flag = _flags.scalable;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.dataRetained;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.flipDraw;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.sizeWasExplicitlySet;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.useEPSOnResolutionMismatch;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.colorMatchPreferred;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.multipleResolutionMatching;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.cacheSeparately;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
flag = _flags.unboundedCacheDepth;
|
|
|
|
[coder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
|
|
|
// FIXME: The documentation says to archive only the file name,
|
|
|
|
// if not data retained!
|
|
|
|
/*
|
|
|
|
* Now encode an array of all the image reps (excluding cache)
|
|
|
|
*/
|
|
|
|
a = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
e = [[self representations] objectEnumerator];
|
|
|
|
while ((r = [e nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([r isKindOfClass: cachedClass] == NO)
|
|
|
|
{
|
|
|
|
[a addObject: r];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[coder encodeValueOfObjCType: @encode(id) at: &a];
|
|
|
|
}
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
|
1999-03-02 08:58:30 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)coder
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
BOOL flag;
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2001-09-01 20:57:51 +00:00
|
|
|
_reps = [[NSMutableArray alloc] initWithCapacity: 2];
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder allowsKeyedCoding])
|
1999-12-28 16:02:01 +00:00
|
|
|
{
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder containsValueForKey: @"NSColor"])
|
|
|
|
{
|
2008-11-16 23:21:58 +00:00
|
|
|
[self setBackgroundColor: [coder decodeObjectForKey: @"NSColor"]];
|
|
|
|
}
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder containsValueForKey: @"NSImageFlags"])
|
|
|
|
{
|
|
|
|
//FIXME
|
2011-02-09 22:20:00 +00:00
|
|
|
//int flags = [coder decodeIntForKey: @"NSImageFlags"];
|
2008-11-16 23:21:58 +00:00
|
|
|
}
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder containsValueForKey: @"NSReps"])
|
|
|
|
{
|
2008-11-16 23:21:58 +00:00
|
|
|
NSArray *reps;
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2008-11-16 23:21:58 +00:00
|
|
|
// FIXME: NSReps is in a strange format. It is a mutable array with one
|
2004-10-10 22:36:02 +00:00
|
|
|
// element which is an array with a first element 0 and than the image rep.
|
2008-11-16 23:21:58 +00:00
|
|
|
reps = [coder decodeObjectForKey: @"NSReps"];
|
|
|
|
reps = [reps objectAtIndex: 0];
|
|
|
|
[self addRepresentation: [reps objectAtIndex: 1]];
|
|
|
|
}
|
2004-10-10 22:36:02 +00:00
|
|
|
if ([coder containsValueForKey: @"NSSize"])
|
|
|
|
{
|
2008-11-16 23:21:58 +00:00
|
|
|
[self setSize: [coder decodeSizeForKey: @"NSSize"]];
|
|
|
|
}
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-08-30 22:02:38 +00:00
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2004-10-10 22:36:02 +00:00
|
|
|
if (flag == YES)
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSString *theName = [coder decodeObject];
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2008-11-16 23:21:58 +00:00
|
|
|
RELEASE(self);
|
|
|
|
self = RETAIN([NSImage imageNamed: theName]);
|
|
|
|
}
|
2004-10-10 22:36:02 +00:00
|
|
|
else
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSArray *a;
|
2008-11-16 23:21:58 +00:00
|
|
|
|
|
|
|
[coder decodeValueOfObjCType: @encode(NSSize) at: &_size];
|
|
|
|
[coder decodeValueOfObjCType: @encode(id) at: &_color];
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.scalable = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.dataRetained = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.flipDraw = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.sizeWasExplicitlySet = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.useEPSOnResolutionMismatch = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.colorMatchPreferred = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.multipleResolutionMatching = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.cacheSeparately = flag;
|
|
|
|
[coder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
_flags.unboundedCacheDepth = flag;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get the image reps and add them.
|
|
|
|
*/
|
|
|
|
a = [coder decodeObject];
|
|
|
|
[self addRepresentations: a];
|
|
|
|
}
|
1999-12-28 16:02:01 +00:00
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
return self;
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
- (id) awakeAfterUsingCoder: (NSCoder*)aDecoder
|
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
if (_name && [nameDict objectForKey: _name])
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2000-12-23 14:19:23 +00:00
|
|
|
return [nameDict objectForKey: _name];
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
+ (BOOL) canInitWithPasteboard: (NSPasteboard *)pasteboard
|
|
|
|
{
|
|
|
|
int i, count;
|
|
|
|
NSArray* array = [NSImageRep registeredImageRepClasses];
|
|
|
|
|
|
|
|
count = [array count];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
if ([[array objectAtIndex: i] canInitWithPasteboard: pasteboard])
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageUnfilteredFileTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
2008-12-15 17:14:30 +00:00
|
|
|
@selector(imageUnfilteredFileTypes));
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageFileTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
2008-12-15 17:14:30 +00:00
|
|
|
@selector(imageFileTypes));
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageUnfilteredPasteboardTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
2008-12-15 17:14:30 +00:00
|
|
|
@selector(imageUnfilteredPasteboardTypes));
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imagePasteboardTypes
|
|
|
|
{
|
|
|
|
return iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
2008-12-15 17:14:30 +00:00
|
|
|
@selector(imagePasteboardTypes));
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
@end
|
|
|
|
|
1996-08-22 18:51:08 +00:00
|
|
|
/* For every image rep, call the specified method to obtain an
|
|
|
|
array of objects. Add these together, with duplicates
|
|
|
|
weeded out. Used by imageUnfilteredPasteboardTypes,
|
|
|
|
imageUnfilteredFileTypes, etc. */
|
2003-10-30 00:23:23 +00:00
|
|
|
static NSArray *
|
1996-08-22 18:51:08 +00:00
|
|
|
iterate_reps_for_types(NSArray* imageReps, SEL method)
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSMutableArray *types;
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
types = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
|
|
|
|
// Iterate through all the image reps
|
|
|
|
e = [imageReps objectEnumerator];
|
|
|
|
rep = [e nextObject];
|
|
|
|
while (rep)
|
|
|
|
{
|
|
|
|
id e1;
|
|
|
|
id obj;
|
|
|
|
NSArray* pb_list;
|
|
|
|
|
|
|
|
// Have the image rep perform the operation
|
1997-08-27 21:20:19 +00:00
|
|
|
pb_list = [rep performSelector: method];
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
// Iterate through the returned array
|
|
|
|
// and add elements to types list, duplicates weeded.
|
|
|
|
e1 = [pb_list objectEnumerator];
|
|
|
|
obj = [e1 nextObject];
|
|
|
|
while (obj)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
|
|
|
if ([types indexOfObject: obj] == NSNotFound)
|
|
|
|
[types addObject: obj];
|
|
|
|
obj = [e1 nextObject];
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
|
|
|
rep = [e nextObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NSArray *)types;
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
@implementation NSImage (Private)
|
|
|
|
|
|
|
|
- (BOOL)_loadFromData: (NSData *)data
|
|
|
|
{
|
|
|
|
BOOL ok;
|
|
|
|
Class rep;
|
|
|
|
|
|
|
|
ok = NO;
|
|
|
|
rep = [NSImageRep imageRepClassForData: data];
|
|
|
|
if (rep && [rep respondsToSelector: @selector(imageRepsWithData:)])
|
|
|
|
{
|
|
|
|
NSArray* array;
|
|
|
|
array = [rep imageRepsWithData: data];
|
|
|
|
if (array)
|
2008-12-15 17:14:30 +00:00
|
|
|
ok = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
[self addRepresentations: array];
|
|
|
|
}
|
|
|
|
else if (rep)
|
|
|
|
{
|
|
|
|
NSImageRep* image;
|
|
|
|
image = [rep imageRepWithData: data];
|
|
|
|
if (image)
|
2008-12-15 17:14:30 +00:00
|
|
|
ok = YES;
|
2000-12-23 14:19:23 +00:00
|
|
|
[self addRepresentation: image];
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _loadFromFile: (NSString *)fileName
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSArray *array;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
array = [NSImageRep imageRepsWithContentsOfFile: fileName];
|
|
|
|
if (array)
|
|
|
|
[self addRepresentations: array];
|
|
|
|
|
|
|
|
return (array) ? YES : NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _useFromFile: (NSString *)fileName
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
NSArray *array;
|
|
|
|
NSString *ext;
|
2000-12-23 14:19:23 +00:00
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
|
|
|
|
if ([manager fileExistsAtPath: fileName] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2010-01-17 23:37:11 +00:00
|
|
|
ext = [[fileName pathExtension] lowercaseString];
|
2000-12-23 14:19:23 +00:00
|
|
|
if (!ext)
|
|
|
|
return NO;
|
|
|
|
array = [isa imageFileTypes];
|
|
|
|
if ([array indexOfObject: ext] == NSNotFound)
|
|
|
|
return NO;
|
2001-08-11 18:34:22 +00:00
|
|
|
|
|
|
|
ASSIGN(_fileName, fileName);
|
2000-12-23 14:19:23 +00:00
|
|
|
_flags.syncLoad = YES;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache the bestRepresentation. If the bestRepresentation is not itself
|
|
|
|
// a cache and no cache exists, create one and draw the representation in it
|
|
|
|
// If a cache exists, but is not valid, redraw the cache from the original
|
|
|
|
// image (if there is one).
|
2008-12-13 19:32:54 +00:00
|
|
|
- (NSCachedImageRep *) _doImageCache: (NSImageRep *)rep
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
GSRepData *repd;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
repd = [self _cacheForRep: rep];
|
|
|
|
rep = repd->rep;
|
|
|
|
if ([rep isKindOfClass: cachedClass] == NO)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
NSDebugLLog(@"NSImage", @"Cached image rep is %p", rep);
|
|
|
|
/*
|
|
|
|
* if the cache is not valid, it's background color will not exist
|
|
|
|
* and we must draw the background then render from the original
|
|
|
|
* image rep into the cache.
|
|
|
|
*/
|
|
|
|
if (repd->bg == nil)
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
[self lockFocusOnRepresentation: rep];
|
|
|
|
[self drawRepresentation: repd->original
|
2008-12-15 17:14:30 +00:00
|
|
|
inRect: NSMakeRect(0, 0, _size.width, _size.height)];
|
2008-12-13 19:32:54 +00:00
|
|
|
[self unlockFocus];
|
|
|
|
|
|
|
|
NSDebugLLog(@"NSImage", @"Rendered rep %p on background %@",
|
|
|
|
rep, repd->bg);
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
return (NSCachedImageRep *)rep;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
- (GSRepData*) _cacheForRep: (NSImageRep*)rep
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
if ([rep isKindOfClass: cachedClass] == YES)
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
2008-12-13 19:32:54 +00:00
|
|
|
return repd_for_rep(_reps, rep);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If this is not a cached image rep - try to find the cache rep
|
|
|
|
* for this image rep. If none is found create a cache to be used to
|
|
|
|
* render the image rep into, and switch to the cached rep.
|
|
|
|
*/
|
|
|
|
unsigned count = [_reps count];
|
2000-12-23 14:19:23 +00:00
|
|
|
|
|
|
|
if (count > 0)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
|
|
|
GSRepData *invalidCache = nil;
|
|
|
|
GSRepData *partialCache = nil;
|
|
|
|
GSRepData *reps[count];
|
|
|
|
unsigned partialCount = 0;
|
|
|
|
unsigned i;
|
|
|
|
BOOL opaque = [rep isOpaque];
|
|
|
|
|
|
|
|
[_reps getObjects: reps];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search the cached image reps for any whose original is our
|
|
|
|
* 'best' image rep. See if we can notice any invalidated
|
|
|
|
* cache as we go - if we don't find a valid cache, we want to
|
|
|
|
* re-use an invalidated one rather than creating a new one.
|
|
|
|
* NB. If the image rep is opaque, then any cached rep is valid
|
|
|
|
* irrespective of the background color it was drawn with.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
GSRepData *repd = reps[i];
|
2008-12-13 19:32:54 +00:00
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
if (repd->original == rep && repd->rep != nil)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
|
|
|
if (repd->bg == nil)
|
|
|
|
{
|
2010-04-10 17:48:46 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"Invalid %@ ... %@ %@",
|
2008-12-13 19:32:54 +00:00
|
|
|
repd->bg, _color, repd->rep);
|
|
|
|
invalidCache = repd;
|
|
|
|
}
|
|
|
|
else if (opaque == YES || [repd->bg isEqual: _color] == YES)
|
|
|
|
{
|
2010-04-10 17:48:46 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"Exact %@ ... %@ %@",
|
2008-12-13 19:32:54 +00:00
|
|
|
repd->bg, _color, repd->rep);
|
2008-12-15 17:14:30 +00:00
|
|
|
return repd;
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-04-10 17:48:46 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"Partial %@ ... %@ %@",
|
2008-12-13 19:32:54 +00:00
|
|
|
repd->bg, _color, repd->rep);
|
|
|
|
partialCache = repd;
|
|
|
|
partialCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
if (invalidCache != nil)
|
2008-12-13 19:32:54 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
/*
|
|
|
|
* If there is an unused cache - use it rather than
|
|
|
|
* re-using this one, since we might get a request
|
|
|
|
* to draw with this color again.
|
|
|
|
*/
|
|
|
|
return invalidCache;
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
|
|
|
else if (partialCache != nil && partialCount > 2)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Only re-use partially correct caches if there are already
|
|
|
|
* a few partial matches - otherwise we fall default to
|
|
|
|
* creating a new cache.
|
|
|
|
*/
|
|
|
|
if (NSImageForceCaching == NO && opaque == NO)
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
DESTROY(partialCache->bg);
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
return partialCache;
|
2008-12-13 19:32:54 +00:00
|
|
|
}
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
// We end here, when no representation are there or no match is found.
|
|
|
|
{
|
|
|
|
NSImageRep *cacheRep = nil;
|
2008-12-13 19:32:54 +00:00
|
|
|
GSRepData *repd;
|
2008-12-15 17:14:30 +00:00
|
|
|
NSSize imageSize = [self size];
|
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
if (imageSize.width == 0 || imageSize.height == 0)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
// Create a new cached image rep without any contents.
|
|
|
|
cacheRep = [[cachedClass alloc]
|
2008-12-15 17:14:30 +00:00
|
|
|
initWithSize: imageSize
|
2008-12-13 19:32:54 +00:00
|
|
|
depth: [[NSScreen mainScreen] depth]
|
2008-12-15 17:14:30 +00:00
|
|
|
separate: _flags.cacheSeparately
|
|
|
|
alpha: [rep hasAlpha]];
|
2008-12-13 19:32:54 +00:00
|
|
|
repd = [GSRepData new];
|
|
|
|
repd->rep = cacheRep;
|
2000-12-23 14:19:23 +00:00
|
|
|
repd->original = rep;
|
2008-12-13 19:32:54 +00:00
|
|
|
[_reps addObject: repd];
|
2008-12-15 17:14:30 +00:00
|
|
|
RELEASE(repd); /* Retained in _reps array. */
|
2008-12-13 19:32:54 +00:00
|
|
|
|
|
|
|
return repd;
|
|
|
|
}
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2009-09-27 08:54:03 +00:00
|
|
|
|
|
|
|
@implementation NSImage (GSTheme)
|
|
|
|
|
2010-05-09 06:55:33 +00:00
|
|
|
/* This method is used by the theming system to replace a named image
|
|
|
|
* without disturbing the proxy ... so that all views and cells using
|
|
|
|
* the named image are automatically updated to use the new image.
|
|
|
|
* This is the counterpart to the -setName: method, which replaces the
|
|
|
|
* proxy (to change a named image without updating the image used by
|
|
|
|
* existing views and cells).
|
|
|
|
*/
|
2009-09-27 08:54:03 +00:00
|
|
|
+ (NSImage*) _setImage: (NSImage*)image name: (NSString*)name
|
|
|
|
{
|
|
|
|
GSThemeProxy *proxy = nil;
|
|
|
|
|
|
|
|
NSAssert([image isKindOfClass: [NSImage class]], NSInvalidArgumentException);
|
|
|
|
NSAssert(![image isProxy], NSInvalidArgumentException);
|
|
|
|
NSAssert([name isKindOfClass: [NSString class]], NSInvalidArgumentException);
|
|
|
|
NSAssert([name length] > 0, NSInvalidArgumentException);
|
|
|
|
NSAssert([image name] == nil, NSInvalidArgumentException);
|
|
|
|
|
|
|
|
[imageLock lock];
|
|
|
|
ASSIGNCOPY(image->_name, name);
|
|
|
|
if ((proxy = [nameDict objectForKey: image->_name]) == nil)
|
|
|
|
{
|
|
|
|
proxy = [GSThemeProxy alloc];
|
|
|
|
[nameDict setObject: proxy forKey: image->_name];
|
|
|
|
[proxy release];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Remove the name from the old image.
|
|
|
|
*/
|
|
|
|
DESTROY(((NSImage*)[proxy _resource])->_name);
|
|
|
|
}
|
|
|
|
[proxy _setResource: image];
|
|
|
|
IF_NO_GC([[proxy retain] autorelease]);
|
2010-08-03 21:11:00 +00:00
|
|
|
|
|
|
|
/* Force the image to be archived by name. This prevents
|
|
|
|
* problems such as when/if gorm is being used with a theme
|
|
|
|
* active, it will not save the image which was loaded
|
|
|
|
* here and will, instead save the name so that the proper
|
|
|
|
* image gets loaded in the future.
|
|
|
|
*/
|
|
|
|
image->_flags.archiveByName = YES;
|
|
|
|
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
|
|
|
return (NSImage*)proxy;
|
|
|
|
}
|
|
|
|
@end
|