Bug Summary

File:Frameworks/AIUtilities Framework/Source/AIAttributedStringAdditions.m
Location:line 167, column 9
Description:dead store

Annotated Source Code

1/*-------------------------------------------------------------------------------------------------------*\
2| Adium, Copyright (C) 2001-2005, Adam Iser (adamiser@mac.com | http://www.adiumx.com) |
3\---------------------------------------------------------------------------------------------------------/
4| This program is free software; you can redistribute it and/or modify it under the terms of the GNU
5| General Public License as published by the Free Software Foundation; either version 2 of the License,
6| or (at your option) any later version.
7|
8| This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
9| the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
10| Public License for more details.
11|
12| You should have received a copy of the GNU General Public License along with this program; if not,
13| write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14\------------------------------------------------------------------------------------------------------ */
15
16/*
17 Some useful additions for attributed strings
18 */
19
20#import "AIAttributedStringAdditions.h"
21#import "AIColorAdditions.h"
22#import "AITextAttributes.h"
23#import "AIApplicationAdditions.h"
24#import "AIStringUtilities.h"
25
26NSString *AIFontFamilyAttributeName = @"AIFontFamily";
27NSString *AIFontSizeAttributeName = @"AIFontSize";
28NSString *AIFontWeightAttributeName = @"AIFontWeight";
29NSString *AIFontStyleAttributeName = @"AIFontStyle";
30
31@implementation NSMutableAttributedString (AIAttributedStringAdditions)
32
33//Append a plain string, adding the specified attributes
34- (void)appendString:(NSString *)aString withAttributes:(NSDictionary *)attrs
35{
36 NSAttributedString *tempString;
37
38 if (attrs) {
39 tempString = [[NSAttributedString alloc] initWithString:aString attributes:attrs];
40 } else {
41 tempString = [[NSAttributedString alloc] initWithString:aString];
42 }
43
44 [self appendAttributedString:tempString];
45 [tempString release];
46}
47
48- (unsigned int)replaceOccurrencesOfString:(NSString *)target withString:(NSString*)replacement options:(unsigned)opts range:(NSRange)searchRange
49{
50 NSRange theRange;
51 unsigned numberOfReplacements = 0, replacementLength = [replacement length];
52
53 while ( (theRange = [[self string] rangeOfString:target
54 options:opts
55 range:searchRange]).location != NSNotFound ) {
56 [self replaceCharactersInRange:theRange withString:replacement];
57 numberOfReplacements++;
58 searchRange.length = searchRange.length - ((theRange.location + theRange.length) - searchRange.location);
59
60 searchRange.location = theRange.location + replacementLength;
61 if (searchRange.length - searchRange.location < 1)
62 break;
63 }
64 return numberOfReplacements;
65}
66
67- (unsigned int)replaceOccurrencesOfString:(NSString *)target withString:(NSString*)replacement attributes:(NSDictionary*)attributes options:(unsigned)opts range:(NSRange)searchRange
68{
69 NSRange theRange;
70 unsigned numberOfReplacements = 0, replacementLength = [replacement length];
71 NSAttributedString *replacementString = [[NSAttributedString alloc] initWithString:replacement
72 attributes:attributes];
73
74 while ( (theRange = [[self string] rangeOfString:target
75 options:opts
76 range:searchRange]).location != NSNotFound ) {
77
78 [self replaceCharactersInRange:theRange withAttributedString:replacementString];
79 numberOfReplacements++;
80 searchRange.length = searchRange.length - ((theRange.location + theRange.length) - searchRange.location);
81
82 searchRange.location = theRange.location + replacementLength;
83 if (searchRange.length - searchRange.location < 1)
84 break;
85 }
86
87 [replacementString release];
88
89 return numberOfReplacements;
90}
91
92
93//from Adium 1.6 AIAttributedStringFormattingAdditions
94//adjust the colors in the string so they're visible on the background
95- (void)adjustColorsToShowOnBackground:(NSColor *)backgroundColor
96{
97 int index = 0;
98 int stringLength = [self length];
99 float backgroundBrightness, backgroundSum;
100
101 //--get the brightness of our background--
102 backgroundColor = [backgroundColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
103 backgroundBrightness = [backgroundColor brightnessComponent];
104 backgroundSum = [backgroundColor redComponent] + [backgroundColor greenComponent] + [backgroundColor blueComponent];
105 //we need to scan each colored "chunk" of the message - and check to make sure it is a "visible" color
106 while (index < stringLength) {
107 NSColor *fontColor;
108 NSRange effectiveRange;
109 float brightness, sum;
110 float deltaBrightness, deltaSum;
111 BOOL colorChanged = NO( BOOL ) 0;
112
113 //--get the font color--
114 fontColor = [self attribute:NSForegroundColorAttributeName atIndex:index effectiveRange:&effectiveRange];
115 if (fontColor == nil0) fontColor = [NSColor blackColor];
116 fontColor = [fontColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
117
118 //--check brightness--
119 brightness = [fontColor brightnessComponent];
120 deltaBrightness = backgroundBrightness - brightness;
121 if (deltaBrightness >= 0 && deltaBrightness < 0.4) { //too close
122 //change the color
123 fontColor = [NSColor colorWithCalibratedHue:[fontColor hueComponent] saturation:[fontColor saturationComponent] brightness:backgroundBrightness - 0.4 alpha:[fontColor alphaComponent]];
124 fontColor = [fontColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
125 colorChanged = YES( BOOL ) 1;
126
127 } else if (deltaBrightness < 0 && deltaBrightness > -0.4) { //too close
128 //change the color
129 fontColor = [NSColor colorWithCalibratedHue:[fontColor hueComponent] saturation:[fontColor saturationComponent] brightness:backgroundBrightness + 0.4 alpha:[fontColor alphaComponent]];
130 fontColor = [fontColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
131
132 colorChanged = YES( BOOL ) 1;
133 }
134
135 //--check components--
136 sum = [fontColor redComponent] + [fontColor greenComponent] + [fontColor blueComponent];
137 deltaSum = backgroundSum - sum;
138 if (deltaSum < 1.0 && deltaSum > -1.0) { //still too similar
139 //just give up and make the color black or white
140 if (backgroundBrightness <= 0.5) {
141 fontColor = [[NSColor whiteColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
142 } else {
143 fontColor = [[NSColor blackColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
144 }
145 colorChanged = YES( BOOL ) 1;
146 }
147
148 if (colorChanged) {
149 [self addAttribute:NSForegroundColorAttributeName value:fontColor range:effectiveRange];
150 }
151
152 index = effectiveRange.location + effectiveRange.length;
153 }
154}
155
156//adjust the colors in the string so they're visible on the background, adjusting brightness in proportion to the original background
157- (void)adjustColorsToShowOnBackgroundRelativeToOriginalBackground:(NSColor *)backgroundColor
158{
159 int index = 0;
160 int stringLength = [self length];
161 float backgroundBrightness=0.0f, backgroundSum=0.0f;
162 NSColor *backColor=nil0;
163 //--get the brightness of our background--
164 if (backgroundColor) {
165 backColor = [backgroundColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
166 backgroundBrightness = [backColor brightnessComponent];
Value stored to 'backgroundSum' is never read
167 backgroundSum = [backColor redComponent] + [backColor greenComponent] + [backColor blueComponent];
168 }
169
170 //we need to scan each colored "chunk" of the message - and check to make sure it is a "visible" color
171 while (index < stringLength) {
172 NSColor *fontColor;
173 NSColor *fontBackColor;
174
175 NSRange effectiveRange, backgroundRange;
176 float brightness, newBrightness;
177 float deltaBrightness, deltaSum;
178 BOOL colorChanged = NO( BOOL ) 0, backgroundIsDark, fontBackIsDark;
179
180 //--get the font color--
181 fontColor = [self attribute:NSForegroundColorAttributeName atIndex:index effectiveRange:&effectiveRange];
182 //--get the background color in this range
183 fontBackColor = [self attribute:NSBackgroundColorAttributeName atIndex:index effectiveRange:&backgroundRange];
184 if (!fontBackColor) {
185 //Background coloring
186 fontBackColor = [self attribute:AIBodyColorAttributeName@ "AIBodyColor" atIndex:index effectiveRange:&backgroundRange];
187 if (!fontBackColor) {
188 fontBackColor = [NSColor whiteColor];
189 fontBackColor = [fontBackColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
190 }
191 }
192
193 //--use the shorter of these two ranges
194 if (backgroundRange.length < effectiveRange.length)
195 effectiveRange.length = backgroundRange.length;
196
197 if (!fontColor) fontColor = [NSColor blackColor];
198 fontColor = [fontColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
199
200 brightness = [fontColor brightnessComponent];
201
202 if (!backgroundColor) {
203 backColor = fontBackColor;
204 backgroundBrightness = [backColor brightnessComponent];
205 backgroundSum = [backColor redComponent] + [backColor greenComponent] + [backColor blueComponent];
206 } else {
207 deltaBrightness = (brightness - [fontBackColor brightnessComponent]);
208 backgroundIsDark = [backgroundColor colorIsDark];
209 fontBackIsDark = [fontBackColor colorIsDark];
210 if (!backgroundIsDark && fontBackIsDark) {
211 newBrightness = brightness - (deltaBrightness)/2;
212 if (newBrightness <= 0)
213 newBrightness = .2;
214 colorChanged = YES( BOOL ) 1;
215 }
216 else if (backgroundIsDark && !fontBackIsDark) {
217 newBrightness = brightness + (deltaBrightness)/2;
218 if (newBrightness >= 1)
219 newBrightness = .8;
220 colorChanged = YES( BOOL ) 1;
221 }
222
223 if (colorChanged) {
224 fontColor = [NSColor colorWithCalibratedHue:[fontColor hueComponent] saturation:[fontColor saturationComponent] brightness:newBrightness alpha:[fontColor alphaComponent]];
225 fontColor = [fontColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
226 }
227 }
228
229 //--check brightness--
230 brightness = [fontColor brightnessComponent];
231 deltaBrightness = backgroundBrightness - brightness;
232 if (deltaBrightness >= 0 && deltaBrightness <= 0.4) { //too close
233 fontColor = [fontColor adjustHue:0.0 saturation:0.0 brightness:-.4]; //change the color
234 colorChanged = YES( BOOL ) 1;
235
236 } else if (deltaBrightness >= -0.4 && deltaBrightness <0) { //too close
237 //change the color
238
239 fontColor = [fontColor adjustHue:0.0 saturation:0.0 brightness:.4];
240
241 colorChanged = YES( BOOL ) 1;
242 }
243
244 //--check luminance--
245 float hue,saturation;
246 float fontLuminance,backLuminance;
247
248 [fontColor getHue:&hue saturation:&saturation brightness:&fontLuminance alpha:NULL( ( void * ) 0 )];
249 [backColor getHue:&hue saturation:&saturation brightness:&backLuminance alpha:NULL( ( void * ) 0 )];
250
251 deltaSum = backLuminance - fontLuminance;
252
253 if (deltaSum >= -0.3 && deltaSum <= 0.3) { //still too similar
254 if (backgroundBrightness <= 0.5) {
255 fontColor = [[NSColor whiteColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
256 } else {
257 fontColor = [[NSColor blackColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
258 }
259
260 colorChanged = YES( BOOL ) 1;
261 }
262
263 if (colorChanged) {
264 [self addAttribute:NSForegroundColorAttributeName value:fontColor range:effectiveRange];
265 }
266
267 index = effectiveRange.location + effectiveRange.length;
268 }
269}
270
271- (void)addFormattingForLinks
272{
273 NSRange searchRange;
274 unsigned length = [self length];
275
276 searchRange = NSMakeRange(0,0);
277 while (searchRange.location < length) {
278 NSDictionary *attributes = [self attributesAtIndex:searchRange.location effectiveRange:&searchRange];
279 if ([attributes objectForKey:NSLinkAttributeName] != nil0) {
280 [self addAttribute:NSForegroundColorAttributeName value:[NSColor blueColor] range:searchRange];
281 [self addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithBool:YES( BOOL ) 1] range:searchRange];
282 }
283 searchRange.location += searchRange.length;
284 }
285}
286
287- (void)convertAttachmentsToStringsUsingPlaceholder:(NSString *)placeholder
288{
289 if ([self length] && [self containsAttachments]) {
290 int currentLocation = 0;
291 NSRange attachmentRange;
292 NSString *attachmentCharacterString = [NSString stringWithFormat:@"%C",NSAttachmentCharacter];
293
294 //find attachment
295 attachmentRange = [[self string] rangeOfString:attachmentCharacterString
296 options:0
297 range:NSMakeRange(currentLocation,
298 [self length] - currentLocation)];
299
300 while (attachmentRange.length != 0) { //if we found an attachment
301 NSTextAttachment *attachment = [self attribute:NSAttachmentAttributeName
302 atIndex:attachmentRange.location
303 effectiveRange:nil0];
304 NSString *replacement = nil0;
305 if ([attachment respondsToSelector:@selector(string)]) {
306 replacement = [attachment performSelector:@selector(string)];
307 }
308
309 if (!replacement) {
310 replacement = placeholder;
311 }
312
313 //remove the attachment, replacing it with the original text
314 [self removeAttribute:NSAttachmentAttributeName range:attachmentRange];
315 [self replaceCharactersInRange:attachmentRange withString:replacement];
316
317 attachmentRange.length = [replacement length];
318
319 currentLocation = attachmentRange.location + attachmentRange.length;
320
321 //find the next attachment
322 attachmentRange = [[self string] rangeOfString:attachmentCharacterString
323 options:0
324 range:NSMakeRange(currentLocation,
325 [self length] - currentLocation)];
326 }
327 }
328}
329
330
331@end
332
333@implementation NSAttributedString (AIAttributedStringAdditions)
334
335+ (NSSet *)CSSCapableAttributesSet
336{
337 return [NSSet setWithObjects:
338 NSFontAttributeName,
339 AIFontFamilyAttributeName,
340 AIFontSizeAttributeName,
341 AIFontWeightAttributeName,
342 AIFontStyleAttributeName,
343 NSForegroundColorAttributeName,
344 NSBackgroundColorAttributeName,
345 NSShadowAttributeName,
346 NSCursorAttributeName,
347 NSUnderlineStyleAttributeName,
348 NSStrikethroughStyleAttributeName,
349 NSSuperscriptAttributeName,
350 nil0];
351}
352+ (NSString *)CSSStringForTextAttributes:(NSDictionary *)attrs
353{
354 static NSDictionary *attributeNamesToCSSPropertyNames = nil0;
355 if (!attributeNamesToCSSPropertyNames) {
356 attributeNamesToCSSPropertyNames = [[NSDictionary alloc] initWithObjectsAndKeys:
357 @"font", NSFontAttributeName,
358 @"font-family", AIFontFamilyAttributeName,
359 @"font-size", AIFontSizeAttributeName,
360 @"font-weight", AIFontWeightAttributeName,
361 @"font-style", AIFontStyleAttributeName,
362 @"color", NSForegroundColorAttributeName,
363 @"background-color", NSBackgroundColorAttributeName,
364 @"text-shadow", NSShadowAttributeName,
365 @"cursor", NSCursorAttributeName,
366 nil0];
367 }
368
369 NSMutableArray *CSSProperties = [NSMutableArray arrayWithCapacity:[attrs count]];
370
371 BOOL hasLineThrough = NO( BOOL ) 0, hasUnderline = NO( BOOL ) 0;
372
373 NSEnumerator *keysEnum = [attrs keyEnumerator];
374 NSString *key;
375 while ((key = [keysEnum nextObject])) {
376 if ([key isEqualToString:NSUnderlineStyleAttributeName]) {
377 hasUnderline = YES( BOOL ) 1;
378 } else if ([key isEqualToString:NSStrikethroughStyleAttributeName]) {
379 hasLineThrough = YES( BOOL ) 1;
380 } else if ([key isEqualToString:NSSuperscriptAttributeName]) {
381 [CSSProperties addObject:@"vertical-align: baseline;"];
382 } else {
383 NSString *CSSPropertyName = [attributeNamesToCSSPropertyNames objectForKey:key];
384 id obj = [attrs objectForKey:key];
385 if (CSSPropertyName) {
386 if ([obj respondsToSelector:@selector(CSSRepresentation)]) {
387 obj = [obj CSSRepresentation];
388 } else if ([obj respondsToSelector:@selector(stringValue)]) {
389 obj = [obj stringValue];
390 } else if ([obj respondsToSelector:@selector(absoluteString)]) {
391 obj = [obj absoluteString];
392 }
393
394 [CSSProperties addObject:[NSString stringWithFormat:@"%@: %@;", CSSPropertyName, obj]];
395 }
396 }
397 }
398
399 if (hasLineThrough && hasUnderline) {
400 [CSSProperties addObject:@"text-decoration: line-through underline;"];
401 } else if (hasLineThrough) {
402 [CSSProperties addObject:@"text-decoration: line-through;"];
403 } else if (hasUnderline) {
404 [CSSProperties addObject:@"text-decoration: underline;"];
405 }
406
407 [CSSProperties sortUsingSelector:@selector(compare:)];
408
409 return [CSSProperties componentsJoinedByString:@" "];
410}
411
412//Height of a string
413#define FONT_HEIGHT_STRING @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789()"
414+ (float)stringHeightForAttributes:(NSDictionary *)attributes
415{
416 NSAttributedString *string = [[[NSAttributedString alloc] initWithString:FONT_HEIGHT_STRING@ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789()"
417 attributes:attributes] autorelease];
418 return [string heightWithWidth:1e7];
419}
420
421+ (NSAttributedString *)stringWithString:(NSString *)inString
422{
423 return [[[NSAttributedString alloc] initWithString:inString] autorelease];
424}
425
426- (float)heightWithWidth:(float)width
427{
428 //Setup the layout manager and text container
429 NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self];
430 NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(width, 1e7)];
431 NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
432
433 //Configure
434 [textContainer setLineFragmentPadding:0.0];
435 [layoutManager addTextContainer:textContainer];
436 [textStorage addLayoutManager:layoutManager];
437
438 //Force the layout manager to layout its text
439 (void)[layoutManager glyphRangeForTextContainer:textContainer];
440
441 float height = [layoutManager usedRectForTextContainer:textContainer].size.height;
442
443 [textStorage release];
444 [textContainer release];
445 [layoutManager release];
446
447 return height;
448}
449
450- (NSData *)dataRepresentation
451{
452 return [NSArchiver archivedDataWithRootObject:self];
453}
454
455+ (NSAttributedString *)stringWithData:(NSData *)inData
456{
457 NSAttributedString *returnValue = nil0;
458
459 /* We use an exception handler here because NSUnarchiver can throw an NSInvalidArgumentException with a reason:
460 * -[NSPlaceholderDictionary initWithObjects_ex:forKeys:count:]: attempt to insert nil value
461 * if we feed it invalid data.
462 */
463 @try
464 {
465 if (inData && [inData length]) {
466 //If inData (which must bt non-nil) is not valid archived data, this returns nil.
467 NSUnarchiver *unarchiver = [[NSUnarchiver alloc] initForReadingWithData:inData];
468
469 if (unarchiver) {
470 /* NSUnarchiver's decodeObject returns an object which is retained by the unarchiver and released
471 * when the unarchiver is deallocated. We could rely upon autoreleasing the unarchiver, but it
472 * is cleaner to make the NSAttributedString autorelease itself.
473 */
474 returnValue = (NSAttributedString *)[[[unarchiver decodeObject] retain] autorelease];
475
476 } else {
477 /* For reading previously stored NSData objects - we used to store them as RTF data, but that
478 * method is both slower and buggier. Any modern storage will use NSUnarchiver, so leaving this
479 * here isn't a speed problem. We previously used AIHTMLDecoder to handle Jaguar old-data unarchiving...
480 * but that's in Adium.framework and the cross over most certainly isn't worth it.
481 */
482 returnValue = ([[[NSAttributedString alloc] initWithRTF:inData
483 documentAttributes:nil0] autorelease]);
484 }
485
486 [unarchiver release];
487 }
488 }
489 @catch(id exc) { }
490
491 return returnValue;
492}
493
494- (NSAttributedString *)attributedStringByConvertingAttachmentsToStrings
495{
496 if ([self length] && [self containsAttachments]) {
497 NSMutableAttributedString *newAttributedString = [[self mutableCopy] autorelease];
498 [newAttributedString convertAttachmentsToStringsUsingPlaceholder:AILocalizedString[ [ NSBundle bundleForClass : [ self class ] ] localizedStringForKey
: ( @ "<<Attachment>>" ) value : @ "" table : ( 0
) ]
(@"<<Attachment>>", nil)];
499
500 return newAttributedString;
501
502 } else {
503 return self;
504 }
505}
506
507/* Deprecated */
508- (NSAttributedString *)safeString
509{
510 NSLog(@"%@", @"**** You are using an out of date external Adium plugin [most likely the SQL Logger]. Please recompile and reinstall the plugin. This will crash in a future release. ****");
511 return [self attributedStringByConvertingAttachmentsToStrings];
512}
513
514- (NSAttributedString *)attributedStringByConvertingLinksToStrings
515{
516 NSMutableAttributedString *newAttributedString = nil0;
517 unsigned length = [self length];
518
519 if (length) {
520 NSRange searchRange = NSMakeRange(0,0);
521 NSAttributedString *currentAttributedString = self;
522
523 while (searchRange.location < length) {
524 NSURL *URL = [currentAttributedString attribute:NSLinkAttributeName
525 atIndex:searchRange.location
526 effectiveRange:&searchRange];
527
528 if (URL) {
529 if (!newAttributedString) {
530 newAttributedString = [[self mutableCopy] autorelease];
531 currentAttributedString = newAttributedString;
532 }
533
534 NSString *absoluteString = [URL absoluteString];
535 NSString *originalTitle = [[newAttributedString string] substringWithRange:searchRange];
536 NSString *replacementString;
537
538 if ([originalTitle caseInsensitiveCompare:absoluteString] == NSOrderedSame) {
539 replacementString = originalTitle;
540
541 } else {
542 replacementString = [NSString stringWithFormat:@"%@ (%@)", originalTitle, absoluteString];
543 }
544
545 [newAttributedString replaceCharactersInRange:searchRange
546 withString:replacementString];
547
548 //Modify our searchRange and cached length to reflect the string we just inserted.
549 searchRange.length = [replacementString length];
550 length = [newAttributedString length];
551
552 //Now remove the link attribute
553 [newAttributedString removeAttribute:NSLinkAttributeName range:searchRange];
554 }
555
556 searchRange.location += searchRange.length;
557 }
558 }
559
560 return (newAttributedString ? newAttributedString : [[self copy] autorelease]);
561}
562
563- (NSAttributedString *)stringByAddingFormattingForLinks
564{
565 NSMutableAttributedString *str = [self mutableCopy];
566 [str addFormattingForLinks];
567 return [str autorelease];
568}
569
570@end
571
572@implementation NSData (AIAttributedStringAdditions)
573
574- (NSAttributedString *)attributedString
575{
576 return [NSAttributedString stringWithData:self];
577}
578
579@end