Bug Summary

File:Frameworks/ShortcutRecorder/Source/CTGradient.m
Location:line 55, column 22
Description:dead initialization

Annotated Source Code

1//
2// CTGradient.m
3//
4// Created by Chad Weider on 12/3/05.
5// Copyright (c) 2006 Cotingent.
6// Some rights reserved: <http://creativecommons.org/licenses/by/2.5/>
7//
8// Version: 1.5
9
10#import "CTGradient.h"
11
12@interface CTGradient (Private)
13- (void)_commonInit;
14- (void)setBlendingMode:(CTGradientBlendingMode)mode;
15- (void)addElement:(CTGradientElement*)newElement;
16
17- (CTGradientElement *)elementAtIndex:(unsigned)index;
18
19- (CTGradientElement)removeElementAtIndex:(unsigned)index;
20- (CTGradientElement)removeElementAtPosition:(float)position;
21@end
22
23//C Fuctions for color blending
24void linearEvaluation (void *info, const float *in, float *out);
25void chromaticEvaluation(void *info, const float *in, float *out);
26void inverseChromaticEvaluation(void *info, const float *in, float *out);
27void transformRGB_HSV(float *components);
28void transformHSV_RGB(float *components);
29void resolveHSV(float *color1, float *color2);
30
31
32@implementation CTGradient
33/////////////////////////////////////Initialization Type Stuff
34- (id)init
35 {
36 self = [super init];
37
38 if (self != nil0)
39 {
40 [self _commonInit];
41 [self setBlendingMode:CTLinearBlendingMode];
42 }
43 return self;
44 }
45
46- (void)_commonInit
47 {
48 elementList = nil0;
49 }
50
51- (void)dealloc
52 {
53 CGFunctionRelease(gradientFunction);
54
Value stored to 'elementToRemove' during its initialization is never read
55 CTGradientElement *elementToRemove = elementList;
56 while(elementList != nil0)
57 {
58 elementToRemove = elementList;
59 elementList = elementList->nextElement;
60 free(elementToRemove);
61 }
62
63 [super dealloc];
64 }
65
66- (id)copyWithZone:(NSZone *)zone
67 {
68 CTGradient *copy = [[[self class] allocWithZone:zone] init];
69
70 //now just copy my elementlist
71 CTGradientElement *currentElement = elementList;
72 while(currentElement != nil0)
73 {
74 [copy addElement:currentElement];
75 currentElement = currentElement->nextElement;
76 }
77
78 [copy setBlendingMode:blendingMode];
79
80 return copy;
81 }
82
83- (void)encodeWithCoder:(NSCoder *)coder
84 {
85 if([coder allowsKeyedCoding])
86 {
87 unsigned count = 0;
88 CTGradientElement *currentElement = elementList;
89 while(currentElement != nil0)
90 {
91 [coder encodeValueOfObjCType:@encode(float) at:&(currentElement->red)];
92 [coder encodeValueOfObjCType:@encode(float) at:&(currentElement->green)];
93 [coder encodeValueOfObjCType:@encode(float) at:&(currentElement->blue)];
94 [coder encodeValueOfObjCType:@encode(float) at:&(currentElement->alpha)];
95 [coder encodeValueOfObjCType:@encode(float) at:&(currentElement->position)];
96
97 count++;
98 currentElement = currentElement->nextElement;
99 }
100 [coder encodeInt:count forKey:@"CTGradientElementCount"];
101 [coder encodeInt:blendingMode forKey:@"CTGradientBlendingMode"];
102 }
103 else
104 [NSException raise:NSInvalidArchiveOperationException format:@"Only supports NSKeyedArchiver coders"];
105 }
106
107- (id)initWithCoder:(NSCoder *)coder
108 {
109 [self _commonInit];
110
111 [self setBlendingMode:[coder decodeIntForKey:@"CTGradientBlendingMode"]];
112 unsigned count = [coder decodeIntForKey:@"CTGradientElementCount"];
113
114 while(count != 0)
115 {
116 CTGradientElement newElement;
117
118 [coder decodeValueOfObjCType:@encode(float) at:&(newElement.red)];
119 [coder decodeValueOfObjCType:@encode(float) at:&(newElement.green)];
120 [coder decodeValueOfObjCType:@encode(float) at:&(newElement.blue)];
121 [coder decodeValueOfObjCType:@encode(float) at:&(newElement.alpha)];
122 [coder decodeValueOfObjCType:@encode(float) at:&(newElement.position)];
123
124 count--;
125 [self addElement:&newElement];
126 }
127 return self;
128 }
129
130
131#pragma mark -
132
133
134
135#pragma mark Creation
136+ (id)gradientWithBeginningColor:(NSColor *)begin endingColor:(NSColor *)end
137 {
138 id newInstance = [[[self class] alloc] init];
139
140 CTGradientElement color1;
141 CTGradientElement color2;
142
143 [[begin colorUsingColorSpaceName:NSCalibratedRGBColorSpace] getRed:&color1.red
144 green:&color1.green
145 blue:&color1.blue
146 alpha:&color1.alpha];
147
148 [[end colorUsingColorSpaceName:NSCalibratedRGBColorSpace] getRed:&color2.red
149 green:&color2.green
150 blue:&color2.blue
151 alpha:&color2.alpha];
152 color1.position = 0;
153 color2.position = 1;
154
155 [newInstance addElement:&color1];
156 [newInstance addElement:&color2];
157
158 return [newInstance autorelease];
159 }
160
161+ (id)aquaSelectedGradient
162 {
163 id newInstance = [[[self class] alloc] init];
164
165 CTGradientElement color1;
166 color1.red = 0.58;
167 color1.green = 0.86;
168 color1.blue = 0.98;
169 color1.alpha = 1.00;
170 color1.position = 0;
171
172 CTGradientElement color2;
173 color2.red = 0.42;
174 color2.green = 0.68;
175 color2.blue = 0.90;
176 color2.alpha = 1.00;
177 color2.position = 11.5/23;
178
179 CTGradientElement color3;
180 color3.red = 0.64;
181 color3.green = 0.80;
182 color3.blue = 0.94;
183 color3.alpha = 1.00;
184 color3.position = 11.5/23;
185
186 CTGradientElement color4;
187 color4.red = 0.56;
188 color4.green = 0.70;
189 color4.blue = 0.90;
190 color4.alpha = 1.00;
191 color4.position = 1;
192
193 [newInstance addElement:&color1];
194 [newInstance addElement:&color2];
195 [newInstance addElement:&color3];
196 [newInstance addElement:&color4];
197
198 return [newInstance autorelease];
199 }
200
201+ (id)aquaNormalGradient
202 {
203 id newInstance = [[[self class] alloc] init];
204
205 CTGradientElement color1;
206 color1.red = color1.green = color1.blue = 0.95;
207 color1.alpha = 1.00;
208 color1.position = 0;
209
210 CTGradientElement color2;
211 color2.red = color2.green = color2.blue = 0.83;
212 color2.alpha = 1.00;
213 color2.position = 11.5/23;
214
215 CTGradientElement color3;
216 color3.red = color3.green = color3.blue = 0.95;
217 color3.alpha = 1.00;
218 color3.position = 11.5/23;
219
220 CTGradientElement color4;
221 color4.red = color4.green = color4.blue = 0.92;
222 color4.alpha = 1.00;
223 color4.position = 1;
224
225 [newInstance addElement:&color1];
226 [newInstance addElement:&color2];
227 [newInstance addElement:&color3];
228 [newInstance addElement:&color4];
229
230 return [newInstance autorelease];
231 }
232
233+ (id)aquaPressedGradient
234 {
235 id newInstance = [[[self class] alloc] init];
236
237 CTGradientElement color1;
238 color1.red = color1.green = color1.blue = 0.80;
239 color1.alpha = 1.00;
240 color1.position = 0;
241
242 CTGradientElement color2;
243 color2.red = color2.green = color2.blue = 0.64;
244 color2.alpha = 1.00;
245 color2.position = 11.5/23;
246
247 CTGradientElement color3;
248 color3.red = color3.green = color3.blue = 0.80;
249 color3.alpha = 1.00;
250 color3.position = 11.5/23;
251
252 CTGradientElement color4;
253 color4.red = color4.green = color4.blue = 0.77;
254 color4.alpha = 1.00;
255 color4.position = 1;
256
257 [newInstance addElement:&color1];
258 [newInstance addElement:&color2];
259 [newInstance addElement:&color3];
260 [newInstance addElement:&color4];
261
262 return [newInstance autorelease];
263 }
264
265+ (id)unifiedSelectedGradient
266 {
267 id newInstance = [[[self class] alloc] init];
268
269 CTGradientElement color1;
270 color1.red = color1.green = color1.blue = 0.85;
271 color1.alpha = 1.00;
272 color1.position = 0;
273
274 CTGradientElement color2;
275 color2.red = color2.green = color2.blue = 0.95;
276 color2.alpha = 1.00;
277 color2.position = 1;
278
279 [newInstance addElement:&color1];
280 [newInstance addElement:&color2];
281
282 return [newInstance autorelease];
283 }
284
285+ (id)unifiedNormalGradient
286 {
287 id newInstance = [[[self class] alloc] init];
288
289 CTGradientElement color1;
290 color1.red = color1.green = color1.blue = 0.75;
291 color1.alpha = 1.00;
292 color1.position = 0;
293
294 CTGradientElement color2;
295 color2.red = color2.green = color2.blue = 0.90;
296 color2.alpha = 1.00;
297 color2.position = 1;
298
299 [newInstance addElement:&color1];
300 [newInstance addElement:&color2];
301
302 return [newInstance autorelease];
303 }
304
305+ (id)unifiedPressedGradient
306 {
307 id newInstance = [[[self class] alloc] init];
308
309 CTGradientElement color1;
310 color1.red = color1.green = color1.blue = 0.60;
311 color1.alpha = 1.00;
312 color1.position = 0;
313
314 CTGradientElement color2;
315 color2.red = color2.green = color2.blue = 0.75;
316 color2.alpha = 1.00;
317 color2.position = 1;
318
319 [newInstance addElement:&color1];
320 [newInstance addElement:&color2];
321
322 return [newInstance autorelease];
323 }
324
325+ (id)unifiedDarkGradient
326 {
327 id newInstance = [[[self class] alloc] init];
328
329 CTGradientElement color1;
330 color1.red = color1.green = color1.blue = 0.68;
331 color1.alpha = 1.00;
332 color1.position = 0;
333
334 CTGradientElement color2;
335 color2.red = color2.green = color2.blue = 0.83;
336 color2.alpha = 1.00;
337 color2.position = 1;
338
339 [newInstance addElement:&color1];
340 [newInstance addElement:&color2];
341
342 return [newInstance autorelease];
343 }
344
345+ (id)sourceListSelectedGradient
346 {
347 id newInstance = [[[self class] alloc] init];
348
349 CTGradientElement color1;
350 color1.red = 0.06;
351 color1.green = 0.37;
352 color1.blue = 0.85;
353 color1.alpha = 1.00;
354 color1.position = 0;
355
356 CTGradientElement color2;
357 color2.red = 0.30;
358 color2.green = 0.60;
359 color2.blue = 0.92;
360 color2.alpha = 1.00;
361 color2.position = 1;
362
363 [newInstance addElement:&color1];
364 [newInstance addElement:&color2];
365
366 return [newInstance autorelease];
367 }
368
369+ (id)sourceListUnselectedGradient
370 {
371 id newInstance = [[[self class] alloc] init];
372
373 CTGradientElement color1;
374 color1.red = 0.43;
375 color1.green = 0.43;
376 color1.blue = 0.43;
377 color1.alpha = 1.00;
378 color1.position = 0;
379
380 CTGradientElement color2;
381 color2.red = 0.60;
382 color2.green = 0.60;
383 color2.blue = 0.60;
384 color2.alpha = 1.00;
385 color2.position = 1;
386
387 [newInstance addElement:&color1];
388 [newInstance addElement:&color2];
389
390 return [newInstance autorelease];
391 }
392
393+ (id)rainbowGradient
394 {
395 id newInstance = [[[self class] alloc] init];
396
397 CTGradientElement color1;
398 color1.red = 1.00;
399 color1.green = 0.00;
400 color1.blue = 0.00;
401 color1.alpha = 1.00;
402 color1.position = 0.0;
403
404 CTGradientElement color2;
405 color2.red = 0.54;
406 color2.green = 0.00;
407 color2.blue = 1.00;
408 color2.alpha = 1.00;
409 color2.position = 1.0;
410
411 [newInstance addElement:&color1];
412 [newInstance addElement:&color2];
413
414 [newInstance setBlendingMode:CTChromaticBlendingMode];
415
416 return [newInstance autorelease];
417 }
418
419+ (id)hydrogenSpectrumGradient
420 {
421 id newInstance = [[[self class] alloc] init];
422
423 struct {float hue; float position; float width;} colorBands[4];
424
425 colorBands[0].hue = 22;
426 colorBands[0].position = .145;
427 colorBands[0].width = .01;
428
429 colorBands[1].hue = 200;
430 colorBands[1].position = .71;
431 colorBands[1].width = .008;
432
433 colorBands[2].hue = 253;
434 colorBands[2].position = .885;
435 colorBands[2].width = .005;
436
437 colorBands[3].hue = 275;
438 colorBands[3].position = .965;
439 colorBands[3].width = .003;
440
441 int i;
442 /////////////////////////////
443 for(i = 0; i < 4; i++)
444 {
445 float color[4];
446 color[0] = colorBands[i].hue - 180*colorBands[i].width;
447 color[1] = 1;
448 color[2] = 0.001;
449 color[3] = 1;
450 transformHSV_RGB(color);
451 CTGradientElement fadeIn;
452 fadeIn.red = color[0];
453 fadeIn.green = color[1];
454 fadeIn.blue = color[2];
455 fadeIn.alpha = color[3];
456 fadeIn.position = colorBands[i].position - colorBands[i].width;
457
458
459 color[0] = colorBands[i].hue;
460 color[1] = 1;
461 color[2] = 1;
462 color[3] = 1;
463 transformHSV_RGB(color);
464 CTGradientElement band;
465 band.red = color[0];
466 band.green = color[1];
467 band.blue = color[2];
468 band.alpha = color[3];
469 band.position = colorBands[i].position;
470
471 color[0] = colorBands[i].hue + 180*colorBands[i].width;
472 color[1] = 1;
473 color[2] = 0.001;
474 color[3] = 1;
475 transformHSV_RGB(color);
476 CTGradientElement fadeOut;
477 fadeOut.red = color[0];
478 fadeOut.green = color[1];
479 fadeOut.blue = color[2];
480 fadeOut.alpha = color[3];
481 fadeOut.position = colorBands[i].position + colorBands[i].width;
482
483
484 [newInstance addElement:&fadeIn];
485 [newInstance addElement:&band];
486 [newInstance addElement:&fadeOut];
487 }
488
489 [newInstance setBlendingMode:CTChromaticBlendingMode];
490
491 return [newInstance autorelease];
492 }
493
494#pragma mark -
495
496
497
498#pragma mark Modification
499- (CTGradient *)gradientWithAlphaComponent:(float)alpha
500 {
501 id newInstance = [[[self class] alloc] init];
502
503 CTGradientElement *curElement = elementList;
504 CTGradientElement tempElement;
505
506 while(curElement != nil0)
507 {
508 tempElement = *curElement;
509 tempElement.alpha = alpha;
510 [newInstance addElement:&tempElement];
511
512 curElement = curElement->nextElement;
513 }
514
515 return [newInstance autorelease];
516 }
517
518- (CTGradient *)gradientWithBlendingMode:(CTGradientBlendingMode)mode
519 {
520 CTGradient *newGradient = [self copy];
521
522 [newGradient setBlendingMode:mode];
523
524 return [newGradient autorelease];
525 }
526
527
528//Adds a color stop with <color> at <position> in elementList
529//(if two elements are at the same position then added imediatly after the one that was there already)
530- (CTGradient *)addColorStop:(NSColor *)color atPosition:(float)position
531 {
532 CTGradient *newGradient = [self copy];
533 CTGradientElement newGradientElement;
534
535 //put the components of color into the newGradientElement - must make sure it is a RGB color (not Gray or CMYK)
536 [[color colorUsingColorSpaceName:NSCalibratedRGBColorSpace] getRed:&newGradientElement.red
537 green:&newGradientElement.green
538 blue:&newGradientElement.blue
539 alpha:&newGradientElement.alpha];
540 newGradientElement.position = position;
541
542 //Pass it off to addElement to take care of adding it to the elementList
543 [newGradient addElement:&newGradientElement];
544
545 return [newGradient autorelease];
546 }
547
548
549//Removes the color stop at <position> from elementList
550- (CTGradient *)removeColorStopAtPosition:(float)position
551 {
552 CTGradient *newGradient = [self copy];
553 CTGradientElement removedElement = [newGradient removeElementAtPosition:position];
554
555 if(isnan( sizeof ( removedElement . position ) == sizeof ( float ) ? __inline_isnanf
( ( float ) ( removedElement . position ) ) : sizeof ( removedElement
. position ) == sizeof ( double ) ? __inline_isnand ( ( double
) ( removedElement . position ) ) : __inline_isnan ( ( long double
) ( removedElement . position ) ) )
(removedElement.position))
556 [NSException raise:NSRangeException format:@"-[%@ removeColorStopAtPosition:]: no such colorStop at position (%f)", [self class], position];
557
558 return [newGradient autorelease];
559 }
560
561- (CTGradient *)removeColorStopAtIndex:(unsigned)index
562 {
563 CTGradient *newGradient = [self copy];
564 CTGradientElement removedElement = [newGradient removeElementAtIndex:index];
565
566 if(isnan( sizeof ( removedElement . position ) == sizeof ( float ) ? __inline_isnanf
( ( float ) ( removedElement . position ) ) : sizeof ( removedElement
. position ) == sizeof ( double ) ? __inline_isnand ( ( double
) ( removedElement . position ) ) : __inline_isnan ( ( long double
) ( removedElement . position ) ) )
(removedElement.position))
567 [NSException raise:NSRangeException format:@"-[%@ removeColorStopAtIndex:]: index (%i) beyond bounds", [self class], index];
568
569 return [newGradient autorelease];
570 }
571#pragma mark -
572
573
574
575#pragma mark Information
576- (CTGradientBlendingMode)blendingMode
577 {
578 return blendingMode;
579 }
580
581//Returns color at <position> in gradient
582- (NSColor *)colorStopAtIndex:(unsigned)index
583 {
584 CTGradientElement *element = [self elementAtIndex:index];
585
586 if(element != nil0)
587 return [NSColor colorWithCalibratedRed:element->red
588 green:element->green
589 blue:element->blue
590 alpha:element->alpha];
591
592 [NSException raise:NSRangeException format:@"-[%@ removeColorStopAtIndex:]: index (%i) beyond bounds", [self class], index];
593
594 return nil0;
595 }
596
597- (NSColor *)colorAtPosition:(float)position
598 {
599 float components[4];
600
601 switch(blendingMode)
602 {
603 case CTLinearBlendingMode:
604 linearEvaluation(&elementList, &position, components); break;
605 case CTChromaticBlendingMode:
606 chromaticEvaluation(&elementList, &position, components); break;
607 case CTInverseChromaticBlendingMode:
608 inverseChromaticEvaluation(&elementList, &position, components); break;
609 }
610
611
612 return [NSColor colorWithCalibratedRed:components[0]
613 green:components[1]
614 blue:components[2]
615 alpha:components[3]];
616 }
617#pragma mark -
618
619
620
621#pragma mark Drawing
622- (void)drawSwatchInRect:(NSRect)rect
623 {
624 [self fillRect:rect angle:45];
625 }
626
627- (void)fillRect:(NSRect)rect angle:(float)angle
628 {
629 //First Calculate where the beginning and ending points should be
630 CGPoint startPoint;
631 CGPoint endPoint;
632
633 if(angle == 0) //screw the calculations - we know the answer
634 {
635 startPoint = CGPointMake(NSMinX(rect), NSMinY(rect)); //right of rect
636 endPoint = CGPointMake(NSMaxX(rect), NSMinY(rect)); //left of rect
637 }
638 else if(angle == 90) //same as above
639 {
640 startPoint = CGPointMake(NSMinX(rect), NSMinY(rect)); //bottom of rect
641 endPoint = CGPointMake(NSMinX(rect), NSMaxY(rect)); //top of rect
642 }
643 else //ok, we'll do the calculations now
644 {
645 float x,y;
646 float sina, cosa, tana;
647
648 float length;
649 float deltax,
650 deltay;
651
652 float rangle = angle * pi/180; //convert the angle to radians
653
654 if(fabsf(tan(rangle))<=1) //for range [-45,45], [135,225]
655 {
656 x = NSWidth(rect);
657 y = NSHeight(rect);
658
659 sina = sin(rangle);
660 cosa = cos(rangle);
661 tana = tan(rangle);
662
663 length = x/fabsf(cosa)+(y-x*fabsf(tana))*fabsf(sina);
664
665 deltax = length*cosa/2;
666 deltay = length*sina/2;
667 }
668 else //for range [45,135], [225,315]
669 {
670 x = NSHeight(rect);
671 y = NSWidth(rect);
672
673 sina = sin(rangle - 90*pi/180);
674 cosa = cos(rangle - 90*pi/180);
675 tana = tan(rangle - 90*pi/180);
676
677 length = x/fabsf(cosa)+(y-x*fabsf(tana))*fabsf(sina);
678
679 deltax =-length*sina/2;
680 deltay = length*cosa/2;
681 }
682
683 startPoint = CGPointMake(NSMidX(rect)-deltax, NSMidY(rect)-deltay);
684 endPoint = CGPointMake(NSMidX(rect)+deltax, NSMidY(rect)+deltay);
685 }
686
687 //Calls to CoreGraphics
688 CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
689 CGContextSaveGState(currentContext);
690 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
691 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
692 #else
693 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
694 #endif
695
696 CGShadingRef myCGShading = CGShadingCreateAxial(colorspace, startPoint, endPoint, gradientFunction, false0, false0);
697
698 CGContextClipToRect(currentContext , *(CGRect *)&rect); //This is where the action happens
699 CGContextDrawShading(currentContext, myCGShading);
700
701 CGShadingRelease (myCGShading);
702 CGColorSpaceRelease(colorspace );
703 CGContextRestoreGState(currentContext);
704 }
705
706- (void)radialFillRect:(NSRect)rect
707 {
708 CGPoint startPoint , endPoint;
709 float startRadius, endRadius;
710
711 startPoint = endPoint = CGPointMake(NSMidX(rect), NSMidY(rect));
712
713 startRadius = 1;
714
715 if(NSHeight(rect)>NSWidth(rect))
716 endRadius = NSHeight(rect)/2;
717 else
718 endRadius = NSWidth(rect)/2;
719
720 //Calls to CoreGraphics
721 CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
722 CGContextSaveGState(currentContext);
723 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
724 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
725 #else
726 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
727 #endif
728
729 CGShadingRef myCGShading = CGShadingCreateRadial(colorspace, startPoint, startRadius, endPoint, endRadius, gradientFunction, true1, true1);
730
731 CGContextClipToRect (currentContext , *(CGRect *)&rect);
732 CGContextDrawShading(currentContext , myCGShading); //This is where the action happens
733
734 CGShadingRelease (myCGShading);
735 CGColorSpaceRelease (colorspace);
736 CGContextRestoreGState(currentContext);
737 }
738
739#pragma mark -
740
741
742
743#pragma mark Private Methods
744- (void)setBlendingMode:(CTGradientBlendingMode)mode;
745 {
746 blendingMode = mode;
747
748 //Choose what blending function to use
749 void *evaluationFunction = NULL( ( void * ) 0 );
750 switch(blendingMode)
751 {
752 case CTLinearBlendingMode:
753 evaluationFunction = &linearEvaluation; break;
754 case CTChromaticBlendingMode:
755 evaluationFunction = &chromaticEvaluation; break;
756 case CTInverseChromaticBlendingMode:
757 evaluationFunction = &inverseChromaticEvaluation; break;
758 }
759
760 //replace the current CoreGraphics Function with new one
761 if(gradientFunction != NULL( ( void * ) 0 ))
762 CGFunctionRelease(gradientFunction);
763
764 CGFunctionCallbacks evaluationCallbackInfo = {0 , evaluationFunction, NULL( ( void * ) 0 )}; //Version, evaluator function, cleanup function
765
766 static const float input_value_range [2] = { 0, 1 }; //range for the evaluator input
767 static const float output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 }; //ranges for the evaluator output (4 returned values)
768
769 gradientFunction = CGFunctionCreate(&elementList, //the two transition colors
770 1, input_value_range , //number of inputs (just fraction of progression)
771 4, output_value_ranges, //number of outputs (4 - RGBa)
772 &evaluationCallbackInfo); //info for using the evaluator function
773 }
774
775- (void)addElement:(CTGradientElement *)newElement
776{
777 if(elementList == nil0 || newElement->position < elementList->position) //inserting at beginning of list
778 {
779 CTGradientElement *tmpNext = elementList;
780 elementList = malloc(sizeof(CTGradientElement));
781 *elementList = *newElement;
782 elementList->nextElement = tmpNext;
783 }
784 else //inserting somewhere inside list
785 {
786 CTGradientElement *curElement = elementList;
787
788 while(curElement->nextElement != nil0 && !((curElement->position <= newElement->position) && (newElement->position < curElement->nextElement->position)))
789 {
790 curElement = curElement->nextElement;
791 }
792
793 CTGradientElement *tmpNext = curElement->nextElement;
794 curElement->nextElement = malloc(sizeof(CTGradientElement));
795 *(curElement->nextElement) = *newElement;
796 curElement->nextElement->nextElement = tmpNext;
797 }
798 }
799
800- (CTGradientElement)removeElementAtIndex:(unsigned)index
801 {
802 CTGradientElement removedElement;
803
804 if(elementList != nil0)
805 {
806 if(index == 0)
807 {
808 CTGradientElement *tmpNext = elementList;
809 elementList = elementList->nextElement;
810
811 removedElement = *tmpNext;
812 free(tmpNext);
813
814 return removedElement;
815 }
816
817 unsigned count = 1; //we want to start one ahead
818 CTGradientElement *currentElement = elementList;
819 while(currentElement->nextElement != nil0)
820 {
821 if(count == index)
822 {
823 CTGradientElement *tmpNext = currentElement->nextElement;
824 currentElement->nextElement = currentElement->nextElement->nextElement;
825
826 removedElement = *tmpNext;
827 free(tmpNext);
828
829 return removedElement;
830 }
831
832 count++;
833 currentElement = currentElement->nextElement;
834 }
835 }
836
837 //element is not found, return empty element
838 removedElement.red = 0.0;
839 removedElement.green = 0.0;
840 removedElement.blue = 0.0;
841 removedElement.alpha = 0.0;
842 removedElement.position = NAN__builtin_nanf ( "0x7fc00000" );
843 removedElement.nextElement = nil0;
844
845 return removedElement;
846 }
847
848- (CTGradientElement)removeElementAtPosition:(float)position
849 {
850 CTGradientElement removedElement;
851
852 if(elementList != nil0)
853 {
854 if(elementList->position == position)
855 {
856 CTGradientElement *tmpNext = elementList;
857 elementList = elementList->nextElement;
858
859 removedElement = *tmpNext;
860 free(tmpNext);
861
862 return removedElement;
863 }
864 else
865 {
866 CTGradientElement *curElement = elementList;
867 while(curElement->nextElement != nil0)
868 {
869 if(curElement->nextElement->position == position)
870 {
871 CTGradientElement *tmpNext = curElement->nextElement;
872 curElement->nextElement = curElement->nextElement->nextElement;
873
874 removedElement = *tmpNext;
875 free(tmpNext);
876
877 return removedElement;
878 }
879 }
880 }
881 }
882
883 //element is not found, return empty element
884 removedElement.red = 0.0;
885 removedElement.green = 0.0;
886 removedElement.blue = 0.0;
887 removedElement.alpha = 0.0;
888 removedElement.position = NAN__builtin_nanf ( "0x7fc00000" );
889 removedElement.nextElement = nil0;
890
891 return removedElement;
892 }
893
894
895- (CTGradientElement *)elementAtIndex:(unsigned)index;
896 {
897 unsigned count = 0;
898 CTGradientElement *currentElement = elementList;
899
900 while(currentElement != nil0)
901 {
902 if(count == index)
903 return currentElement;
904
905 count++;
906 currentElement = currentElement->nextElement;
907 }
908
909 return nil0;
910 }
911#pragma mark -
912
913
914
915#pragma mark Core Graphics
916//////////////////////////////////////Blending Functions/////////////////////////////////////
917void linearEvaluation (void *info, const float *in, float *out)
918 {
919 float position = *in;
920
921 if(*(CTGradientElement **)info == nil0) //if elementList is empty return clear color
922 {
923 out[0] = out[1] = out[2] = out[3] = 1;
924 return;
925 }
926
927 //This grabs the first two colors in the sequence
928 CTGradientElement *color1 = *(CTGradientElement **)info;
929 CTGradientElement *color2 = color1->nextElement;
930
931 //make sure first color and second color are on other sides of position
932 while(color2 != nil0 && color2->position < position)
933 {
934 color1 = color2;
935 color2 = color1->nextElement;
936 }
937 //if we don't have another color then make next color the same color
938 if(color2 == nil0)
939 {
940 color2 = color1;
941 }
942
943 //----------FailSafe settings----------
944 //color1->red = 1; color2->red = 0;
945 //color1->green = 1; color2->green = 0;
946 //color1->blue = 1; color2->blue = 0;
947 //color1->alpha = 1; color2->alpha = 1;
948 //color1->position = .5;
949 //color2->position = .5;
950 //-------------------------------------
951
952 if(position <= color1->position) //Make all below color color1's position equal to color1
953 {
954 out[0] = color1->red;
955 out[1] = color1->green;
956 out[2] = color1->blue;
957 out[3] = color1->alpha;
958 }
959 else if (position >= color2->position) //Make all above color color2's position equal to color2
960 {
961 out[0] = color2->red;
962 out[1] = color2->green;
963 out[2] = color2->blue;
964 out[3] = color2->alpha;
965 }
966 else //Interpolate color at postions between color1 and color1
967 {
968 //adjust position so that it goes from 0 to 1 in the range from color 1 & 2's position
969 position = (position-color1->position)/(color2->position - color1->position);
970
971 out[0] = (color2->red - color1->red )*position + color1->red;
972 out[1] = (color2->green - color1->green)*position + color1->green;
973 out[2] = (color2->blue - color1->blue )*position + color1->blue;
974 out[3] = (color2->alpha - color1->alpha)*position + color1->alpha;
975 }
976 }
977
978
979
980
981//Chromatic Evaluation -
982// This blends colors by their Hue, Saturation, and Value(Brightness) right now I just
983// transform the RGB values stored in the CTGradientElements to HSB, in the future I may
984// streamline it to avoid transforming in and out of HSB colorspace *for later*
985//
986// For the chromatic blend we shift the hue of color1 to meet the hue of color2. To do
987// this we will add to the hue's angle (if we subtract we'll be doing the inverse
988// chromatic...scroll down more for that). All we need to do is keep adding to the hue
989// until we wrap around the colorwheel and get to color2.
990void chromaticEvaluation(void *info, const float *in, float *out)
991 {
992 float position = *in;
993
994 if(*(CTGradientElement **)info == nil0) //if elementList is empty return clear color
995 {
996 out[0] = out[1] = out[2] = out[3] = 1;
997 return;
998 }
999
1000 //This grabs the first two colors in the sequence
1001 CTGradientElement *color1 = *(CTGradientElement **)info;
1002 CTGradientElement *color2 = color1->nextElement;
1003
1004 float c1[4];
1005 float c2[4];
1006
1007 //make sure first color and second color are on other sides of position
1008 while(color2 != nil0 && color2->position < position)
1009 {
1010 color1 = color2;
1011 color2 = color1->nextElement;
1012 }
1013 //if we don't have another color then make next color the same color
1014 if(color2 == nil0)
1015 {
1016 color2 = color1;
1017 }
1018
1019
1020 c1[0] = color1->red;
1021 c1[1] = color1->green;
1022 c1[2] = color1->blue;
1023 c1[3] = color1->alpha;
1024
1025 c2[0] = color2->red;
1026 c2[1] = color2->green;
1027 c2[2] = color2->blue;
1028 c2[3] = color2->alpha;
1029
1030 transformRGB_HSV(c1);
1031 transformRGB_HSV(c2);
1032 resolveHSV(c1,c2);
1033
1034 if(c1[0] > c2[0]) //if color1's hue is higher than color2's hue then
1035 c2[0] += 360; // we need to move c2 one revolution around the wheel
1036
1037
1038 if(position <= color1->position) //Make all below color color1's position equal to color1
1039 {
1040 out[0] = c1[0];
1041 out[1] = c1[1];
1042 out[2] = c1[2];
1043 out[3] = c1[3];
1044 }
1045 else if (position >= color2->position) //Make all above color color2's position equal to color2
1046 {
1047 out[0] = c2[0];
1048 out[1] = c2[1];
1049 out[2] = c2[2];
1050 out[3] = c2[3];
1051 }
1052 else //Interpolate color at postions between color1 and color1
1053 {
1054 //adjust position so that it goes from 0 to 1 in the range from color 1 & 2's position
1055 position = (position-color1->position)/(color2->position - color1->position);
1056
1057 out[0] = (c2[0] - c1[0])*position + c1[0];
1058 out[1] = (c2[1] - c1[1])*position + c1[1];
1059 out[2] = (c2[2] - c1[2])*position + c1[2];
1060 out[3] = (c2[3] - c1[3])*position + c1[3];
1061 }
1062
1063 transformHSV_RGB(out);
1064
1065 //if(position > -1 && out[0] == out[1] && out[1] == out[2] && out[0]==0)
1066 //printf("%.4f: %.4f,%.4f,%.4f\n",position,out[0],out[1],out[2]);
1067 //printf("%.4f: %.4f,%.4f,%.4f\n",position,color1->red,color1->green,color1->blue);
1068 }
1069
1070
1071
1072//Inverse Chromatic Evaluation -
1073// Inverse Chromatic is about the same story as Chromatic Blend, but here the Hue
1074// is strictly decreasing, that is we need to get from color1 to color2 by decreasing
1075// the 'angle' (i.e. 90º -> 180º would be done by subtracting 270º and getting -180º...
1076// which is equivalent to 180º mod 360º
1077void inverseChromaticEvaluation(void *info, const float *in, float *out)
1078 {
1079 float position = *in;
1080
1081 if(*(CTGradientElement **)info == nil0) //if elementList is empty return clear color
1082 {
1083 out[0] = out[1] = out[2] = out[3] = 1;
1084 return;
1085 }
1086
1087 //This grabs the first two colors in the sequence
1088 CTGradientElement *color1 = *(CTGradientElement **)info;
1089 CTGradientElement *color2 = color1->nextElement;
1090
1091 float c1[4];
1092 float c2[4];
1093
1094 //make sure first color and second color are on other sides of position
1095 while(color2 != nil0 && color2->position < position)
1096 {
1097 color1 = color2;
1098 color2 = color1->nextElement;
1099 }
1100 //if we don't have another color then make next color the same color
1101 if(color2 == nil0)
1102 {
1103 color2 = color1;
1104 }
1105
1106 c1[0] = color1->red;
1107 c1[1] = color1->green;
1108 c1[2] = color1->blue;
1109 c1[3] = color1->alpha;
1110
1111 c2[0] = color2->red;
1112 c2[1] = color2->green;
1113 c2[2] = color2->blue;
1114 c2[3] = color2->alpha;
1115
1116 transformRGB_HSV(c1);
1117 transformRGB_HSV(c2);
1118 resolveHSV(c1,c2);
1119
1120 if(c1[0] < c2[0]) //if color1's hue is higher than color2's hue then
1121 c1[0] += 360; // we need to move c2 one revolution back on the wheel
1122
1123
1124 if(position <= color1->position) //Make all below color color1's position equal to color1
1125 {
1126 out[0] = c1[0];
1127 out[1] = c1[1];
1128 out[2] = c1[2];
1129 out[3] = c1[3];
1130 }
1131 else if (position >= color2->position) //Make all above color color2's position equal to color2
1132 {
1133 out[0] = c2[0];
1134 out[1] = c2[1];
1135 out[2] = c2[2];
1136 out[3] = c2[3];
1137 }
1138 else //Interpolate color at postions between color1 and color1
1139 {
1140 //adjust position so that it goes from 0 to 1 in the range from color 1 & 2's position
1141 position = (position-color1->position)/(color2->position - color1->position);
1142
1143 out[0] = (c2[0] - c1[0])*position + c1[0];
1144 out[1] = (c2[1] - c1[1])*position + c1[1];
1145 out[2] = (c2[2] - c1[2])*position + c1[2];
1146 out[3] = (c2[3] - c1[3])*position + c1[3];
1147 }
1148
1149 transformHSV_RGB(out);
1150 }
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161void transformRGB_HSV(float *components) //H,S,B -> R,G,B
1162 {
1163 float H = 0.0, S = 0.0, V = 0.0;
1164 float R = components[0],
1165 G = components[1],
1166 B = components[2];
1167
1168 float MAX = R > G ? (R > B ? R : B) : (G > B ? G : B),
1169 MIN = R < G ? (R < B ? R : B) : (G < B ? G : B);
1170
1171 if(MAX == MIN)
1172 H = NAN__builtin_nanf ( "0x7fc00000" );
1173 else if(MAX == R)
1174 if(G >= B)