3 Copyright 2002, Apple, Inc. All rights reserved.
6 #import "WebKitNSStringExtras.h"
8 #import <WebKit/WebNSObjectExtras.h>
9 #import <WebKit/WebTextRenderer.h>
10 #import <WebKit/WebTextRendererFactory.h>
11 #import <Foundation/NSFileManager_NSURLExtras.h>
13 #import <unicode/uchar.h>
15 @implementation NSString (WebKitExtras)
17 static BOOL canUseFastRenderer(const UniChar *buffer, unsigned length)
20 for (i = 0; i < length; i++) {
21 UCharDirection direction = u_charDirection(buffer[i]);
22 if (direction == U_RIGHT_TO_LEFT || direction > U_WHITE_SPACE_NEUTRAL) {
29 - (void)_web_drawAtPoint:(NSPoint)point font:(NSFont *)font textColor:(NSColor *)textColor;
31 unsigned length = [self length];
32 UniChar *buffer = (UniChar *)malloc(sizeof(UniChar) * length);
34 [self getCharacters:buffer];
36 if (canUseFastRenderer(buffer, length)){
37 WebTextRenderer *renderer = [[WebTextRendererFactory sharedFactory] rendererWithFont:font usingPrinterFont:NO];
40 WebCoreInitializeTextRun (&run, buffer, length, 0, length);
41 WebCoreTextStyle style;
42 WebCoreInitializeEmptyTextStyle(&style);
43 style.applyRunRounding = NO;
44 style.applyWordRounding = NO;
45 style.textColor = textColor;
46 WebCoreTextGeometry geometry;
47 WebCoreInitializeEmptyTextGeometry(&geometry);
48 geometry.point = point;
49 [renderer drawRun:&run style:&style geometry:&geometry];
52 // WebTextRenderer assumes drawing from baseline.
53 if ([[NSView focusView] isFlipped])
54 point.y -= [font ascender];
56 point.y += [font descender];
58 [self drawAtPoint:point withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil]];
64 - (void)_web_drawDoubledAtPoint:(NSPoint)textPoint
65 withTopColor:(NSColor *)topColor
66 bottomColor:(NSColor *)bottomColor
69 // turn off font smoothing so translucent text draws correctly (Radar 3118455)
70 [NSGraphicsContext saveGraphicsState];
71 CGContextSetShouldSmoothFonts([[NSGraphicsContext currentContext] graphicsPort], false);
72 [self _web_drawAtPoint:textPoint
74 textColor:bottomColor];
77 [self _web_drawAtPoint:textPoint
80 [NSGraphicsContext restoreGraphicsState];
83 - (float)_web_widthWithFont:(NSFont *)font
85 unsigned length = [self length];
87 UniChar *buffer = (UniChar *)malloc(sizeof(UniChar) * length);
89 [self getCharacters:buffer];
91 if (canUseFastRenderer(buffer, length)){
92 WebTextRenderer *renderer = [[WebTextRendererFactory sharedFactory] rendererWithFont:font usingPrinterFont:NO];
95 WebCoreInitializeTextRun (&run, buffer, length, 0, length);
96 WebCoreTextStyle style;
97 WebCoreInitializeEmptyTextStyle(&style);
98 style.applyRunRounding = NO;
99 style.applyWordRounding = NO;
100 width = [renderer floatWidthForRun:&run style:&style widths: 0];
103 width = [self sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]].width;
111 - (NSString *)_web_stringByAbbreviatingWithTildeInPath
113 NSString *resolvedHomeDirectory = [NSHomeDirectory() stringByResolvingSymlinksInPath];
116 if ([self hasPrefix:resolvedHomeDirectory]) {
117 NSString *relativePath = [self substringFromIndex:[resolvedHomeDirectory length]];
118 path = [NSHomeDirectory() stringByAppendingPathComponent:relativePath];
123 return [path stringByAbbreviatingWithTildeInPath];
126 - (NSString *)_web_stringByStrippingReturnCharacters
128 NSMutableString *newString = [[self mutableCopy] autorelease];
129 [newString replaceOccurrencesOfString:@"\r" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
130 [newString replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
134 + (NSStringEncoding)_web_encodingForResource:(Handle)resource
136 short resRef = HomeResFile(resource);
137 if (ResError() != noErr) {
138 return NSMacOSRomanStringEncoding;
141 // Get the FSRef for the current resource file
143 OSStatus error = FSGetForkCBInfo(resRef, 0, NULL, NULL, NULL, &fref, NULL);
144 if (error != noErr) {
145 return NSMacOSRomanStringEncoding;
148 CFURLRef URL = CFURLCreateFromFSRef(NULL, &fref);
150 return NSMacOSRomanStringEncoding;
153 NSString *path = [(NSURL *)URL path];
156 // Get the lproj directory name
157 path = [path stringByDeletingLastPathComponent];
158 if (![[path pathExtension] _webkit_isCaseInsensitiveEqualToString:@"lproj"]) {
159 return NSMacOSRomanStringEncoding;
162 NSString *directoryName = [[path stringByDeletingPathExtension] lastPathComponent];
163 CFStringRef locale = CFLocaleCreateCanonicalLocaleIdentifierFromString(NULL, (CFStringRef)directoryName);
164 if (locale == NULL) {
165 return NSMacOSRomanStringEncoding;
170 error = LocaleStringToLangAndRegionCodes([(NSString *)locale UTF8String], &lang, ®ion);
172 if (error != noErr) {
173 return NSMacOSRomanStringEncoding;
176 TextEncoding encoding;
177 error = UpgradeScriptInfoToTextEncoding(kTextScriptDontCare, lang, region, NULL, &encoding);
178 if (error != noErr) {
179 return NSMacOSRomanStringEncoding;
182 return CFStringConvertEncodingToNSStringEncoding(encoding);
185 - (BOOL)_webkit_isCaseInsensitiveEqualToString:(NSString *)string
187 return [self compare:string options:(NSCaseInsensitiveSearch|NSLiteralSearch)] == NSOrderedSame;
190 -(BOOL)_webkit_hasCaseInsensitivePrefix:(NSString *)prefix
192 return [self rangeOfString:prefix options:(NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound;
195 -(BOOL)_webkit_hasCaseInsensitiveSuffix:(NSString *)suffix
197 return [self rangeOfString:suffix options:(NSCaseInsensitiveSearch | NSBackwardsSearch | NSAnchoredSearch)].location != NSNotFound;
200 -(BOOL)_webkit_hasCaseInsensitiveSubstring:(NSString *)substring
202 return [self rangeOfString:substring options:NSCaseInsensitiveSearch].location != NSNotFound;
205 -(NSString *)_webkit_filenameByFixingIllegalCharacters
207 NSMutableString *filename = [[self mutableCopy] autorelease];
209 // Strip null characters.
210 unichar nullChar = 0;
211 [filename replaceOccurrencesOfString:[NSString stringWithCharacters:&nullChar length:0] withString:@"" options:0 range:NSMakeRange(0, [filename length])];
213 // Replace "/" with "-".
214 [filename replaceOccurrencesOfString:@"/" withString:@"-" options:0 range:NSMakeRange(0, [filename length])];
216 // Replace ":" with "-".
217 [filename replaceOccurrencesOfString:@":" withString:@"-" options:0 range:NSMakeRange(0, [filename length])];
219 // Strip leading dots.
220 while ([filename hasPrefix:@"."]) {
221 [filename deleteCharactersInRange:NSMakeRange(0,1)];
227 -(NSString *)_webkit_stringByTrimmingWhitespace
229 NSMutableString *trimmed = [[self mutableCopy] autorelease];
230 CFStringTrimWhitespace((CFMutableStringRef)trimmed);
234 - (NSString *)_webkit_stringByCollapsingNonPrintingCharacters
236 NSMutableString *result = [NSMutableString string];
237 static NSCharacterSet *charactersToTurnIntoSpaces = nil;
238 static NSCharacterSet *charactersToNotTurnIntoSpaces = nil;
240 if (charactersToTurnIntoSpaces == nil) {
241 NSMutableCharacterSet *set = [[NSMutableCharacterSet alloc] init];
242 [set addCharactersInRange:NSMakeRange(0x00, 0x21)];
243 [set addCharactersInRange:NSMakeRange(0x7F, 0x01)];
244 charactersToTurnIntoSpaces = [set copy];
246 charactersToNotTurnIntoSpaces = [[charactersToTurnIntoSpaces invertedSet] retain];
249 unsigned length = [self length];
250 unsigned position = 0;
251 while (position != length) {
252 NSRange nonSpace = [self rangeOfCharacterFromSet:charactersToNotTurnIntoSpaces
253 options:0 range:NSMakeRange(position, length - position)];
254 if (nonSpace.location == NSNotFound) {
258 NSRange space = [self rangeOfCharacterFromSet:charactersToTurnIntoSpaces
259 options:0 range:NSMakeRange(nonSpace.location, length - nonSpace.location)];
260 if (space.location == NSNotFound) {
261 space.location = length;
264 if (space.location > nonSpace.location) {
266 [result appendString:@" "];
268 [result appendString:[self substringWithRange:
269 NSMakeRange(nonSpace.location, space.location - nonSpace.location)]];
272 position = space.location;
278 -(NSString *)_webkit_fixedCarbonPOSIXPath
280 NSFileManager *fileManager = [NSFileManager defaultManager];
281 if ([fileManager fileExistsAtPath:self]) {
282 // Files exists, no need to fix.
286 NSMutableArray *pathComponents = [[[self pathComponents] mutableCopy] autorelease];
287 NSString *volumeName = [pathComponents objectAtIndex:1];
288 if ([volumeName isEqualToString:@"Volumes"]) {
289 // Path starts with "/Volumes", so the volume name is the next path component.
290 volumeName = [pathComponents objectAtIndex:2];
291 // Remove "Volumes" from the path because it may incorrectly be part of the path (3163647).
292 // We'll add it back if we have to.
293 [pathComponents removeObjectAtIndex:1];
297 // Should only happen if self == "/", so this shouldn't happen because that always exists.
301 if ([[fileManager _web_startupVolumeName] isEqualToString:volumeName]) {
302 // Startup volume name is included in path, remove it.
303 [pathComponents removeObjectAtIndex:1];
304 } else if ([[fileManager directoryContentsAtPath:@"/Volumes"] containsObject:volumeName]) {
305 // Path starts with other volume name, prepend "/Volumes".
306 [pathComponents insertObject:@"Volumes" atIndex:1];
312 NSString *path = [NSString pathWithComponents:pathComponents];
314 if (![fileManager fileExistsAtPath:path]) {
315 // File at canonicalized path doesn't exist, return original.