summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/mac
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/mac')
-rw-r--r--Source/WebCore/platform/mac/FileSystemMac.mm13
-rw-r--r--Source/WebCore/platform/mac/HTMLConverter.h88
-rw-r--r--Source/WebCore/platform/mac/HTMLConverter.mm1682
-rw-r--r--Source/WebCore/platform/mac/LoggingMac.mm2
-rw-r--r--Source/WebCore/platform/mac/PasteboardMac.mm29
-rw-r--r--Source/WebCore/platform/mac/PlatformScreenMac.mm13
-rw-r--r--Source/WebCore/platform/mac/SSLKeyGeneratorMac.cpp70
-rw-r--r--Source/WebCore/platform/mac/SSLKeyGeneratorMac.mm49
-rw-r--r--Source/WebCore/platform/mac/ScrollAnimatorMac.h17
-rw-r--r--Source/WebCore/platform/mac/ScrollAnimatorMac.mm161
-rw-r--r--Source/WebCore/platform/mac/ScrollbarThemeMac.h3
-rw-r--r--Source/WebCore/platform/mac/ScrollbarThemeMac.mm8
-rw-r--r--Source/WebCore/platform/mac/ThemeMac.mm5
-rw-r--r--Source/WebCore/platform/mac/WebCoreKeyGenerator.h32
-rw-r--r--Source/WebCore/platform/mac/WebCoreKeyGenerator.m63
-rw-r--r--Source/WebCore/platform/mac/WebCoreObjCExtras.mm5
-rw-r--r--Source/WebCore/platform/mac/WebCoreSystemInterface.h15
-rw-r--r--Source/WebCore/platform/mac/WebCoreSystemInterface.mm10
-rw-r--r--Source/WebCore/platform/mac/WidgetMac.mm11
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;
}