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
|
|
|
|
2016-02-03 00:08:23 +00:00
|
|
|
Copyright (C) 1996-2016 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/NSKeyedArchiver.h>
|
2012-01-09 14:39:50 +00:00
|
|
|
#import <Foundation/NSLock.h>
|
|
|
|
#import <Foundation/NSNotification.h>
|
2009-09-27 08:54:03 +00:00
|
|
|
#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"
|
2011-10-06 11:06:31 +00:00
|
|
|
#import "AppKit/DPSOperators.h"
|
2009-09-27 08:54:03 +00:00
|
|
|
#import "GNUstepGUI/GSDisplayServer.h"
|
|
|
|
#import "GSThemePrivate.h"
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2008-12-15 17:14:30 +00:00
|
|
|
BOOL NSImageForceCaching = NO; /* use on missmatch */
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2015-11-12 08:33:35 +00:00
|
|
|
static NSDictionary *nsmapping = nil;
|
|
|
|
|
2017-03-05 22:12:15 +00:00
|
|
|
// OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
|
|
|
|
NSString *const NSImageNameQuickLookTemplate = @"NSQuickLookTemplate";
|
|
|
|
NSString *const NSImageNameBluetooth = @"NSBluetoothTemplate";
|
|
|
|
NSString *const NSImageNameIChatTheater = @"NSIChatTheaterTemplate";
|
|
|
|
NSString *const NSImageNameSlideshow = @"NSSlideshowTemplate";
|
|
|
|
NSString *const NSImageNameAction = @"NSActionTemplate";
|
|
|
|
NSString *const NSImageNameSmartBadge = @"NSSmartBadgeTemplate";
|
|
|
|
NSString *const NSImageNameIconView = @"NSIconViewTemplate";
|
|
|
|
NSString *const NSImageNameListView = @"NSListViewTemplate";
|
|
|
|
NSString *const NSImageNameColumnView = @"NSColumnViewTemplate";
|
|
|
|
NSString *const NSImageNameFlowView = @"NSFlowViewTemplate";
|
|
|
|
NSString *const NSImageNamePath = @"NSPathTemplate";
|
|
|
|
NSString *const NSImageNameInvalidDataFreestanding = @"NSInvalidDataFreestandingTemplate";
|
|
|
|
NSString *const NSImageNameLockLocked = @"NSLockLockedTemplate";
|
|
|
|
NSString *const NSImageNameLockUnlocked = @"NSLockUnlockedTemplate";
|
|
|
|
NSString *const NSImageNameGoRight = @"NSGoRightTemplate";
|
|
|
|
NSString *const NSImageNameGoLeft = @"NSGoLeftTemplate";
|
|
|
|
NSString *const NSImageNameRightFacingTriangle = @"NSRightFacingTriangleTemplate";
|
|
|
|
NSString *const NSImageNameLeftFacingTriangle = @"NSLeftFacingTriangleTemplate";
|
|
|
|
NSString *const NSImageNameAdd = @"NSAddTemplate";
|
|
|
|
NSString *const NSImageNameRemove = @"NSRemoveTemplate";
|
|
|
|
NSString *const NSImageNameRevealFreestanding = @"NSRevealFreestandingTemplate";
|
|
|
|
NSString *const NSImageNameFollowLinkFreestanding = @"NSFollowLinkFreestandingTemplate";
|
|
|
|
NSString *const NSImageNameEnterFullScreen = @"NSEnterFullScreenTemplate";
|
|
|
|
NSString *const NSImageNameExitFullScreen = @"NSExitFullScreenTemplate";
|
|
|
|
NSString *const NSImageNameStopProgress = @"NSStopProgressTemplate";
|
|
|
|
NSString *const NSImageNameStopProgressFreestanding = @"NSStopProgressFreestandingTemplate";
|
|
|
|
NSString *const NSImageNameRefresh = @"NSRefreshTemplate";
|
|
|
|
NSString *const NSImageNameRefreshFreestanding = @"NSRefreshFreestandingTemplate";
|
|
|
|
NSString *const NSImageNameBonjour = @"NSBonjour";
|
|
|
|
NSString *const NSImageNameComputer = @"NSComputer";
|
|
|
|
NSString *const NSImageNameFolderBurnable = @"NSFolderBurnable";
|
|
|
|
NSString *const NSImageNameFolderSmart = @"NSFolderSmart";
|
|
|
|
NSString *const NSImageNameNetwork = @"NSNetwork";
|
|
|
|
|
2014-10-05 19:59:37 +00:00
|
|
|
@interface NSView (Private)
|
|
|
|
- (void) _lockFocusInContext: (NSGraphicsContext *)ctxt inRect: (NSRect)rect;
|
|
|
|
@end
|
|
|
|
|
2002-09-25 22:55:44 +00:00
|
|
|
@implementation NSBundle (NSImageAdditions)
|
|
|
|
|
2015-11-12 08:33:35 +00:00
|
|
|
static NSArray*
|
|
|
|
imageTypes()
|
2002-09-25 22:55:44 +00:00
|
|
|
{
|
2015-11-12 08:33:35 +00:00
|
|
|
NSArray *types;
|
2002-09-25 22:55:44 +00:00
|
|
|
|
2015-11-12 08:33:35 +00:00
|
|
|
/* If the extension is one of the image types,
|
|
|
|
* remove it from the name and place it in the
|
|
|
|
* type argument.
|
|
|
|
*/
|
|
|
|
types = [[[GSTheme theme] imageClass] imageUnfilteredFileTypes];
|
|
|
|
if (nil == types)
|
2002-09-25 22:55:44 +00:00
|
|
|
{
|
2015-11-12 08:33:35 +00:00
|
|
|
types = [NSImage imageUnfilteredFileTypes];
|
|
|
|
}
|
|
|
|
return types;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fixupImageNameAndType(NSString **name, NSString **type)
|
|
|
|
{
|
|
|
|
NSString *ext = [*name pathExtension];
|
2002-09-25 22:55:44 +00:00
|
|
|
|
2015-11-12 08:33:35 +00:00
|
|
|
if ([ext length] > 0)
|
|
|
|
{
|
|
|
|
/* If the extension is one of the image types,
|
|
|
|
* remove it from the name and place it in the
|
|
|
|
* type argument.
|
|
|
|
*/
|
|
|
|
if ([imageTypes() indexOfObject: ext] != NSNotFound)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
2015-11-12 08:33:35 +00:00
|
|
|
*type = ext;
|
|
|
|
*name = [*name stringByDeletingPathExtension];
|
2008-12-15 17:14:30 +00:00
|
|
|
}
|
2002-09-25 22:55:44 +00:00
|
|
|
}
|
2015-11-12 08:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _pathForImageNamed: (NSString *)aName
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
subdirectory: (NSString *)aDir
|
|
|
|
inBundle: (NSBundle *)aBundle
|
|
|
|
{
|
|
|
|
NSEnumerator *e;
|
|
|
|
id o;
|
|
|
|
|
|
|
|
if (ext != nil)
|
|
|
|
{
|
|
|
|
return [aBundle pathForResource: aName ofType: ext inDirectory: aDir];
|
|
|
|
}
|
|
|
|
|
|
|
|
e = [imageTypes() objectEnumerator];
|
|
|
|
while ((o = [e nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
path = [aBundle pathForResource: aName ofType: o inDirectory: aDir];
|
|
|
|
if ([path length] > 0)
|
|
|
|
{
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _pathForLibraryImageNamed: (NSString *)aName
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)aDir
|
|
|
|
{
|
|
|
|
NSEnumerator *e;
|
|
|
|
id o;
|
|
|
|
|
|
|
|
if (ext != nil)
|
|
|
|
{
|
|
|
|
return [NSBundle pathForLibraryResource: aName
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: aDir];
|
|
|
|
}
|
|
|
|
|
|
|
|
e = [imageTypes() objectEnumerator];
|
|
|
|
while ((o = [e nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
path = [NSBundle pathForLibraryResource: aName
|
|
|
|
ofType: o
|
|
|
|
inDirectory: aDir];
|
|
|
|
if ([path length] > 0)
|
|
|
|
{
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _pathForSystemImageNamed: (NSString *)realName
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
{
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
path = [self _pathForLibraryImageNamed: realName
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: @"Images"];
|
|
|
|
|
|
|
|
/* If not found then search in system using the reverse NSImage nsmapping */
|
|
|
|
if (nil == path)
|
|
|
|
{
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSString *aliasName;
|
|
|
|
|
|
|
|
e = [[nsmapping allKeysForObject: realName] objectEnumerator];
|
|
|
|
while ((aliasName = [e nextObject]) != nil)
|
|
|
|
{
|
|
|
|
path = [self _pathForLibraryImageNamed: aliasName
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: @"Images"];
|
|
|
|
|
|
|
|
if (path != nil)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nsmapping.strings maps alternative image naming schemes to the GSTheme
|
|
|
|
* standard image naming scheme. For example, NSSwitch (from OpenStep) and
|
|
|
|
* common_SwitchOff (from GNUstep) are mapped to GSSwitch. In nameDict that
|
|
|
|
* tracks image instances, the keys are image names from GSTheme such as
|
|
|
|
* GSSwitch or additional icon names such NSApplicationIcon or
|
|
|
|
* NSToolbarShowColors. In the long run, it would be cleaner to move built-in
|
|
|
|
* theme images into a GNUstep.theme bundle.
|
|
|
|
*
|
|
|
|
* If you pass NSSwitch to +imageNamed:, nsmapping is used to get GSSwitch as
|
|
|
|
* the real name, then _pathForImageNamed: will look up the image first in the
|
|
|
|
* theme and fall back on the Library images. For the library images, we do a
|
|
|
|
* reverse lookup in nsmapping (using allKeysForObject:) to get the image file
|
|
|
|
* name (e.g. from GSSwitch to common_SwitchOff). This reverse lookup is
|
|
|
|
* similar to the one supported for getting image file names from the
|
|
|
|
* bundle, this reverse lookup could be handled by GSTheme rather than being
|
|
|
|
*
|
|
|
|
* The type received in argument is meaningfull for searching image files
|
|
|
|
* using the proposed image name, but useless otherwise.
|
|
|
|
*/
|
|
|
|
- (NSString *) _pathForThemeImageNamed: (NSString *)name
|
|
|
|
ofType: (NSString *)ext
|
|
|
|
{
|
|
|
|
GSTheme *theme;
|
|
|
|
NSDictionary *themeMapping;
|
|
|
|
NSString *mappedName;
|
|
|
|
NSString *path = nil;
|
|
|
|
|
|
|
|
theme = [GSTheme theme];
|
|
|
|
themeMapping = [[theme infoDictionary] objectForKey: @"GSThemeImages"];
|
|
|
|
mappedName = [themeMapping objectForKey: name];
|
|
|
|
|
|
|
|
/* First search among the theme images using the GSTheme mapping */
|
|
|
|
if (mappedName != nil)
|
|
|
|
{
|
|
|
|
NSString *extension = nil;
|
|
|
|
NSString *proposedName = mappedName;
|
|
|
|
|
|
|
|
fixupImageNameAndType(&proposedName, &extension);
|
|
|
|
|
|
|
|
/* If the image file name from the theme mapping uses an extension,
|
|
|
|
* this extension is used to look up the path. If the image file
|
|
|
|
* cannot be found, _pathForImageNamed:ofType:subdirectory:inBundle:
|
|
|
|
* searches an image file for the file extensions from -imageFileTypes.
|
|
|
|
*/
|
|
|
|
path = [self _pathForImageNamed: proposedName
|
|
|
|
ofType: extension
|
|
|
|
subdirectory: @"ThemeImages"
|
|
|
|
inBundle: [theme bundle]];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If not found, search among the theme images using the reverse NSImage
|
|
|
|
* mapping (for GNUstep and OpenStep image names such as common_SwitchOff
|
|
|
|
* or NSSwitch)
|
|
|
|
*/
|
|
|
|
if (nil == path)
|
|
|
|
{
|
|
|
|
NSEnumerator *e;
|
|
|
|
NSString *aliasName;
|
|
|
|
|
|
|
|
e = [[nsmapping allKeysForObject: name] objectEnumerator];
|
|
|
|
while (nil == path && (aliasName = [e nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSAssert([[aliasName pathExtension] length] == 0,
|
|
|
|
@"nsmapping.strings "
|
|
|
|
"must include no extensions in image file names");
|
|
|
|
|
|
|
|
path = [self _pathForImageNamed: aliasName
|
|
|
|
ofType: nil
|
|
|
|
subdirectory: @"ThemeImages"
|
|
|
|
inBundle: [theme bundle]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If not found, search among the theme images using the image name directly
|
|
|
|
*/
|
|
|
|
if (path == nil)
|
2002-09-25 22:55:44 +00:00
|
|
|
{
|
2015-11-12 08:33:35 +00:00
|
|
|
path = [self _pathForImageNamed: name
|
|
|
|
ofType: ext
|
|
|
|
subdirectory: @"ThemeImages"
|
|
|
|
inBundle: [theme bundle]];
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) pathForImageResource: (NSString*)name
|
|
|
|
{
|
|
|
|
NSString *ext = nil;
|
|
|
|
NSString *path = nil;
|
|
|
|
NSString *ident;
|
|
|
|
|
|
|
|
fixupImageNameAndType(&name, &ext);
|
|
|
|
if (nil != (ident = [self bundleIdentifier]))
|
|
|
|
{
|
|
|
|
NSString *subdir;
|
|
|
|
|
|
|
|
subdir = [@"ThemeImages" stringByAppendingPathComponent: ident];
|
|
|
|
path = [self _pathForImageNamed: name
|
|
|
|
ofType: ext
|
|
|
|
subdirectory: subdir
|
|
|
|
inBundle: [[GSTheme theme] bundle]];
|
|
|
|
}
|
|
|
|
if (nil == path)
|
|
|
|
{
|
|
|
|
path = [self _pathForImageNamed: name
|
|
|
|
ofType: ext
|
|
|
|
subdirectory: nil
|
|
|
|
inBundle: self];
|
|
|
|
if (nil == path)
|
|
|
|
{
|
|
|
|
path = [self _pathForThemeImageNamed: name ofType: ext];
|
|
|
|
if (nil == path)
|
|
|
|
{
|
|
|
|
path = [self _pathForSystemImageNamed: name ofType: ext];
|
|
|
|
}
|
|
|
|
}
|
2002-09-25 22:55:44 +00:00
|
|
|
}
|
|
|
|
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 NSColor *clearColor = nil;
|
2008-12-15 17:14:30 +00:00
|
|
|
static Class cachedClass = 0;
|
|
|
|
static Class bitmapClass = 0;
|
2012-01-09 14:39:50 +00:00
|
|
|
// Cache for the supported file types
|
|
|
|
static NSArray *imageUnfilteredFileTypes = nil;
|
|
|
|
static NSArray *imageFileTypes = nil;
|
|
|
|
static NSArray *imageUnfilteredPasteboardTypes = nil;
|
|
|
|
static NSArray *imagePasteboardTypes = nil;
|
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)
|
2012-01-10 19:16:46 +00:00
|
|
|
+ (void) _clearFileTypeCaches: (NSNotification*)notif;
|
2013-04-06 19:30:48 +00:00
|
|
|
+ (void) _reloadCachedImages;
|
2000-12-23 14:19:23 +00:00
|
|
|
- (BOOL) _useFromFile: (NSString *)fileName;
|
|
|
|
- (BOOL) _loadFromData: (NSData *)data;
|
|
|
|
- (BOOL) _loadFromFile: (NSString *)fileName;
|
2012-01-10 18:55:57 +00:00
|
|
|
- (BOOL) _resetAndUseFromFile: (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)
|
2013-04-06 19:30:30 +00:00
|
|
|
nsmapping = RETAIN([[NSString stringWithContentsOfFile: path]
|
2008-12-15 17:14:30 +00:00
|
|
|
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];
|
2012-01-09 14:39:50 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
2012-01-10 19:16:46 +00:00
|
|
|
selector: @selector(_clearFileTypeCaches:)
|
|
|
|
name: NSImageRepRegistryChangedNotification
|
|
|
|
object: [NSImageRep class]];
|
2009-09-27 08:54:03 +00:00
|
|
|
[imageLock unlock];
|
1997-03-05 01:11:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-10 04:38:10 +00:00
|
|
|
+ (id) imageNamed: (NSString *)aName
|
|
|
|
{
|
|
|
|
NSImage *image;
|
2013-07-04 15:46:11 +00:00
|
|
|
NSString *realName;
|
2008-12-15 17:14:30 +00:00
|
|
|
|
2012-01-10 04:38:10 +00:00
|
|
|
[imageLock lock];
|
2013-07-04 15:46:11 +00:00
|
|
|
|
|
|
|
realName = [nsmapping objectForKey: aName];
|
|
|
|
if (realName == nil)
|
2012-01-10 04:38:10 +00:00
|
|
|
{
|
2013-07-04 15:46:11 +00:00
|
|
|
realName = aName;
|
|
|
|
}
|
|
|
|
image = (NSImage*)[nameDict objectForKey: realName];
|
|
|
|
|
|
|
|
if (image == nil && realName != nil)
|
|
|
|
{
|
2015-11-12 08:33:35 +00:00
|
|
|
NSString *path = [[NSBundle mainBundle] pathForImageResource: realName];
|
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
|
|
|
{
|
2012-01-14 17:55:43 +00:00
|
|
|
image = [[[[GSTheme theme] imageClass] alloc]
|
|
|
|
initByReferencingFile: path];
|
2008-12-15 17:14:30 +00:00
|
|
|
if (image != nil)
|
|
|
|
{
|
2017-10-28 07:48:36 +00:00
|
|
|
[image setName: realName];
|
|
|
|
image->_flags.archiveByName = YES;
|
2012-01-14 17:55:43 +00:00
|
|
|
AUTORELEASE(image);
|
2008-12-15 17:14:30 +00:00
|
|
|
}
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
2013-07-04 15:46:11 +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;
|
2012-01-10 04:38:10 +00:00
|
|
|
|
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
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
if ((array == nil) || ([array count] == 0)
|
|
|
|
|| (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
|
|
|
|
2013-03-18 22:50:11 +00:00
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
{
|
|
|
|
if (self == anObject)
|
|
|
|
return YES;
|
|
|
|
if (![anObject isKindOfClass: [NSImage class]])
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2013-12-26 12:34:57 +00:00
|
|
|
- (NSString*) description
|
|
|
|
{
|
|
|
|
return [NSString stringWithFormat: @"<%@ %p Name=%@ Size=%@ Reps=%@>",
|
|
|
|
[self class],
|
|
|
|
self,
|
|
|
|
[self name],
|
|
|
|
NSStringFromSize([self size]),
|
|
|
|
[self representations]];
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
2002-04-03 16:59:43 +00:00
|
|
|
- (BOOL) setName: (NSString *)aName
|
1996-08-22 18:51:08 +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.
|
|
|
|
*/
|
2012-01-10 04:38:10 +00:00
|
|
|
if (aName != nil && [nameDict objectForKey: aName] != 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]);
|
2012-01-10 19:16:46 +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);
|
2012-01-10 04:38:10 +00:00
|
|
|
|
|
|
|
[nameDict setObject: self forKey: _name];
|
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-25 17:39:11 +00:00
|
|
|
_size = aSize;
|
2001-08-11 18:34:22 +00:00
|
|
|
_flags.sizeWasExplicitlySet = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (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;
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger 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
|
|
|
|
{
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger 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
|
|
|
|
{
|
2011-11-12 00:40:18 +00:00
|
|
|
// FIXME: This currently breaks NSImage.
|
|
|
|
// See the test case in GSTest/Image-test that uses this method.
|
|
|
|
|
|
|
|
// _flags.scalable = flag;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
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
|
|
|
{
|
2011-06-14 06:08:40 +00:00
|
|
|
[self compositeToPoint: aPoint
|
|
|
|
fromRect: NSZeroRect
|
|
|
|
operation: op
|
|
|
|
fraction: 1.0];
|
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
|
2011-06-14 06:08:40 +00:00
|
|
|
fromRect: aRect
|
|
|
|
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
|
2013-02-16 00:08:33 +00:00
|
|
|
fraction: (CGFloat)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
[self compositeToPoint: aPoint
|
2011-06-14 06:08:40 +00:00
|
|
|
fromRect: NSZeroRect
|
|
|
|
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
|
2013-02-16 00:08:33 +00:00
|
|
|
fraction: (CGFloat)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2011-04-18 23:12:28 +00:00
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
2008-12-13 19:32:54 +00:00
|
|
|
|
2011-04-18 23:12:28 +00:00
|
|
|
// Calculate the user space scale factor of the current window
|
|
|
|
NSView *focusView = [NSView focusView];
|
|
|
|
CGFloat scaleFactor = 1.0;
|
|
|
|
if (focusView != nil)
|
2005-07-08 23:51:49 +00:00
|
|
|
{
|
2011-04-18 23:12:28 +00:00
|
|
|
scaleFactor = [[focusView window] userSpaceScaleFactor];
|
2005-07-08 23:51:49 +00:00
|
|
|
}
|
2011-04-18 23:12:28 +00:00
|
|
|
|
|
|
|
// Set the CTM to the identity matrix with the current translation
|
|
|
|
// and the user space scale factor
|
|
|
|
{
|
2013-09-23 16:58:18 +00:00
|
|
|
NSAffineTransform *backup = [[ctxt GSCurrentCTM] retain];
|
2011-04-18 23:12:28 +00:00
|
|
|
NSAffineTransform *newTransform = [NSAffineTransform transform];
|
|
|
|
NSPoint translation = [backup transformPoint: aPoint];
|
|
|
|
[newTransform translateXBy: translation.x
|
|
|
|
yBy: translation.y];
|
|
|
|
[newTransform scaleBy: scaleFactor];
|
|
|
|
|
|
|
|
[ctxt GSSetCTM: newTransform];
|
|
|
|
|
2011-06-14 06:08:40 +00:00
|
|
|
[self drawAtPoint: NSMakePoint(0, 0)
|
2011-04-18 23:12:28 +00:00
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta];
|
|
|
|
|
|
|
|
[ctxt GSSetCTM: backup];
|
2013-09-23 16:58:18 +00:00
|
|
|
|
|
|
|
[backup release];
|
2011-04-18 23:12:28 +00:00
|
|
|
}
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2013-02-16 00:08:33 +00:00
|
|
|
- (void) dissolveToPoint: (NSPoint)aPoint fraction: (CGFloat)aFloat
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
[self dissolveToPoint: aPoint
|
2011-06-14 06:08:40 +00:00
|
|
|
fromRect: NSZeroRect
|
|
|
|
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
|
2013-02-16 00:08:33 +00:00
|
|
|
fraction: (CGFloat)aFloat
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
2005-07-08 23:51:49 +00:00
|
|
|
[self compositeToPoint: aPoint
|
2011-06-14 06:08:40 +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;
|
2011-10-06 11:06:31 +00:00
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
2005-01-24 23:28:07 +00:00
|
|
|
|
2011-10-06 11:06:31 +00:00
|
|
|
DPSgsave(ctxt);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
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];
|
|
|
|
|
2011-10-06 11:06:31 +00:00
|
|
|
DPSgrestore(ctxt);
|
2005-01-24 23:28:07 +00:00
|
|
|
|
|
|
|
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
|
2013-02-16 00:08:33 +00:00
|
|
|
fraction: (CGFloat)delta
|
2001-08-11 18:34:22 +00:00
|
|
|
{
|
2011-06-14 06:08:40 +00:00
|
|
|
[self drawInRect: NSMakeRect(point.x, point.y, srcRect.size.width, srcRect.size.height)
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
2011-08-18 23:57:50 +00:00
|
|
|
fraction: delta
|
|
|
|
respectFlipped: NO
|
|
|
|
hints: nil];
|
2001-08-11 18:34:22 +00:00
|
|
|
}
|
|
|
|
|
2016-02-03 00:08:23 +00:00
|
|
|
- (void) drawInRect: (NSRect)rect
|
|
|
|
{
|
|
|
|
[self drawInRect: rect
|
|
|
|
fromRect: NSZeroRect
|
|
|
|
operation: NSCompositeSourceOver
|
|
|
|
fraction: 1.0];
|
|
|
|
}
|
|
|
|
|
2010-06-01 11:04:36 +00:00
|
|
|
- (void) drawInRect: (NSRect)dstRect
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
2013-02-16 00:08:33 +00:00
|
|
|
fraction: (CGFloat)delta
|
2010-06-01 11:04:36 +00:00
|
|
|
{
|
2011-08-18 23:57:50 +00:00
|
|
|
[self drawInRect: dstRect
|
|
|
|
fromRect: srcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta
|
|
|
|
respectFlipped: NO
|
|
|
|
hints: nil];
|
2010-06-01 11:04:36 +00:00
|
|
|
}
|
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
/**
|
|
|
|
* Base drawing method in NSImage; all other draw methods call this one
|
|
|
|
*/
|
|
|
|
- (void) drawInRect: (NSRect)dstRect // Negative width/height => Nothing draws.
|
2011-07-16 02:09:06 +00:00
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
operation: (NSCompositingOperation)op
|
2013-02-16 00:08:33 +00:00
|
|
|
fraction: (CGFloat)delta
|
2011-07-16 02:09:06 +00:00
|
|
|
respectFlipped: (BOOL)respectFlipped
|
|
|
|
hints: (NSDictionary*)hints
|
|
|
|
{
|
2011-08-18 23:57:50 +00:00
|
|
|
NSImageRep *rep;
|
|
|
|
NSGraphicsContext *ctxt;
|
|
|
|
NSSize imgSize, repSize;
|
|
|
|
NSRect repSrcRect;
|
2011-07-16 02:09:06 +00:00
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
ctxt = GSCurrentContext();
|
|
|
|
imgSize = [self size];
|
2011-07-16 02:09:06 +00:00
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
// Handle abbreviated parameters
|
2011-07-16 02:09:06 +00:00
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
if (NSEqualRects(srcRect, NSZeroRect))
|
|
|
|
{
|
|
|
|
srcRect.size = imgSize;
|
|
|
|
}
|
|
|
|
if (NSEqualSizes(dstRect.size, NSZeroSize)) // For -drawAtPoint:fromRect:operation:fraction:
|
|
|
|
{
|
|
|
|
dstRect.size = imgSize;
|
|
|
|
}
|
2011-07-16 02:09:06 +00:00
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
if (imgSize.width <= 0 || imgSize.height <= 0)
|
|
|
|
return;
|
2011-07-16 02:09:06 +00:00
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
// Select a rep
|
2011-07-16 02:09:06 +00:00
|
|
|
|
2011-08-18 23:57:50 +00:00
|
|
|
rep = [self bestRepresentationForRect: dstRect
|
|
|
|
context: ctxt
|
|
|
|
hints: hints];
|
|
|
|
if (rep == nil)
|
|
|
|
return;
|
2011-08-19 19:06:41 +00:00
|
|
|
|
|
|
|
// Try to cache / get a cached version of the best rep
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We only use caching on backends that can efficiently draw a rect from the cache
|
|
|
|
* onto the current graphics context respecting the CTM, which is currently cairo.
|
|
|
|
*/
|
|
|
|
if (_cacheMode != NSImageCacheNever &&
|
|
|
|
[ctxt supportsDrawGState])
|
|
|
|
{
|
|
|
|
NSCachedImageRep *cache = [self _doImageCache: rep];
|
|
|
|
if (cache != nil)
|
|
|
|
{
|
|
|
|
rep = cache;
|
|
|
|
}
|
|
|
|
}
|
2011-08-18 23:57:50 +00:00
|
|
|
|
|
|
|
repSize = [rep size];
|
|
|
|
|
|
|
|
// Convert srcRect from image coordinate space to rep coordinate space
|
|
|
|
{
|
|
|
|
const CGFloat imgToRepWidthScaleFactor = repSize.width / imgSize.width;
|
|
|
|
const CGFloat imgToRepHeightScaleFactor = repSize.height / imgSize.height;
|
|
|
|
|
|
|
|
repSrcRect = NSMakeRect(srcRect.origin.x * imgToRepWidthScaleFactor,
|
|
|
|
srcRect.origin.y * imgToRepHeightScaleFactor,
|
|
|
|
srcRect.size.width * imgToRepWidthScaleFactor,
|
|
|
|
srcRect.size.height * imgToRepHeightScaleFactor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Draw background?
|
|
|
|
|
|
|
|
[rep drawInRect: dstRect
|
|
|
|
fromRect: repSrcRect
|
|
|
|
operation: op
|
|
|
|
fraction: delta
|
|
|
|
respectFlipped: respectFlipped
|
|
|
|
hints: hints];
|
2011-07-16 02:09:06 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2013-09-29 16:37:59 +00:00
|
|
|
if (imageRep != nil)
|
|
|
|
{
|
|
|
|
repd = [GSRepData new];
|
|
|
|
repd->rep = RETAIN(imageRep);
|
|
|
|
[_reps addObject: repd];
|
|
|
|
RELEASE(repd);
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addRepresentations: (NSArray *)imageRepArray
|
|
|
|
{
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger i, count;
|
2008-12-15 17:14:30 +00:00
|
|
|
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
|
|
|
|
{
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger i;
|
2008-12-15 17:14:30 +00:00
|
|
|
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
|
|
|
|
2011-09-08 20:13:42 +00:00
|
|
|
if (NSEqualSizes(NSZeroSize, [self size]))
|
2011-09-08 18:42:31 +00:00
|
|
|
[NSException raise: NSImageCacheException
|
2011-09-08 20:13:42 +00:00
|
|
|
format: @"Cannot lock focus on image with size (0, 0)"];
|
|
|
|
|
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];
|
2011-08-19 19:06:41 +00:00
|
|
|
if (repd == nil)
|
|
|
|
return;
|
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
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)
|
2014-10-05 19:59:37 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSImageCacheException
|
|
|
|
format: @"Cannot lock focus on nil rep"];
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: This is needed to get image caching working while printing. A better solution
|
|
|
|
// needs to remove the viewIsPrinting variable from NSView.
|
|
|
|
[_lockedView _lockFocusInContext: [window graphicsContext] inRect: [_lockedView bounds]];
|
2008-12-15 17:14:30 +00:00
|
|
|
if (repd->bg == nil)
|
2008-11-16 23:21:58 +00:00
|
|
|
{
|
2011-10-06 11:06:31 +00:00
|
|
|
NSRect fillrect = NSMakeRect(0, 0, _size.width, _size.height);
|
|
|
|
|
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.) */
|
2011-10-06 11:06:31 +00:00
|
|
|
NSRectFillUsingOperation(fillrect, NSCompositeClear);
|
2008-11-16 23:21:58 +00:00
|
|
|
}
|
2008-12-15 17:14:30 +00:00
|
|
|
|
|
|
|
repd->bg = [_color copy];
|
|
|
|
|
|
|
|
if ([repd->bg alphaComponent] == 1.0)
|
|
|
|
{
|
|
|
|
[imageRep setOpaque: YES];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[imageRep setOpaque: [repd->original isOpaque]];
|
|
|
|
}
|
|
|
|
|
2011-10-06 11:06:31 +00:00
|
|
|
// Fill with background colour and draw repesentation
|
|
|
|
[self drawRepresentation: repd->original
|
|
|
|
inRect: fillrect];
|
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
|
|
|
}
|
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
/* Determine the number of color components in the device and
|
|
|
|
filter out reps with a different number of color components.
|
|
|
|
|
|
|
|
If the device lacks a color space name, all reps are treated
|
|
|
|
as matching.
|
|
|
|
|
|
|
|
If a rep lacks a color space name, it is assumed to match the
|
|
|
|
device.
|
|
|
|
|
|
|
|
WARNING: Be careful not to inadvertently mix greyscale and color
|
|
|
|
representations in a TIFF. The greyscale representations
|
|
|
|
will never be selected as a best rep unless you are drawing on
|
|
|
|
a greyscale surface, or all reps in the TIFF are greyscale.
|
2003-01-21 05:08:26 +00:00
|
|
|
*/
|
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
2008-12-15 17:14:30 +00:00
|
|
|
withColorMatch: (NSDictionary*)deviceDescription
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
NSMutableArray *breps = [NSMutableArray array];
|
|
|
|
NSString *deviceColorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
|
|
|
|
|
|
|
|
if (deviceColorSpace != nil)
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
NSUInteger deviceColors = NSNumberOfColorComponents(deviceColorSpace);
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
NSImageRep *rep;
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([rep colorSpaceName] == nil ||
|
|
|
|
NSNumberOfColorComponents([rep colorSpaceName]) == deviceColors)
|
|
|
|
{
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
}
|
2011-06-13 22:32:28 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
2011-06-13 22:32:28 +00:00
|
|
|
{
|
|
|
|
[breps setArray: reps];
|
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
return breps;
|
|
|
|
}
|
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
/**
|
|
|
|
* Returns YES if x in an integer multiple of y
|
|
|
|
*/
|
|
|
|
static BOOL GSIsMultiple(CGFloat x, CGFloat y)
|
|
|
|
{
|
|
|
|
// FIXME: Test when CGFloat is float and make sure this test isn't
|
|
|
|
// too strict due to floating point rounding errors.
|
|
|
|
return (x/y) == floor(x/y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns YES if there exist integers p and q such that
|
|
|
|
* (baseSize.width * p == size.width) && (baseSize.height * q == size.height)
|
|
|
|
*/
|
|
|
|
static BOOL GSSizeIsIntegerMultipleOfSize(NSSize size, NSSize baseSize)
|
|
|
|
{
|
|
|
|
return NSEqualSizes(size, baseSize) ||
|
|
|
|
(GSIsMultiple(size.width, baseSize.width) &&
|
|
|
|
GSIsMultiple(size.height, baseSize.height));
|
|
|
|
}
|
|
|
|
|
2011-08-15 20:19:21 +00:00
|
|
|
/**
|
|
|
|
* Returns {0, 0} if the image rep doesn't have a size set,
|
|
|
|
* or the pixelsWide or pixelsHigh are NSImageRepMatchesDevice
|
|
|
|
*/
|
2011-06-13 22:32:28 +00:00
|
|
|
static NSSize GSResolutionOfImageRep(NSImageRep *rep)
|
|
|
|
{
|
2011-08-15 20:19:21 +00:00
|
|
|
const int pixelsWide = [rep pixelsWide];
|
|
|
|
const int pixelsHigh = [rep pixelsHigh];
|
|
|
|
const NSSize repSize = [rep size];
|
|
|
|
|
|
|
|
if (repSize.width == 0 || repSize.height == 0)
|
|
|
|
{
|
|
|
|
return NSMakeSize(0, 0);
|
|
|
|
}
|
|
|
|
else if (pixelsWide == NSImageRepMatchesDevice ||
|
|
|
|
pixelsHigh == NSImageRepMatchesDevice)
|
|
|
|
{
|
|
|
|
return NSMakeSize(0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NSMakeSize(72.0 * (CGFloat)pixelsWide / repSize.width,
|
|
|
|
72.0 * (CGFloat)pixelsHigh / repSize.height);
|
|
|
|
}
|
2011-06-13 22:32:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find reps that match the resolution (DPI) of the device (including integer
|
|
|
|
multiples of the device resplition if [self multipleResolutionMatching]
|
|
|
|
is YES).
|
|
|
|
|
|
|
|
If there are no DPI matches, use any available vector reps if
|
|
|
|
[self usesEPSOnResolutionMismatch] is YES. Otherwise, use the bitmap reps
|
|
|
|
that have the highest DPI.
|
|
|
|
*/
|
2003-01-21 05:08:26 +00:00
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
2008-12-15 17:14:30 +00:00
|
|
|
withResolutionMatch: (NSDictionary*)deviceDescription
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
2011-05-04 01:33:21 +00:00
|
|
|
NSMutableArray *breps = [NSMutableArray array];
|
2003-01-21 05:08:26 +00:00
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
NSValue *resolution = [deviceDescription objectForKey: NSDeviceResolution];
|
|
|
|
|
|
|
|
// 1. Look for exact resolution matches, or integer multiples if permitted.
|
1999-04-28 11:16:26 +00:00
|
|
|
|
2011-05-04 01:33:21 +00:00
|
|
|
if (nil != resolution)
|
1996-08-22 18:51:08 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
const NSSize dres = [resolution sizeValue];
|
2011-05-04 01:33:21 +00:00
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
if (![self matchesOnMultipleResolution])
|
2011-05-04 01:33:21 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
2011-05-04 01:33:21 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
if (NSEqualSizes(GSResolutionOfImageRep(rep), dres))
|
|
|
|
{
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // [self matchesOnMultipleResolution]
|
|
|
|
{
|
|
|
|
NSMutableArray *integerMultiples = [NSMutableArray array];
|
|
|
|
NSSize closestRes = NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX);
|
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
// Iterate through the reps, keeping track of which ones
|
|
|
|
// have a resolution which is an integer multiple of the device
|
|
|
|
// res, and keep track of the cloest resolution
|
|
|
|
|
|
|
|
enumerator = [reps objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
const NSSize repRes = GSResolutionOfImageRep(rep);
|
|
|
|
if (GSSizeIsIntegerMultipleOfSize(repRes, dres))
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
const NSSize repResDifference
|
|
|
|
= NSMakeSize(fabs(repRes.width - dres.width),
|
|
|
|
fabs(repRes.height - dres.height));
|
|
|
|
const NSSize closestResolutionDifference
|
|
|
|
= NSMakeSize(fabs(closestRes.width - dres.width),
|
|
|
|
fabs(closestRes.height - dres.height));
|
|
|
|
if (repResDifference.width
|
|
|
|
< closestResolutionDifference.width
|
|
|
|
&& repResDifference.height
|
|
|
|
< closestResolutionDifference.height)
|
2011-06-13 22:32:28 +00:00
|
|
|
{
|
|
|
|
closestRes = repRes;
|
|
|
|
}
|
|
|
|
[integerMultiples addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enumerator = [integerMultiples objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
const NSSize repRes = GSResolutionOfImageRep(rep);
|
|
|
|
if (NSEqualSizes(repRes, closestRes))
|
|
|
|
{
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
2011-05-04 01:33:21 +00:00
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
}
|
2011-05-04 01:33:21 +00:00
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
// 2. If no exact matches found, use vector reps, if they are preferred
|
2003-01-21 05:08:26 +00:00
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
if ([breps count] == 0 && [self usesEPSOnResolutionMismatch])
|
2011-05-04 01:33:21 +00:00
|
|
|
{
|
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([rep pixelsWide] == NSImageRepMatchesDevice &&
|
|
|
|
[rep pixelsHigh] == NSImageRepMatchesDevice)
|
|
|
|
{
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
// 3. If there are still no matches, use all of the bitmaps with the highest
|
|
|
|
// resolution (DPI)
|
2011-05-04 01:33:21 +00:00
|
|
|
|
|
|
|
if ([breps count] == 0)
|
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
NSSize maxRes = NSMakeSize(0,0);
|
2011-05-04 01:33:21 +00:00
|
|
|
NSImageRep *rep;
|
2011-06-13 22:32:28 +00:00
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
// Determine maxRes
|
|
|
|
|
|
|
|
enumerator = [reps objectEnumerator];
|
2011-05-04 01:33:21 +00:00
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
const NSSize res = GSResolutionOfImageRep(rep);
|
|
|
|
if (res.width > maxRes.width &&
|
|
|
|
res.height > maxRes.height)
|
2011-05-04 01:33:21 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
maxRes = res;
|
2011-05-04 01:33:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
// Use all reps with maxRes
|
2011-05-04 01:33:21 +00:00
|
|
|
enumerator = [reps objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
const NSSize res = GSResolutionOfImageRep(rep);
|
|
|
|
if (NSEqualSizes(res, maxRes))
|
2011-05-04 01:33:21 +00:00
|
|
|
{
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
// 4. If there are still none, use all available reps.
|
|
|
|
// Note that this handles using vector reps in the case where there are
|
|
|
|
// no bitmap reps, but [self usesEPSOnResolutionMismatch] is NO.
|
|
|
|
|
2011-05-04 01:33:21 +00:00
|
|
|
if ([breps count] == 0)
|
|
|
|
{
|
|
|
|
[breps setArray: reps];
|
|
|
|
}
|
2011-06-13 22:32:28 +00:00
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
return breps;
|
|
|
|
}
|
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
/* Find the reps that match the bitsPerSample of the device,
|
|
|
|
or if none match exactly, return all that have the highest bitsPerSample.
|
|
|
|
|
|
|
|
If the device lacks a bps, all reps are treated as matching.
|
|
|
|
|
|
|
|
If a rep has NSImageRepMatchesDevice as its bps, it is treated as matching.
|
|
|
|
*/
|
2003-01-21 05:08:26 +00:00
|
|
|
- (NSMutableArray *) _bestRep: (NSArray *)reps
|
2008-12-15 17:14:30 +00:00
|
|
|
withBpsMatch: (NSDictionary*)deviceDescription
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
NSMutableArray *breps = [NSMutableArray array];
|
|
|
|
NSNumber *bpsValue = [deviceDescription objectForKey: NSDeviceBitsPerSample];
|
2003-01-21 05:08:26 +00:00
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
if (bpsValue != nil)
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
2011-06-13 22:32:28 +00:00
|
|
|
NSInteger deviceBps = [bpsValue integerValue];
|
|
|
|
NSInteger maxBps = -1;
|
|
|
|
BOOL haveDeviceBps = NO;
|
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
// Determine maxBps
|
2003-01-21 05:08:26 +00:00
|
|
|
|
2011-06-13 22:32:28 +00:00
|
|
|
enumerator = [reps objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([rep bitsPerSample] > maxBps)
|
|
|
|
{
|
|
|
|
maxBps = [rep bitsPerSample];
|
|
|
|
}
|
|
|
|
if ([rep bitsPerSample] == deviceBps)
|
|
|
|
{
|
|
|
|
haveDeviceBps = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use all reps with deviceBps if haveDeviceBps is YES,
|
|
|
|
// otherwise use all reps with maxBps
|
|
|
|
enumerator = [reps objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if ([rep bitsPerSample] == NSImageRepMatchesDevice ||
|
|
|
|
(!haveDeviceBps && [rep bitsPerSample] == maxBps) ||
|
|
|
|
(haveDeviceBps && [rep bitsPerSample] == deviceBps))
|
|
|
|
{
|
|
|
|
[breps addObject: rep];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
|
|
|
|
/* If there are no matches, pass all the reps */
|
|
|
|
if ([breps count] == 0)
|
2011-06-13 22:32:28 +00:00
|
|
|
{
|
|
|
|
[breps setArray: reps];
|
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
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
|
|
|
{
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger 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)
|
|
|
|
{
|
2016-03-21 10:01:25 +00:00
|
|
|
return [NSMutableArray array];
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-12-15 17:14:30 +00:00
|
|
|
id repList[count];
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger 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
|
|
|
}
|
2016-03-21 10:01:25 +00:00
|
|
|
return [NSMutableArray arrayWithObjects: repList count: j];
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
}
|
1996-08-22 18:51:08 +00:00
|
|
|
|
2011-06-14 19:00:23 +00:00
|
|
|
- (NSArray *) _bestRepresentationsForDevice: (NSDictionary*)deviceDescription
|
2003-01-21 05:08:26 +00:00
|
|
|
{
|
|
|
|
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];
|
2011-06-13 22:32:28 +00:00
|
|
|
|
2011-06-14 19:00:23 +00:00
|
|
|
return reps;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSImageRep *) bestRepresentationForDevice: (NSDictionary*)deviceDescription
|
|
|
|
{
|
|
|
|
NSArray *reps = [self _bestRepresentationsForDevice: deviceDescription];
|
|
|
|
|
2011-05-31 07:35:57 +00:00
|
|
|
/* If we have more than one match check for a representation whose size
|
2011-11-12 01:57:01 +00:00
|
|
|
* matches the image size exactly. Otherwise, arbitrarily choose the first
|
2011-05-31 07:35:57 +00:00
|
|
|
* representation. */
|
|
|
|
if ([reps count] > 1)
|
|
|
|
{
|
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
if (NSEqualSizes(_size, [rep size]) == YES)
|
|
|
|
{
|
|
|
|
return rep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-13 19:24:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
if ([reps count] > 0)
|
|
|
|
{
|
|
|
|
return [reps objectAtIndex: 0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2003-01-21 05:08:26 +00:00
|
|
|
}
|
|
|
|
|
2011-06-14 19:00:23 +00:00
|
|
|
- (NSImageRep *) bestRepresentationForRect: (NSRect)rect
|
|
|
|
context: (NSGraphicsContext *)context
|
|
|
|
hints: (NSDictionary *)deviceDescription
|
|
|
|
{
|
|
|
|
NSArray *reps = [self _bestRepresentationsForDevice: deviceDescription];
|
|
|
|
const NSSize desiredSize = rect.size;
|
|
|
|
NSImageRep *bestRep = nil;
|
|
|
|
|
|
|
|
// Pick the smallest rep that is greater than or equal to the
|
|
|
|
// desired size.
|
|
|
|
|
|
|
|
{
|
|
|
|
NSSize bestSize = NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX);
|
|
|
|
NSImageRep *rep;
|
|
|
|
NSEnumerator *enumerator = [reps objectEnumerator];
|
|
|
|
while ((rep = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
const NSSize repSize = [rep size];
|
2015-11-01 15:38:47 +00:00
|
|
|
if ((repSize.width >= desiredSize.width)
|
|
|
|
&& (repSize.height >= desiredSize.height)
|
|
|
|
&& (repSize.width < bestSize.width)
|
|
|
|
&& (repSize.height < bestSize.height))
|
2011-06-14 19:00:23 +00:00
|
|
|
{
|
|
|
|
bestSize = repSize;
|
|
|
|
bestRep = rep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bestRep == nil)
|
|
|
|
{
|
|
|
|
bestRep = [reps lastObject];
|
|
|
|
}
|
|
|
|
|
|
|
|
return bestRep;
|
|
|
|
}
|
|
|
|
|
2003-01-21 05:08:26 +00:00
|
|
|
- (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
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
NSArray *reps;
|
|
|
|
NSData *data;
|
2007-03-08 09:35:09 +00:00
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
/* As a result of using bitmap representations,
|
|
|
|
* new drawing wont show on the tiff data.
|
|
|
|
*/
|
|
|
|
reps = [self _representationsWithCachedImages: NO];
|
|
|
|
data = [bitmapClass TIFFRepresentationOfImageRepsInArray: reps];
|
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];
|
2012-02-01 10:49:35 +00:00
|
|
|
if (nil != rep)
|
|
|
|
{
|
|
|
|
[self addRepresentation: rep];
|
|
|
|
data = [rep TIFFRepresentation];
|
|
|
|
RELEASE(rep);
|
|
|
|
}
|
2007-03-08 09:35:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
NSArray *reps;
|
|
|
|
NSData *data;
|
2007-03-08 09:35:09 +00:00
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
/* As a result of using bitmap representations,
|
|
|
|
* new drawing wont show on the tiff data.
|
|
|
|
*/
|
|
|
|
reps = [self _representationsWithCachedImages: NO];
|
|
|
|
data = [bitmapClass TIFFRepresentationOfImageRepsInArray: reps
|
|
|
|
usingCompression: comp
|
|
|
|
factor: aFloat];
|
2007-03-08 09:35:09 +00:00
|
|
|
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
NSBitmapImageRep *rep;
|
|
|
|
NSSize size = [self size];
|
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
/* If there isn't a bitmap representation to output,
|
|
|
|
* create one and store it.
|
|
|
|
*/
|
2007-03-08 09:35:09 +00:00
|
|
|
[self lockFocus];
|
|
|
|
rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:
|
2015-11-01 15:38:47 +00:00
|
|
|
NSMakeRect(0.0, 0.0, size.width, size.height)];
|
2007-03-08 09:35:09 +00:00
|
|
|
[self unlockFocus];
|
2012-02-01 10:49:35 +00:00
|
|
|
if (nil != rep)
|
|
|
|
{
|
|
|
|
[self addRepresentation: rep];
|
|
|
|
data = [rep TIFFRepresentationUsingCompression: comp factor: aFloat];
|
|
|
|
RELEASE(rep);
|
|
|
|
}
|
2007-03-08 09:35:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2013-03-18 22:50:11 +00:00
|
|
|
int flags = 0;
|
|
|
|
|
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;
|
|
|
|
|
2013-03-18 22:50:11 +00:00
|
|
|
if ([_reps count] > 0)
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
2013-03-18 22:50:11 +00:00
|
|
|
[reps addObject: [NSNumber numberWithInt: 0]];
|
|
|
|
while ((rd = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[reps addObject: rd->rep];
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the reps to the container...
|
|
|
|
[container addObject: reps];
|
|
|
|
[coder encodeObject: container forKey: @"NSReps"];
|
2008-12-15 17:14:30 +00:00
|
|
|
}
|
|
|
|
}
|
2006-08-09 01:37:32 +00:00
|
|
|
else
|
2008-12-15 17:14:30 +00:00
|
|
|
{
|
2013-03-18 22:50:11 +00:00
|
|
|
[coder encodeObject: _name forKey: @"NSName"];
|
2008-12-15 17:14:30 +00:00
|
|
|
}
|
2006-08-09 01:37:32 +00:00
|
|
|
|
|
|
|
// encode the rest...
|
2013-03-18 22:50:11 +00:00
|
|
|
if (_color != nil)
|
|
|
|
{
|
|
|
|
[coder encodeObject: _color forKey: @"NSColor"];
|
|
|
|
}
|
|
|
|
flags |= [self scalesWhenResized] ? 0x8000000 : 0;
|
|
|
|
flags |= _flags.sizeWasExplicitlySet ? 0x2000000 : 0;
|
|
|
|
flags |= [self usesEPSOnResolutionMismatch] ? 0x0200000 : 0;
|
|
|
|
flags |= [self prefersColorMatch] ? 0x0100000 : 0;
|
|
|
|
flags |= [self matchesOnMultipleResolution] ? 0x0080000 : 0;
|
|
|
|
flags |= [self isFlipped] ? 0x0008000 : 0;
|
|
|
|
flags |= [self cacheMode] << 11;
|
|
|
|
[coder encodeInt: flags forKey: @"NSImageFlags"];
|
|
|
|
if (_flags.sizeWasExplicitlySet)
|
|
|
|
{
|
|
|
|
[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;
|
2017-10-28 07:45:05 +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
|
|
|
{
|
2013-03-18 22:50:11 +00:00
|
|
|
if ([coder containsValueForKey: @"NSName"])
|
|
|
|
{
|
2017-10-29 14:34:02 +00:00
|
|
|
NSImage *replacementImage;
|
|
|
|
NSString *imageName;
|
|
|
|
|
2017-10-29 14:25:47 +00:00
|
|
|
imageName = [coder decodeObjectForKey: @"NSName"];
|
2017-10-28 07:45:05 +00:00
|
|
|
replacementImage = [NSImage imageNamed: imageName];
|
2017-10-29 14:25:47 +00:00
|
|
|
if (replacementImage)
|
|
|
|
{
|
2017-10-29 14:34:02 +00:00
|
|
|
RELEASE(self);
|
2017-10-29 14:25:47 +00:00
|
|
|
return RETAIN(replacementImage);
|
|
|
|
}
|
2017-10-29 14:34:02 +00:00
|
|
|
|
|
|
|
[self setName: imageName];
|
|
|
|
self->_flags.archiveByName = YES;
|
2013-03-18 22:50:11 +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"])
|
|
|
|
{
|
2013-03-18 22:50:11 +00:00
|
|
|
int flags = [coder decodeIntForKey: @"NSImageFlags"];
|
|
|
|
|
|
|
|
[self setScalesWhenResized: ((flags & 0x8000000) != 0)];
|
|
|
|
// _flags.sizeWasExplicitlySet = ((flags & 0x2000000) != 0);
|
|
|
|
[self setUsesEPSOnResolutionMismatch: ((flags & 0x0200000) != 0)];
|
|
|
|
[self setPrefersColorMatch: ((flags & 0x0100000) != 0)];
|
|
|
|
[self setMatchesOnMultipleResolution: ((flags & 0x0080000) != 0)];
|
|
|
|
[self setFlipped: ((flags & 0x0008000) != 0)];
|
|
|
|
// ALIASED ((flags & 0x0004000) != 0)
|
|
|
|
[self setCacheMode: ((flags & 0x0001800) >> 11)];
|
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;
|
2013-03-18 22:50:11 +00:00
|
|
|
NSUInteger i;
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
/* FIXME: NSReps is in a strange format. It is a mutable array
|
|
|
|
* with one 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];
|
2013-03-18 22:50:11 +00:00
|
|
|
for (i = 1; i < [reps count]; i++)
|
|
|
|
{
|
|
|
|
id rep = [reps objectAtIndex: i];
|
|
|
|
if ([rep isKindOfClass: [NSImageRep class]])
|
|
|
|
{
|
|
|
|
[self addRepresentation: rep];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ([rep isKindOfClass: [NSURL class]])
|
|
|
|
{
|
|
|
|
NSURL *tmp = (NSURL*)rep;
|
|
|
|
rep = [NSImageRep imageRepWithContentsOfURL: rep];
|
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
/* If we are unable to resolved the URL,
|
|
|
|
* try to get it from the resources folder.
|
|
|
|
*/
|
2013-03-18 22:50:11 +00:00
|
|
|
if (rep == nil)
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
NSString *fileName;
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
fileName = [[tmp absoluteString] lastPathComponent];
|
|
|
|
path = [[NSBundle mainBundle]
|
|
|
|
pathForImageResource: fileName];
|
2013-03-18 22:50:11 +00:00
|
|
|
rep = [NSImageRep imageRepWithContentsOfFile: path];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the representation was found, add it...
|
|
|
|
if (rep != nil)
|
|
|
|
{
|
|
|
|
[self addRepresentation: rep];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-16 23:21:58 +00:00
|
|
|
}
|
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)
|
|
|
|
{
|
2017-10-29 14:34:02 +00:00
|
|
|
NSImage *replacementImage;
|
2008-12-15 17:14:30 +00:00
|
|
|
NSString *theName = [coder decodeObject];
|
1999-12-28 16:02:01 +00:00
|
|
|
|
2017-10-29 14:25:47 +00:00
|
|
|
replacementImage = [NSImage imageNamed: theName];
|
|
|
|
if (replacementImage)
|
|
|
|
{
|
2017-10-29 14:34:02 +00:00
|
|
|
RELEASE(self);
|
2017-10-29 14:25:47 +00:00
|
|
|
self = RETAIN(replacementImage);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self setName: theName];
|
|
|
|
self->_flags.archiveByName = YES;
|
|
|
|
}
|
2008-11-16 23:21:58 +00:00
|
|
|
}
|
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
|
|
|
+ (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
|
|
|
|
{
|
2012-01-09 14:39:50 +00:00
|
|
|
if (nil == imageUnfilteredFileTypes)
|
|
|
|
{
|
|
|
|
ASSIGN(imageUnfilteredFileTypes,
|
|
|
|
iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imageUnfilteredFileTypes)));
|
|
|
|
}
|
|
|
|
return imageUnfilteredFileTypes;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageFileTypes
|
|
|
|
{
|
2012-01-09 14:39:50 +00:00
|
|
|
if (nil == imageFileTypes)
|
|
|
|
{
|
|
|
|
ASSIGN(imageFileTypes,
|
|
|
|
iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imageFileTypes)));
|
|
|
|
}
|
|
|
|
return imageFileTypes;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imageUnfilteredPasteboardTypes
|
|
|
|
{
|
2012-01-09 14:39:50 +00:00
|
|
|
if (nil == imageUnfilteredPasteboardTypes)
|
|
|
|
{
|
|
|
|
ASSIGN(imageUnfilteredPasteboardTypes,
|
|
|
|
iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imageUnfilteredPasteboardTypes)));
|
|
|
|
}
|
|
|
|
return imageUnfilteredPasteboardTypes;
|
1996-08-22 18:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) imagePasteboardTypes
|
|
|
|
{
|
2012-01-09 14:39:50 +00:00
|
|
|
if (nil == imagePasteboardTypes)
|
|
|
|
{
|
|
|
|
ASSIGN(imagePasteboardTypes,
|
|
|
|
iterate_reps_for_types([NSImageRep registeredImageRepClasses],
|
|
|
|
@selector(imagePasteboardTypes)));
|
|
|
|
}
|
|
|
|
return 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)
|
|
|
|
|
2012-01-10 19:16:46 +00:00
|
|
|
+ (void) _clearFileTypeCaches: (NSNotification*)notif
|
2012-01-09 14:39:50 +00:00
|
|
|
{
|
2012-01-11 08:12:43 +00:00
|
|
|
DESTROY(imageUnfilteredFileTypes);
|
|
|
|
DESTROY(imageFileTypes);
|
|
|
|
DESTROY(imageUnfilteredPasteboardTypes);
|
|
|
|
DESTROY(imagePasteboardTypes);
|
2012-01-09 14:39:50 +00:00
|
|
|
}
|
|
|
|
|
2013-04-06 19:30:48 +00:00
|
|
|
/**
|
|
|
|
* For all NSImage instances cached in nameDict, recompute the
|
|
|
|
* path using +_pathForImageNamed: and if it has changed,
|
|
|
|
* reload the image contents using the new path.
|
|
|
|
*/
|
|
|
|
+ (void) _reloadCachedImages
|
2012-01-10 19:16:46 +00:00
|
|
|
{
|
2013-04-06 19:30:48 +00:00
|
|
|
NSString *name;
|
2013-07-04 15:46:11 +00:00
|
|
|
NSEnumerator *e = [nameDict keyEnumerator];
|
2012-01-10 19:16:46 +00:00
|
|
|
|
2012-01-14 17:55:43 +00:00
|
|
|
[imageLock lock];
|
2013-04-06 19:30:48 +00:00
|
|
|
while ((name = [e nextObject]) != nil)
|
2012-01-10 19:16:46 +00:00
|
|
|
{
|
2013-04-06 19:30:48 +00:00
|
|
|
NSImage *image = [nameDict objectForKey: name];
|
2015-11-12 08:33:35 +00:00
|
|
|
NSString *path = [[NSBundle mainBundle] pathForImageResource: name];
|
2013-07-04 15:46:11 +00:00
|
|
|
|
|
|
|
//NSLog(@"Loaded image %@ from %@", name, path);
|
|
|
|
|
|
|
|
if (path != nil && ![path isEqual: image->_fileName])
|
2012-01-14 17:55:43 +00:00
|
|
|
{
|
|
|
|
/* Reset the existing image to use the contents of
|
|
|
|
* the specified file.
|
|
|
|
*/
|
|
|
|
[image _resetAndUseFromFile: path];
|
2013-07-04 15:46:11 +00:00
|
|
|
}
|
2012-01-10 19:16:46 +00:00
|
|
|
}
|
|
|
|
[imageLock unlock];
|
|
|
|
}
|
|
|
|
|
2013-07-04 15:46:11 +00:00
|
|
|
|
2013-07-22 15:24:32 +00:00
|
|
|
+ (NSString *) _resourceNameForImageNamed: (NSString *)aName
|
|
|
|
type: (NSString **)aType
|
|
|
|
{
|
|
|
|
NSString *name = aName;
|
|
|
|
NSString *ext = [aName pathExtension];
|
|
|
|
|
|
|
|
if (ext != nil && [ext length] == 0)
|
|
|
|
{
|
|
|
|
ext = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if extension is one of the image types */
|
|
|
|
if (ext != nil && [[self imageFileTypes] indexOfObject: ext] != NSNotFound)
|
|
|
|
{
|
|
|
|
/* Extension is one of the image types, so remove from the name */
|
|
|
|
name = [aName stringByDeletingPathExtension];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise extension is not an image type, so leave it alone */
|
|
|
|
ext = nil;
|
|
|
|
}
|
|
|
|
|
2015-11-01 15:38:47 +00:00
|
|
|
*aType = ext;
|
|
|
|
return name;
|
2013-07-22 15:24:32 +00:00
|
|
|
}
|
|
|
|
|
2015-11-12 08:33:35 +00:00
|
|
|
- (BOOL) _loadFromData: (NSData *)data
|
2000-12-23 14:19:23 +00:00
|
|
|
{
|
|
|
|
BOOL ok;
|
|
|
|
Class rep;
|
|
|
|
|
|
|
|
ok = NO;
|
|
|
|
rep = [NSImageRep imageRepClassForData: data];
|
|
|
|
if (rep && [rep respondsToSelector: @selector(imageRepsWithData:)])
|
|
|
|
{
|
|
|
|
NSArray* array;
|
2011-08-26 07:35:41 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
array = [rep imageRepsWithData: data];
|
2011-08-26 07:35:41 +00:00
|
|
|
if (array && ([array count] > 0))
|
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;
|
2011-08-26 07:35:41 +00:00
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
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];
|
2011-08-26 07:35:41 +00:00
|
|
|
if (array)
|
2000-12-23 14:19:23 +00:00
|
|
|
[self addRepresentations: array];
|
|
|
|
|
2011-08-26 07:35:41 +00:00
|
|
|
return (array && ([array count] > 0)) ? YES : NO;
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (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;
|
2011-07-14 07:17:24 +00:00
|
|
|
array = [object_getClass(self) imageFileTypes];
|
2000-12-23 14:19:23 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-10 18:55:57 +00:00
|
|
|
- (BOOL) _resetAndUseFromFile: (NSString *)fileName
|
|
|
|
{
|
|
|
|
[_reps removeAllObjects];
|
|
|
|
|
|
|
|
if (!_flags.sizeWasExplicitlySet)
|
|
|
|
{
|
|
|
|
_size = NSZeroSize;
|
|
|
|
}
|
|
|
|
return [self _useFromFile: fileName];
|
|
|
|
}
|
|
|
|
|
2000-12-23 14:19:23 +00:00
|
|
|
// 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;
|
2011-08-19 19:06:41 +00:00
|
|
|
NSCachedImageRep *cache;
|
2000-12-23 14:19:23 +00:00
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
repd = [self _cacheForRep: rep];
|
2011-08-19 19:06:41 +00:00
|
|
|
if (repd == nil)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
cache = (NSCachedImageRep*)(repd->rep);
|
|
|
|
if ([cache isKindOfClass: cachedClass] == NO)
|
2008-12-13 19:32:54 +00:00
|
|
|
return nil;
|
|
|
|
|
2011-08-19 19:06:41 +00:00
|
|
|
NSDebugLLog(@"NSImage", @"Cached image rep is %p", cache);
|
2008-12-13 19:32:54 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
{
|
2011-08-19 19:06:41 +00:00
|
|
|
[self lockFocusOnRepresentation: cache];
|
2008-12-13 19:32:54 +00:00
|
|
|
[self unlockFocus];
|
|
|
|
|
|
|
|
NSDebugLLog(@"NSImage", @"Rendered rep %p on background %@",
|
2011-08-19 19:06:41 +00:00
|
|
|
cache, repd->bg);
|
2000-12-23 14:19:23 +00:00
|
|
|
}
|
|
|
|
|
2011-08-19 19:06:41 +00:00
|
|
|
return cache;
|
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.
|
|
|
|
*/
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger 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];
|
2013-02-16 00:08:33 +00:00
|
|
|
NSUInteger partialCount = 0;
|
|
|
|
NSUInteger i;
|
2008-12-13 19:32:54 +00:00
|
|
|
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;
|
2011-08-19 19:06:41 +00:00
|
|
|
NSSize imageSize = [self size];
|
2011-09-09 19:49:08 +00:00
|
|
|
NSSize repSize;
|
2013-02-16 00:08:33 +00:00
|
|
|
NSInteger pixelsWide, pixelsHigh;
|
2008-12-15 17:14:30 +00:00
|
|
|
|
2011-09-09 19:49:08 +00:00
|
|
|
if (rep != nil)
|
|
|
|
{
|
|
|
|
repSize = [rep size];
|
2008-12-13 19:32:54 +00:00
|
|
|
|
2011-09-09 19:49:08 +00:00
|
|
|
if (repSize.width <= 0 || repSize.height <= 0)
|
|
|
|
repSize = imageSize;
|
2011-08-19 19:06:41 +00:00
|
|
|
|
2011-09-09 19:49:08 +00:00
|
|
|
pixelsWide = [rep pixelsWide];
|
|
|
|
pixelsHigh = [rep pixelsHigh];
|
|
|
|
|
|
|
|
if (pixelsWide == NSImageRepMatchesDevice ||
|
|
|
|
pixelsHigh == NSImageRepMatchesDevice)
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
/* FIXME: Since the cached rep must be a bitmap,
|
|
|
|
* we must rasterize vector reps at a particular DPI.
|
|
|
|
* Here we hardcode 72, but we should choose the DPI
|
|
|
|
* more intelligently.
|
|
|
|
*/
|
2011-09-09 19:49:08 +00:00
|
|
|
pixelsWide = repSize.width;
|
|
|
|
pixelsHigh = repSize.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // e.g. when there are no representations at all
|
2011-08-19 19:06:41 +00:00
|
|
|
{
|
2011-09-09 19:49:08 +00:00
|
|
|
repSize = imageSize;
|
2015-11-01 15:38:47 +00:00
|
|
|
/* FIXME: assumes 72 DPI. Also truncates,
|
|
|
|
* not sure if that is a problem.
|
|
|
|
*/
|
2011-09-09 19:49:08 +00:00
|
|
|
pixelsWide = imageSize.width;
|
|
|
|
pixelsHigh = imageSize.height;
|
2011-08-19 19:06:41 +00:00
|
|
|
}
|
2011-09-09 19:49:08 +00:00
|
|
|
|
|
|
|
if (repSize.width <= 0 || repSize.height <= 0 ||
|
|
|
|
pixelsWide <= 0 || pixelsHigh <= 0)
|
|
|
|
return nil;
|
2011-08-19 19:06:41 +00:00
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
// Create a new cached image rep without any contents.
|
|
|
|
cacheRep = [[cachedClass alloc]
|
2011-08-19 19:06:41 +00:00
|
|
|
initWithSize: repSize
|
|
|
|
pixelsWide: pixelsWide
|
|
|
|
pixelsHigh: pixelsHigh
|
|
|
|
depth: [[NSScreen mainScreen] depth]
|
|
|
|
separate: _flags.cacheSeparately
|
|
|
|
alpha: [rep hasAlpha]];
|
2013-09-29 16:37:59 +00:00
|
|
|
if (cacheRep == nil)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2008-12-13 19:32:54 +00:00
|
|
|
repd = [GSRepData new];
|
|
|
|
repd->rep = cacheRep;
|
2011-09-09 19:49:08 +00:00
|
|
|
repd->original = rep; // may be nil!
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-27 08:54:03 +00:00
|
|
|
@end
|