WebNSAttributedStringExtras.mm   [plain text]


/*
 * Copyright (C) 2005, 2007, 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer. 
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution. 
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#import "WebNSAttributedStringExtras.h"

#import "DOMRangeInternal.h"
#import "WebDataSourcePrivate.h"
#import "WebFrame.h"
#import "WebFrameInternal.h"
#import "WebTypesInternal.h"
#import <WebCore/BlockExceptions.h>
#import <WebCore/ColorMac.h>
#import <WebCore/CSSHelper.h>
#import <WebCore/Document.h>
#import <WebCore/Element.h>
#import <WebCore/Frame.h>
#import <WebCore/FrameLoader.h>
#import <WebCore/HTMLNames.h>
#import <WebCore/Image.h>
#import <WebCore/InlineTextBox.h>
#import <WebCore/Range.h>
#import <WebCore/RenderImage.h>
#import <WebCore/RenderListItem.h>
#import <WebCore/RenderObject.h>
#import <WebCore/RenderStyle.h>
#import <WebCore/RenderText.h>
#import <WebCore/SimpleFontData.h>
#import <WebCore/Text.h>
#import <WebCore/TextIterator.h>

using namespace WebCore;
using namespace HTMLNames;

struct ListItemInfo {
    unsigned start;
    unsigned end;
};

static NSFileWrapper *fileWrapperForElement(Element* e)
{
    NSFileWrapper *wrapper = nil;
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    
    const AtomicString& attr = e->getAttribute(srcAttr);
    if (!attr.isEmpty()) {
        NSURL *URL = e->document()->completeURL(attr);
        wrapper = [[kit(e->document()->frame()) _dataSource] _fileWrapperForURL:URL];
    }
    if (!wrapper) {
        RenderImage* renderer = static_cast<RenderImage*>(e->renderer());
        if (renderer->cachedImage() && !renderer->cachedImage()->errorOccurred()) {
            wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData *)(renderer->cachedImage()->image()->getTIFFRepresentation())];
            [wrapper setPreferredFilename:@"image.tiff"];
            [wrapper autorelease];
        }
    }

    return wrapper;

    END_BLOCK_OBJC_EXCEPTIONS;

    return nil;
}

@implementation NSAttributedString (WebKitExtras)

- (NSAttributedString *)_web_attributedStringByStrippingAttachmentCharacters
{
    // This code was originally copied from NSTextView
    NSRange attachmentRange;
    NSString *originalString = [self string];
    static NSString *attachmentCharString = nil;
    
    if (!attachmentCharString) {
        unichar chars[2];
        if (!attachmentCharString) {
            chars[0] = NSAttachmentCharacter;
            chars[1] = 0;
            attachmentCharString = [[NSString alloc] initWithCharacters:chars length:1];
        }
    }
    
    attachmentRange = [originalString rangeOfString:attachmentCharString];
    if (attachmentRange.location != NSNotFound && attachmentRange.length > 0) {
        NSMutableAttributedString *newAttributedString = [[self mutableCopyWithZone:NULL] autorelease];
        
        while (attachmentRange.location != NSNotFound && attachmentRange.length > 0) {
            [newAttributedString replaceCharactersInRange:attachmentRange withString:@""];
            attachmentRange = [[newAttributedString string] rangeOfString:attachmentCharString];
        }
        return newAttributedString;
    }
    
    return self;
}

+ (NSAttributedString *)_web_attributedStringFromRange:(Range*)range
{
    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
    NSUInteger stringLength = 0;
    RetainPtr<NSMutableDictionary> attrs(AdoptNS, [[NSMutableDictionary alloc] init]);

    for (TextIterator it(range); !it.atEnd(); it.advance()) {
        RefPtr<Range> currentTextRange = it.range();
        ExceptionCode ec = 0;
        Node* startContainer = currentTextRange->startContainer(ec);
        Node* endContainer = currentTextRange->endContainer(ec);
        int startOffset = currentTextRange->startOffset(ec);
        int endOffset = currentTextRange->endOffset(ec);
        
        if (startContainer == endContainer && (startOffset == endOffset - 1)) {
            Node* node = startContainer->childNode(startOffset);
            if (node && node->hasTagName(imgTag)) {
                NSFileWrapper *fileWrapper = fileWrapperForElement(static_cast<Element*>(node));
                NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
                [string appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
                [attachment release];
            }
        }

        int currentTextLength = it.length();
        if (!currentTextLength)
            continue;

        RenderObject* renderer = startContainer->renderer();
        ASSERT(renderer);
        if (!renderer)
            continue;
        RenderStyle* style = renderer->style();
        NSFont *font = style->font().primaryFont()->getNSFont();
        [attrs.get() setObject:font forKey:NSFontAttributeName];
        if (style->color().isValid())
            [attrs.get() setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
        else
            [attrs.get() removeObjectForKey:NSForegroundColorAttributeName];
        if (style->backgroundColor().isValid())
            [attrs.get() setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
        else
            [attrs.get() removeObjectForKey:NSBackgroundColorAttributeName];

        RetainPtr<NSString> substring(AdoptNS, [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(it.characters()) length:currentTextLength freeWhenDone:NO]);
        [string replaceCharactersInRange:NSMakeRange(stringLength, 0) withString:substring.get()];
        [string setAttributes:attrs.get() range:NSMakeRange(stringLength, currentTextLength)];
        stringLength += currentTextLength;
    }

    return [string autorelease];
}

@end