18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1.  Redistributions of source code must retain the above copyright
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer.
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2.  Redistributions in binary form must reproduce the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     notice, this list of conditions and the following disclaimer in the
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     documentation and/or other materials provided with the distribution.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     its contributors may be used to endorse or promote products derived
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *     from this software without specific prior written permission.
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import "WebKitNSStringExtras.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#import <WebCore/Font.h>
320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#import <WebCore/GraphicsContext.h>
33ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch#import <WebCore/TextRun.h>
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <WebCore/WebCoreNSStringExtras.h>
350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#import <WebKit/WebNSFileManagerExtras.h>
360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#import <WebKit/WebNSObjectExtras.h>
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <unicode/uchar.h>
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#import <sys/param.h>
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochNSString *WebKitLocalCacheDefaultsKey = @"WebKitLocalCache";
410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic inline CGFloat webkit_CGCeiling(CGFloat value)
430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (sizeof(value) == sizeof(float))
450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return ceilf(value);
460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return ceil(value);
470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochusing namespace WebCore;
500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project@implementation NSString (WebKitExtras)
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic BOOL canUseFastRenderer(const UniChar *buffer, unsigned length)
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned i;
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = 0; i < length; i++) {
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UCharDirection direction = u_charDirection(buffer[i]);
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (direction == U_RIGHT_TO_LEFT || direction > U_OTHER_NEUTRAL)
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return NO;
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return YES;
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
64563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark- (void)_web_drawAtPoint:(NSPoint)point font:(NSFont *)font textColor:(NSColor *)textColor
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
66967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    [self _web_drawAtPoint:point font:font textColor:textColor allowingFontSmoothing:YES];
67967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
68967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
69967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch- (void)_web_drawAtPoint:(NSPoint)point font:(NSFont *)font textColor:(NSColor *)textColor allowingFontSmoothing:(BOOL)fontSmoothingIsAllowed
70967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned length = [self length];
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Vector<UniChar, 2048> buffer(length);
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    [self getCharacters:buffer.data()];
75967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (canUseFastRenderer(buffer.data(), length)) {
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The following is a half-assed attempt to match AppKit's rounding rules for drawAtPoint.
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // It's probably incorrect for high DPI.
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If you change this, be sure to test all the text drawn this way in Safari, including
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // the status bar, bookmarks bar, tab bar, and activity window.
810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        point.y = webkit_CGCeiling(point.y);
820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CGContextRef cgContext = static_cast<CGContextRef>([nsContext graphicsPort]);
850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        GraphicsContext graphicsContext(cgContext);
860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // Safari doesn't flip the NSGraphicsContext before calling WebKit, yet WebCore requires a flipped graphics context.
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        BOOL flipped = [nsContext isFlipped];
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (!flipped)
900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            CGContextScaleCTM(cgContext, 1, -1);
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
926b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        Font webCoreFont(FontPlatformData(font, [font pointSize]), ![nsContext isDrawingToScreen], fontSmoothingIsAllowed ? AutoSmoothing : Antialiased);
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        TextRun run(buffer.data(), length);
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CGFloat red;
960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CGFloat green;
970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CGFloat blue;
980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        CGFloat alpha;
990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        [[textColor colorUsingColorSpaceName:NSDeviceRGBColorSpace] getRed:&red green:&green blue:&blue alpha:&alpha];
100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        graphicsContext.setFillColor(makeRGBA(red * 255, green * 255, blue * 255, alpha * 255), ColorSpaceDeviceRGB);
1010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        webCoreFont.drawText(&graphicsContext, run, FloatPoint(point.x, (flipped ? point.y : (-1 * point.y))));
1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (!flipped)
1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            CGContextScaleCTM(cgContext, 1, -1);
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // The given point is on the baseline.
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if ([[NSView focusView] isFlipped])
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            point.y -= [font ascender];
1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            point.y += [font descender];
1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [self drawAtPoint:point withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil]];
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (void)_web_drawDoubledAtPoint:(NSPoint)textPoint
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project             withTopColor:(NSColor *)topColor
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project              bottomColor:(NSColor *)bottomColor
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                     font:(NSFont *)font
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // turn off font smoothing so translucent text draws correctly (Radar 3118455)
123967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    [self _web_drawAtPoint:textPoint font:font textColor:bottomColor allowingFontSmoothing:NO];
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    textPoint.y += 1;
126967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    [self _web_drawAtPoint:textPoint font:font textColor:topColor allowingFontSmoothing:NO];
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (float)_web_widthWithFont:(NSFont *)font
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned length = [self length];
1320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Vector<UniChar, 2048> buffer(length);
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    [self getCharacters:buffer.data()];
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (canUseFastRenderer(buffer.data(), length)) {
1376b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        Font webCoreFont(FontPlatformData(font, [font pointSize]), ![[NSGraphicsContext currentContext] isDrawingToScreen]);
1380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        TextRun run(buffer.data(), length);
13981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return webCoreFont.width(run);
1400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
1410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return [self sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]].width;
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_stringByAbbreviatingWithTildeInPath
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *resolvedHomeDirectory = [NSHomeDirectory() stringByResolvingSymlinksInPath];
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *path;
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([self hasPrefix:resolvedHomeDirectory]) {
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSString *relativePath = [self substringFromIndex:[resolvedHomeDirectory length]];
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        path = [NSHomeDirectory() stringByAppendingPathComponent:relativePath];
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        path = self;
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [path stringByAbbreviatingWithTildeInPath];
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_web_stringByStrippingReturnCharacters
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableString *newString = [[self mutableCopy] autorelease];
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [newString replaceOccurrencesOfString:@"\r" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    [newString replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return newString;
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSStringEncoding)_web_encodingForResource:(Handle)resource
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
170635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return CFStringConvertEncodingToNSStringEncoding(stringEncodingForResource(resource));
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (BOOL)_webkit_isCaseInsensitiveEqualToString:(NSString *)string
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
175635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return stringIsCaseInsensitiveEqualToString(self, string);
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(BOOL)_webkit_hasCaseInsensitivePrefix:(NSString *)prefix
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [self rangeOfString:prefix options:(NSCaseInsensitiveSearch | NSAnchoredSearch)].location != NSNotFound;
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(BOOL)_webkit_hasCaseInsensitiveSuffix:(NSString *)suffix
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hasCaseInsensitiveSuffix(self, suffix);
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(BOOL)_webkit_hasCaseInsensitiveSubstring:(NSString *)substring
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return hasCaseInsensitiveSubstring(self, substring);
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSString *)_webkit_filenameByFixingIllegalCharacters
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return filenameByFixingIllegalCharacters(self);
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSString *)_webkit_stringByTrimmingWhitespace
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableString *trimmed = [[self mutableCopy] autorelease];
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CFStringTrimWhitespace((CFMutableStringRef)trimmed);
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return trimmed;
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_stringByCollapsingNonPrintingCharacters
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableString *result = [NSMutableString string];
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *charactersToTurnIntoSpaces = nil;
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *charactersToNotTurnIntoSpaces = nil;
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (charactersToTurnIntoSpaces == nil) {
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSMutableCharacterSet *set = [[NSMutableCharacterSet alloc] init];
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [set addCharactersInRange:NSMakeRange(0x00, 0x21)];
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [set addCharactersInRange:NSMakeRange(0x7F, 0x01)];
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        charactersToTurnIntoSpaces = [set copy];
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [set release];
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        charactersToNotTurnIntoSpaces = [[charactersToTurnIntoSpaces invertedSet] retain];
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned length = [self length];
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned position = 0;
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (position != length) {
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange nonSpace = [self rangeOfCharacterFromSet:charactersToNotTurnIntoSpaces
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            options:0 range:NSMakeRange(position, length - position)];
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (nonSpace.location == NSNotFound) {
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange space = [self rangeOfCharacterFromSet:charactersToTurnIntoSpaces
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            options:0 range:NSMakeRange(nonSpace.location, length - nonSpace.location)];
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (space.location == NSNotFound) {
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            space.location = length;
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (space.location > nonSpace.location) {
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (position != 0) {
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                [result appendString:@" "];
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [result appendString:[self substringWithRange:
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                NSMakeRange(nonSpace.location, space.location - nonSpace.location)]];
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        position = space.location;
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return result;
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project- (NSString *)_webkit_stringByCollapsingWhitespaceCharacters
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableString *result = [[NSMutableString alloc] initWithCapacity:[self length]];
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSCharacterSet *spaces = [NSCharacterSet whitespaceAndNewlineCharacterSet];
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    static NSCharacterSet *notSpaces = nil;
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (notSpaces == nil)
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        notSpaces = [[spaces invertedSet] retain];
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned length = [self length];
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned position = 0;
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (position != length) {
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange nonSpace = [self rangeOfCharacterFromSet:notSpaces options:0 range:NSMakeRange(position, length - position)];
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (nonSpace.location == NSNotFound)
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        NSRange space = [self rangeOfCharacterFromSet:spaces options:0 range:NSMakeRange(nonSpace.location, length - nonSpace.location)];
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (space.location == NSNotFound)
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            space.location = length;
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (space.location > nonSpace.location) {
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (position != 0)
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                [result appendString:@" "];
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            [result appendString:[self substringWithRange:NSMakeRange(nonSpace.location, space.location - nonSpace.location)]];
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        position = space.location;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [result autorelease];
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project-(NSString *)_webkit_fixedCarbonPOSIXPath
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSFileManager *fileManager = [NSFileManager defaultManager];
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([fileManager fileExistsAtPath:self]) {
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Files exists, no need to fix.
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSMutableArray *pathComponents = [[[self pathComponents] mutableCopy] autorelease];
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *volumeName = [pathComponents objectAtIndex:1];
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([volumeName isEqualToString:@"Volumes"]) {
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Path starts with "/Volumes", so the volume name is the next path component.
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        volumeName = [pathComponents objectAtIndex:2];
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remove "Volumes" from the path because it may incorrectly be part of the path (3163647).
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // We'll add it back if we have to.
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [pathComponents removeObjectAtIndex:1];
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!volumeName) {
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Should only happen if self == "/", so this shouldn't happen because that always exists.
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ([[fileManager _webkit_startupVolumeName] isEqualToString:volumeName]) {
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Startup volume name is included in path, remove it.
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [pathComponents removeObjectAtIndex:1];
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if ([[fileManager contentsOfDirectoryAtPath:@"/Volumes" error:NULL] containsObject:volumeName]) {
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Path starts with other volume name, prepend "/Volumes".
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        [pathComponents insertObject:@"Volumes" atIndex:1];
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // It's valid.
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    NSString *path = [NSString pathWithComponents:pathComponents];
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (![fileManager fileExistsAtPath:path])
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // File at canonicalized path doesn't exist, return original.
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return self;
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return path;
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project+ (NSString *)_webkit_localCacheDirectoryWithBundleIdentifier:(NSString*)bundleIdentifier
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
3260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    NSString *cacheDir = [defaults objectForKey:WebKitLocalCacheDefaultsKey];
3270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!cacheDir || ![cacheDir isKindOfClass:[NSString class]]) {
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#ifdef BUILDING_ON_TIGER
3300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        cacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#else
3320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        char cacheDirectory[MAXPATHLEN];
3330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        size_t cacheDirectoryLen = confstr(_CS_DARWIN_USER_CACHE_DIR, cacheDirectory, MAXPATHLEN);
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (cacheDirectoryLen)
3360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            cacheDir = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:cacheDirectory length:cacheDirectoryLen - 1];
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
3380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return [cacheDir stringByAppendingPathComponent:bundleIdentifier];
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project@end
344