Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -15,24 +15,143 @@ #include "config.h" #import "OFColor.h" #import "OFOnce.h" +#import "OFString.h" #import "OFInvalidArgumentException.h" + +@interface OFColor () ++ (instancetype)of_alloc; +@end + +@interface OFColorSingleton: OFColor +@end + +@interface OFColorPlaceholder: OFColorSingleton +@end + +#ifdef OF_OBJFW_RUNTIME +@interface OFTaggedPointerColor: OFColorSingleton +@end +#endif + +static struct { + Class isa; +} placeholder; + +#ifdef OF_OBJFW_RUNTIME +static int colorTag; +#endif + +@implementation OFColorSingleton +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OFMaxRetainCount; +} +@end + +@implementation OFColorPlaceholder +- (instancetype)initWithRed: (float)red + green: (float)green + blue: (float)blue + alpha: (float)alpha +{ +#ifdef OF_OBJFW_RUNTIME + uint8_t redInt = red * 255; + uint8_t greenInt = green * 255; + uint8_t blueInt = blue * 255; + + if (red * 255 == redInt && green * 255 == greenInt && + blue * 255 == blueInt && alpha == 1) { + id ret = objc_createTaggedPointer(colorTag, + (uintptr_t)redInt << 16 | (uintptr_t)greenInt << 8 | + (uintptr_t)blueInt); + + if (ret != nil) + return ret; + } +#endif + + return (id)[[OFColor of_alloc] initWithRed: red + green: green + blue: blue + alpha: alpha]; +} +@end + +#ifdef OF_OBJFW_RUNTIME +@implementation OFTaggedPointerColor +- (void)getRed: (float *)red + green: (float *)green + blue: (float *)blue + alpha: (float *)alpha +{ + uintptr_t value = object_getTaggedPointerValue(self); + + *red = (float)(value >> 16) / 255; + *green = (float)((value >> 8) & 0xFF) / 255; + *blue = (float)(value & 0xFF) / 255; + + if (alpha != NULL) + *alpha = 1; +} +@end +#endif @implementation OFColor ++ (void)initialize +{ + if (self != [OFColor class]) + return; + + placeholder.isa = [OFColorPlaceholder class]; +#ifdef OF_OBJFW_RUNTIME + colorTag = + objc_registerTaggedPointerClass([OFTaggedPointerColor class]); +#endif +} + ++ (instancetype)of_alloc +{ + return [super alloc]; +} + ++ (instancetype)alloc +{ + if (self == [OFColor class]) + return (id)&placeholder; + + return [super alloc]; +} + #define PREDEFINED_COLOR(name, redValue, greenValue, blueValue) \ static OFColor *name##Color = nil; \ \ static void \ initPredefinedColor_##name(void) \ { \ - name##Color = [[OFColor alloc] initWithRed: redValue \ - green: greenValue \ - blue: blueValue \ - alpha: 1]; \ + name##Color = [[OFColorSingleton alloc] \ + initWithRed: redValue \ + green: greenValue \ + blue: blueValue \ + alpha: 1]; \ } \ \ + (OFColor *)name \ { \ static OFOnceControl onceControl = OFOnceControlInitValue; \ @@ -157,6 +276,17 @@ *blue = _blue; if (alpha != NULL) *alpha = _alpha; } + +- (OFString *)description +{ + float red, green, blue, alpha; + + [self getRed: &red green: &green blue: &blue alpha: &alpha]; + + return [OFString stringWithFormat: + @"", + red, green, blue, alpha]; +} @end Index: src/OFMatrix4x4.m ================================================================== --- src/OFMatrix4x4.m +++ src/OFMatrix4x4.m @@ -14,13 +14,12 @@ */ #include "config.h" #import "OFMatrix4x4.h" -#import "OFString.h" - #import "OFOnce.h" +#import "OFString.h" static const float identityValues[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -19,10 +19,11 @@ STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ OFCharacterSetTests.m \ + OFColorTests.m \ OFDataTests.m \ OFDateTests.m \ OFDictionaryTests.m \ OFHMACTests.m \ OFINIFileTests.m \ ADDED tests/OFColorTests.m Index: tests/OFColorTests.m ================================================================== --- tests/OFColorTests.m +++ tests/OFColorTests.m @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFColor"; + +@implementation TestsAppDelegate (OFColorTests) +- (void)colorTests +{ + void *pool = objc_autoreleasePoolPush(); + OFColor *color; + float red, green, blue, alpha; + + TEST(@"+[colorWithRed:green:blue:alpha:]", + (color = [OFColor colorWithRed: 63.f / 255 + green: 127.f / 255 + blue: 1 + alpha: 1])) + +#ifdef OF_OBJFW_RUNTIME + TEST(@"+[colorWithRed:green:blue:alpha:] returns tagged pointer", + object_isTaggedPointer(color)) +#endif + + TEST(@"-[getRed:green:blue:alpha:]", + R([color getRed: &red green: &green blue: &blue alpha: &alpha]) && + red == 63.f / 255 && green == 127.f / 255 && blue == 1 && + alpha == 1) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -68,10 +68,14 @@ @end @interface TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests; @end + +@interface TestsAppDelegate (OFColorTests) +- (void)colorTests; +@end @interface TestsAppDelegate (OFDDPSocketTests) - (void)DDPSocketTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -389,10 +389,11 @@ [self listTests]; [self setTests]; [self dateTests]; [self valueTests]; [self numberTests]; + [self colorTests]; [self streamTests]; [self memoryStreamTests]; [self notificationCenterTests]; [self MD5HashTests]; [self RIPEMD160HashTests];