webengine/osswebengine/WebKit/Misc/WebKitNSStringExtras.m
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import "WebKitNSStringExtras.h"
       
    30 
       
    31 #import <WebKit/WebNSObjectExtras.h>
       
    32 #import <WebKit/WebNSFileManagerExtras.h>
       
    33 
       
    34 #import <WebCore/WebCoreNSStringExtras.h>
       
    35 #import <WebCore/WebCoreTextRenderer.h>
       
    36 
       
    37 #import <unicode/uchar.h>
       
    38 
       
    39 @implementation NSString (WebKitExtras)
       
    40 
       
    41 static BOOL canUseFastRenderer(const UniChar *buffer, unsigned length)
       
    42 {
       
    43     unsigned i;
       
    44     for (i = 0; i < length; i++) {
       
    45         UCharDirection direction = u_charDirection(buffer[i]);
       
    46         if (direction == U_RIGHT_TO_LEFT || direction > U_OTHER_NEUTRAL)
       
    47             return NO;
       
    48     }
       
    49     return YES;
       
    50 }
       
    51 
       
    52 - (void)_web_drawAtPoint:(NSPoint)point font:(NSFont *)font textColor:(NSColor *)textColor;
       
    53 {
       
    54     // FIXME: Would be more efficient to change this to C++ and use Vector<UChar, 2048>.
       
    55     unsigned length = [self length];
       
    56     UniChar *buffer = malloc(sizeof(UniChar) * length);
       
    57 
       
    58     [self getCharacters:buffer];
       
    59     
       
    60     if (canUseFastRenderer(buffer, length)) {
       
    61         // The following is a half-assed attempt to match AppKit's rounding rules for drawAtPoint.
       
    62         // It's probably incorrect for high DPI.
       
    63         // If you change this, be sure to test all the text drawn this way in Safari, including
       
    64         // the status bar, bookmarks bar, tab bar, and activity window.
       
    65         point.y = ceilf(point.y);
       
    66         WebCoreDrawTextAtPoint(buffer, length, point, font, textColor);
       
    67     } else {
       
    68         // WebTextRenderer assumes drawing from baseline.
       
    69         if ([[NSView focusView] isFlipped])
       
    70             point.y -= [font ascender];
       
    71         else {
       
    72             point.y += [font descender];
       
    73         }
       
    74         [self drawAtPoint:point withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil]];
       
    75     }
       
    76 
       
    77     free(buffer);
       
    78 }
       
    79 
       
    80 - (void)_web_drawDoubledAtPoint:(NSPoint)textPoint
       
    81              withTopColor:(NSColor *)topColor
       
    82               bottomColor:(NSColor *)bottomColor
       
    83                      font:(NSFont *)font
       
    84 {
       
    85     // turn off font smoothing so translucent text draws correctly (Radar 3118455)
       
    86     [NSGraphicsContext saveGraphicsState];
       
    87     CGContextSetShouldSmoothFonts([[NSGraphicsContext currentContext] graphicsPort], false);
       
    88     [self _web_drawAtPoint:textPoint
       
    89                       font:font
       
    90                  textColor:bottomColor];
       
    91 
       
    92     textPoint.y += 1;
       
    93     [self _web_drawAtPoint:textPoint
       
    94                       font:font
       
    95                  textColor:topColor];
       
    96     [NSGraphicsContext restoreGraphicsState];
       
    97 }
       
    98 
       
    99 - (float)_web_widthWithFont:(NSFont *)font
       
   100 {
       
   101     unsigned length = [self length];
       
   102     float width;
       
   103     UniChar *buffer = (UniChar *)malloc(sizeof(UniChar) * length);
       
   104 
       
   105     [self getCharacters:buffer];
       
   106 
       
   107     if (canUseFastRenderer(buffer, length))
       
   108         width = WebCoreTextFloatWidth(buffer, length, font);
       
   109     else
       
   110         width = [self sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]].width;
       
   111     
       
   112     free(buffer);
       
   113     
       
   114     return width;
       
   115 }
       
   116 
       
   117 - (NSString *)_web_stringByAbbreviatingWithTildeInPath
       
   118 {
       
   119     NSString *resolvedHomeDirectory = [NSHomeDirectory() stringByResolvingSymlinksInPath];
       
   120     NSString *path;
       
   121     
       
   122     if ([self hasPrefix:resolvedHomeDirectory]) {
       
   123         NSString *relativePath = [self substringFromIndex:[resolvedHomeDirectory length]];
       
   124         path = [NSHomeDirectory() stringByAppendingPathComponent:relativePath];
       
   125     } else {
       
   126         path = self;
       
   127     }
       
   128         
       
   129     return [path stringByAbbreviatingWithTildeInPath];
       
   130 }
       
   131 
       
   132 - (NSString *)_web_stringByStrippingReturnCharacters
       
   133 {
       
   134     NSMutableString *newString = [[self mutableCopy] autorelease];
       
   135     [newString replaceOccurrencesOfString:@"\r" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
       
   136     [newString replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
       
   137     return newString;
       
   138 }
       
   139 
       
   140 + (NSStringEncoding)_web_encodingForResource:(Handle)resource
       
   141 {
       
   142     short resRef = HomeResFile(resource);
       
   143     if (ResError() != noErr) {
       
   144         return NSMacOSRomanStringEncoding;
       
   145     }
       
   146     
       
   147     // Get the FSRef for the current resource file
       
   148     FSRef fref;
       
   149     OSStatus error = FSGetForkCBInfo(resRef, 0, NULL, NULL, NULL, &fref, NULL);
       
   150     if (error != noErr) {
       
   151         return NSMacOSRomanStringEncoding;
       
   152     }
       
   153     
       
   154     CFURLRef URL = CFURLCreateFromFSRef(NULL, &fref);
       
   155     if (URL == NULL) {
       
   156         return NSMacOSRomanStringEncoding;
       
   157     }
       
   158     
       
   159     NSString *path = [(NSURL *)URL path];
       
   160     CFRelease(URL);
       
   161     
       
   162     // Get the lproj directory name
       
   163     path = [path stringByDeletingLastPathComponent];
       
   164     if (![[path pathExtension] _webkit_isCaseInsensitiveEqualToString:@"lproj"]) {
       
   165         return NSMacOSRomanStringEncoding;
       
   166     }
       
   167     
       
   168     NSString *directoryName = [[path stringByDeletingPathExtension] lastPathComponent];
       
   169     CFStringRef locale = CFLocaleCreateCanonicalLocaleIdentifierFromString(NULL, (CFStringRef)directoryName);
       
   170     if (locale == NULL) {
       
   171         return NSMacOSRomanStringEncoding;
       
   172     }
       
   173             
       
   174     LangCode lang;
       
   175     RegionCode region;
       
   176     error = LocaleStringToLangAndRegionCodes([(NSString *)locale UTF8String], &lang, &region);
       
   177     CFRelease(locale);
       
   178     if (error != noErr) {
       
   179         return NSMacOSRomanStringEncoding;
       
   180     }
       
   181     
       
   182     TextEncoding encoding;
       
   183     error = UpgradeScriptInfoToTextEncoding(kTextScriptDontCare, lang, region, NULL, &encoding);
       
   184     if (error != noErr) {
       
   185         return NSMacOSRomanStringEncoding;
       
   186     }
       
   187     
       
   188     return CFStringConvertEncodingToNSStringEncoding(encoding);
       
   189 }
       
   190 
       
   191 - (BOOL)_webkit_isCaseInsensitiveEqualToString:(NSString *)string
       
   192 {
       
   193   return [self compare:string options:(NSCaseInsensitiveSearch|NSLiteralSearch)] == NSOrderedSame;
       
   194 }
       
   195 
       
   196 -(BOOL)_webkit_hasCaseInsensitivePrefix:(NSString *)prefix
       
   197 {
       
   198     return [self rangeOfString:prefix options:(NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound;
       
   199 }
       
   200 
       
   201 -(BOOL)_webkit_hasCaseInsensitiveSuffix:(NSString *)suffix
       
   202 {
       
   203     return hasCaseInsensitiveSuffix(self, suffix);
       
   204 }
       
   205 
       
   206 -(BOOL)_webkit_hasCaseInsensitiveSubstring:(NSString *)substring
       
   207 {
       
   208     return hasCaseInsensitiveSubstring(self, substring);
       
   209 }
       
   210 
       
   211 -(NSString *)_webkit_filenameByFixingIllegalCharacters
       
   212 {
       
   213     return filenameByFixingIllegalCharacters(self);
       
   214 }
       
   215 
       
   216 -(NSString *)_webkit_stringByTrimmingWhitespace
       
   217 {
       
   218     NSMutableString *trimmed = [[self mutableCopy] autorelease];
       
   219     CFStringTrimWhitespace((CFMutableStringRef)trimmed);
       
   220     return trimmed;
       
   221 }
       
   222 
       
   223 - (NSString *)_webkit_stringByCollapsingNonPrintingCharacters
       
   224 {
       
   225     NSMutableString *result = [NSMutableString string];
       
   226     static NSCharacterSet *charactersToTurnIntoSpaces = nil;
       
   227     static NSCharacterSet *charactersToNotTurnIntoSpaces = nil;
       
   228     
       
   229     if (charactersToTurnIntoSpaces == nil) {
       
   230         NSMutableCharacterSet *set = [[NSMutableCharacterSet alloc] init];
       
   231         [set addCharactersInRange:NSMakeRange(0x00, 0x21)];
       
   232         [set addCharactersInRange:NSMakeRange(0x7F, 0x01)];
       
   233         charactersToTurnIntoSpaces = [set copy];
       
   234         [set release];
       
   235         charactersToNotTurnIntoSpaces = [[charactersToTurnIntoSpaces invertedSet] retain];
       
   236     }
       
   237     
       
   238     unsigned length = [self length];
       
   239     unsigned position = 0;
       
   240     while (position != length) {
       
   241         NSRange nonSpace = [self rangeOfCharacterFromSet:charactersToNotTurnIntoSpaces
       
   242             options:0 range:NSMakeRange(position, length - position)];
       
   243         if (nonSpace.location == NSNotFound) {
       
   244             break;
       
   245         }
       
   246 
       
   247         NSRange space = [self rangeOfCharacterFromSet:charactersToTurnIntoSpaces
       
   248             options:0 range:NSMakeRange(nonSpace.location, length - nonSpace.location)];
       
   249         if (space.location == NSNotFound) {
       
   250             space.location = length;
       
   251         }
       
   252 
       
   253         if (space.location > nonSpace.location) {
       
   254             if (position != 0) {
       
   255                 [result appendString:@" "];
       
   256             }
       
   257             [result appendString:[self substringWithRange:
       
   258                 NSMakeRange(nonSpace.location, space.location - nonSpace.location)]];
       
   259         }
       
   260 
       
   261         position = space.location;
       
   262     }
       
   263     
       
   264     return result;
       
   265 }
       
   266 
       
   267 - (NSString *)_webkit_stringByCollapsingWhitespaceCharacters
       
   268 {
       
   269     NSMutableString *result = [[NSMutableString alloc] initWithCapacity:[self length]];
       
   270     NSCharacterSet *spaces = [NSCharacterSet whitespaceAndNewlineCharacterSet];
       
   271     static NSCharacterSet *notSpaces = nil;
       
   272 
       
   273     if (notSpaces == nil)
       
   274         notSpaces = [[spaces invertedSet] retain];
       
   275 
       
   276     unsigned length = [self length];
       
   277     unsigned position = 0;
       
   278     while (position != length) {
       
   279         NSRange nonSpace = [self rangeOfCharacterFromSet:notSpaces options:0 range:NSMakeRange(position, length - position)];
       
   280         if (nonSpace.location == NSNotFound)
       
   281             break;
       
   282 
       
   283         NSRange space = [self rangeOfCharacterFromSet:spaces options:0 range:NSMakeRange(nonSpace.location, length - nonSpace.location)];
       
   284         if (space.location == NSNotFound)
       
   285             space.location = length;
       
   286 
       
   287         if (space.location > nonSpace.location) {
       
   288             if (position != 0)
       
   289                 [result appendString:@" "];
       
   290             [result appendString:[self substringWithRange:NSMakeRange(nonSpace.location, space.location - nonSpace.location)]];
       
   291         }
       
   292 
       
   293         position = space.location;
       
   294     }
       
   295 
       
   296     return [result autorelease];
       
   297 }
       
   298 
       
   299 -(NSString *)_webkit_fixedCarbonPOSIXPath
       
   300 {
       
   301     NSFileManager *fileManager = [NSFileManager defaultManager];
       
   302     if ([fileManager fileExistsAtPath:self]) {
       
   303         // Files exists, no need to fix.
       
   304         return self;
       
   305     }
       
   306 
       
   307     NSMutableArray *pathComponents = [[[self pathComponents] mutableCopy] autorelease];
       
   308     NSString *volumeName = [pathComponents objectAtIndex:1];
       
   309     if ([volumeName isEqualToString:@"Volumes"]) {
       
   310         // Path starts with "/Volumes", so the volume name is the next path component.
       
   311         volumeName = [pathComponents objectAtIndex:2];
       
   312         // Remove "Volumes" from the path because it may incorrectly be part of the path (3163647).
       
   313         // We'll add it back if we have to.
       
   314         [pathComponents removeObjectAtIndex:1];
       
   315     }
       
   316 
       
   317     if (!volumeName) {
       
   318         // Should only happen if self == "/", so this shouldn't happen because that always exists.
       
   319         return self;
       
   320     }
       
   321 
       
   322     if ([[fileManager _webkit_startupVolumeName] isEqualToString:volumeName]) {
       
   323         // Startup volume name is included in path, remove it.
       
   324         [pathComponents removeObjectAtIndex:1];
       
   325     } else if ([[fileManager directoryContentsAtPath:@"/Volumes"] containsObject:volumeName]) {
       
   326         // Path starts with other volume name, prepend "/Volumes".
       
   327         [pathComponents insertObject:@"Volumes" atIndex:1];
       
   328     } else {
       
   329         // It's valid.
       
   330         return self;
       
   331     }
       
   332 
       
   333     NSString *path = [NSString pathWithComponents:pathComponents];
       
   334 
       
   335     if (![fileManager fileExistsAtPath:path]) {
       
   336         // File at canonicalized path doesn't exist, return original.
       
   337         return self;
       
   338     }
       
   339 
       
   340     return path;
       
   341 }
       
   342 
       
   343 @end