diff options
author | Steve Block <steveblock@google.com> | 2011-06-08 08:26:01 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-06-08 08:26:01 -0700 |
commit | 3742ac093d35d923c81693096ab6671e9b147700 (patch) | |
tree | c2add9100f789dad45ef1ec5328bddde02c47a4c /Source/WebCore/platform/mac | |
parent | 901401d90459bc22580842455d4588b9a697514d (diff) | |
parent | e5926f4a0d6adc9ad4a75824129f117181953560 (diff) | |
download | external_webkit-3742ac093d35d923c81693096ab6671e9b147700.zip external_webkit-3742ac093d35d923c81693096ab6671e9b147700.tar.gz external_webkit-3742ac093d35d923c81693096ab6671e9b147700.tar.bz2 |
Merge changes I55c6d71a,Ifb3277d4,Ia1b847a2,I7ba9cf3f,Ida2b2a8a,I1280ec90,I72f818d5,I2e3b588b,I9a4e6289,Ia724c78b,Icd8612c8,Ie31b15d7,Ie125edae,I77941a88,I89dae78b,I3516e5ca,I1a4c17b5,I2c4ecc1a,I9c8e6537,Ifac13115,Ie1f80e09,Ia541ed77,I60ce9d78
* changes:
Merge WebKit at r82507: Update ThirdPartyProject.prop
Merge WebKit at r82507: Cherry-pick change r88166 to add INSPECTOR guards to ScriptProfiler
Merge WebKit at r82507: Work around a V8 bug
Merge WebKit at r82507: JNIType renamed to JavaType
Merge WebKit at r82507: IconDatabaseClient interface expanded
Merge WebKit at r82507: Don't use new loss-free code path in HTMLCanvasElement::toDataURL()
Merge WebKit at r82507: IcondDatabaseBase::iconForPageURL() renamed
Merge WebKit at r82507: IconDatabaseBase::Open() signature changed
Merge WebKit at r82507: Node::isContentEditable() renamed
Merge WebKit at r82507: Use icon database through IconDatabaseBase
Merge WebKit at r82507: toInputElement() is now a member of Node
Merge WebKit at r82507: FrameLoaderClient::objectContentType() signature changed
Merge WebKit at r82507: StringImpl::computeHash() removed
Merge WebKit at r82507: Stub out FontPlatformData::setOrientation()
Merge WebKit at r82507: Path::strokeBoundingRect() is now const
Merge WebKit at r82507: Add missing UnusedParam.h include in ApplicationCacheGroup.cpp
Merge WebKit at r82507: Continue to use Android's version of FontPlatformData.h
Merge WebKit at r82507: Update signature of FontCustomPlatformData::fontPlatformData()
Merge WebKit at r82507: Fix conflicts due to JNI refactoring
Merge WebKit at r82507: Fix conflicts due to new StorageTracker
Merge WebKit at r82507: Fix conflicts
Merge WebKit at r82507: Fix makefiles
Merge WebKit at r82507: Initial merge by git
Diffstat (limited to 'Source/WebCore/platform/mac')
19 files changed, 2065 insertions, 211 deletions
diff --git a/Source/WebCore/platform/mac/FileSystemMac.mm b/Source/WebCore/platform/mac/FileSystemMac.mm index 8cdd382..a9cbcf4 100644 --- a/Source/WebCore/platform/mac/FileSystemMac.mm +++ b/Source/WebCore/platform/mac/FileSystemMac.mm @@ -41,28 +41,29 @@ String homeDirectoryPath() return NSHomeDirectory(); } -CString openTemporaryFile(const char* prefix, PlatformFileHandle& platformFileHandle) +String openTemporaryFile(const String& prefix, PlatformFileHandle& platformFileHandle) { platformFileHandle = invalidPlatformFileHandle; Vector<char> temporaryFilePath(PATH_MAX); if (!confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryFilePath.data(), temporaryFilePath.size())) - return CString(); + return String(); // Shrink the vector. temporaryFilePath.shrink(strlen(temporaryFilePath.data())); ASSERT(temporaryFilePath.last() == '/'); - // Append the file name. - temporaryFilePath.append(prefix, strlen(prefix)); + // Append the file name. + CString prefixUtf8 = prefix.utf8(); + temporaryFilePath.append(prefixUtf8.data(), prefixUtf8.length()); temporaryFilePath.append("XXXXXX", 6); temporaryFilePath.append('\0'); platformFileHandle = mkstemp(temporaryFilePath.data()); if (platformFileHandle == invalidPlatformFileHandle) - return CString(); + return String(); - return CString(temporaryFilePath.data()); + return String::fromUTF8(temporaryFilePath.data()); } bool canExcludeFromBackup() diff --git a/Source/WebCore/platform/mac/HTMLConverter.h b/Source/WebCore/platform/mac/HTMLConverter.h new file mode 100644 index 0000000..645c1d7 --- /dev/null +++ b/Source/WebCore/platform/mac/HTMLConverter.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "DOM.h" +#import "DOMDocument.h" +#import "DOMRange.h" + +namespace WebCore { +class DocumentLoader; +} + +@interface WebHTMLConverter : NSObject { + NSMutableAttributedString *_attrStr; + NSURL *_baseURL; + DOMDocument *_document; + DOMRange *_domRange; + NSMutableArray *_domStartAncestors; + WebCore::DocumentLoader *_dataSource; + NSString *_standardFontFamily; + CGFloat _textSizeMultiplier; + CGFloat _webViewTextSizeMultiplier; + CGFloat _defaultTabInterval; + CGFloat _defaultFontSize; + CGFloat _minimumFontSize; + NSMutableArray *_textLists; + NSMutableArray *_textBlocks; + NSMutableArray *_textTables; + NSMutableDictionary *_textTableFooters; + NSMutableArray *_textTableSpacings; + NSMutableArray *_textTablePaddings; + NSMutableArray *_textTableRows; + NSMutableArray *_textTableRowArrays; + NSMutableArray *_textTableRowBackgroundColors; + NSMutableDictionary *_computedStylesForElements; + NSMutableDictionary *_specifiedStylesForElements; + NSMutableDictionary *_stringsForNodes; + NSMutableDictionary *_floatsForNodes; + NSMutableDictionary *_colorsForNodes; + NSMutableDictionary *_attributesForElements; + NSMutableDictionary *_elementIsBlockLevel; + NSMutableDictionary *_fontCache; + NSMutableArray *_writingDirectionArray; + NSUInteger _domRangeStartIndex; + NSInteger _indexingLimit; + NSUInteger _thumbnailLimit; + NSInteger _errorCode; + NSInteger _quoteLevel; + + struct { + unsigned int isSoft:1; + unsigned int reachedStart:1; + unsigned int reachedEnd:1; + unsigned int isIndexing:1; + unsigned int isTesting:1; + unsigned int hasTrailingNewline:1; + unsigned int pad:26; + } _flags; +} + +- (id)init; +- (id)initWithDOMRange:(DOMRange *)domRange; + +- (NSAttributedString *)attributedString; + +@end + diff --git a/Source/WebCore/platform/mac/HTMLConverter.mm b/Source/WebCore/platform/mac/HTMLConverter.mm new file mode 100644 index 0000000..a4864c2 --- /dev/null +++ b/Source/WebCore/platform/mac/HTMLConverter.mm @@ -0,0 +1,1682 @@ +/* + * Copyright (C) 2011 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "config.h" +#import "HTMLConverter.h" + +#import "ArchiveResource.h" +#import "Document.h" +#import "DocumentLoader.h" +#import "DOMDocumentInternal.h" +#import "DOMElementInternal.h" +#import "DOMHTMLTableCellElement.h" +#import "DOMPrivate.h" +#import "Element.h" +#import "Frame.h" +#import "HTMLNames.h" +#import "HTMLParserIdioms.h" +#import <wtf/ASCIICType.h> + +using namespace WebCore; +using namespace HTMLNames; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +// Additional control Unicode characters +const unichar WebNextLineCharacter = 0x0085; + +@interface NSTextList (TextListPrivate) ++ (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs; +@end + +@interface NSTextAttachment (NSIgnoreOrientation) +- (void)setIgnoresOrientation:(BOOL)flag; +- (BOOL)ignoresOrientation; +@end + +@interface NSURL (WebDataURL) ++ (NSURL *)_web_uniqueWebDataURL; ++ (NSURL *)_web_uniqueWebDataURLWithRelativeString:(NSString *)string; ++ (NSURL *)_web_URLWithString:(NSString *)string relativeToURL:(NSURL *)baseURL; +- (NSString *)_web_suggestedFilenameWithMIMEType:(NSString *)MIMEType; +@end + +@interface WebHTMLConverter(WebHTMLConverterPrivate) + +- (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key; +- (NSColor *)_colorForNode:(DOMNode *)node property:(NSString *)key; +- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key; +- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded; +- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth; + +@end + +// Returns the font to be used if the NSFontAttributeName doesn't exist +static NSFont *WebDefaultFont() +{ + static NSFont *defaultFont = nil; + + if (defaultFont) + return defaultFont; + + NSFont *font = [NSFont fontWithName:@"Helvetica" size:12]; + if (!font) + font = [NSFont systemFontOfSize:12]; + + defaultFont = [font retain]; + + return defaultFont; +} + +@implementation WebHTMLConverter + +static NSFont *_fontForNameAndSize(NSString *fontName, CGFloat size, NSMutableDictionary *cache) +{ + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSFont *font = [cache objectForKey:fontName]; + + if (font) { + font = [fontManager convertFont:font toSize:size]; + return font; + } + font = [fontManager fontWithFamily:fontName traits:0 weight:0 size:size]; + if (!font) { + NSArray *availableFamilyNames = [fontManager availableFontFamilies]; + NSRange dividingRange, dividingSpaceRange = [fontName rangeOfString:@" " options:NSBackwardsSearch], dividingDashRange = [fontName rangeOfString:@"-" options:NSBackwardsSearch]; + dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange); + while (0 < dividingRange.length) { + NSString *familyName = [fontName substringToIndex:dividingRange.location]; + if ([availableFamilyNames containsObject:familyName]) { + NSArray *familyMemberArray; + NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)]; + NSArray *familyMemberArrays = [fontManager availableMembersOfFontFamily:familyName]; + NSEnumerator *familyMemberArraysEnum = [familyMemberArrays objectEnumerator]; + while ((familyMemberArray = [familyMemberArraysEnum nextObject])) { + NSString *familyMemberFaceName = [familyMemberArray objectAtIndex:1]; + if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) { + NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue]; + NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue]; + font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size]; + break; + } + } + if (!font) { + if (0 < [familyMemberArrays count]) { + NSArray *familyMemberArray = [familyMemberArrays objectAtIndex:0]; + NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue]; + NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue]; + font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size]; + } + } + break; + } else { + dividingSpaceRange = [familyName rangeOfString:@" " options:NSBackwardsSearch]; + dividingDashRange = [familyName rangeOfString:@"-" options:NSBackwardsSearch]; + dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange); + } + } + } + if (!font) font = [NSFont fontWithName:@"Times" size:size]; + if (!font) font = [NSFont userFontOfSize:size]; + if (!font) font = [fontManager convertFont:WebDefaultFont() toSize:size]; + if (!font) font = WebDefaultFont(); + [cache setObject:font forKey:fontName]; + return font; +} + ++ (NSParagraphStyle *)defaultParagraphStyle +{ + static NSMutableParagraphStyle *defaultParagraphStyle = nil; + if (!defaultParagraphStyle) { + defaultParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + [defaultParagraphStyle setDefaultTabInterval:36]; + [defaultParagraphStyle setTabStops:[NSArray array]]; + } + return defaultParagraphStyle; +} + +- (NSArray *)_childrenForNode:(DOMNode *)node +{ + NSMutableArray *array = [NSMutableArray array]; + DOMNode *child = [node firstChild]; + while (child) { + [array addObject:child]; + child = [child nextSibling]; + } + return array; +} + +- (DOMCSSStyleDeclaration *)_computedStyleForElement:(DOMElement *)element +{ + DOMDocument *document = [element ownerDocument]; + DOMCSSStyleDeclaration *result = nil; + result = [_computedStylesForElements objectForKey:element]; + if (result) { + if ([[NSNull null] isEqual:result]) result = nil; + } else { + result = [document getComputedStyle:element pseudoElement:@""] ; + [_computedStylesForElements setObject:(result ? (id)result : (id)[NSNull null]) forKey:element]; + } + return result; +} + +- (DOMCSSStyleDeclaration *)_specifiedStyleForElement:(DOMElement *)element +{ + DOMCSSStyleDeclaration *result = [_specifiedStylesForElements objectForKey:element]; + if (result) { + if ([[NSNull null] isEqual:result]) result = nil; + } else { + result = [element style]; + [_specifiedStylesForElements setObject:(result ? (id)result : (id)[NSNull null]) forKey:element]; + } + return result; +} + +- (NSString *)_computedStringForNode:(DOMNode *)node property:(NSString *)key +{ + NSString *result = nil; + BOOL inherit = YES; + DOMElement *element = (DOMElement *)node; + if (element && [element nodeType] == DOM_ELEMENT_NODE) { + DOMCSSStyleDeclaration *computedStyle, *specifiedStyle; + inherit = NO; + if (!result && (computedStyle = [self _computedStyleForElement:element])) { + DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key]; + if (computedValue) { + unsigned short valueType = [computedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE) { + unsigned short primitiveType = [computedValue primitiveType]; + if (primitiveType == DOM_CSS_STRING || primitiveType == DOM_CSS_URI || primitiveType == DOM_CSS_IDENT || primitiveType == DOM_CSS_ATTR) { + result = [computedValue getStringValue]; + if (result && [result length] == 0) result = nil; + } + } else if (valueType == DOM_CSS_VALUE_LIST) { + result = [computedStyle getPropertyValue:key]; + } + } + } + if (!result && (specifiedStyle = [self _specifiedStyleForElement:element])) { + DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key]; + if (specifiedValue) { + unsigned short valueType = [specifiedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE) { + unsigned short primitiveType = [specifiedValue primitiveType]; + if (primitiveType == DOM_CSS_STRING || primitiveType == DOM_CSS_URI || primitiveType == DOM_CSS_IDENT || primitiveType == DOM_CSS_ATTR) { + result = [specifiedValue getStringValue]; + if (result && [result length] == 0) result = nil; + // ??? hack alert + if (!result) { + result = [specifiedStyle getPropertyValue:key]; + } + } + } else if (valueType == DOM_CSS_INHERIT) { + inherit = YES; + } else if (valueType == DOM_CSS_VALUE_LIST) { + result = [specifiedStyle getPropertyValue:key]; + } + } + } + if (!result) { + Element* coreElement = core(element); + if ([@"display" isEqualToString:key]) { + if (coreElement->hasTagName(headTag) || coreElement->hasTagName(scriptTag) || coreElement->hasTagName(appletTag) || coreElement->hasTagName(noframesTag)) + result = @"none"; + else if (coreElement->hasTagName(addressTag) || coreElement->hasTagName(blockquoteTag) || coreElement->hasTagName(bodyTag) || coreElement->hasTagName(centerTag) + || coreElement->hasTagName(ddTag) || coreElement->hasTagName(dirTag) || coreElement->hasTagName(divTag) || coreElement->hasTagName(dlTag) + || coreElement->hasTagName(dtTag) || coreElement->hasTagName(fieldsetTag) || coreElement->hasTagName(formTag) || coreElement->hasTagName(frameTag) + || coreElement->hasTagName(framesetTag) || coreElement->hasTagName(hrTag) || coreElement->hasTagName(htmlTag) || coreElement->hasTagName(h1Tag) + || coreElement->hasTagName(h2Tag) || coreElement->hasTagName(h3Tag) || coreElement->hasTagName(h4Tag) || coreElement->hasTagName(h5Tag) + || coreElement->hasTagName(h6Tag) || coreElement->hasTagName(iframeTag) || coreElement->hasTagName(menuTag) || coreElement->hasTagName(noscriptTag) + || coreElement->hasTagName(olTag) || coreElement->hasTagName(pTag) || coreElement->hasTagName(preTag) || coreElement->hasTagName(ulTag)) + result = @"block"; + else if (coreElement->hasTagName(liTag)) + result = @"list-item"; + else if (coreElement->hasTagName(tableTag)) + result = @"table"; + else if (coreElement->hasTagName(trTag)) + result = @"table-row"; + else if (coreElement->hasTagName(thTag) || coreElement->hasTagName(tdTag)) + result = @"table-cell"; + else if (coreElement->hasTagName(theadTag)) + result = @"table-header-group"; + else if (coreElement->hasTagName(tbodyTag)) + result = @"table-row-group"; + else if (coreElement->hasTagName(tfootTag)) + result = @"table-footer-group"; + else if (coreElement->hasTagName(colTag)) + result = @"table-column"; + else if (coreElement->hasTagName(colgroupTag)) + result = @"table-column-group"; + else if (coreElement->hasTagName(captionTag)) + result = @"table-caption"; + } else if ([@"white-space" isEqualToString:key]) { + if (coreElement->hasTagName(preTag)) + result = @"pre"; + else + inherit = YES; + } else if ([@"font-style" isEqualToString:key]) { + if (coreElement->hasTagName(iTag) || coreElement->hasTagName(citeTag) || coreElement->hasTagName(emTag) || coreElement->hasTagName(varTag) || coreElement->hasTagName(addressTag)) + result = @"italic"; + else + inherit = YES; + } else if ([@"font-weight" isEqualToString:key]) { + if (coreElement->hasTagName(bTag) || coreElement->hasTagName(strongTag) || coreElement->hasTagName(thTag)) + result = @"bolder"; + else + inherit = YES; + } else if ([@"text-decoration" isEqualToString:key]) { + if (coreElement->hasTagName(uTag) || coreElement->hasTagName(insTag)) + result = @"underline"; + else if (coreElement->hasTagName(sTag) || coreElement->hasTagName(strikeTag) || coreElement->hasTagName(delTag)) + result = @"line-through"; + else + inherit = YES; // ??? this is not strictly correct + } else if ([@"text-align" isEqualToString:key]) { + if (coreElement->hasTagName(centerTag) || coreElement->hasTagName(captionTag) || coreElement->hasTagName(thTag)) + result = @"center"; + else + inherit = YES; + } else if ([@"vertical-align" isEqualToString:key]) { + if (coreElement->hasTagName(supTag)) + result = @"super"; + else if (coreElement->hasTagName(subTag)) + result = @"sub"; + else if (coreElement->hasTagName(theadTag) || coreElement->hasTagName(tbodyTag) || coreElement->hasTagName(tfootTag)) + result = @"middle"; + else if (coreElement->hasTagName(trTag) || coreElement->hasTagName(thTag) || coreElement->hasTagName(tdTag)) + inherit = YES; + } else if ([@"font-family" isEqualToString:key] || [@"font-variant" isEqualToString:key] || [@"font-effect" isEqualToString:key] + || [@"text-transform" isEqualToString:key] || [@"text-shadow" isEqualToString:key] || [@"visibility" isEqualToString:key] + || [@"border-collapse" isEqualToString:key] || [@"empty-cells" isEqualToString:key] || [@"word-spacing" isEqualToString:key] + || [@"list-style-type" isEqualToString:key] || [@"direction" isEqualToString:key]) { + inherit = YES; + } + } + } + if (!result && inherit) { + DOMNode *parentNode = [node parentNode]; + if (parentNode) result = [self _stringForNode:parentNode property:key]; + } + return result ? [result lowercaseString] : nil; +} + +- (NSString *)_stringForNode:(DOMNode *)node property:(NSString *)key +{ + NSString *result = nil; + NSMutableDictionary *attributeDictionary = [_stringsForNodes objectForKey:node]; + if (!attributeDictionary) { + attributeDictionary = [[NSMutableDictionary alloc] init]; + [_stringsForNodes setObject:attributeDictionary forKey:node]; + [attributeDictionary release]; + } + result = [attributeDictionary objectForKey:key]; + if (result) { + if ([@"" isEqualToString:result]) result = nil; + } else { + result = [self _computedStringForNode:node property:key]; + [attributeDictionary setObject:(result ? result : @"") forKey:key]; + } + return result; +} + +static inline BOOL _getFloat(DOMCSSPrimitiveValue *primitiveValue, CGFloat *val) +{ + if (!val) + return NO; + switch ([primitiveValue primitiveType]) { + case DOM_CSS_PX: + *val = [primitiveValue getFloatValue:DOM_CSS_PX]; + return YES; + case DOM_CSS_PT: + *val = 4 * [primitiveValue getFloatValue:DOM_CSS_PT] / 3; + return YES; + case DOM_CSS_PC: + *val = 16 * [primitiveValue getFloatValue:DOM_CSS_PC]; + return YES; + case DOM_CSS_CM: + *val = 96 * [primitiveValue getFloatValue:DOM_CSS_CM] / (CGFloat)2.54; + return YES; + case DOM_CSS_MM: + *val = 96 * [primitiveValue getFloatValue:DOM_CSS_MM] / (CGFloat)25.4; + return YES; + case DOM_CSS_IN: + *val = 96 * [primitiveValue getFloatValue:DOM_CSS_IN]; + return YES; + default: + return NO; + } +} + +- (BOOL)_getComputedFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key +{ + BOOL result = NO, inherit = YES; + CGFloat floatVal = 0; + DOMElement *element = (DOMElement *)node; + if (element && [element nodeType] == DOM_ELEMENT_NODE) { + DOMCSSStyleDeclaration *computedStyle, *specifiedStyle; + inherit = NO; + if (!result && (computedStyle = [self _computedStyleForElement:element])) { + DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key]; + if (computedValue && [computedValue cssValueType] == DOM_CSS_PRIMITIVE_VALUE) { + result = _getFloat(computedValue, &floatVal); + } + } + if (!result && (specifiedStyle = [self _specifiedStyleForElement:element])) { + DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key]; + if (specifiedValue) { + unsigned short valueType = [specifiedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE) { + result = _getFloat(specifiedValue, &floatVal); + } else if (valueType == DOM_CSS_INHERIT) { + inherit = YES; + } + } + } + if (!result) { + if ([@"text-indent" isEqualToString:key] || [@"letter-spacing" isEqualToString:key] || [@"word-spacing" isEqualToString:key] + || [@"line-height" isEqualToString:key] || [@"widows" isEqualToString:key] || [@"orphans" isEqualToString:key]) + inherit = YES; + } + } + if (!result && inherit) { + DOMNode *parentNode = [node parentNode]; + if (parentNode) result = [self _getFloat:&floatVal forNode:parentNode property:key]; + } + if (result && val) + *val = floatVal; + return result; +} + +- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(NSString *)key +{ + BOOL result = NO; + CGFloat floatVal = 0; + NSNumber *floatNumber; + NSMutableDictionary *attributeDictionary = [_floatsForNodes objectForKey:node]; + if (!attributeDictionary) { + attributeDictionary = [[NSMutableDictionary alloc] init]; + [_floatsForNodes setObject:attributeDictionary forKey:node]; + [attributeDictionary release]; + } + floatNumber = [attributeDictionary objectForKey:key]; + if (floatNumber) { + if (![[NSNull null] isEqual:floatNumber]) { + result = YES; + floatVal = [floatNumber floatValue]; + } + } else { + result = [self _getComputedFloat:&floatVal forNode:node property:key]; + [attributeDictionary setObject:(result ? (id)[NSNumber numberWithDouble:floatVal] : (id)[NSNull null]) forKey:key]; + } + if (result && val) *val = floatVal; + return result; +} + +static inline NSColor *_colorForRGBColor(DOMRGBColor *domRGBColor, BOOL ignoreBlack) +{ + NSColor *color = [domRGBColor _color]; + NSColorSpace *colorSpace = [color colorSpace]; + const CGFloat ColorEpsilon = 1 / (2 * (CGFloat)255.0); + + if (color) { + if ([colorSpace isEqual:[NSColorSpace genericGrayColorSpace]] || [colorSpace isEqual:[NSColorSpace deviceGrayColorSpace]]) { + CGFloat white, alpha; + [color getWhite:&white alpha:&alpha]; + if (white < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon)) color = nil; + } else { + NSColor *rgbColor = nil; + if ([colorSpace isEqual:[NSColorSpace genericRGBColorSpace]] || [colorSpace isEqual:[NSColorSpace deviceRGBColorSpace]]) rgbColor = color; + if (!rgbColor) rgbColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + if (rgbColor) { + CGFloat red, green, blue, alpha; + [rgbColor getRed:&red green:&green blue:&blue alpha:&alpha]; + if (red < ColorEpsilon && green < ColorEpsilon && blue < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon)) color = nil; + } + } + } + return color; +} + +static inline NSShadow *_shadowForShadowStyle(NSString *shadowStyle) +{ + NSShadow *shadow = nil; + NSUInteger shadowStyleLength = [shadowStyle length]; + NSRange openParenRange = [shadowStyle rangeOfString:@"("], closeParenRange = [shadowStyle rangeOfString:@")"], firstRange = NSMakeRange(NSNotFound, 0), secondRange = NSMakeRange(NSNotFound, 0), thirdRange = NSMakeRange(NSNotFound, 0), spaceRange; + if (openParenRange.length > 0 && closeParenRange.length > 0 && NSMaxRange(openParenRange) < closeParenRange.location) { + NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@","]; + if ([components count] >= 3) { + CGFloat red = [[components objectAtIndex:0] floatValue] / 255, green = [[components objectAtIndex:1] floatValue] / 255, blue = [[components objectAtIndex:2] floatValue] / 255, alpha = ([components count] >= 4) ? [[components objectAtIndex:3] floatValue] / 255 : 1; + NSColor *shadowColor = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha]; + NSSize shadowOffset; + CGFloat shadowBlurRadius; + firstRange = [shadowStyle rangeOfString:@"px"]; + if (firstRange.length > 0 && NSMaxRange(firstRange) < shadowStyleLength) secondRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))]; + if (secondRange.length > 0 && NSMaxRange(secondRange) < shadowStyleLength) thirdRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))]; + if (firstRange.location > 0 && firstRange.length > 0 && secondRange.length > 0 && thirdRange.length > 0) { + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, firstRange.location)]; + if (spaceRange.length == 0) spaceRange = NSMakeRange(0, 0); + shadowOffset.width = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), firstRange.location - NSMaxRange(spaceRange))] floatValue]; + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, secondRange.location)]; + if (spaceRange.length == 0) spaceRange = NSMakeRange(0, 0); + shadowOffset.height = -[[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), secondRange.location - NSMaxRange(spaceRange))] floatValue]; + spaceRange = [shadowStyle rangeOfString:@" " options:NSBackwardsSearch range:NSMakeRange(0, thirdRange.location)]; + if (spaceRange.length == 0) spaceRange = NSMakeRange(0, 0); + shadowBlurRadius = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), thirdRange.location - NSMaxRange(spaceRange))] floatValue]; + shadow = [[[NSShadow alloc] init] autorelease]; + [shadow setShadowColor:shadowColor]; + [shadow setShadowOffset:shadowOffset]; + [shadow setShadowBlurRadius:shadowBlurRadius]; + } + } + } + return shadow; +} + +- (BOOL)_elementIsBlockLevel:(DOMElement *)element +{ + BOOL isBlockLevel = NO; + NSNumber *val = nil; + val = [_elementIsBlockLevel objectForKey:element]; + if (val) { + isBlockLevel = [val boolValue]; + } else { + NSString *displayVal = [self _stringForNode:element property:@"display"], *floatVal = [self _stringForNode:element property:@"float"]; + if (floatVal && ([@"left" isEqualToString:floatVal] || [@"right" isEqualToString:floatVal])) { + isBlockLevel = YES; + } else if (displayVal) { + isBlockLevel = ([@"block" isEqualToString:displayVal] || [@"list-item" isEqualToString:displayVal] || [displayVal hasPrefix:@"table"]); + } + [_elementIsBlockLevel setObject:[NSNumber numberWithBool:isBlockLevel] forKey:element]; + } + return isBlockLevel; +} + +- (BOOL)_elementHasOwnBackgroundColor:(DOMElement *)element +{ + // In the text system, text blocks (table elements) and documents (body elements) have their own background colors, which should not be inherited + if ([self _elementIsBlockLevel:element]) { + Element* coreElement = core(element); + NSString *displayVal = [self _stringForNode:element property:@"display"]; + if (coreElement->hasTagName(htmlTag) || coreElement->hasTagName(bodyTag) || [displayVal hasPrefix:@"table"]) + return YES; + } + return NO; +} + +- (DOMElement *)_blockLevelElementForNode:(DOMNode *)node +{ + DOMElement *element = (DOMElement *)node; + while (element && [element nodeType] != DOM_ELEMENT_NODE) + element = (DOMElement *)[element parentNode]; + if (element && ![self _elementIsBlockLevel:element]) + element = [self _blockLevelElementForNode:[element parentNode]]; + return element; +} + +- (NSColor *)_computedColorForNode:(DOMNode *)node property:(NSString *)key +{ + NSColor *result = nil; + BOOL inherit = YES, haveResult = NO, isColor = [@"color" isEqualToString:key], isBackgroundColor = [@"background-color" isEqualToString:key]; + DOMElement *element = (DOMElement *)node; + if (element && [element nodeType] == DOM_ELEMENT_NODE) { + DOMCSSStyleDeclaration *computedStyle, *specifiedStyle; + inherit = NO; + if (!haveResult && (computedStyle = [self _computedStyleForElement:element])) { + DOMCSSPrimitiveValue *computedValue = (DOMCSSPrimitiveValue *)[computedStyle getPropertyCSSValue:key]; + if (computedValue && [computedValue cssValueType] == DOM_CSS_PRIMITIVE_VALUE && [computedValue primitiveType] == DOM_CSS_RGBCOLOR) { + result = _colorForRGBColor([computedValue getRGBColorValue], isColor); + haveResult = YES; + } + } + if (!haveResult && (specifiedStyle = [self _specifiedStyleForElement:element])) { + DOMCSSPrimitiveValue *specifiedValue = (DOMCSSPrimitiveValue *)[specifiedStyle getPropertyCSSValue:key]; + if (specifiedValue) { + unsigned short valueType = [specifiedValue cssValueType]; + if (valueType == DOM_CSS_PRIMITIVE_VALUE && [specifiedValue primitiveType] == DOM_CSS_RGBCOLOR) { + result = _colorForRGBColor([specifiedValue getRGBColorValue], isColor); + haveResult = YES; + } else if (valueType == DOM_CSS_INHERIT) { + inherit = YES; + } + } + } + if (!result) { + if ((isColor && !haveResult) || (isBackgroundColor && ![self _elementHasOwnBackgroundColor:element])) inherit = YES; + } + } + if (!result && inherit) { + DOMNode *parentNode = [node parentNode]; + if (parentNode && !(isBackgroundColor && [parentNode nodeType] == DOM_ELEMENT_NODE && [self _elementHasOwnBackgroundColor:(DOMElement *)parentNode])) { + result = [self _colorForNode:parentNode property:key]; + } + } + return result; +} + +- (NSColor *)_colorForNode:(DOMNode *)node property:(NSString *)key +{ + NSColor *result = nil; + NSMutableDictionary *attributeDictionary = [_colorsForNodes objectForKey:node]; + if (!attributeDictionary) { + attributeDictionary = [[NSMutableDictionary alloc] init]; + [_colorsForNodes setObject:attributeDictionary forKey:node]; + [attributeDictionary release]; + } + result = [attributeDictionary objectForKey:key]; + if (result) { + if ([[NSColor clearColor] isEqual:result]) result = nil; + } else { + result = [self _computedColorForNode:node property:key]; + [attributeDictionary setObject:(result ? result : [NSColor clearColor]) forKey:key]; + } + return result; +} + +- (NSDictionary *)_computedAttributesForElement:(DOMElement *)element +{ + DOMElement *blockElement = [self _blockLevelElementForNode:element]; + NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSString *fontEffect = [self _stringForNode:element property:@"font-effect"], *textDecoration = [self _stringForNode:element property:@"text-decoration"], *verticalAlign = [self _stringForNode:element property:@"vertical-align"], *textShadow = [self _stringForNode:element property:@"text-shadow"]; + CGFloat fontSize = 0, baselineOffset = 0, kerning = 0; + NSFont *font = nil, *actualFont = [element _font]; + NSColor *foregroundColor = [self _colorForNode:element property:@"color"], *backgroundColor = [self _colorForNode:element property:@"background-color"]; + + if (![self _getFloat:&fontSize forNode:element property:@"font-size"] || fontSize <= 0.0) fontSize = _defaultFontSize; + fontSize *= _textSizeMultiplier; + if (fontSize < _minimumFontSize) fontSize = _minimumFontSize; + if (fabs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) < 0.05) { + fontSize = (CGFloat)floor(2.0 * fontSize + 0.5) / 2; + } else if (fabs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) < 0.005) { + fontSize = (CGFloat)floor(10.0 * fontSize + 0.5) / 10; + } + if (fontSize <= 0.0) fontSize = 12; + + if (actualFont) font = [fontManager convertFont:actualFont toSize:fontSize]; + if (!font) { + NSString *fontName = [[self _stringForNode:element property:@"font-family"] capitalizedString], *fontStyle = [self _stringForNode:element property:@"font-style"], *fontWeight = [self _stringForNode:element property:@"font-weight"], *fontVariant = [self _stringForNode:element property:@"font-variant"]; + + if (!fontName) fontName = _standardFontFamily; + if (fontName) font = _fontForNameAndSize(fontName, fontSize, _fontCache); + if (!font) font = [NSFont fontWithName:@"Times" size:fontSize]; + if ([@"italic" isEqualToString:fontStyle] || [@"oblique" isEqualToString:fontStyle]) { + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSItalicFontMask]; + if (!font) font = originalFont; + } + if ([fontWeight hasPrefix:@"bold"] || [fontWeight integerValue] >= 700) { + // ??? handle weight properly using NSFontManager + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSBoldFontMask]; + if (!font) font = originalFont; + } + if ([@"small-caps" isEqualToString:fontVariant]) { + // ??? synthesize small-caps if [font isEqual:originalFont] + NSFont *originalFont = font; + font = [fontManager convertFont:font toHaveTrait:NSSmallCapsFontMask]; + if (!font) font = originalFont; + } + } + if (font) [attrs setObject:font forKey:NSFontAttributeName]; + if (foregroundColor) [attrs setObject:foregroundColor forKey:NSForegroundColorAttributeName]; + if (backgroundColor && ![self _elementHasOwnBackgroundColor:element]) [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName]; + if (fontEffect) { + if ([fontEffect rangeOfString:@"outline"].location != NSNotFound) [attrs setObject:[NSNumber numberWithDouble:3.0] forKey:NSStrokeWidthAttributeName]; + if ([fontEffect rangeOfString:@"emboss"].location != NSNotFound) [attrs setObject:[[[NSShadow alloc] init] autorelease] forKey:NSShadowAttributeName]; + } + if (textDecoration && [textDecoration length] > 4) { + if ([textDecoration rangeOfString:@"underline"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName]; + if ([textDecoration rangeOfString:@"line-through"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName]; + } + if (verticalAlign) { + if ([verticalAlign rangeOfString:@"super"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName]; + if ([verticalAlign rangeOfString:@"sub"].location != NSNotFound) [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName]; + } + if ([self _getFloat:&baselineOffset forNode:element property:@"vertical-align"]) [attrs setObject:[NSNumber numberWithDouble:baselineOffset] forKey:NSBaselineOffsetAttributeName]; + if ([self _getFloat:&kerning forNode:element property:@"letter-spacing"]) [attrs setObject:[NSNumber numberWithDouble:kerning] forKey:NSKernAttributeName]; + if (textShadow && [textShadow length] > 4) { + NSShadow *shadow = _shadowForShadowStyle(textShadow); + if (shadow) [attrs setObject:shadow forKey:NSShadowAttributeName]; + } + if (element != blockElement && [_writingDirectionArray count] > 0) [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray] forKey:NSWritingDirectionAttributeName]; + + if (blockElement) { + NSMutableParagraphStyle *paragraphStyle = [[[self class] defaultParagraphStyle] mutableCopy]; + NSString *blockTag = [blockElement tagName]; + BOOL isParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length])); + NSString *textAlign = [self _stringForNode:blockElement property:@"text-align"], *direction = [self _stringForNode:blockElement property:@"direction"]; + CGFloat leftMargin = 0, rightMargin = 0, bottomMargin = 0, textIndent = 0, lineHeight = 0; + if (textAlign) { + // WebKit can return -khtml-left, -khtml-right, -khtml-center + if ([textAlign hasSuffix:@"left"]) [paragraphStyle setAlignment:NSLeftTextAlignment]; + else if ([textAlign hasSuffix:@"right"]) [paragraphStyle setAlignment:NSRightTextAlignment]; + else if ([textAlign hasSuffix:@"center"]) [paragraphStyle setAlignment:NSCenterTextAlignment]; + else if ([textAlign hasSuffix:@"justify"]) [paragraphStyle setAlignment:NSJustifiedTextAlignment]; + } + if (direction) { + if ([direction isEqualToString:@"ltr"]) [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight]; + else if ([direction isEqualToString:@"rtl"]) [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft]; + } + if ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]) { + NSInteger headerLevel = [blockTag characterAtIndex:1] - '0'; + if (1 <= headerLevel && headerLevel <= 6) [paragraphStyle setHeaderLevel:headerLevel]; + } + if (isParagraph) { + //if ([self _getFloat:&topMargin forNode:blockElement property:@"margin-top"] && topMargin > 0.0) [paragraphStyle setParagraphSpacingBefore:topMargin]; + if ([self _getFloat:&leftMargin forNode:blockElement property:@"margin-left"] && leftMargin > 0.0) [paragraphStyle setHeadIndent:leftMargin]; + if ([self _getFloat:&textIndent forNode:blockElement property:@"text-indent"]) [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent]; + if ([self _getFloat:&rightMargin forNode:blockElement property:@"margin-right"] && rightMargin > 0.0) [paragraphStyle setTailIndent:-rightMargin]; + if ([self _getFloat:&bottomMargin forNode:blockElement property:@"margin-bottom"] && bottomMargin > 0.0) [paragraphStyle setParagraphSpacing:bottomMargin]; + } + if (_webViewTextSizeMultiplier > 0.0 && [self _getFloat:&lineHeight forNode:element property:@"line-height"] && lineHeight > 0.0) { + [paragraphStyle setMinimumLineHeight:lineHeight / _webViewTextSizeMultiplier]; + } + if ([_textLists count] > 0) [paragraphStyle setTextLists:_textLists]; + if ([_textBlocks count] > 0) [paragraphStyle setTextBlocks:_textBlocks]; + [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName]; + [paragraphStyle release]; + } + return attrs; +} + +- (NSDictionary *)_attributesForElement:(DOMElement *)element +{ + NSDictionary *result; + if (element) { + result = [_attributesForElements objectForKey:element]; + if (!result) { + result = [self _computedAttributesForElement:element]; + [_attributesForElements setObject:result forKey:element]; + } + } else { + result = [NSDictionary dictionary]; + } + return result; + +} + +- (void)_newParagraphForElement:(DOMElement *)element tag:(NSString *)tag allowEmpty:(BOOL)flag suppressTrailingSpace:(BOOL)suppress +{ + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + NSRange rangeToReplace = (suppress && _flags.isSoft && (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0); + BOOL needBreak = (flag || lastChar != '\n'); + if (needBreak) { + NSString *string = (([@"BODY" isEqualToString:tag] || [@"HTML" isEqualToString:tag]) ? @"" : @"\n"); + [_writingDirectionArray removeAllObjects]; + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += [string length] - rangeToReplace.length; + rangeToReplace.length = [string length]; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + _flags.isSoft = YES; + } +} + +- (void)_newLineForElement:(DOMElement *)element +{ + unichar c = NSLineSeparatorCharacter; + NSString *string = [[NSString alloc] initWithCharacters:&c length:1]; + NSUInteger textLength = [_attrStr length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + [string release]; + _flags.isSoft = YES; +} + +- (void)_newTabForElement:(DOMElement *)element +{ + NSString *string = @"\t"; + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + NSRange rangeToReplace = (_flags.isSoft && lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + [string release]; + _flags.isSoft = YES; +} + +static NSFileWrapper *fileWrapperForURL(DocumentLoader *dataSource, NSURL *URL) +{ + if ([URL isFileURL]) { + NSString *path = [[URL path] stringByResolvingSymlinksInPath]; + return [[[NSFileWrapper alloc] initWithPath:path] autorelease]; + } + + RefPtr<ArchiveResource> resource = dataSource->subresource(URL); + if (resource) { + NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[resource->data()->createNSData() autorelease]] autorelease]; + NSString *filename = resource->response().suggestedFilename(); + if (!filename || ![filename length]) { + NSURL *URL = resource->url(); + filename = [URL _web_suggestedFilenameWithMIMEType:resource->mimeType()]; + } + [wrapper setPreferredFilename:filename]; + return wrapper; + } + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL]; + + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; + [request release]; + + if (cachedResponse) { + NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease]; + [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]]; + return wrapper; + } + + return nil; +} + +- (BOOL)_addAttachmentForElement:(DOMElement *)element URL:(NSURL *)url needsParagraph:(BOOL)needsParagraph usePlaceholder:(BOOL)flag +{ + BOOL retval = NO, notFound = NO; + NSFileWrapper *fileWrapper = nil; + static NSImage *missingImage = nil; + Frame* frame = core([element ownerDocument])->frame(); + DocumentLoader *dataSource = frame->loader()->frameHasLoaded() ? frame->loader()->documentLoader() : 0; + BOOL ignoreOrientation = YES; + + if (_flags.isIndexing) return NO; + if ([url isFileURL]) { + NSString *path = [[url path] stringByStandardizingPath]; + if (path) fileWrapper = [[[NSFileWrapper alloc] initWithPath:path] autorelease]; + } + if (!fileWrapper) { + RefPtr<ArchiveResource> resource = dataSource->subresource(url); + if (!resource) resource = dataSource->subresource(url); + if (flag && resource && [@"text/html" isEqual:resource->mimeType()]) notFound = YES; + if (resource && !notFound) { + fileWrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[resource->data()->createNSData() autorelease]] autorelease]; + [fileWrapper setPreferredFilename:[url _web_suggestedFilenameWithMIMEType:resource->mimeType()]]; + } + } + if (!fileWrapper && !notFound) { + fileWrapper = fileWrapperForURL(dataSource, url); + if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES; + if (notFound) fileWrapper = nil; + } + if (!fileWrapper && !notFound) { + fileWrapper = fileWrapperForURL(_dataSource, url); + if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES; + if (notFound) fileWrapper = nil; + } + if (fileWrapper || flag) { + NSUInteger textLength = [_attrStr length]; + NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; + NSTextAttachmentCell *cell; + NSString *string = [[NSString alloc] initWithFormat:(needsParagraph ? @"%C\n" : @"%C"), NSAttachmentCharacter]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + NSDictionary *attrs; + if (fileWrapper) { + if (ignoreOrientation) [attachment setIgnoresOrientation:YES]; + } else { + cell = [[NSTextAttachmentCell alloc] initImageCell:missingImage]; + [attachment setAttachmentCell:cell]; + [cell release]; + } + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) { + [_attrStr setAttributes:attrs range:rangeToReplace]; + rangeToReplace.length = 1; + [_attrStr addAttribute:NSAttachmentAttributeName value:attachment range:rangeToReplace]; + } + [string release]; + [attachment release]; + _flags.isSoft = NO; + retval = YES; + } + return retval; +} + +- (void)_addQuoteForElement:(DOMElement *)element opening:(BOOL)opening level:(NSInteger)level +{ + unichar c = ((level % 2) == 0) ? (opening ? 0x201c : 0x201d) : (opening ? 0x2018 : 0x2019); + NSString *string = [[NSString alloc] initWithCharacters:&c length:1]; + NSUInteger textLength = [_attrStr length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + [_attrStr replaceCharactersInRange:rangeToReplace withString:string]; + rangeToReplace.length = [string length]; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + [string release]; + _flags.isSoft = NO; +} + +- (void)_addValue:(NSString *)value forElement:(DOMElement *)element +{ + NSUInteger textLength = [_attrStr length], valueLength = [value length]; + NSRange rangeToReplace = NSMakeRange(textLength, 0); + if (valueLength > 0) { + [_attrStr replaceCharactersInRange:rangeToReplace withString:value]; + rangeToReplace.length = valueLength; + if (rangeToReplace.location < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length; + if (!_flags.isIndexing) { + NSDictionary *attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + _flags.isSoft = NO; + } +} + +- (void)_fillInBlock:(NSTextBlock *)block forElement:(DOMElement *)element backgroundColor:(NSColor *)backgroundColor extraMargin:(CGFloat)extraMargin extraPadding:(CGFloat)extraPadding isTable:(BOOL)isTable +{ + CGFloat val = 0; + NSColor *color = nil; + BOOL isTableCellElement = [element isKindOfClass:[DOMHTMLTableCellElement class]]; + NSString *width = isTableCellElement ? [(DOMHTMLTableCellElement *)element width] : [element getAttribute:@"width"]; + + if ((width && [width length] > 0) || !isTable) { + if ([self _getFloat:&val forNode:element property:@"width"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockWidth]; + } + + if ([self _getFloat:&val forNode:element property:@"min-width"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumWidth]; + if ([self _getFloat:&val forNode:element property:@"max-width"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumWidth]; + if ([self _getFloat:&val forNode:element property:@"min-height"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumHeight]; + if ([self _getFloat:&val forNode:element property:@"max-height"]) [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumHeight]; + + if ([self _getFloat:&val forNode:element property:@"padding-left"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge]; + if ([self _getFloat:&val forNode:element property:@"padding-top"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; + if ([self _getFloat:&val forNode:element property:@"padding-right"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; + if ([self _getFloat:&val forNode:element property:@"padding-bottom"]) [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; + + if ([self _getFloat:&val forNode:element property:@"border-left-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinXEdge]; + if ([self _getFloat:&val forNode:element property:@"border-top-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinYEdge]; + if ([self _getFloat:&val forNode:element property:@"border-right-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxXEdge]; + if ([self _getFloat:&val forNode:element property:@"border-bottom-width"]) [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxYEdge]; + + if ([self _getFloat:&val forNode:element property:@"margin-left"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; + if ([self _getFloat:&val forNode:element property:@"margin-top"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; + if ([self _getFloat:&val forNode:element property:@"margin-right"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; + if ([self _getFloat:&val forNode:element property:@"margin-bottom"]) [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; + + if ((color = [self _colorForNode:element property:@"background-color"])) [block setBackgroundColor:color]; + if (!color && backgroundColor) [block setBackgroundColor:backgroundColor]; + if ((color = [self _colorForNode:element property:@"border-left-color"])) [block setBorderColor:color forEdge:NSMinXEdge]; + if ((color = [self _colorForNode:element property:@"border-top-color"])) [block setBorderColor:color forEdge:NSMinYEdge]; + if ((color = [self _colorForNode:element property:@"border-right-color"])) [block setBorderColor:color forEdge:NSMaxXEdge]; + if ((color = [self _colorForNode:element property:@"border-bottom-color"])) [block setBorderColor:color forEdge:NSMaxYEdge]; +} + +static inline BOOL read2DigitNumber(const char **pp, int8_t *outval) +{ + BOOL result = NO; + char c1 = *(*pp)++, c2; + if (isASCIIDigit(c1)) { + c2 = *(*pp)++; + if (isASCIIDigit(c2)) { + *outval = 10 * (c1 - '0') + (c2 - '0'); + result = YES; + } + } + return result; +} + +static inline NSDate *_dateForString(NSString *string) +{ + CFGregorianDate date; + const char *p = [string UTF8String]; + int8_t secval = 0; + BOOL wellFormed = YES; + + date.year = 0; + while (*p && isASCIIDigit(*p)) date.year = 10 * date.year + *p++ - '0'; + if (*p++ != '-') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.month) || *p++ != '-') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.day) || *p++ != 'T') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.hour) || *p++ != ':') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &date.minute) || *p++ != ':') wellFormed = NO; + if (!wellFormed || !read2DigitNumber(&p, &secval) || *p++ != 'Z') wellFormed = NO; + if (wellFormed) date.second = secval; + return wellFormed ? [(NSDate *)CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(date, NULL)) autorelease] : nil; +} + +static NSInteger _colCompare(id block1, id block2, void *) +{ + NSInteger col1 = [(NSTextTableBlock *)block1 startingColumn], col2 = [(NSTextTableBlock *)block2 startingColumn]; + return ((col1 < col2) ? NSOrderedAscending : ((col1 == col2) ? NSOrderedSame : NSOrderedDescending)); +} + +- (BOOL)_enterElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal +{ + if (!displayVal || !([@"none" isEqualToString:displayVal] || [@"table-column" isEqualToString:displayVal] || [@"table-column-group" isEqualToString:displayVal])) { + if ([self _elementIsBlockLevel:element] && ![@"BR" isEqualToString:tag] && !([@"table-cell" isEqualToString:displayVal] && [_textTables count] == 0) + && !([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag])) + [self _newParagraphForElement:element tag:tag allowEmpty:NO suppressTrailingSpace:YES]; + return YES; + } + return NO; +} + +- (void)_addTableForElement:(DOMElement *)tableElement +{ + NSTextTable *table = [[NSTextTable alloc] init]; + CGFloat cellSpacingVal = 1, cellPaddingVal = 1; + [table setNumberOfColumns:1]; + [table setLayoutAlgorithm:NSTextTableAutomaticLayoutAlgorithm]; + [table setCollapsesBorders:NO]; + [table setHidesEmptyCells:NO]; + if (tableElement) { + NSString *borderCollapse = [self _stringForNode:tableElement property:@"border-collapse"], *emptyCells = [self _stringForNode:tableElement property:@"empty-cells"], *tableLayout = [self _stringForNode:tableElement property:@"table-layout"]; + if ([tableElement respondsToSelector:@selector(cellSpacing)]) { + NSString *cellSpacing = [(DOMHTMLTableElement *)tableElement cellSpacing]; + if (cellSpacing && [cellSpacing length] > 0 && ![cellSpacing hasSuffix:@"%"]) cellSpacingVal = [cellSpacing floatValue]; + } + if ([tableElement respondsToSelector:@selector(cellPadding)]) { + NSString *cellPadding = [(DOMHTMLTableElement *)tableElement cellPadding]; + if (cellPadding && [cellPadding length] > 0 && ![cellPadding hasSuffix:@"%"]) cellPaddingVal = [cellPadding floatValue]; + } + [self _fillInBlock:table forElement:tableElement backgroundColor:nil extraMargin:0 extraPadding:0 isTable:YES]; + if ([@"collapse" isEqualToString:borderCollapse]) { + [table setCollapsesBorders:YES]; + cellSpacingVal = 0; + } + if ([@"hide" isEqualToString:emptyCells]) [table setHidesEmptyCells:YES]; + if ([@"fixed" isEqualToString:tableLayout]) [table setLayoutAlgorithm:NSTextTableFixedLayoutAlgorithm]; + } + [_textTables addObject:table]; + [_textTableSpacings addObject:[NSNumber numberWithDouble:cellSpacingVal]]; + [_textTablePaddings addObject:[NSNumber numberWithDouble:cellPaddingVal]]; + [_textTableRows addObject:[NSNumber numberWithInteger:0]]; + [_textTableRowArrays addObject:[NSMutableArray array]]; + [table release]; +} + +- (void)_addTableCellForElement:(DOMElement *)tableCellElement +{ + NSTextTable *table = [_textTables lastObject]; + NSInteger rowNumber = [[_textTableRows lastObject] integerValue], columnNumber = 0, rowSpan = 1, colSpan = 1; + NSMutableArray *rowArray = [_textTableRowArrays lastObject]; + NSUInteger i, count = [rowArray count]; + NSColor *color = ([_textTableRowBackgroundColors count] > 0) ? [_textTableRowBackgroundColors lastObject] : nil; + NSTextTableBlock *block, *previousBlock; + CGFloat cellSpacingVal = [[_textTableSpacings lastObject] floatValue]; + if ([color isEqual:[NSColor clearColor]]) color = nil; + for (i = 0; i < count; i++) { + previousBlock = [rowArray objectAtIndex:i]; + if (columnNumber >= [previousBlock startingColumn] && columnNumber < [previousBlock startingColumn] + [previousBlock columnSpan]) columnNumber = [previousBlock startingColumn] + [previousBlock columnSpan]; + } + if (tableCellElement) { + if ([tableCellElement respondsToSelector:@selector(rowSpan)]) { + rowSpan = [(DOMHTMLTableCellElement *)tableCellElement rowSpan]; + if (rowSpan < 1) rowSpan = 1; + } + if ([tableCellElement respondsToSelector:@selector(colSpan)]) { + colSpan = [(DOMHTMLTableCellElement *)tableCellElement colSpan]; + if (colSpan < 1) colSpan = 1; + } + } + block = [[NSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]; + if (tableCellElement) { + NSString *verticalAlign = [self _stringForNode:tableCellElement property:@"vertical-align"]; + [self _fillInBlock:block forElement:tableCellElement backgroundColor:color extraMargin:cellSpacingVal / 2 extraPadding:0 isTable:NO]; + if ([@"middle" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockMiddleAlignment]; + else if ([@"bottom" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockBottomAlignment]; + else if ([@"baseline" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockBaselineAlignment]; + else if ([@"top" isEqualToString:verticalAlign]) [block setVerticalAlignment:NSTextBlockTopAlignment]; + } + [_textBlocks addObject:block]; + [rowArray addObject:block]; + [rowArray sortUsingFunction:_colCompare context:NULL]; + [block release]; +} + +- (BOOL)_processElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth +{ + BOOL retval = YES, isBlockLevel = [self _elementIsBlockLevel:element]; + if (isBlockLevel) { + [_writingDirectionArray removeAllObjects]; + } else { + NSString *bidi = [self _stringForNode:element property:@"unicode-bidi"]; + if (bidi && [bidi isEqualToString:@"embed"]) { + NSUInteger val = NSTextWritingDirectionEmbedding; + NSString *direction = [self _stringForNode:element property:@"direction"]; + if ([direction isEqualToString:@"rtl"]) val |= NSWritingDirectionRightToLeft; + [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]]; + } else if (bidi && [bidi isEqualToString:@"bidi-override"]) { + NSUInteger val = NSTextWritingDirectionOverride; + NSString *direction = [self _stringForNode:element property:@"direction"]; + if ([direction isEqualToString:@"rtl"]) val |= NSWritingDirectionRightToLeft; + [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]]; + } + } + if ([@"table" isEqualToString:displayVal] || ([_textTables count] == 0 && [@"table-row-group" isEqualToString:displayVal])) { + DOMElement *tableElement = element; + if ([@"table-row-group" isEqualToString:displayVal]) { + // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table + tableElement = [self _blockLevelElementForNode:[element parentNode]]; + if (![@"table" isEqualToString:[self _stringForNode:tableElement property:@"display"]]) tableElement = element; + } + while ([_textTables count] > [_textBlocks count]) { + [self _addTableCellForElement:nil]; + } + [self _addTableForElement:tableElement]; + } else if ([@"table-footer-group" isEqualToString:displayVal] && [_textTables count] > 0) { + [_textTableFooters setObject:element forKey:[NSValue valueWithNonretainedObject:[_textTables lastObject]]]; + retval = NO; + } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 0) { + NSColor *color = [self _colorForNode:element property:@"background-color"]; + if (!color) color = [NSColor clearColor]; + [_textTableRowBackgroundColors addObject:color]; + } else if ([@"table-cell" isEqualToString:displayVal]) { + while ([_textTables count] < [_textBlocks count] + 1) { + [self _addTableForElement:nil]; + } + [self _addTableCellForElement:element]; + } else if ([@"IMG" isEqualToString:tag]) { + NSString *urlString = [element getAttribute:@"src"]; + if (urlString && [urlString length] > 0) { + NSURL *url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); + if (!url) url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL]; + if (url) [self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:YES]; + } + retval = NO; + } else if ([@"OBJECT" isEqualToString:tag]) { + NSString *baseString = [element getAttribute:@"codebase"], *urlString = [element getAttribute:@"data"], *declareString = [element getAttribute:@"declare"]; + if (urlString && [urlString length] > 0 && ![@"true" isEqualToString:declareString]) { + NSURL *baseURL = nil, *url = nil; + if (baseString && [baseString length] > 0) { + baseURL = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(baseString)); + if (!baseURL) baseURL = [NSURL _web_URLWithString:[baseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL]; + } + if (baseURL) url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:baseURL]; + if (!url) url =core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); + if (!url) url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL]; + if (url) retval = ![self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:NO]; + } + } else if ([@"FRAME" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(contentDocument)]) { + DOMDocument *contentDocument = [(DOMHTMLFrameElement *)element contentDocument]; + if (contentDocument) [self _traverseNode:contentDocument depth:depth + 1 embedded:YES]; + } + retval = NO; + } else if ([@"IFRAME" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(contentDocument)]) { + DOMDocument *contentDocument = [(DOMHTMLIFrameElement *)element contentDocument]; + if (contentDocument) { + [self _traverseNode:contentDocument depth:depth + 1 embedded:YES]; + retval = NO; + } + } + } else if ([@"BR" isEqualToString:tag]) { + DOMElement *blockElement = [self _blockLevelElementForNode:[element parentNode]]; + NSString *breakClass = [element getAttribute:@"class"], *blockTag = [blockElement tagName]; + BOOL isExtraBreak = [@"Apple-interchange-newline" isEqualToString:breakClass], blockElementIsParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length])); + if (isExtraBreak) { + _flags.hasTrailingNewline = YES; + } else { + if (blockElement && blockElementIsParagraph) { + [self _newLineForElement:element]; + } else { + [self _newParagraphForElement:element tag:tag allowEmpty:YES suppressTrailingSpace:NO]; + } + } + } else if ([@"UL" isEqualToString:tag]) { + NSTextList *list; + NSString *listStyleType = [self _stringForNode:element property:@"list-style-type"]; + if (!listStyleType || [listStyleType length] == 0) listStyleType = @"disc"; + list = [[NSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}", listStyleType] options:0]; + [_textLists addObject:list]; + [list release]; + } else if ([@"OL" isEqualToString:tag]) { + NSTextList *list; + NSString *listStyleType = [self _stringForNode:element property:@"list-style-type"]; + if (!listStyleType || [listStyleType length] == 0) listStyleType = @"decimal"; + list = [[NSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}.", listStyleType] options:0]; + if ([element respondsToSelector:@selector(start)]) { + NSInteger startingItemNumber = [(DOMHTMLOListElement *)element start]; + [list setStartingItemNumber:startingItemNumber]; + } + [_textLists addObject:list]; + [list release]; + } else if ([@"Q" isEqualToString:tag]) { + [self _addQuoteForElement:element opening:YES level:_quoteLevel++]; + } else if ([@"INPUT" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(type)] && [element respondsToSelector:@selector(value)] && [@"text" compare:[(DOMHTMLInputElement *)element type] options:NSCaseInsensitiveSearch] == NSOrderedSame) { + NSString *value = [(DOMHTMLInputElement *)element value]; + if (value && [value length] > 0) [self _addValue:value forElement:element]; + } + } else if ([@"TEXTAREA" isEqualToString:tag]) { + if ([element respondsToSelector:@selector(value)]) { + NSString *value = [(DOMHTMLTextAreaElement *)element value]; + if (value && [value length] > 0) [self _addValue:value forElement:element]; + } + retval = NO; + } + return retval; +} + +- (void)_addMarkersToList:(NSTextList *)list range:(NSRange)range +{ + NSInteger itemNum = [list startingItemNumber]; + NSString *string = [_attrStr string], *stringToInsert; + NSDictionary *attrsToInsert = nil; + NSFont *font; + NSParagraphStyle *paragraphStyle; + NSMutableParagraphStyle *newStyle; + NSTextTab *tab = nil, *tabToRemove; + NSRange paragraphRange, styleRange; + NSUInteger textLength = [_attrStr length], listIndex, idx, insertLength, i, count; + NSArray *textLists; + CGFloat markerLocation, listLocation, pointSize; + + if (range.length == 0 || range.location >= textLength) return; + if (NSMaxRange(range) > textLength) range.length = textLength - range.location; + paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:range.location effectiveRange:NULL]; + if (paragraphStyle) { + textLists = [paragraphStyle textLists]; + listIndex = [textLists indexOfObject:list]; + if (textLists && listIndex != NSNotFound) { + for (idx = range.location; idx < NSMaxRange(range);) { + paragraphRange = [string paragraphRangeForRange:NSMakeRange(idx, 0)]; + paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:idx effectiveRange:&styleRange]; + font = [_attrStr attribute:NSFontAttributeName atIndex:idx effectiveRange:NULL]; + pointSize = font ? [font pointSize] : 12; + if ([[paragraphStyle textLists] count] == listIndex + 1) { + stringToInsert = [NSString stringWithFormat:@"\t%@\t", [list markerForItemNumber:itemNum++]]; + insertLength = [stringToInsert length]; + if (!_flags.isIndexing && !_flags.isTesting) attrsToInsert = [NSTextList _standardMarkerAttributesForAttributes:[_attrStr attributesAtIndex:paragraphRange.location effectiveRange:NULL]]; + [_attrStr replaceCharactersInRange:NSMakeRange(paragraphRange.location, 0) withString:stringToInsert]; + if (!_flags.isIndexing && !_flags.isTesting) [_attrStr setAttributes:attrsToInsert range:NSMakeRange(paragraphRange.location, insertLength)]; + range.length += insertLength; + paragraphRange.length += insertLength; + if (paragraphRange.location < _domRangeStartIndex) _domRangeStartIndex += insertLength; + + newStyle = [paragraphStyle mutableCopy]; + listLocation = (listIndex + 1) * 36; + markerLocation = listLocation - 25; + [newStyle setFirstLineHeadIndent:0]; + [newStyle setHeadIndent:listLocation]; + while ((count = [[newStyle tabStops] count]) > 0) { + for (i = 0, tabToRemove = nil; !tabToRemove && i < count; i++) { + tab = [[newStyle tabStops] objectAtIndex:i]; + if ([tab location] <= listLocation) tabToRemove = tab; + } + if (tabToRemove) [newStyle removeTabStop:tab]; else break; + } + tab = [[NSTextTab alloc] initWithType:NSLeftTabStopType location:markerLocation]; + [newStyle addTabStop:tab]; + [tab release]; + tab = [[NSTextTab alloc] initWithTextAlignment:NSNaturalTextAlignment location:listLocation options:nil]; + [newStyle addTabStop:tab]; + [tab release]; + if (!_flags.isIndexing && !_flags.isTesting) [_attrStr addAttribute:NSParagraphStyleAttributeName value:newStyle range:paragraphRange]; + [newStyle release]; + + idx = NSMaxRange(paragraphRange); + } else { + // skip any deeper-nested lists + idx = NSMaxRange(styleRange); + } + } + } + } +} + +- (void)_exitElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth startIndex:(NSUInteger)startIndex +{ + NSRange range = NSMakeRange(startIndex, [_attrStr length] - startIndex); + if (range.length > 0 && [@"A" isEqualToString:tag]) { + NSString *urlString = [element getAttribute:@"href"], *strippedString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (urlString && [urlString length] > 0 && strippedString && [strippedString length] > 0 && ![strippedString hasPrefix:@"#"]) { + NSURL *url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); + if (!url) url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(strippedString)); + if (!url) url = [NSURL _web_URLWithString:strippedString relativeToURL:_baseURL]; + if (!_flags.isIndexing && !_flags.isTesting) [_attrStr addAttribute:NSLinkAttributeName value:url ? (id)url : (id)urlString range:range]; + } + } + if (!_flags.reachedEnd && [self _elementIsBlockLevel:element]) { + [_writingDirectionArray removeAllObjects]; + if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] == 0) { + [self _newTabForElement:element]; + } else if ([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag]) { + [self _newLineForElement:element]; + } else { + [self _newParagraphForElement:element tag:tag allowEmpty:(range.length == 0) suppressTrailingSpace:YES]; + } + } else if ([_writingDirectionArray count] > 0) { + NSString *bidi = [self _stringForNode:element property:@"unicode-bidi"]; + if (bidi && ([bidi isEqualToString:@"embed"] || [bidi isEqualToString:@"bidi-override"])) { + [_writingDirectionArray removeLastObject]; + } + } + range = NSMakeRange(startIndex, [_attrStr length] - startIndex); + if ([@"table" isEqualToString:displayVal] && [_textTables count] > 0) { + NSValue *key = [NSValue valueWithNonretainedObject:[_textTables lastObject]]; + DOMNode *footer = [_textTableFooters objectForKey:key]; + while ([_textTables count] < [_textBlocks count] + 1) { + [_textBlocks removeLastObject]; + } + if (footer) { + [self _traverseFooterNode:footer depth:depth + 1]; + [_textTableFooters removeObjectForKey:key]; + } + [_textTables removeLastObject]; + [_textTableSpacings removeLastObject]; + [_textTablePaddings removeLastObject]; + [_textTableRows removeLastObject]; + [_textTableRowArrays removeLastObject]; + } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 0) { + NSTextTable *table = [_textTables lastObject]; + NSTextTableBlock *block; + NSMutableArray *rowArray = [_textTableRowArrays lastObject], *previousRowArray; + NSUInteger i, count; + NSInteger numberOfColumns = [table numberOfColumns]; + NSInteger openColumn; + NSInteger rowNumber = [[_textTableRows lastObject] integerValue]; + do { + rowNumber++; + previousRowArray = rowArray; + rowArray = [NSMutableArray array]; + count = [previousRowArray count]; + for (i = 0; i < count; i++) { + block = [previousRowArray objectAtIndex:i]; + if ([block startingColumn] + [block columnSpan] > numberOfColumns) numberOfColumns = [block startingColumn] + [block columnSpan]; + if ([block startingRow] + [block rowSpan] > rowNumber) [rowArray addObject:block]; + } + count = [rowArray count]; + openColumn = 0; + for (i = 0; i < count; i++) { + block = [rowArray objectAtIndex:i]; + if (openColumn >= [block startingColumn] && openColumn < [block startingColumn] + [block columnSpan]) openColumn = [block startingColumn] + [block columnSpan]; + } + } while (openColumn >= numberOfColumns); + if ((NSUInteger)numberOfColumns > [table numberOfColumns]) [table setNumberOfColumns:numberOfColumns]; + [_textTableRows removeLastObject]; + [_textTableRows addObject:[NSNumber numberWithInteger:rowNumber]]; + [_textTableRowArrays removeLastObject]; + [_textTableRowArrays addObject:rowArray]; + if ([_textTableRowBackgroundColors count] > 0) [_textTableRowBackgroundColors removeLastObject]; + } else if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] > 0) { + while ([_textTables count] > [_textBlocks count]) { + [_textTables removeLastObject]; + [_textTableSpacings removeLastObject]; + [_textTablePaddings removeLastObject]; + [_textTableRows removeLastObject]; + [_textTableRowArrays removeLastObject]; + } + [_textBlocks removeLastObject]; + } else if (([@"UL" isEqualToString:tag] || [@"OL" isEqualToString:tag]) && [_textLists count] > 0) { + NSTextList *list = [_textLists lastObject]; + [self _addMarkersToList:list range:range]; + [_textLists removeLastObject]; + } else if ([@"Q" isEqualToString:tag]) { + [self _addQuoteForElement:element opening:NO level:--_quoteLevel]; + } else if ([@"SPAN" isEqualToString:tag]) { + NSString *className = [element getAttribute:@"class"]; + NSMutableString *mutableString; + NSUInteger i, count = 0; + unichar c; + if ([@"Apple-converted-space" isEqualToString:className]) { + mutableString = [_attrStr mutableString]; + for (i = range.location; i < NSMaxRange(range); i++) { + c = [mutableString characterAtIndex:i]; + if (0xa0 == c) [mutableString replaceCharactersInRange:NSMakeRange(i, 1) withString:@" "]; + } + } else if ([@"Apple-converted-tab" isEqualToString:className]) { + mutableString = [_attrStr mutableString]; + for (i = range.location; i < NSMaxRange(range); i++) { + NSRange rangeToReplace = NSMakeRange(NSNotFound, 0); + c = [mutableString characterAtIndex:i]; + if (' ' == c || 0xa0 == c) { + count++; + if (count >= 4 || i + 1 >= NSMaxRange(range)) rangeToReplace = NSMakeRange(i + 1 - count, count); + } else { + if (count > 0) rangeToReplace = NSMakeRange(i - count, count); + } + if (rangeToReplace.length > 0) { + [mutableString replaceCharactersInRange:rangeToReplace withString:@"\t"]; + range.length -= (rangeToReplace.length - 1); + i -= (rangeToReplace.length - 1); + if (NSMaxRange(rangeToReplace) <= _domRangeStartIndex) { + _domRangeStartIndex -= (rangeToReplace.length - 1); + } else if (rangeToReplace.location < _domRangeStartIndex) { + _domRangeStartIndex = rangeToReplace.location; + } + count = 0; + } + } + } + } +} + +- (void)_processText:(DOMCharacterData *)text +{ + NSString *instr = [text data], *outstr = instr, *whitespaceVal, *transformVal; + NSUInteger textLength = [_attrStr length], startOffset = 0, endOffset = [instr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n'; + BOOL wasSpace = NO, wasLeading = YES, suppressLeadingSpace = ((_flags.isSoft && lastChar == ' ') || lastChar == '\n' || lastChar == '\r' || lastChar == '\t' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == NSFormFeedCharacter || lastChar == WebNextLineCharacter); + NSRange rangeToReplace = NSMakeRange(textLength, 0); + CFMutableStringRef mutstr = NULL; + whitespaceVal = [self _stringForNode:text property:@"white-space"]; + transformVal = [self _stringForNode:text property:@"text-transform"]; + + if (_domRange) { + if (text == [_domRange startContainer]) { + startOffset = (NSUInteger)[_domRange startOffset]; + _domRangeStartIndex = [_attrStr length]; + _flags.reachedStart = YES; + } + if (text == [_domRange endContainer]) { + endOffset = (NSUInteger)[_domRange endOffset]; + _flags.reachedEnd = YES; + } + if ((startOffset > 0 || endOffset < [instr length]) && endOffset >= startOffset) { + instr = [instr substringWithRange:NSMakeRange(startOffset, endOffset - startOffset)]; + outstr = instr; + } + } + if ([whitespaceVal hasPrefix:@"pre"]) { + if (textLength > 0 && [instr length] > 0 && _flags.isSoft) { + unichar c = [instr characterAtIndex:0]; + if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter) rangeToReplace = NSMakeRange(textLength - 1, 1); + } + } else { + CFStringInlineBuffer inlineBuffer; + const unsigned int TextBufferSize = 255; + + unichar buffer[TextBufferSize + 1]; + NSUInteger i, count = [instr length], idx = 0; + + mutstr = CFStringCreateMutable(NULL, 0); + CFStringInitInlineBuffer((CFStringRef)instr, &inlineBuffer, CFRangeMake(0, count)); + for (i = 0; i < count; i++) { + unichar c = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i); + if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b) { + wasSpace = (!wasLeading || !suppressLeadingSpace); + } else { + if (wasSpace) buffer[idx++] = ' '; + buffer[idx++] = c; + if (idx >= TextBufferSize) { + CFStringAppendCharacters(mutstr, buffer, idx); + idx = 0; + } + wasSpace = wasLeading = NO; + } + } + if (wasSpace) buffer[idx++] = ' '; + if (idx > 0) CFStringAppendCharacters(mutstr, buffer, idx); + outstr = (NSString *)mutstr; + } + if ([outstr length] > 0) { + if ([@"capitalize" isEqualToString:transformVal]) { + outstr = [outstr capitalizedString]; + } else if ([@"uppercase" isEqualToString:transformVal]) { + outstr = [outstr uppercaseString]; + } else if ([@"lowercase" isEqualToString:transformVal]) { + outstr = [outstr lowercaseString]; + } + [_attrStr replaceCharactersInRange:rangeToReplace withString:outstr]; + rangeToReplace.length = [outstr length]; + if (!_flags.isIndexing) { + NSDictionary *attrs; + DOMElement *element = (DOMElement *)text; + while (element && [element nodeType] != DOM_ELEMENT_NODE) element = (DOMElement *)[element parentNode]; + attrs = [self _attributesForElement:element]; + if (!_flags.isTesting && rangeToReplace.length > 0) [_attrStr setAttributes:attrs range:rangeToReplace]; + } + _flags.isSoft = wasSpace; + } + if (mutstr) CFRelease(mutstr); +} + +- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded +{ + unsigned short nodeType; + NSArray *childNodes; + NSUInteger i, count, startOffset, endOffset; + BOOL isStart = NO, isEnd = NO; + + if (_flags.reachedEnd) return; + if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node]) return; + + nodeType = [node nodeType]; + childNodes = [self _childrenForNode:node]; + count = [childNodes count]; + startOffset = 0; + endOffset = count; + + if (_domRange) { + if (node == [_domRange startContainer]) { + startOffset = (NSUInteger)[_domRange startOffset]; + isStart = YES; + _flags.reachedStart = YES; + } + if (node == [_domRange endContainer]) { + endOffset = (NSUInteger)[_domRange endOffset]; + isEnd = YES; + } + } + + if (nodeType == DOM_DOCUMENT_NODE || nodeType == DOM_DOCUMENT_FRAGMENT_NODE) { + for (i = 0; i < count; i++) { + if (isStart && i == startOffset) _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded]; + if (isEnd && i + 1 >= endOffset) _flags.reachedEnd = YES; + if (_thumbnailLimit > 0 && [_attrStr length] >= _thumbnailLimit) _flags.reachedEnd = YES; + if (_flags.reachedEnd) break; + } + } else if (nodeType == DOM_ELEMENT_NODE) { + DOMElement *element = (DOMElement *)node; + NSString *tag = [element tagName], *displayVal = [self _stringForNode:element property:@"display"], *floatVal = [self _stringForNode:element property:@"float"]; + BOOL isBlockLevel = NO; + if (floatVal && ([@"left" isEqualToString:floatVal] || [@"right" isEqualToString:floatVal])) { + isBlockLevel = YES; + } else if (displayVal) { + isBlockLevel = ([@"block" isEqualToString:displayVal] || [@"list-item" isEqualToString:displayVal] || [displayVal hasPrefix:@"table"]); + } + [_elementIsBlockLevel setObject:[NSNumber numberWithBool:isBlockLevel] forKey:element]; + if ([self _enterElement:element tag:tag display:displayVal]) { + NSUInteger startIndex = [_attrStr length]; + if ([self _processElement:element tag:tag display:displayVal depth:depth]) { + for (i = 0; i < count; i++) { + if (isStart && i == startOffset) _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded]; + if (isEnd && i + 1 >= endOffset) _flags.reachedEnd = YES; + if (_flags.reachedEnd) break; + } + [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex]; + } + } + } else if (nodeType == DOM_TEXT_NODE || nodeType == DOM_CDATA_SECTION_NODE) { + [self _processText:(DOMCharacterData *)node]; + } + + if (isEnd) _flags.reachedEnd = YES; +} + +- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth +{ + DOMElement *element = (DOMElement *)node; + NSArray *childNodes = [self _childrenForNode:node]; + NSString *tag = @"TBODY", *displayVal = @"table-row-group"; + NSUInteger i, count = [childNodes count], startOffset = 0, endOffset = count; + BOOL isStart = NO, isEnd = NO; + + if (_flags.reachedEnd) return; + if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node]) return; + if (_domRange) { + if (node == [_domRange startContainer]) { + startOffset = (NSUInteger)[_domRange startOffset]; + isStart = YES; + _flags.reachedStart = YES; + } + if (node == [_domRange endContainer]) { + endOffset = (NSUInteger)[_domRange endOffset]; + isEnd = YES; + } + } + if ([self _enterElement:element tag:tag display:displayVal]) { + NSUInteger startIndex = [_attrStr length]; + if ([self _processElement:element tag:tag display:displayVal depth:depth]) { + for (i = 0; i < count; i++) { + if (isStart && i == startOffset) _domRangeStartIndex = [_attrStr length]; + if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i)) [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:YES]; + if (isEnd && i + 1 >= endOffset) _flags.reachedEnd = YES; + if (_flags.reachedEnd) break; + } + [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex]; + } + } + if (isEnd) _flags.reachedEnd = YES; +} + +- (void)_adjustTrailingNewline +{ + NSUInteger textLength = [_attrStr length]; + unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : 0; + BOOL alreadyHasTrailingNewline = (lastChar == '\n' || lastChar == '\r' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == WebNextLineCharacter); + if (_flags.hasTrailingNewline && !alreadyHasTrailingNewline) + [_attrStr replaceCharactersInRange:NSMakeRange(textLength, 0) withString:@"\n"]; +} + +- (void)_loadFromDOMRange +{ + if (-1 == _errorCode) { + DOMNode *commonAncestorContainer = [_domRange commonAncestorContainer], *ancestorContainer = [_domRange startContainer]; + + _domStartAncestors = [[NSMutableArray alloc] init]; + while (ancestorContainer) { + [_domStartAncestors addObject:ancestorContainer]; + if (ancestorContainer == commonAncestorContainer) break; + ancestorContainer = [ancestorContainer parentNode]; + } + _document = [commonAncestorContainer ownerDocument]; + _dataSource = (DocumentLoader *)core(_document)->frame()->loader()->documentLoader(); + if (_textSizeMultiplier <= 0.0) _textSizeMultiplier = 1; + if (_defaultFontSize <= 0.0) _defaultFontSize = 12; + if (_minimumFontSize < 1.0) _minimumFontSize = 1; + if (_document && _dataSource) { + _domRangeStartIndex = 0; + _errorCode = 0; + [self _traverseNode:commonAncestorContainer depth:0 embedded:NO]; + if (_domRangeStartIndex > 0 && _domRangeStartIndex <= [_attrStr length]) [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)]; + } + } +} + +- (void)dealloc +{ + [_attrStr release]; + [_domRange release]; + [_domStartAncestors release]; + [_standardFontFamily release]; + [_textLists release]; + [_textBlocks release]; + [_textTables release]; + [_textTableFooters release]; + [_textTableSpacings release]; + [_textTablePaddings release]; + [_textTableRows release]; + [_textTableRowArrays release]; + [_textTableRowBackgroundColors release]; + [_computedStylesForElements release]; + [_specifiedStylesForElements release]; + [_stringsForNodes release]; + [_floatsForNodes release]; + [_colorsForNodes release]; + [_attributesForElements release]; + [_elementIsBlockLevel release]; + [_fontCache release]; + [_writingDirectionArray release]; + [super dealloc]; +} + +- (id)init +{ + self = [super init]; + if (!self) return nil; + + _attrStr = [[NSMutableAttributedString alloc] init]; + + _textLists = [[NSMutableArray alloc] init]; + _textBlocks = [[NSMutableArray alloc] init]; + _textTables = [[NSMutableArray alloc] init]; + _textTableFooters = [[NSMutableDictionary alloc] init]; + _textTableSpacings = [[NSMutableArray alloc] init]; + _textTablePaddings = [[NSMutableArray alloc] init]; + _textTableRows = [[NSMutableArray alloc] init]; + _textTableRowArrays = [[NSMutableArray alloc] init]; + _textTableRowBackgroundColors = [[NSMutableArray alloc] init]; + _computedStylesForElements = [[NSMutableDictionary alloc] init]; + _specifiedStylesForElements = [[NSMutableDictionary alloc] init]; + _stringsForNodes = [[NSMutableDictionary alloc] init]; + _floatsForNodes = [[NSMutableDictionary alloc] init]; + _colorsForNodes = [[NSMutableDictionary alloc] init]; + _attributesForElements = [[NSMutableDictionary alloc] init]; + _elementIsBlockLevel = [[NSMutableDictionary alloc] init]; + _fontCache = [[NSMutableDictionary alloc] init]; + _writingDirectionArray = [[NSMutableArray alloc] init]; + + _textSizeMultiplier = 1; + _webViewTextSizeMultiplier = 0; + _defaultTabInterval = 36; + _defaultFontSize = 12; + _minimumFontSize = 1; + _errorCode = -1; + _indexingLimit = 0; + _thumbnailLimit = 0; + + _flags.isIndexing = (_indexingLimit > 0); + _flags.isTesting = 0; + + return self; +} + +- (id)initWithDOMRange:(DOMRange *)domRange +{ + self = [self init]; + if (!self) return nil; + _domRange = [domRange retain]; + return self; +} + +- (NSAttributedString *)attributedString +{ + [self _loadFromDOMRange]; + return (0 == _errorCode) ? [[_attrStr retain] autorelease] : nil; +} + +@end +#endif diff --git a/Source/WebCore/platform/mac/LoggingMac.mm b/Source/WebCore/platform/mac/LoggingMac.mm index ee2f39e..168d0cc 100644 --- a/Source/WebCore/platform/mac/LoggingMac.mm +++ b/Source/WebCore/platform/mac/LoggingMac.mm @@ -23,6 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" + #include "Logging.h" namespace WebCore { diff --git a/Source/WebCore/platform/mac/PasteboardMac.mm b/Source/WebCore/platform/mac/PasteboardMac.mm index 8c6610a..da06606 100644 --- a/Source/WebCore/platform/mac/PasteboardMac.mm +++ b/Source/WebCore/platform/mac/PasteboardMac.mm @@ -38,6 +38,10 @@ #import "FrameLoaderClient.h" #import "HitTestResult.h" #import "HTMLAnchorElement.h" +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#import "HTMLConverter.h" +#endif +#import "htmlediting.h" #import "HTMLNames.h" #import "Image.h" #import "KURL.h" @@ -144,9 +148,30 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTyp Pasteboard::generalPasteboard(); // Initializes pasteboard types. ASSERT(selectedRange); + // If the selection is at the beginning of content inside an anchor tag + // we move the selection start to include the anchor. + // This way the attributed string will contain the url attribute as well. + // See <rdar://problem/9084267>. + ExceptionCode ec; + Node* commonAncestor = selectedRange->commonAncestorContainer(ec); + ASSERT(commonAncestor); + Node* enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(commonAncestor), HTMLNames::aTag); + if (enclosingAnchor && comparePositions(firstPositionInOrBeforeNode(selectedRange->startPosition().anchorNode()), selectedRange->startPosition()) >= 0) + selectedRange->setStart(enclosingAnchor, 0, ec); + // Using different API for WebKit and WebKit2. - // FIXME - We need to have a way to create the NSAttributedString for WebKit2 that doesn't require accessing the WebFrame. - NSAttributedString *attributedString = (frame->view()->platformWidget()) ? [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease] : [[[NSAttributedString alloc] initWithString:selectedRange->text()] autorelease]; + NSAttributedString *attributedString = nil; + if (frame->view()->platformWidget()) + attributedString = [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease]; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + else { + // In WebKit2 we are using a different way to create the NSAttributedString from the DOMrange that doesn't require access to the WebView. + RetainPtr<WebHTMLConverter> converter = [[WebHTMLConverter alloc] initWithDOMRange:kit(selectedRange)]; + if (converter) + attributedString = [converter.get() attributedString]; + } +#endif + #ifdef BUILDING_ON_TIGER // 4930197: Mail overrides [WebHTMLView pasteboardTypesForSelection] in order to add another type to the pasteboard // after WebKit does. On Tiger we must call this function so that Mail code will be executed, meaning that diff --git a/Source/WebCore/platform/mac/PlatformScreenMac.mm b/Source/WebCore/platform/mac/PlatformScreenMac.mm index 5dbfcf4..916fc9f 100644 --- a/Source/WebCore/platform/mac/PlatformScreenMac.mm +++ b/Source/WebCore/platform/mac/PlatformScreenMac.mm @@ -76,12 +76,21 @@ NSScreen *screenForWindow(NSWindow *window) return nil; } +static CGFloat windowScaleFactor(NSWindow *window) +{ +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + return [window backingScaleFactor]; +#else + return [window userSpaceScaleFactor]; +#endif +} + FloatRect toUserSpace(const NSRect& rect, NSWindow *destination) { FloatRect userRect = rect; userRect.setY(NSMaxY([screenForWindow(destination) frame]) - (userRect.y() + userRect.height())); // flip if (destination) - userRect.scale(1 / [destination userSpaceScaleFactor]); // scale down + userRect.scale(1 / windowScaleFactor(destination)); // scale down return userRect; } @@ -89,7 +98,7 @@ NSRect toDeviceSpace(const FloatRect& rect, NSWindow *source) { FloatRect deviceRect = rect; if (source) - deviceRect.scale([source userSpaceScaleFactor]); // scale up + deviceRect.scale(windowScaleFactor(source)); // scale up deviceRect.setY(NSMaxY([screenForWindow(source) frame]) - (deviceRect.y() + deviceRect.height())); // flip return deviceRect; } diff --git a/Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp b/Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp new file mode 100644 index 0000000..0a1a4d8 --- /dev/null +++ b/Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2003, 2005, 2008, 2011 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. + */ + +#include "config.h" +#include "SSLKeyGenerator.h" + +#include "KURL.h" +#include "LocalizedStrings.h" +#include "WebCoreSystemInterface.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +void getSupportedKeySizes(Vector<String>& supportedKeySizes) +{ + ASSERT(supportedKeySizes.isEmpty()); + supportedKeySizes.append(keygenMenuItem2048()); + supportedKeySizes.append(keygenMenuItem1024()); + supportedKeySizes.append(keygenMenuItem512()); +} + +String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const KURL& url) +{ + // This switch statement must always be synced with the UI strings returned by getSupportedKeySizes. + UInt32 keySize; + switch (keySizeIndex) { + case 0: + keySize = 2048; + break; + case 1: + keySize = 1024; + break; + case 2: + keySize = 512; + break; + default: + ASSERT_NOT_REACHED(); + return String(); + } + + RetainPtr<CFStringRef> challengeStringCF(AdoptCF, challengeString.createCFString()); + RetainPtr<CFStringRef> keyDescription(AdoptCF, keygenKeychainItemName(url.host()).createCFString()); + RetainPtr<CFStringRef> result(AdoptCF, wkSignedPublicKeyAndChallengeString(keySize, challengeStringCF.get(), keyDescription.get())); + + return result.get(); +} + +} diff --git a/Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm b/Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm deleted file mode 100644 index dd76b59..0000000 --- a/Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2003, 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR - * 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 "config.h" -#import "SSLKeyGenerator.h" - -#import "KURL.h" -#import "WebCoreKeyGenerator.h" - -namespace WebCore { - -void getSupportedKeySizes(Vector<String>& supportedKeySizes) -{ - NSEnumerator *enumerator = [[[WebCoreKeyGenerator sharedGenerator] strengthMenuItemTitles] objectEnumerator]; - NSString *string; - while ((string = [enumerator nextObject]) != nil) - supportedKeySizes.append(string); -} - -String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const KURL& url) -{ - return [[WebCoreKeyGenerator sharedGenerator] signedPublicKeyAndChallengeStringWithStrengthIndex:keySizeIndex - challenge:challengeString - pageURL:url]; -} - -} diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.h b/Source/WebCore/platform/mac/ScrollAnimatorMac.h index 2bafbf5..f7b6332 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.h +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.h @@ -30,7 +30,6 @@ #include "FloatPoint.h" #include "FloatSize.h" -#include "HeaderDetection.h" #include "ScrollAnimator.h" #include "Timer.h" #include "WebCoreSystemInterface.h" @@ -67,6 +66,8 @@ public: #endif #endif + virtual void cancelAnimations(); + void immediateScrollToPoint(const FloatPoint& newPosition); void immediateScrollByDeltaX(float deltaX); void immediateScrollByDeltaY(float deltaY); @@ -74,14 +75,25 @@ public: void setIsDrawingIntoLayer(bool b) { m_drawingIntoLayer = b; } bool isDrawingIntoLayer() const { return m_drawingIntoLayer; } + bool haveScrolledSincePageLoad() const { return m_haveScrolledSincePageLoad; } + +#if USE(WK_SCROLLBAR_PAINTER) + bool scrollbarPaintTimerIsActive() const; + void startScrollbarPaintTimer(); + void stopScrollbarPaintTimer(); +#endif + private: RetainPtr<id> m_scrollAnimationHelper; RetainPtr<ScrollAnimationHelperDelegate> m_scrollAnimationHelperDelegate; -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) RetainPtr<WKScrollbarPainterControllerRef> m_scrollbarPainterController; RetainPtr<ScrollbarPainterControllerDelegate> m_scrollbarPainterControllerDelegate; RetainPtr<id> m_scrollbarPainterDelegate; + + void initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*); + Timer<ScrollAnimatorMac> m_initialScrollbarPaintTimer; #endif virtual void notityPositionChanged(); @@ -131,6 +143,7 @@ private: Timer<ScrollAnimatorMac> m_snapRubberBandTimer; #endif bool m_drawingIntoLayer; + bool m_haveScrolledSincePageLoad; }; } // namespace WebCore diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm index 67c0904..5725880 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm @@ -141,7 +141,7 @@ static NSSize abs(NSSize size) @end -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) @interface ScrollbarPainterControllerDelegate : NSObject { @@ -240,6 +240,13 @@ static NSSize abs(NSSize size) verticalScrollbar->controlSize(), false); macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter); + wkSetPainterForPainterController(painterController, newVerticalPainter, false); + + // The different scrollbar styles have different thicknesses, so we must re-set the + // frameRect to the new thickness, and the re-layout below will ensure the position + // and length are properly updated. + int thickness = macTheme->scrollbarThickness(verticalScrollbar->controlSize()); + verticalScrollbar->setFrameRect(WebCore::IntRect(0, 0, thickness, thickness)); } WKScrollbarPainterRef oldHorizontalPainter = wkHorizontalScrollbarPainterForController(painterController); @@ -250,9 +257,19 @@ static NSSize abs(NSSize size) horizontalScrollbar->controlSize(), true); macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter); + wkSetPainterForPainterController(painterController, newHorizontalPainter, true); + + // The different scrollbar styles have different thicknesses, so we must re-set the + // frameRect to the new thickness, and the re-layout below will ensure the position + // and length are properly updated. + int thickness = macTheme->scrollbarThickness(horizontalScrollbar->controlSize()); + horizontalScrollbar->setFrameRect(WebCore::IntRect(0, 0, thickness, thickness)); } wkSetScrollbarPainterControllerStyle(painterController, newRecommendedScrollerStyle); + + // The different scrollbar styles affect layout, so we must re-layout everything. + _animator->scrollableArea()->scrollbarStyleChanged(); } @end @@ -329,6 +346,7 @@ static NSSize abs(NSSize size) RetainPtr<ScrollbarPartAnimation> _horizontalTrackAnimation; } - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; +- (void)cancelAnimations; @end @implementation ScrollbarPainterDelegate @@ -343,6 +361,14 @@ static NSSize abs(NSSize size) return self; } +- (void)cancelAnimations +{ + [_verticalKnobAnimation.get() stopAnimation]; + [_horizontalKnobAnimation.get() stopAnimation]; + [_verticalTrackAnimation.get() stopAnimation]; + [_horizontalTrackAnimation.get() stopAnimation]; +} + - (NSRect)convertRectToBacking:(NSRect)aRect { return aRect; @@ -367,12 +393,29 @@ static NSSize abs(NSSize size) - (void)setUpAnimation:(RetainPtr<ScrollbarPartAnimation>&)scrollbarPartAnimation scrollerPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration { + // If the user has scrolled the page, then the scrollbars must be animated here. + // This overrides the early returns. + bool mustAnimate = _animator->haveScrolledSincePageLoad(); + + if (_animator->scrollbarPaintTimerIsActive() && !mustAnimate) + return; + + if (_animator->scrollableArea()->shouldSuspendScrollAnimations() && !mustAnimate) { + _animator->startScrollbarPaintTimer(); + return; + } + + // At this point, we are definitely going to animate now, so stop the timer. + _animator->stopScrollbarPaintTimer(); + // If we are currently animating, stop if (scrollbarPartAnimation) { [scrollbarPartAnimation.get() stopAnimation]; scrollbarPartAnimation = nil; } - + + [NSAnimationContext beginGrouping]; + [[NSAnimationContext currentContext] setDuration:duration]; scrollbarPartAnimation.adoptNS([[ScrollbarPartAnimation alloc] initWithScrollbarPainter:scrollerPainter part:part scrollAnimator:_animator @@ -380,6 +423,7 @@ static NSSize abs(NSSize size) duration:duration]); [scrollbarPartAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking]; [scrollbarPartAnimation.get() startAnimation]; + [NSAnimationContext endGrouping]; } - (void)scrollerImp:(id)scrollerImp animateKnobAlphaTo:(CGFloat)newKnobAlpha duration:(NSTimeInterval)duration @@ -388,9 +432,6 @@ static NSSize abs(NSSize size) return; WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; - if (newKnobAlpha == wkScrollbarPainterKnobAlpha(scrollerPainter)) - return; - if (wkScrollbarPainterIsHorizontal(scrollerPainter)) [self setUpAnimation:_horizontalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; else @@ -403,9 +444,6 @@ static NSSize abs(NSSize size) return; WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; - if (newTrackAlpha == wkScrollbarPainterTrackAlpha(scrollerPainter)) - return; - if (wkScrollbarPainterIsHorizontal(scrollerPainter)) [self setUpAnimation:_horizontalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; else @@ -414,20 +452,8 @@ static NSSize abs(NSSize size) - (void)scrollerImp:(id)scrollerImp overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState { - if (!_animator) - return; - - WKScrollbarPainterRef scrollbarPainter = (WKScrollbarPainterRef)scrollerImp; - wkScrollbarPainterSetOverlayState(scrollbarPainter, newOverlayScrollerState); - - if (wkScrollbarPainterIsHorizontal(scrollbarPainter)) { - WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar(); - _animator->scrollableArea()->invalidateScrollbarRect(horizontalScrollbar, WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); - } else { - WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar(); - _animator->scrollableArea()->invalidateScrollbarRect(verticalScrollbar, WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); - - } + UNUSED_PARAM(scrollerImp); + UNUSED_PARAM(newOverlayScrollerState); } - (void)scrollAnimatorDestroyed @@ -440,7 +466,8 @@ static NSSize abs(NSSize size) } @end -#endif // #if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + +#endif // USE(WK_SCROLLBAR_PAINTER) namespace WebCore { @@ -451,6 +478,9 @@ PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) : ScrollAnimator(scrollableArea) +#if USE(WK_SCROLLBAR_PAINTER) + , m_initialScrollbarPaintTimer(this, &ScrollAnimatorMac::initialScrollbarPaintTimerFired) +#endif #if ENABLE(RUBBER_BANDING) , m_inScrollGesture(false) , m_momentumScrollInProgress(false) @@ -460,11 +490,12 @@ ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired) #endif , m_drawingIntoLayer(false) + , m_haveScrolledSincePageLoad(false) { m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]); m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]); -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) m_scrollbarPainterControllerDelegate.adoptNS([[ScrollbarPainterControllerDelegate alloc] initWithScrollAnimator:this]); m_scrollbarPainterController = wkMakeScrollbarPainterController(m_scrollbarPainterControllerDelegate.get()); m_scrollbarPainterDelegate.adoptNS([[ScrollbarPainterDelegate alloc] initWithScrollAnimator:this]); @@ -473,7 +504,7 @@ ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) ScrollAnimatorMac::~ScrollAnimatorMac() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) [m_scrollbarPainterControllerDelegate.get() scrollAnimatorDestroyed]; [(id)m_scrollbarPainterController.get() setDelegate:nil]; [m_scrollbarPainterDelegate.get() scrollAnimatorDestroyed]; @@ -483,6 +514,8 @@ ScrollAnimatorMac::~ScrollAnimatorMac() bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) { + m_haveScrolledSincePageLoad = true; + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollAnimationEnabled"]) return ScrollAnimator::scroll(orientation, granularity, step, multiplier); @@ -561,7 +594,7 @@ void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY) void ScrollAnimatorMac::notityPositionChanged() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaScrolled(m_scrollbarPainterController.get()); #endif ScrollAnimator::notityPositionChanged(); @@ -569,70 +602,70 @@ void ScrollAnimatorMac::notityPositionChanged() void ScrollAnimatorMac::contentAreaWillPaint() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaWillPaint(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::mouseEnteredContentArea() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkMouseEnteredContentArea(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::mouseExitedContentArea() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkMouseExitedContentArea(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::mouseMovedInContentArea() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkMouseMovedInContentArea(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::willStartLiveResize() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkWillStartLiveResize(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::contentsResized() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaResized(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::willEndLiveResize() { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkWillEndLiveResize(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::contentAreaDidShow() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaDidShow(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::contentAreaDidHide() const { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) wkContentAreaDidHide(m_scrollbarPainterController.get()); #endif } void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, false); @@ -645,7 +678,7 @@ void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, nil); wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, false); @@ -656,7 +689,7 @@ void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, true); @@ -669,7 +702,7 @@ void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); wkScrollbarPainterSetDelegate(painter, nil); wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, true); @@ -678,6 +711,17 @@ void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) #endif } +void ScrollAnimatorMac::cancelAnimations() +{ + m_haveScrolledSincePageLoad = false; + +#if USE(WK_SCROLLBAR_PAINTER) + if (scrollbarPaintTimerIsActive()) + stopScrollbarPaintTimer(); + [m_scrollbarPainterDelegate.get() cancelAnimations]; +#endif +} + #if ENABLE(RUBBER_BANDING) static const float scrollVelocityZeroingTimeout = 0.10f; @@ -720,6 +764,8 @@ static float scrollWheelMultiplier() void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent) { + m_haveScrolledSincePageLoad = true; + if (!wheelEvent.hasPreciseScrollingDeltas()) { ScrollAnimator::handleWheelEvent(wheelEvent); return; @@ -751,18 +797,18 @@ bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) if (fabsf(deltaY) >= fabsf(deltaX)) { if (deltaY < 0) { // We are trying to scroll up. Make sure we are not pinned to the top - limitDelta.setHeight(m_scrollableArea->visibleContentRect().y()); + limitDelta.setHeight(m_scrollableArea->visibleContentRect().y() + + m_scrollableArea->scrollOrigin().y()); } else { // We are trying to scroll down. Make sure we are not pinned to the bottom - limitDelta.setHeight(m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleContentRect().maxY()); + limitDelta.setHeight(m_scrollableArea->contentsSize().height() - (m_scrollableArea->visibleContentRect().maxY() + m_scrollableArea->scrollOrigin().y())); } } else if (deltaX != 0) { if (deltaX < 0) { // We are trying to scroll left. Make sure we are not pinned to the left - limitDelta.setWidth(m_scrollableArea->visibleContentRect().x()); + limitDelta.setWidth(m_scrollableArea->visibleContentRect().x() + m_scrollableArea->scrollOrigin().x()); } else { // We are trying to scroll right. Make sure we are not pinned to the right - limitDelta.setWidth(m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleContentRect().maxX()); + limitDelta.setWidth(m_scrollableArea->contentsSize().width() - (m_scrollableArea->visibleContentRect().maxX() + m_scrollableArea->scrollOrigin().x())); } } @@ -793,6 +839,8 @@ bool ScrollAnimatorMac::allowsHorizontalStretching() const void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) { + m_haveScrolledSincePageLoad = true; + float deltaX = m_overflowScrollDelta.width(); float deltaY = m_overflowScrollDelta.height(); @@ -925,7 +973,7 @@ void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY); FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height()))); - FloatPoint origOrigin = m_scrollableArea->visibleContentRect().location() - stretchAmount; + FloatPoint origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - stretchAmount; FloatPoint newOrigin = origOrigin + dampedDelta; if (origOrigin != newOrigin) { @@ -945,6 +993,7 @@ void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) void ScrollAnimatorMac::beginScrollGesture() { + m_haveScrolledSincePageLoad = true; m_inScrollGesture = true; m_momentumScrollInProgress = false; m_ignoreMomentumScrolls = false; @@ -1017,7 +1066,7 @@ void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) return; } - m_origOrigin = m_scrollableArea->visibleContentRect().location() - m_startStretch; + m_origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - m_startStretch; m_origVelocity = m_momentumVelocity; // Just like normal scrolling, prefer vertical rubberbanding @@ -1069,6 +1118,28 @@ void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) } #endif +#if USE(WK_SCROLLBAR_PAINTER) +void ScrollAnimatorMac::startScrollbarPaintTimer() +{ + m_initialScrollbarPaintTimer.startOneShot(0.1); +} + +bool ScrollAnimatorMac::scrollbarPaintTimerIsActive() const +{ + return m_initialScrollbarPaintTimer.isActive(); +} + +void ScrollAnimatorMac::stopScrollbarPaintTimer() +{ + m_initialScrollbarPaintTimer.stop(); +} + +void ScrollAnimatorMac::initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*) +{ + wkScrollbarPainterForceFlashScrollers(m_scrollbarPainterController.get()); +} +#endif + } // namespace WebCore #endif // ENABLE(SMOOTH_SCROLLING) diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.h b/Source/WebCore/platform/mac/ScrollbarThemeMac.h index 844a088..bd56808 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.h +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.h @@ -26,7 +26,6 @@ #ifndef ScrollbarThemeMac_h #define ScrollbarThemeMac_h -#include "HeaderDetection.h" #include "ScrollbarThemeComposite.h" #include "WebCoreSystemInterface.h" @@ -52,7 +51,7 @@ public: virtual void registerScrollbar(Scrollbar*); virtual void unregisterScrollbar(Scrollbar*); -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) void setNewPainterForScrollbar(Scrollbar*, WKScrollbarPainterRef); WKScrollbarPainterRef painterForScrollbar(Scrollbar*); #endif diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm index 5a3796d..5504f5c 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -169,7 +169,7 @@ void ScrollbarThemeMac::unregisterScrollbar(Scrollbar* scrollbar) scrollbarMap()->remove(scrollbar); } -#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +#if USE(WK_SCROLLBAR_PAINTER) void ScrollbarThemeMac::setNewPainterForScrollbar(Scrollbar* scrollbar, WKScrollbarPainterRef newPainter) { scrollbarMap()->set(scrollbar, newPainter); @@ -440,7 +440,11 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co overhang = scrollbar->currentPos() + scrollbar->visibleSize() - scrollbar->totalSize(); } else { // Within the bounds of the scrollable area. - value = scrollbar->currentPos() / scrollbar->maximum(); + int maximum = scrollbar->maximum(); + if (maximum > 0) + value = scrollbar->currentPos() / maximum; + else + value = 0; } ScrollAnimatorMac* scrollAnimator = static_cast<ScrollAnimatorMac*>(scrollbar->scrollableArea()->scrollAnimator()); diff --git a/Source/WebCore/platform/mac/ThemeMac.mm b/Source/WebCore/platform/mac/ThemeMac.mm index e510ea7..918bc07 100644 --- a/Source/WebCore/platform/mac/ThemeMac.mm +++ b/Source/WebCore/platform/mac/ThemeMac.mm @@ -52,6 +52,11 @@ using namespace std; return nil; } +- (BOOL)_automaticFocusRingDisabled +{ + return YES; +} + - (NSRect)_focusRingVisibleRect { return [self visibleRect]; diff --git a/Source/WebCore/platform/mac/WebCoreKeyGenerator.h b/Source/WebCore/platform/mac/WebCoreKeyGenerator.h deleted file mode 100644 index c9260e1..0000000 --- a/Source/WebCore/platform/mac/WebCoreKeyGenerator.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2003 Apple Computer, 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR - * 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. - */ - -@interface WebCoreKeyGenerator : NSObject - -+ (WebCoreKeyGenerator *)sharedGenerator; -- (NSArray *)strengthMenuItemTitles; -- (NSString *)signedPublicKeyAndChallengeStringWithStrengthIndex:(unsigned)index challenge:(NSString *)challenge pageURL:(NSURL *)pageURL; - -@end diff --git a/Source/WebCore/platform/mac/WebCoreKeyGenerator.m b/Source/WebCore/platform/mac/WebCoreKeyGenerator.m deleted file mode 100644 index a1e780c..0000000 --- a/Source/WebCore/platform/mac/WebCoreKeyGenerator.m +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2003 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR - * 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 "config.h" -#import "WebCoreKeyGenerator.h" - -#import <wtf/Assertions.h> -#import <wtf/UnusedParam.h> - -static WebCoreKeyGenerator *sharedGenerator; - -@implementation WebCoreKeyGenerator - -+ (WebCoreKeyGenerator *)sharedGenerator -{ - return sharedGenerator; -} - -- init -{ - ASSERT(!sharedGenerator); - [super init]; - sharedGenerator = [self retain]; - return self; -} - -- (NSArray *)strengthMenuItemTitles -{ - return nil; -} - -- (NSString *)signedPublicKeyAndChallengeStringWithStrengthIndex:(unsigned)unusedIndex challenge:(NSString *)unusedChallenge pageURL:(NSURL *)unusedPageURL -{ - UNUSED_PARAM(unusedIndex); - UNUSED_PARAM(unusedChallenge); - UNUSED_PARAM(unusedPageURL); - - return nil; -} - -@end diff --git a/Source/WebCore/platform/mac/WebCoreObjCExtras.mm b/Source/WebCore/platform/mac/WebCoreObjCExtras.mm index 05d3e01..5a2d564 100644 --- a/Source/WebCore/platform/mac/WebCoreObjCExtras.mm +++ b/Source/WebCore/platform/mac/WebCoreObjCExtras.mm @@ -26,6 +26,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// This file intentionally calls objc_finalizeOnMainThread, which is deprecated. +// According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas +// we need to place this directive before any data or functions are defined. +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #include "config.h" #include "WebCoreObjCExtras.h" diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.h b/Source/WebCore/platform/mac/WebCoreSystemInterface.h index df65ff2..308a551 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.h @@ -86,6 +86,8 @@ class QTMovie; class QTMovieView; #endif +typedef struct _CFURLResponse *CFURLResponseRef; + extern "C" { // In alphabetical order. @@ -115,6 +117,7 @@ extern BOOL (*wkGetGlyphTransformedAdvances)(CGFontRef, NSFont*, CGAffineTransfo extern void (*wkDrawMediaSliderTrack)(int themeStyle, CGContextRef context, CGRect rect, float timeLoaded, float currentTime, float duration, unsigned state); extern void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect rect, unsigned state); +extern CFStringRef (*wkSignedPublicKeyAndChallengeString)(unsigned keySize, CFStringRef challenge, CFStringRef keyDescription); extern NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); extern NSArray* (*wkGetExtensionsForMIMEType)(NSString*); extern NSString* (*wkGetMIMETypeForExtension)(NSString*); @@ -194,10 +197,13 @@ extern CGContextRef (*wkIOSurfaceContextCreate)(IOSurfaceRef surface, unsigned w extern CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); typedef struct __WKScrollbarPainter *WKScrollbarPainterRef; +typedef struct __WKScrollbarPainterController *WKScrollbarPainterControllerRef; + extern WKScrollbarPainterRef (*wkMakeScrollbarPainter)(int controlSize, bool isHorizontal); extern WKScrollbarPainterRef (*wkMakeScrollbarReplacementPainter)(WKScrollbarPainterRef oldPainter, int newStyle, int controlSize, bool isHorizontal); extern void (*wkScrollbarPainterSetDelegate)(WKScrollbarPainterRef, id scrollbarPainterDelegate); extern void (*wkScrollbarPainterPaint)(WKScrollbarPainterRef, bool enabled, double value, CGFloat proportion, CGRect frameRect); +extern void (*wkScrollbarPainterForceFlashScrollers)(WKScrollbarPainterControllerRef); extern int (*wkScrollbarThickness)(int controlSize); extern int (*wkScrollbarMinimumThumbLength)(WKScrollbarPainterRef); extern int (*wkScrollbarMinimumTotalLengthNeededForThumb)(WKScrollbarPainterRef); @@ -208,7 +214,6 @@ extern void (*wkSetScrollbarPainterTrackAlpha)(WKScrollbarPainterRef, CGFloat); extern bool (*wkScrollbarPainterIsHorizontal)(WKScrollbarPainterRef); extern void (*wkScrollbarPainterSetOverlayState)(WKScrollbarPainterRef, int overlayScrollerState); -typedef struct __WKScrollbarPainterController *WKScrollbarPainterControllerRef; extern WKScrollbarPainterControllerRef (*wkMakeScrollbarPainterController)(id painterControllerDelegate); extern void (*wkSetPainterForPainterController)(WKScrollbarPainterControllerRef, WKScrollbarPainterRef, bool isHorizontal); extern WKScrollbarPainterRef (*wkVerticalScrollbarPainterForController)(WKScrollbarPainterControllerRef); @@ -244,12 +249,18 @@ extern CFURLStorageSessionRef (*wkCreatePrivateStorageSession)(CFStringRef); extern NSURLRequest* (*wkCopyRequestWithStorageSession)(CFURLStorageSessionRef, NSURLRequest*); typedef struct OpaqueCFHTTPCookieStorage* CFHTTPCookieStorageRef; -extern CFHTTPCookieStorageRef (*wkCreatePrivateInMemoryHTTPCookieStorage)(CFURLStorageSessionRef); +extern CFHTTPCookieStorageRef (*wkCopyHTTPCookieStorage)(CFURLStorageSessionRef); extern unsigned (*wkGetHTTPCookieAcceptPolicy)(CFHTTPCookieStorageRef); extern NSArray *(*wkHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSURL *); extern void (*wkSetHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSArray *, NSURL *, NSURL *); extern void (*wkDeleteHTTPCookie)(CFHTTPCookieStorageRef, NSHTTPCookie *); +extern CFStringRef (*wkGetCFURLResponseMIMEType)(CFURLResponseRef); +extern CFURLRef (*wkGetCFURLResponseURL)(CFURLResponseRef); +extern CFHTTPMessageRef (*wkGetCFURLResponseHTTPResponse)(CFURLResponseRef); +extern CFStringRef (*wkCopyCFURLResponseSuggestedFilename)(CFURLResponseRef); +extern void (*wkSetCFURLResponseMIMEType)(CFURLResponseRef, CFStringRef mimeType); + } #endif diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm index 50ac236..ab059bd 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -48,6 +48,7 @@ void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); BOOL (*wkMediaControllerThemeAvailable)(int themeStyle); NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); +CFStringRef (*wkSignedPublicKeyAndChallengeString)(unsigned keySize, CFStringRef challenge, CFStringRef keyDescription); NSArray* (*wkGetExtensionsForMIMEType)(NSString*); NSString* (*wkGetMIMETypeForExtension)(NSString*); NSTimeInterval (*wkGetNSURLResponseCalculatedExpiration)(NSURLResponse *response); @@ -132,6 +133,7 @@ WKScrollbarPainterRef (*wkMakeScrollbarPainter)(int controlSize, bool isHorizont WKScrollbarPainterRef (*wkMakeScrollbarReplacementPainter)(WKScrollbarPainterRef oldPainter, int newStyle, int controlSize, bool isHorizontal); void (*wkScrollbarPainterSetDelegate)(WKScrollbarPainterRef, id scrollbarPainterDelegate); void (*wkScrollbarPainterPaint)(WKScrollbarPainterRef, bool enabled, double value, CGFloat proportion, CGRect frameRect); +void (*wkScrollbarPainterForceFlashScrollers)(WKScrollbarPainterControllerRef); int (*wkScrollbarThickness)(int controlSize); int (*wkScrollbarMinimumThumbLength)(WKScrollbarPainterRef); int (*wkScrollbarMinimumTotalLengthNeededForThumb)(WKScrollbarPainterRef); @@ -174,8 +176,14 @@ AXUIElementRef (*wkCreateAXUIElementRef)(id element); CFURLStorageSessionRef (*wkCreatePrivateStorageSession)(CFStringRef); NSURLRequest* (*wkCopyRequestWithStorageSession)(CFURLStorageSessionRef, NSURLRequest*); -CFHTTPCookieStorageRef (*wkCreatePrivateInMemoryHTTPCookieStorage)(CFURLStorageSessionRef); +CFHTTPCookieStorageRef (*wkCopyHTTPCookieStorage)(CFURLStorageSessionRef); unsigned (*wkGetHTTPCookieAcceptPolicy)(CFHTTPCookieStorageRef); NSArray *(*wkHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSURL *); void (*wkSetHTTPCookiesForURL)(CFHTTPCookieStorageRef, NSArray *, NSURL *, NSURL *); void (*wkDeleteHTTPCookie)(CFHTTPCookieStorageRef, NSHTTPCookie *); + +CFStringRef (*wkGetCFURLResponseMIMEType)(CFURLResponseRef); +CFURLRef (*wkGetCFURLResponseURL)(CFURLResponseRef); +CFHTTPMessageRef (*wkGetCFURLResponseHTTPResponse)(CFURLResponseRef); +CFStringRef (*wkCopyCFURLResponseSuggestedFilename)(CFURLResponseRef); +void (*wkSetCFURLResponseMIMEType)(CFURLResponseRef, CFStringRef mimeType); diff --git a/Source/WebCore/platform/mac/WidgetMac.mm b/Source/WebCore/platform/mac/WidgetMac.mm index 96bcde2..f75faaa 100644 --- a/Source/WebCore/platform/mac/WidgetMac.mm +++ b/Source/WebCore/platform/mac/WidgetMac.mm @@ -115,10 +115,15 @@ void Widget::setFocus(bool focused) BEGIN_BLOCK_OBJC_EXCEPTIONS; + // If there's no platformWidget, WK2 is running. The focus() method needs to be used + // to bring focus to the right view on the UIProcess side. NSView *view = [platformWidget() _webcore_effectiveFirstResponder]; - if (Page* page = frame->page()) - page->chrome()->focusNSView(view); - + if (Page* page = frame->page()) { + if (!platformWidget()) + page->chrome()->focus(); + else + page->chrome()->focusNSView(view); + } END_BLOCK_OBJC_EXCEPTIONS; } |