diff options
Diffstat (limited to 'WebCore/page/mac')
-rw-r--r-- | WebCore/page/mac/AXObjectCacheMac.mm | 87 | ||||
-rw-r--r-- | WebCore/page/mac/AccessibilityObjectMac.mm | 38 | ||||
-rw-r--r-- | WebCore/page/mac/AccessibilityObjectWrapper.h | 55 | ||||
-rw-r--r-- | WebCore/page/mac/AccessibilityObjectWrapper.mm | 1996 | ||||
-rw-r--r-- | WebCore/page/mac/ChromeMac.mm | 14 | ||||
-rw-r--r-- | WebCore/page/mac/EventHandlerMac.mm | 127 | ||||
-rw-r--r-- | WebCore/page/mac/FrameMac.mm | 259 | ||||
-rw-r--r-- | WebCore/page/mac/PageMac.cpp | 77 | ||||
-rw-r--r-- | WebCore/page/mac/WebCoreFrameBridge.h | 256 | ||||
-rw-r--r-- | WebCore/page/mac/WebCoreFrameBridge.mm | 1244 | ||||
-rw-r--r-- | WebCore/page/mac/WebCoreFrameView.h | 34 | ||||
-rw-r--r-- | WebCore/page/mac/WebCoreViewFactory.h | 28 | ||||
-rw-r--r-- | WebCore/page/mac/WebDashboardRegion.h | 8 | ||||
-rw-r--r-- | WebCore/page/mac/WebDashboardRegion.m | 2 |
14 files changed, 2426 insertions, 1799 deletions
diff --git a/WebCore/page/mac/AXObjectCacheMac.mm b/WebCore/page/mac/AXObjectCacheMac.mm new file mode 100644 index 0000000..10ae1cc --- /dev/null +++ b/WebCore/page/mac/AXObjectCacheMac.mm @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 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 "AXObjectCache.h" + +#import "AccessibilityObject.h" +#import "AccessibilityObjectWrapper.h" +#import "RenderObject.h" +#import "WebCoreViewFactory.h" + +#import <wtf/PassRefPtr.h> + +// The simple Cocoa calls in this file don't throw exceptions. + +namespace WebCore { + +void AXObjectCache::detachWrapper(AccessibilityObject* obj) +{ + [obj->wrapper() detach]; + [obj->wrapper() release]; + obj->setWrapper(0); +} + +void AXObjectCache::attachWrapper(AccessibilityObject* obj) +{ + obj->setWrapper([[AccessibilityObjectWrapper alloc] initWithAccessibilityObject:obj]); +} + +void AXObjectCache::postNotification(RenderObject* renderer, const String& message) +{ + if (!renderer) + return; + + // notifications for text input objects are sent to that object + // all others are sent to the top WebArea + RefPtr<AccessibilityObject> obj = get(renderer)->observableObject(); + if (!obj) + obj = get(renderer->document()->renderer()); + + if (!obj) + return; + + NSAccessibilityPostNotification(obj->wrapper(), message); +} + +void AXObjectCache::postNotificationToElement(RenderObject* renderer, const String& message) +{ + // send the notification to the specified element itself, not one of its ancestors + if (!renderer) + return; + + RefPtr<AccessibilityObject> obj = get(renderer); + if (!obj) + return; + + NSAccessibilityPostNotification(obj->wrapper(), message); +} + +void AXObjectCache::handleFocusedUIElementChanged() +{ + [[WebCoreViewFactory sharedFactory] accessibilityHandleFocusChanged]; +} + +} diff --git a/WebCore/page/mac/AccessibilityObjectMac.mm b/WebCore/page/mac/AccessibilityObjectMac.mm new file mode 100644 index 0000000..872e108 --- /dev/null +++ b/WebCore/page/mac/AccessibilityObjectMac.mm @@ -0,0 +1,38 @@ +/* + * Copyright (C) 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 "AccessibilityObject.h" + +#import "AccessibilityObjectWrapper.h" + +namespace WebCore { + +bool AccessibilityObject::accessibilityIgnoreAttachment() const +{ + return [[wrapper() attachmentView] accessibilityIsIgnored]; +} + +} // WebCore diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.h b/WebCore/page/mac/AccessibilityObjectWrapper.h new file mode 100644 index 0000000..5a55fe0 --- /dev/null +++ b/WebCore/page/mac/AccessibilityObjectWrapper.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <wtf/RefPtr.h> + +#ifdef __OBJC__ +@class WebCoreTextMarker; +@class WebCoreTextMarkerRange; +#else +class WebCoreTextMarker; +class WebCoreTextMarkerRange; +#endif + +namespace WebCore { + class AccessibilityObject; + class VisiblePosition; +} + +@interface AccessibilityObjectWrapper : NSObject +{ + WebCore::AccessibilityObject* m_object; +} + +- (id)initWithAccessibilityObject:(WebCore::AccessibilityObject*)axObject; +- (void)detach; +- (WebCore::AccessibilityObject*)accessibilityObject; + +- (NSView*)attachmentView; + +@end diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.mm b/WebCore/page/mac/AccessibilityObjectWrapper.mm new file mode 100644 index 0000000..2104ca9 --- /dev/null +++ b/WebCore/page/mac/AccessibilityObjectWrapper.mm @@ -0,0 +1,1996 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "AccessibilityObjectWrapper.h" + +#import "AXObjectCache.h" +#import "AccessibilityListBox.h" +#import "AccessibilityList.h" +#import "AccessibilityRenderObject.h" +#import "AccessibilityTable.h" +#import "AccessibilityTableCell.h" +#import "AccessibilityTableRow.h" +#import "AccessibilityTableColumn.h" +#import "ColorMac.h" +#import "Frame.h" +#import "HTMLAnchorElement.h" +#import "HTMLAreaElement.h" +#import "HTMLImageElement.h" +#import "HTMLInputElement.h" +#import "HTMLTextAreaElement.h" +#import "LocalizedStrings.h" +#import "RenderTextControl.h" +#import "RenderView.h" +#import "RenderWidget.h" +#import "SelectionController.h" +#import "SimpleFontData.h" +#import "TextIterator.h" +#import "WebCoreFrameView.h" +#import "WebCoreObjCExtras.h" +#import "WebCoreViewFactory.h" +#import "htmlediting.h" +#import "visible_units.h" + +using namespace WebCore; +using namespace HTMLNames; +using namespace std; + +// Cell Tables +#ifndef NSAccessibilitySelectedCellsAttribute +#define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells" +#endif + +#ifndef NSAccessibilityVisibleCellsAttribute +#define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells" +#endif + +#ifndef NSAccessibilityRowHeaderUIElementsAttribute +#define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements" +#endif + +#ifndef NSAccessibilityRowIndexRangeAttribute +#define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange" +#endif + +#ifndef NSAccessibilityColumnIndexRangeAttribute +#define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange" +#endif + +#ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute +#define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow" +#endif + +#ifndef NSAccessibilityCellRole +#define NSAccessibilityCellRole @"AXCell" +#endif + +// Lists +#ifndef NSAccessibilityContentListSubrole +#define NSAccessibilityContentListSubrole @"AXContentList" +#endif + +#ifndef NSAccessibilityDefinitionListSubrole +#define NSAccessibilityDefinitionListSubrole @"AXDefinitionList" +#endif + +#ifdef BUILDING_ON_TIGER +typedef unsigned NSUInteger; +#endif + +@interface NSObject (WebKitAccessibilityArrayCategory) + +- (NSUInteger)accessibilityIndexOfChild:(id)child; +- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute; +- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount; + +@end + +@implementation AccessibilityObjectWrapper + +#ifndef BUILDING_ON_TIGER ++ (void)initialize +{ + WebCoreObjCFinalizeOnMainThread(self); +} +#endif + +- (id)initWithAccessibilityObject:(AccessibilityObject*)axObject +{ + [super init]; + + m_object = axObject; + return self; +} + +- (void)unregisterUniqueIdForUIElement +{ + [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self]; +} + +- (void)detach +{ + // Send unregisterUniqueIdForUIElement unconditionally because if it is + // ever accidently not done (via other bugs in our AX implementation) you + // end up with a crash like <rdar://problem/4273149>. It is safe and not + // expensive to send even if the object is not registered. + [self unregisterUniqueIdForUIElement]; + m_object = 0; +} + +- (AccessibilityObject*)accessibilityObject +{ + return m_object; +} + +- (NSView*)attachmentView +{ + ASSERT(m_object->isAttachment()); + Widget* widget = m_object->widgetForAttachmentView(); + if (!widget) + return nil; + return widget->platformWidget(); +} + +static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& visiblePos) +{ + if (visiblePos.isNull()) + return nil; + + Position deepPos = visiblePos.deepEquivalent(); + Node* domNode = deepPos.node(); + ASSERT(domNode); + if (!domNode) + return nil; + + if (domNode->isHTMLElement()) + if (static_cast<HTMLElement*>(domNode)->isPasswordField()) + return nil; + + // locate the renderer, which must exist for a visible dom node + RenderObject* renderer = domNode->renderer(); + ASSERT(renderer); + + // find or create an accessibility object for this renderer + AXObjectCache* cache = renderer->document()->axObjectCache(); + RefPtr<AccessibilityObject> obj = cache->get(renderer); + + // create a text marker, adding an ID for the AccessibilityObject if needed + TextMarkerData textMarkerData; + + // The compiler can add padding to this struct. + // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence. + bzero(&textMarkerData, sizeof(TextMarkerData)); + textMarkerData.axID = obj.get()->axObjectID(); + textMarkerData.node = domNode; + textMarkerData.offset = deepPos.offset(); + textMarkerData.affinity = visiblePos.affinity(); + return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)]; +} + +static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarker) +{ + TextMarkerData textMarkerData; + + if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)]) + return VisiblePosition(); + + VisiblePosition visiblePos = VisiblePosition(textMarkerData.node, textMarkerData.offset, textMarkerData.affinity); + Position deepPos = visiblePos.deepEquivalent(); + if (deepPos.isNull()) + return VisiblePosition(); + + RenderObject* renderer = deepPos.node()->renderer(); + if (!renderer) + return VisiblePosition(); + + AXObjectCache* cache = renderer->document()->axObjectCache(); + if (!cache->isIDinUse(textMarkerData.axID)) + return VisiblePosition(); + + if (deepPos.node() != textMarkerData.node || deepPos.offset() != textMarkerData.offset) + return VisiblePosition(); + + return visiblePos; +} + +static VisiblePosition visiblePositionForStartOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange) +{ + return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]); +} + +static VisiblePosition visiblePositionForEndOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange) +{ + return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]); +} + +static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2) +{ + if (!textMarker1 || !textMarker2) + return nil; + + return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2]; +} + +static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range) +{ + NSDictionary* dict; + + if (font) { + dict = [NSDictionary dictionaryWithObjectsAndKeys: + [font fontName] , NSAccessibilityFontNameKey, + [font familyName] , NSAccessibilityFontFamilyKey, + [font displayName] , NSAccessibilityVisibleNameKey, + [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey, + nil]; + + [attrString addAttribute:attribute value:dict range:range]; + } else + [attrString removeAttribute:attribute range:range]; + +} + +static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor) +{ + // get color information assuming NSDeviceRGBColorSpace + NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + if (rgbColor == nil) + rgbColor = [NSColor blackColor]; + CGFloat components[4]; + [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; + + // create a new CGColorRef to return + CGColorSpaceRef cgColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGColorRef cgColor = CGColorCreate(cgColorSpace, components); + CGColorSpaceRelease(cgColorSpace); + CFMakeCollectable(cgColor); + + // check for match with existing color + if (existingColor && CGColorEqualToColor(cgColor, existingColor)) + cgColor = nil; + + return cgColor; +} + +static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range) +{ + if (color) { + CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil]; + CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor); + if (cgColor) { + [attrString addAttribute:attribute value:(id)cgColor range:range]; + CGColorRelease(cgColor); + } + } else + [attrString removeAttribute:attribute range:range]; +} + +static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range) +{ + if (number) + [attrString addAttribute:attribute value:number range:range]; + else + [attrString removeAttribute:attribute range:range]; +} + +static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) +{ + RenderStyle* style = renderer->style(); + + // set basic font info + AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range); + + // set basic colors + AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range); + AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range); + + // set super/sub scripting + EVerticalAlign alignment = style->verticalAlign(); + if (alignment == SUB) + AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range); + else if (alignment == SUPER) + AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range); + else + [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range]; + + // set shadow + if (style->textShadow()) + AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range); + else + [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range]; + + // set underline and strikethrough + int decor = style->textDecorationsInEffect(); + if ((decor & UNDERLINE) == 0) { + [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range]; + [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range]; + } + + if ((decor & LINE_THROUGH) == 0) { + [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range]; + [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range]; + } + + if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) { + // find colors using quirk mode approach (strict mode would use current + // color for all but the root line box, which would use getTextDecorationColors) + Color underline, overline, linethrough; + renderer->getTextDecorationColors(decor, underline, overline, linethrough); + + if ((decor & UNDERLINE) != 0) { + AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range); + AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range); + } + + if ((decor & LINE_THROUGH) != 0) { + AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range); + AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range); + } + } +} + +static int blockquoteLevel(RenderObject* renderer) +{ + int result = 0; + for (Node* node = renderer->element(); node; node = node->parent()) { + if (node->hasTagName(blockquoteTag)) + result += 1; + } + + return result; +} + +static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) +{ + int quoteLevel = blockquoteLevel(renderer); + + if (quoteLevel) + [attrString addAttribute:@"AXBlockQuoteLevel" value:[NSNumber numberWithInt:quoteLevel] range:range]; + else + [attrString removeAttribute:@"AXBlockQuoteLevel" range:range]; +} + +static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range) +{ + Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node); + Vector<DocumentMarker>::iterator markerIt = markers.begin(); + + unsigned endOffset = (unsigned)offset + range.length; + for ( ; markerIt != markers.end(); markerIt++) { + DocumentMarker marker = *markerIt; + + if (marker.type != DocumentMarker::Spelling) + continue; + + if (marker.endOffset <= (unsigned)offset) + continue; + + if (marker.startOffset > endOffset) + break; + + // add misspelling attribute for the intersection of the marker and the range + int rStart = range.location + (marker.startOffset - offset); + int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset; + NSRange spellRange = NSMakeRange(rStart, rLength); + AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange); + + if (marker.endOffset > endOffset + 1) + break; + } +} + +static void AXAttributeStringSetHeadingLevel(AccessibilityObject* object, NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range) +{ + int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->element()); + + if (parentHeadingLevel) + [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range]; + else + [attrString removeAttribute:@"AXHeadingLevel" range:range]; +} + +static AccessibilityObject* AXLinkElementForNode(Node* node) +{ + RenderObject* obj = node->renderer(); + if (!obj) + return 0; + + RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->get(obj); + Element* anchor = axObj->anchorElement(); + if (!anchor) + return 0; + + RenderObject* anchorRenderer = anchor->renderer(); + if (!anchorRenderer) + return 0; + + return anchorRenderer->document()->axObjectCache()->get(anchorRenderer); +} + +static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range) +{ + if (object && object->isAccessibilityRenderObject()) { + // make a serialiazable AX object + + RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer(); + if (!renderer) + return; + + Document* doc = renderer->document(); + if (!doc) + return; + + AXObjectCache* cache = doc->axObjectCache(); + if (!cache) + return; + + AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()]; + if (axElement) { + [attrString addAttribute:attribute value:(id)axElement range:range]; + CFRelease(axElement); + } + } else + [attrString removeAttribute:attribute range:range]; +} + +static void AXAttributedStringAppendText(AccessibilityObject* object, NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length) +{ + // skip invisible text + if (!node->renderer()) + return; + + // easier to calculate the range before appending the string + NSRange attrStringRange = NSMakeRange([attrString length], length); + + // append the string from this node + [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]]; + + // add new attributes and remove irrelevant inherited ones + // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge + // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means + // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually. + + // remove inherited attachment from prior AXAttributedStringAppendReplaced + [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange]; + + // set new attributes + AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange); + AXAttributeStringSetHeadingLevel(object, attrString, node->renderer(), attrStringRange); + AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange); + AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange); + + // do spelling last because it tends to break up the range + AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange); +} + +static NSString* nsStringForReplacedNode(Node* replacedNode) +{ + // we should always be given a rendered node and a replaced node, but be safe + // replaced nodes are either attachments (widgets) or images + if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) { + ASSERT_NOT_REACHED(); + return nil; + } + + // create an AX object, but skip it if it is not supposed to be seen + RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer()); + if (obj->accessibilityIsIgnored()) + return nil; + + // use the attachmentCharacter to represent the replaced node + const UniChar attachmentChar = NSAttachmentCharacter; + return [NSString stringWithCharacters:&attachmentChar length:1]; +} + +- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange +{ + // extract the start and end VisiblePosition + VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange); + if (startVisiblePosition.isNull()) + return nil; + + VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange); + if (endVisiblePosition.isNull()) + return nil; + + // iterate over the range to build the AX attributed string + NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init]; + TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get()); + while (!it.atEnd()) { + // locate the node and starting offset for this range + int exception = 0; + Node* node = it.range()->startContainer(exception); + ASSERT(node == it.range()->endContainer(exception)); + int offset = it.range()->startOffset(exception); + + // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) + if (it.length() != 0) { + AXAttributedStringAppendText(m_object, attrString, node, offset, it.characters(), it.length()); + } else { + Node* replacedNode = node->childNode(offset); + NSString *attachmentString = nsStringForReplacedNode(replacedNode); + if (attachmentString) { + NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]); + + // append the placeholder string + [[attrString mutableString] appendString:attachmentString]; + + // remove all inherited attributes + [attrString setAttributes:nil range:attrStringRange]; + + // add the attachment attribute + AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer()); + AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange); + } + } + it.advance(); + } + + return [attrString autorelease]; +} + +static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition) +{ + WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition); + WebCoreTextMarker* endTextMarker = textMarkerForVisiblePosition(endPosition); + return textMarkerRangeFromMarkers(startTextMarker, endTextMarker); +} + +- (NSArray*)accessibilityActionNames +{ + static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil]; + static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil]; + static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil]; + + NSArray *actions; + if (m_object->actionElement()) + actions = actionElementActions; + else if (m_object->isMenuRelated()) + actions = menuElementActions; + else if (m_object->isAttachment()) + actions = [[self attachmentView] accessibilityActionNames]; + else + actions = defaultElementActions; + + return actions; +} + +- (NSArray*)accessibilityAttributeNames +{ + if (m_object->isAttachment()) + return [[self attachmentView] accessibilityAttributeNames]; + + static NSArray* attributes = nil; + static NSArray* anchorAttrs = nil; + static NSArray* webAreaAttrs = nil; + static NSArray* textAttrs = nil; + static NSArray* listBoxAttrs = nil; + static NSArray* rangeAttrs = nil; + static NSArray* commonMenuAttrs = nil; + static NSArray* menuAttrs = nil; + static NSArray* menuBarAttrs = nil; + static NSArray* menuItemAttrs = nil; + static NSArray* menuButtonAttrs = nil; + static NSArray* controlAttrs = nil; + static NSArray* tableAttrs = nil; + static NSArray* tableRowAttrs = nil; + static NSArray* tableColAttrs = nil; + static NSArray* tableCellAttrs = nil; + NSMutableArray* tempArray; + if (attributes == nil) { + attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, + NSAccessibilitySubroleAttribute, + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityChildrenAttribute, + NSAccessibilityHelpAttribute, + NSAccessibilityParentAttribute, + NSAccessibilityPositionAttribute, + NSAccessibilitySizeAttribute, + NSAccessibilityTitleAttribute, + NSAccessibilityDescriptionAttribute, + NSAccessibilityValueAttribute, + NSAccessibilityFocusedAttribute, + NSAccessibilityEnabledAttribute, + NSAccessibilityWindowAttribute, + @"AXSelectedTextMarkerRange", + @"AXStartTextMarker", + @"AXEndTextMarker", + @"AXVisited", + NSAccessibilityLinkedUIElementsAttribute, + NSAccessibilitySelectedAttribute, + @"AXBlockQuoteLevel", + NSAccessibilityTopLevelUIElementAttribute, + nil]; + } + if (commonMenuAttrs == nil) { + commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityChildrenAttribute, + NSAccessibilityParentAttribute, + NSAccessibilityEnabledAttribute, + NSAccessibilityPositionAttribute, + NSAccessibilitySizeAttribute, + nil]; + } + if (anchorAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityURLAttribute]; + anchorAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (webAreaAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:@"AXLinkUIElements"]; + [tempArray addObject:@"AXLoaded"]; + [tempArray addObject:@"AXLayoutCount"]; + [tempArray addObject:NSAccessibilityURLAttribute]; + webAreaAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (textAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute]; + [tempArray addObject:NSAccessibilitySelectedTextAttribute]; + [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute]; + [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute]; + [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute]; + [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + textAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (listBoxAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; + [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; + [tempArray addObject:NSAccessibilityOrientationAttribute]; + [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + listBoxAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (rangeAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute]; + [tempArray addObject:NSAccessibilityValueAttribute]; + [tempArray addObject:NSAccessibilityMinValueAttribute]; + [tempArray addObject:NSAccessibilityMaxValueAttribute]; + rangeAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (menuBarAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; + [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; + [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; + [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + menuBarAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (menuAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; + [tempArray addObject:NSAccessibilitySelectedChildrenAttribute]; + [tempArray addObject:NSAccessibilityVisibleChildrenAttribute]; + [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + menuAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (menuItemAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs]; + [tempArray addObject:NSAccessibilityTitleAttribute]; + [tempArray addObject:NSAccessibilityHelpAttribute]; + [tempArray addObject:NSAccessibilitySelectedAttribute]; + [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute]; + [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute]; + [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute]; + [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute]; + [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute]; + [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute]; + [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute]; + menuItemAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (menuButtonAttrs == nil) { + menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute, + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityParentAttribute, + NSAccessibilityPositionAttribute, + NSAccessibilitySizeAttribute, + NSAccessibilityWindowAttribute, + NSAccessibilityTopLevelUIElementAttribute, + NSAccessibilityEnabledAttribute, + NSAccessibilityFocusedAttribute, + NSAccessibilityTitleAttribute, + NSAccessibilityChildrenAttribute, nil]; + } + if (controlAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityTitleUIElementAttribute]; + controlAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (tableAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityRowsAttribute]; + [tempArray addObject:NSAccessibilityVisibleRowsAttribute]; + [tempArray addObject:NSAccessibilityColumnsAttribute]; + [tempArray addObject:NSAccessibilityVisibleColumnsAttribute]; + [tempArray addObject:NSAccessibilityVisibleCellsAttribute]; + [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute]; + [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute]; + [tempArray addObject:NSAccessibilityHeaderAttribute]; + tableAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (tableRowAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityIndexAttribute]; + tableRowAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (tableColAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityIndexAttribute]; + [tempArray addObject:NSAccessibilityHeaderAttribute]; + [tempArray addObject:NSAccessibilityRowsAttribute]; + [tempArray addObject:NSAccessibilityVisibleRowsAttribute]; + tableColAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (tableCellAttrs == nil) { + tempArray = [[NSMutableArray alloc] initWithArray:attributes]; + [tempArray addObject:NSAccessibilityRowIndexRangeAttribute]; + [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute]; + tableCellAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + + if (m_object->isPasswordField()) + return attributes; + + if (m_object->isWebArea()) + return webAreaAttrs; + + if (m_object->isTextControl()) + return textAttrs; + + if (m_object->isAnchor() || m_object->isImage()) + return anchorAttrs; + + if (m_object->isDataTable()) + return tableAttrs; + if (m_object->isTableRow()) + return tableRowAttrs; + if (m_object->isTableColumn()) + return tableColAttrs; + if (m_object->isTableCell()) + return tableCellAttrs; + + if (m_object->isListBox() || m_object->isList()) + return listBoxAttrs; + + if (m_object->isProgressIndicator() || m_object->isSlider()) + return rangeAttrs; + + if (m_object->isControl()) + return controlAttrs; + + if (m_object->isMenu()) + return menuAttrs; + if (m_object->isMenuBar()) + return menuBarAttrs; + if (m_object->isMenuButton()) + return menuButtonAttrs; + if (m_object->isMenuItem()) + return menuItemAttrs; + + return attributes; +} + +- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange +{ + return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange)); +} + +- (NSArray*)renderWidgetChildren +{ + Widget* widget = m_object->widget(); + if (!widget) + return nil; + return [(widget->getOuterView()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute]; +} + +static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector) +{ + unsigned length = [array count]; + vector.reserveCapacity(length); + for (unsigned i = 0; i < length; ++i) { + AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject]; + if (obj) + vector.append(obj); + } +} + +static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector) +{ + unsigned length = vector.size(); + NSMutableArray* array = [NSMutableArray arrayWithCapacity: length]; + for (unsigned i = 0; i < length; ++i) { + ASSERT(vector[i]->wrapper()); + if (vector[i]->wrapper()) + [array addObject:vector[i]->wrapper()]; + } + return array; +} + +- (WebCoreTextMarkerRange*)textMarkerRangeForSelection +{ + Selection selection = m_object->selection(); + if (selection.isNone()) + return nil; + return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd()); +} + +- (NSValue*)position +{ + IntRect rect = m_object->elementRect(); + + // The Cocoa accessibility API wants the lower-left corner. + NSPoint point = NSMakePoint(rect.x(), rect.bottom()); + FrameView* frameView = m_object->documentFrameView(); + if (frameView) { + NSView* view = frameView->documentView(); + point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]]; + } + + return [NSValue valueWithPoint: point]; +} + +typedef HashMap<int, NSString*> AccessibilityRoleMap; + +static const AccessibilityRoleMap& createAccessibilityRoleMap() +{ + struct RoleEntry { + AccessibilityRole value; + NSString* string; + }; + + static const RoleEntry roles[] = { + { UnknownRole, NSAccessibilityUnknownRole }, + { ButtonRole, NSAccessibilityButtonRole }, + { RadioButtonRole, NSAccessibilityRadioButtonRole }, + { CheckBoxRole, NSAccessibilityCheckBoxRole }, + { SliderRole, NSAccessibilitySliderRole }, + { TabGroupRole, NSAccessibilityTabGroupRole }, + { TextFieldRole, NSAccessibilityTextFieldRole }, + { StaticTextRole, NSAccessibilityStaticTextRole }, + { TextAreaRole, NSAccessibilityTextAreaRole }, + { ScrollAreaRole, NSAccessibilityScrollAreaRole }, + { PopUpButtonRole, NSAccessibilityPopUpButtonRole }, + { MenuButtonRole, NSAccessibilityMenuButtonRole }, + { TableRole, NSAccessibilityTableRole }, + { ApplicationRole, NSAccessibilityApplicationRole }, + { GroupRole, NSAccessibilityGroupRole }, + { RadioGroupRole, NSAccessibilityRadioGroupRole }, + { ListRole, NSAccessibilityListRole }, + { ScrollBarRole, NSAccessibilityScrollBarRole }, + { ValueIndicatorRole, NSAccessibilityValueIndicatorRole }, + { ImageRole, NSAccessibilityImageRole }, + { MenuBarRole, NSAccessibilityMenuBarRole }, + { MenuRole, NSAccessibilityMenuRole }, + { MenuItemRole, NSAccessibilityMenuItemRole }, + { ColumnRole, NSAccessibilityColumnRole }, + { RowRole, NSAccessibilityRowRole }, + { ToolbarRole, NSAccessibilityToolbarRole }, + { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole }, + { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole }, + { WindowRole, NSAccessibilityWindowRole }, + { DrawerRole, NSAccessibilityDrawerRole }, + { SystemWideRole, NSAccessibilitySystemWideRole }, + { OutlineRole, NSAccessibilityOutlineRole }, + { IncrementorRole, NSAccessibilityIncrementorRole }, + { BrowserRole, NSAccessibilityBrowserRole }, + { ComboBoxRole, NSAccessibilityComboBoxRole }, + { SplitGroupRole, NSAccessibilitySplitGroupRole }, + { SplitterRole, NSAccessibilitySplitterRole }, + { ColorWellRole, NSAccessibilityColorWellRole }, + { GrowAreaRole, NSAccessibilityGrowAreaRole }, + { SheetRole, NSAccessibilitySheetRole }, + { HelpTagRole, NSAccessibilityHelpTagRole }, + { MatteRole, NSAccessibilityMatteRole }, + { RulerRole, NSAccessibilityRulerRole }, + { RulerMarkerRole, NSAccessibilityRulerMarkerRole }, + { LinkRole, NSAccessibilityLinkRole }, +#ifndef BUILDING_ON_TIGER + { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole }, + { GridRole, NSAccessibilityGridRole }, +#endif + { WebCoreLinkRole, NSAccessibilityLinkRole }, + { ImageMapLinkRole, NSAccessibilityLinkRole }, + { ImageMapRole, @"AXImageMap" }, + { ListMarkerRole, @"AXListMarker" }, + { WebAreaRole, @"AXWebArea" }, + { HeadingRole, @"AXHeading" }, + { ListBoxRole, NSAccessibilityListRole }, + { ListBoxOptionRole, NSAccessibilityStaticTextRole }, + // cells don't exist on tiger or leopard +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + { CellRole, NSAccessibilityGroupRole }, +#else + { CellRole, NSAccessibilityCellRole }, +#endif + { TableHeaderContainerRole, NSAccessibilityGroupRole }, + { DefinitionListDefinitionRole, NSAccessibilityGroupRole }, + { DefinitionListTermRole, NSAccessibilityGroupRole } + + }; + AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap; + + const unsigned numRoles = sizeof(roles) / sizeof(roles[0]); + for (unsigned i = 0; i < numRoles; ++i) + roleMap.set(roles[i].value, roles[i].string); + return roleMap; +} + +static NSString* roleValueToNSString(AccessibilityRole value) +{ + ASSERT(value); + static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap(); + return roleMap.get(value); +} + +- (NSString*)role +{ + if (m_object->isAttachment()) + return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute]; + NSString* string = roleValueToNSString(m_object->roleValue()); + if (string != nil) + return string; + return NSAccessibilityUnknownRole; +} + +- (NSString*)subrole +{ + if (m_object->isPasswordField()) + return NSAccessibilitySecureTextFieldSubrole; + + if (m_object->isAttachment()) { + NSView* attachView = [self attachmentView]; + if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) { + return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute]; + } + } + + if (m_object->isList()) { + AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object); + if (listObject->isUnorderedList() || listObject->isOrderedList()) + return NSAccessibilityContentListSubrole; + if (listObject->isDefinitionList()) + return NSAccessibilityDefinitionListSubrole; + } + + return nil; +} + +- (NSString*)roleDescription +{ + if (!m_object) + return nil; + + // attachments have the AXImage role, but a different subrole + if (m_object->isAttachment()) + return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute]; + + // FIXME 3447564: It would be better to call some AppKit API to get these strings + // (which would be the best way to localize them) + + NSString* axRole = [self role]; + if ([axRole isEqualToString:NSAccessibilityButtonRole]) + return NSAccessibilityRoleDescription(NSAccessibilityButtonRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityPopUpButtonRole]) + return NSAccessibilityRoleDescription(NSAccessibilityPopUpButtonRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityStaticTextRole]) + return NSAccessibilityRoleDescription(NSAccessibilityStaticTextRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityImageRole]) + return NSAccessibilityRoleDescription(NSAccessibilityImageRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityGroupRole]) + return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityCheckBoxRole]) + return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityRadioButtonRole]) + return NSAccessibilityRoleDescription(NSAccessibilityRadioButtonRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityTextFieldRole]) + return NSAccessibilityRoleDescription(NSAccessibilityTextFieldRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityTextAreaRole]) + return NSAccessibilityRoleDescription(NSAccessibilityTextAreaRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityListRole]) + return NSAccessibilityRoleDescription(NSAccessibilityListRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityTableRole]) + return NSAccessibilityRoleDescription(NSAccessibilityTableRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityRowRole]) + return NSAccessibilityRoleDescription(NSAccessibilityRowRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityColumnRole]) + return NSAccessibilityRoleDescription(NSAccessibilityColumnRole, [self subrole]); + + if ([axRole isEqualToString:NSAccessibilityCellRole]) + return NSAccessibilityRoleDescription(NSAccessibilityCellRole, [self subrole]); + + if ([axRole isEqualToString:@"AXWebArea"]) + return AXWebAreaText(); + + if ([axRole isEqualToString:@"AXLink"]) + return AXLinkText(); + + if ([axRole isEqualToString:@"AXListMarker"]) + return AXListMarkerText(); + + if ([axRole isEqualToString:@"AXImageMap"]) + return AXImageMapText(); + + if ([axRole isEqualToString:@"AXHeading"]) + return AXHeadingText(); + + if ([axRole isEqualToString:(NSString*)kAXMenuBarItemRole] || + [axRole isEqualToString:NSAccessibilityMenuRole]) + return nil; + + if ([axRole isEqualToString:NSAccessibilityMenuButtonRole]) + return NSAccessibilityRoleDescription(NSAccessibilityMenuButtonRole, [self subrole]); + + return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil); +} + +// FIXME: split up this function in a better way. +// suggestions: Use a hash table that maps attribute names to function calls, +// or maybe pointers to member functions +- (id)accessibilityAttributeValue:(NSString*)attributeName +{ + if (!m_object) + return nil; + + if ([attributeName isEqualToString: NSAccessibilityRoleAttribute]) + return [self role]; + + if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute]) + return [self subrole]; + + if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute]) + return [self roleDescription]; + + if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) { + if (m_object->isAccessibilityRenderObject()) { + FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView(); + if (fv) + return fv->platformWidget(); + } + + return m_object->parentObjectUnignored()->wrapper(); + } + + if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) { + if (m_object->children().isEmpty()) { + NSArray* children = [self renderWidgetChildren]; + if (children != nil) + return children; + } + return convertToNSArray(m_object->children()); + } + + if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) { + if (m_object->isListBox()) { + AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy; + m_object->selectedChildren(selectedChildrenCopy); + return convertToNSArray(selectedChildrenCopy); + } + return nil; + } + + if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) { + if (m_object->isListBox()) { + AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy; + m_object->visibleChildren(visibleChildrenCopy); + return convertToNSArray(visibleChildrenCopy); + } + else if (m_object->isList()) + return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; + + return nil; + } + + + if (m_object->isWebArea()) { + if ([attributeName isEqualToString: @"AXLinkUIElements"]) { + AccessibilityObject::AccessibilityChildrenVector links; + static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links); + return convertToNSArray(links); + } + if ([attributeName isEqualToString: @"AXLoaded"]) + return [NSNumber numberWithBool: m_object->isLoaded()]; + if ([attributeName isEqualToString: @"AXLayoutCount"]) + return [NSNumber numberWithInt: m_object->layoutCount()]; + } + + if (m_object->isTextControl()) { + if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) { + int length = m_object->textLength(); + if (length < 0) + return nil; + return [NSNumber numberWithUnsignedInt:length]; + } + if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) { + String selectedText = m_object->selectedText(); + if (selectedText.isNull()) + return nil; + return (NSString*)selectedText; + } + if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) { + PlainTextRange textRange = m_object->selectedTextRange(); + if (textRange.isNull()) + return nil; + return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)]; + } + // TODO: Get actual visible range. <rdar://problem/4712101> + if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) + return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())]; + if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) { + // if selectionEnd > 0, then there is selected text and this question should not be answered + if (m_object->isPasswordField() || m_object->selectionEnd() > 0) + return nil; + int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true)); + if (lineNumber < 0) + return nil; + return [NSNumber numberWithInt:lineNumber]; + } + } + + if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) { + KURL url = m_object->url(); + if (url.isNull()) + return nil; + return (NSURL*)url; + } + + if ([attributeName isEqualToString: @"AXVisited"]) + return [NSNumber numberWithBool: m_object->isVisited()]; + + if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) { + if (m_object->isAttachment()) { + if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute]) + return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute]; + } + return m_object->title(); + } + + if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) { + if (m_object->isAttachment()) { + if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute]) + return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute]; + } + return m_object->accessibilityDescription(); + } + + if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) { + if (m_object->isAttachment()) { + if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute]) + return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute]; + } + if (m_object->isProgressIndicator() || m_object->isSlider()) + return [NSNumber numberWithFloat:m_object->valueForRange()]; + if (m_object->hasIntValue()) + return [NSNumber numberWithInt:m_object->intValue()]; + return m_object->stringValue(); + } + + if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute]) + return [NSNumber numberWithFloat:m_object->minValueForRange()]; + + if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute]) + return [NSNumber numberWithFloat:m_object->maxValueForRange()]; + + if ([attributeName isEqualToString: NSAccessibilityHelpAttribute]) + return m_object->helpText(); + + if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) + return [NSNumber numberWithBool: m_object->isFocused()]; + + if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute]) + return [NSNumber numberWithBool: m_object->isEnabled()]; + + if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) { + IntSize s = m_object->size(); + return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())]; + } + + if ([attributeName isEqualToString: NSAccessibilityPositionAttribute]) + return [self position]; + + if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] || + [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) { + FrameView* fv = m_object->documentFrameView(); + if (fv) + return [fv->platformWidget() window]; + return nil; + } + + if (m_object->isDataTable()) { + // TODO: distinguish between visible and non-visible rows + if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || + [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) { + return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows()); + } + // TODO: distinguish between visible and non-visible columns + if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] || + [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) { + return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns()); + } + + // HTML tables don't support these + if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] || + [attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute] || + [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute]) + return nil; + + if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) { + AccessibilityObject::AccessibilityChildrenVector columnHeaders; + static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders); + return convertToNSArray(columnHeaders); + } + + if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) { + AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer(); + if (headerContainer) + return headerContainer->wrapper(); + return nil; + } + + if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) { + AccessibilityObject::AccessibilityChildrenVector rowHeaders; + static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders); + return convertToNSArray(rowHeaders); + } + + if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) { + AccessibilityObject::AccessibilityChildrenVector cells; + static_cast<AccessibilityTable*>(m_object)->cells(cells); + return convertToNSArray(cells); + } + } + + if (m_object->isTableRow()) { + if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) + return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()]; + } + + if (m_object->isTableColumn()) { + if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) + return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()]; + + // rows attribute for a column is the list of all the elements in that column at each row + if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] || + [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) { + return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children()); + } + if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) { + AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject(); + if (!header) + return nil; + return header->wrapper(); + } + } + + if (m_object->isTableCell()) { + if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) { + pair<int, int> rowRange; + static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange); + return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)]; + } + if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) { + pair<int, int> columnRange; + static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange); + return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)]; + } + } + + if ((m_object->isListBox() ||m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute]) + return NSAccessibilityVerticalOrientationValue; + + if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) + return [self textMarkerRangeForSelection]; + + if (m_object->isAccessibilityRenderObject()) { + RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer(); + if (!renderer) + return nil; + + if ([attributeName isEqualToString: @"AXStartTextMarker"]) + return textMarkerForVisiblePosition(startOfDocument(renderer->document())); + if ([attributeName isEqualToString: @"AXEndTextMarker"]) + return textMarkerForVisiblePosition(endOfDocument(renderer->document())); + + if ([attributeName isEqualToString: @"AXBlockQuoteLevel"]) + return [NSNumber numberWithInt:blockquoteLevel(renderer)]; + } + + if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) { + AccessibilityObject::AccessibilityChildrenVector linkedUIElements; + m_object->linkedUIElements(linkedUIElements); + if (linkedUIElements.size() == 0) + return nil; + return convertToNSArray(linkedUIElements); + } + + if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) + return [NSNumber numberWithBool:m_object->isSelected()]; + + if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) { + AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton(); + if (uiElement) + return [NSArray arrayWithObject:uiElement->wrapper()]; + } + + if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) { + AccessibilityObject* obj = m_object->titleUIElement(); + if (obj) + return obj->wrapper(); + return nil; + } + + return nil; +} + +- (id)accessibilityFocusedUIElement +{ + RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement(); + + if (!focusedObj) + return nil; + + return focusedObj->wrapper(); +} + +- (id)accessibilityHitTest:(NSPoint)point +{ + RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point)); + if (axObject) + return NSAccessibilityUnignoredAncestor(axObject->wrapper()); + return NSAccessibilityUnignoredAncestor(self); +} + +- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName +{ + if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) + return YES; + + if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) + return m_object->canSetFocusAttribute(); + + if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) + return m_object->canSetValueAttribute(); + + if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) + return m_object->canSetSelectedAttribute(); + + if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) + return m_object->canSetSelectedChildrenAttribute(); + + if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] || + [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] || + [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) + return m_object->canSetTextRangeAttributes(); + + return NO; +} + +// accessibilityShouldUseUniqueId is an AppKit method we override so that +// objects will be given a unique ID, and therefore allow AppKit to know when they +// become obsolete (e.g. when the user navigates to a new web page, making this one +// unrendered but not deallocated because it is in the back/forward cache). +// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the +// appropriate place (e.g. dealloc) to remove these non-retained references from +// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement. +// +// Registering an object is also required for observing notifications. Only registered objects can be observed. +- (BOOL)accessibilityIsIgnored +{ + if (m_object->isAttachment()) + return [[self attachmentView] accessibilityIsIgnored]; + return m_object->accessibilityIsIgnored(); +} + +- (NSArray* )accessibilityParameterizedAttributeNames +{ + if (m_object->isAttachment()) + return nil; + + static NSArray* paramAttrs = nil; + static NSArray* textParamAttrs = nil; + static NSArray* tableParamAttrs = nil; + if (paramAttrs == nil) { + paramAttrs = [[NSArray alloc] initWithObjects: + @"AXUIElementForTextMarker", + @"AXTextMarkerRangeForUIElement", + @"AXLineForTextMarker", + @"AXTextMarkerRangeForLine", + @"AXStringForTextMarkerRange", + @"AXTextMarkerForPosition", + @"AXBoundsForTextMarkerRange", + @"AXAttributedStringForTextMarkerRange", + @"AXTextMarkerRangeForUnorderedTextMarkers", + @"AXNextTextMarkerForTextMarker", + @"AXPreviousTextMarkerForTextMarker", + @"AXLeftWordTextMarkerRangeForTextMarker", + @"AXRightWordTextMarkerRangeForTextMarker", + @"AXLeftLineTextMarkerRangeForTextMarker", + @"AXRightLineTextMarkerRangeForTextMarker", + @"AXSentenceTextMarkerRangeForTextMarker", + @"AXParagraphTextMarkerRangeForTextMarker", + @"AXNextWordEndTextMarkerForTextMarker", + @"AXPreviousWordStartTextMarkerForTextMarker", + @"AXNextLineEndTextMarkerForTextMarker", + @"AXPreviousLineStartTextMarkerForTextMarker", + @"AXNextSentenceEndTextMarkerForTextMarker", + @"AXPreviousSentenceStartTextMarkerForTextMarker", + @"AXNextParagraphEndTextMarkerForTextMarker", + @"AXPreviousParagraphStartTextMarkerForTextMarker", + @"AXStyleTextMarkerRangeForTextMarker", + @"AXLengthForTextMarkerRange", + NSAccessibilityBoundsForRangeParameterizedAttribute, + nil]; + } + + if (textParamAttrs == nil) { + NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; + [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute]; + [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute]; + textParamAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + if (tableParamAttrs == nil) { + NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs]; + [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute]; + tableParamAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + + if (m_object->isPasswordField()) + return [NSArray array]; + + if (!m_object->isAccessibilityRenderObject()) + return paramAttrs; + + if (m_object->isTextControl()) + return textParamAttrs; + + if (m_object->isDataTable()) + return tableParamAttrs; + + if (m_object->isMenuRelated()) + return nil; + + return paramAttrs; +} + +- (void)accessibilityPerformPressAction +{ + if (m_object->isAttachment()) + [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction]; + + m_object->press(); +} + +- (void)accessibilityPerformShowMenuAction +{ + // This needs to be performed in an iteration of the run loop that did not start from an AX call. + // If it's the same run loop iteration, the menu open notification won't be sent + [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0]; +} + +- (void)accessibilityShowContextMenu +{ + FrameView* frameView = m_object->documentFrameView(); + if (!frameView) + return; + + // simulate a click in the middle of the object + IntPoint clickPoint = m_object->clickPoint(); + NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y()); + + NSView* view = nil; + if (m_object->isAttachment()) + view = [self attachmentView]; + else + view = frameView->documentView(); + + if (!view) + return; + + NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil]; + + // Show the contextual menu for this event. + NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1]; + NSMenu* menu = [view menuForEvent:event]; + + if (menu) + [NSMenu popUpContextMenu:menu withEvent:event forView:view]; +} + +- (void)accessibilityPerformAction:(NSString*)action +{ + if ([action isEqualToString:NSAccessibilityPressAction]) + [self accessibilityPerformPressAction]; + + else if ([action isEqualToString:NSAccessibilityShowMenuAction]) + [self accessibilityPerformShowMenuAction]; +} + +- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName +{ + WebCoreTextMarkerRange* textMarkerRange = nil; + NSNumber* number = nil; + NSString* string = nil; + NSRange range = {0, 0}; + NSArray* array = nil; + + // decode the parameter + if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value]) + textMarkerRange = (WebCoreTextMarkerRange*) value; + + else if ([value isKindOfClass:[NSNumber self]]) + number = value; + + else if ([value isKindOfClass:[NSString self]]) + string = value; + + else if ([value isKindOfClass:[NSValue self]]) + range = [value rangeValue]; + + else if ([value isKindOfClass:[NSArray self]]) + array = value; + + // handle the command + if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) { + ASSERT(textMarkerRange); + m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]); + } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) { + ASSERT(number); + m_object->setFocused([number intValue] != 0); + } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) { + if (!string) + return; + m_object->setValue(string); + } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) { + if (!number) + return; + m_object->setSelected([number boolValue]); + } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) { + if (!array || m_object->roleValue() != ListBoxRole) + return; + AccessibilityObject::AccessibilityChildrenVector selectedChildren; + convertToVector(array, selectedChildren); + static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren); + } else if (m_object->isTextControl()) { + if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) { + m_object->setSelectedText(string); + } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) { + m_object->setSelectedTextRange(PlainTextRange(range.location, range.length)); + } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) { + m_object->makeRangeVisible(PlainTextRange(range.location, range.length)); + } + } +} + +static RenderObject* rendererForView(NSView* view) +{ + if (![view conformsToProtocol:@protocol(WebCoreFrameView)]) + return 0; + + NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view; + Frame* frame = [frameView _web_frame]; + if (!frame) + return 0; + + Node* node = frame->document()->ownerElement(); + if (!node) + return 0; + + return node->renderer(); +} + +- (id)_accessibilityParentForSubview:(NSView*)subview +{ + RenderObject* renderer = rendererForView(subview); + if (!renderer) + return nil; + + AccessibilityObject* obj = renderer->document()->axObjectCache()->get(renderer); + if (obj) + return obj->parentObjectUnignored()->wrapper(); + return nil; +} + +- (NSString*)accessibilityActionDescription:(NSString*)action +{ + // we have no custom actions + return NSAccessibilityActionDescription(action); +} + +// The CFAttributedStringType representation of the text associated with this accessibility +// object that is specified by the given range. +- (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range +{ + PlainTextRange textRange = PlainTextRange(range.location, range.length); + VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange); + return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)]; +} + +// The RTF representation of the text associated with this accessibility object that is +// specified by the given range. +- (NSData*)doAXRTFForRange:(NSRange)range +{ + NSAttributedString* attrString = [self doAXAttributedStringForRange:range]; + return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil]; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter +{ + WebCoreTextMarker* textMarker = nil; + WebCoreTextMarkerRange* textMarkerRange = nil; + NSNumber* number = nil; + NSArray* array = nil; + RefPtr<AccessibilityObject> uiElement = 0; + NSPoint point = NSZeroPoint; + bool pointSet = false; + NSRange range = {0, 0}; + bool rangeSet = false; + + // basic parameter validation + if (!m_object || !attribute || !parameter) + return nil; + + // common parameter type check/casting. Nil checks in handlers catch wrong type case. + // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from + // a parameter of the wrong type. + if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter]) + textMarker = (WebCoreTextMarker*) parameter; + + else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter]) + textMarkerRange = (WebCoreTextMarkerRange*) parameter; + + else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]]) + uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject]; + + else if ([parameter isKindOfClass:[NSNumber self]]) + number = parameter; + + else if ([parameter isKindOfClass:[NSArray self]]) + array = parameter; + + else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) { + pointSet = true; + point = [(NSValue*)parameter pointValue]; + + } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) { + rangeSet = true; + range = [(NSValue*)parameter rangeValue]; + + } else { + // got a parameter of a type we never use + // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally + // while using accesstool (e.g.), forcing you to start over + return nil; + } + + // Convert values to WebCore types + // FIXME: prepping all of these values as WebCore types is unnecessary in many + // cases. Re-organization of this function or performing the conversion on a + // need basis are possible improvements. + VisiblePosition visiblePos; + if (textMarker) + visiblePos = visiblePositionForTextMarker(textMarker); + int intNumber = [number intValue]; + VisiblePositionRange visiblePosRange; + if (textMarkerRange) + visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange]; + IntPoint webCorePoint = IntPoint(point); + PlainTextRange plainTextRange = PlainTextRange(range.location, range.length); + + // dispatch + if ([attribute isEqualToString: @"AXUIElementForTextMarker"]) + return m_object->accessibilityObjectForPosition(visiblePos)->wrapper(); + + if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) { + VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange(); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXLineForTextMarker"]) + return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)]; + + if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) { + VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine(intNumber); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXStringForTextMarkerRange"]) + return m_object->stringForVisiblePositionRange(visiblePosRange); + + if ([attribute isEqualToString: @"AXTextMarkerForPosition"]) + return pointSet ? textMarkerForVisiblePosition(m_object->visiblePositionForPoint(webCorePoint)) : nil; + + if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) { + NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange); + return [NSValue valueWithRect:rect]; + } + + if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) { + VisiblePosition start = m_object->visiblePositionForIndex(range.location); + VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length); + if (start.isNull() || end.isNull()) + return nil; + NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end)); + return [NSValue valueWithRect:rect]; + } + + if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"]) + return [self doAXAttributedStringForTextMarkerRange:textMarkerRange]; + + if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) { + if ([array count] < 2) + return nil; + + WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0]; + WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1]; + if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1] + || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2]) + return nil; + + VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1); + VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2); + VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->nextVisiblePosition(visiblePos)); + + if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->previousVisiblePosition(visiblePos)); + + if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->nextWordEnd(visiblePos)); + + if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->previousWordStart(visiblePos)); + + if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->nextLineEndPosition(visiblePos)); + + if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->previousLineStartPosition(visiblePos)); + + if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->nextSentenceEndPosition(visiblePos)); + + if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->previousSentenceStartPosition(visiblePos)); + + if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->nextParagraphEndPosition(visiblePos)); + + if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"]) + return textMarkerForVisiblePosition(m_object->previousParagraphStartPosition(visiblePos)); + + if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) { + VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos); + return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end); + } + + if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) { + int length = m_object->lengthForVisiblePositionRange(visiblePosRange); + if (length < 0) + return nil; + return [NSNumber numberWithInt:length]; + } + + if (m_object->isDataTable()) { + if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) { + if (array == nil || [array count] != 2) + return nil; + AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]); + if (!cell) + return nil; + + return cell->wrapper(); + } + } + + if (m_object->isTextControl()) { + if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) { + int lineNumber = m_object->doAXLineForIndex(intNumber); + if (lineNumber < 0) + return nil; + return [NSNumber numberWithUnsignedInt:lineNumber]; + } + + if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) { + PlainTextRange textRange = m_object->doAXRangeForLine(intNumber); + return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; + } + + if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) + return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil; + + if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) { + if (!pointSet) + return nil; + PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint); + return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; + } + + if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) { + PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber); + return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; + } + + if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) { + if (!rangeSet) + return nil; + NSRect rect = m_object->doAXBoundsForRange(plainTextRange); + return [NSValue valueWithRect:rect]; + } + + if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute]) + return rangeSet ? [self doAXRTFForRange:range] : nil; + + if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute]) + return rangeSet ? [self doAXAttributedStringForRange:range] : nil; + + if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) { + PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber); + return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)]; + } + } + + return nil; +} + +- (BOOL)accessibilityShouldUseUniqueId +{ + return m_object->accessibilityShouldUseUniqueId(); +} + +// API that AppKit uses for faster access +- (NSUInteger)accessibilityIndexOfChild:(id)child +{ + const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); + + if (children.isEmpty()) + return [[self renderWidgetChildren] indexOfObject:child]; + + unsigned count = children.size(); + for (unsigned k = 0; k < count; ++k) { + if (children[k]->wrapper() == child) + return k; + } + + return NSNotFound; +} + +- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute +{ + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); + if (children.isEmpty()) + return [[self renderWidgetChildren] count]; + + return children.size(); + } + + return [super accessibilityArrayAttributeCount:attribute]; +} + +- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount +{ + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + if (m_object->children().isEmpty()) { + NSArray *children = [self renderWidgetChildren]; + if (!children) + return nil; + + NSUInteger childCount = [children count]; + if (index >= childCount) + return nil; + + NSUInteger arrayLength = min(childCount - index, maxCount); + return [children subarrayWithRange:NSMakeRange(index, arrayLength)]; + } + + const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children(); + unsigned childCount = children.size(); + if (index >= childCount) + return nil; + + unsigned available = min(childCount - index, maxCount); + + NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available]; + for (unsigned added = 0; added < available; ++index, ++added) + [subarray addObject:children[index]->wrapper()]; + + return subarray; + } + + return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount]; +} + +@end diff --git a/WebCore/page/mac/ChromeMac.mm b/WebCore/page/mac/ChromeMac.mm index 9fc8107..aba3449 100644 --- a/WebCore/page/mac/ChromeMac.mm +++ b/WebCore/page/mac/ChromeMac.mm @@ -1,6 +1,5 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,8 +21,7 @@ #import "Chrome.h" #import "BlockExceptions.h" -#import "Frame.h" -#import "Page.h" +#import "ChromeClient.h" namespace WebCore { @@ -31,25 +29,23 @@ void Chrome::focusNSView(NSView* view) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - WebCoreFrameBridge *bridge = m_page->mainFrame()->bridge(); - NSResponder *firstResponder = [bridge firstResponder]; + NSResponder *firstResponder = client()->firstResponder(); if (firstResponder == view) return; if (![view window] || ![view superview] || ![view acceptsFirstResponder]) return; - [bridge makeFirstResponder:view]; + client()->makeFirstResponder(view); // Setting focus can actually cause a style change which might // remove the view from its superview while it's being made // first responder. This confuses AppKit so we must restore // the old first responder. if (![view superview]) - [bridge makeFirstResponder:firstResponder]; + client()->makeFirstResponder(firstResponder); END_BLOCK_OBJC_EXCEPTIONS; } } // namespace WebCore - diff --git a/WebCore/page/mac/EventHandlerMac.mm b/WebCore/page/mac/EventHandlerMac.mm index ca2f94c..562c1dd 100644 --- a/WebCore/page/mac/EventHandlerMac.mm +++ b/WebCore/page/mac/EventHandlerMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,35 +27,27 @@ #include "EventHandler.h" #include "BlockExceptions.h" +#include "ChromeClient.h" #include "ClipboardMac.h" -#include "Cursor.h" -#include "Document.h" -#include "DragController.h" #include "EventNames.h" -#include "FloatPoint.h" #include "FocusController.h" -#include "FoundationExtras.h" #include "FrameLoader.h" #include "Frame.h" -#include "FrameTree.h" #include "FrameView.h" -#include "HTMLFrameOwnerElement.h" -#include "HTMLFrameSetElement.h" -#include "HitTestRequest.h" -#include "HitTestResult.h" #include "KeyboardEvent.h" #include "MouseEventWithHitTestResults.h" #include "Page.h" #include "PlatformKeyboardEvent.h" -#include "PlatformScrollBar.h" #include "PlatformWheelEvent.h" #include "RenderWidget.h" +#include "Scrollbar.h" #include "Settings.h" -#include "WebCoreFrameBridge.h" namespace WebCore { -using namespace EventNames; +unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; + +const double EventHandler::TextDragDelay = 0.15; static RetainPtr<NSEvent>& currentEvent() { @@ -91,10 +83,10 @@ PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const case NSKeyDown: { PlatformKeyboardEvent platformEvent(event); platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown); - return new KeyboardEvent(platformEvent, m_frame->document() ? m_frame->document()->defaultView() : 0); + return KeyboardEvent::create(platformEvent, m_frame->document() ? m_frame->document()->defaultView() : 0); } case NSKeyUp: - return new KeyboardEvent(event, m_frame->document() ? m_frame->document()->defaultView() : 0); + return KeyboardEvent::create(event, m_frame->document() ? m_frame->document()->defaultView() : 0); default: return 0; } @@ -103,9 +95,9 @@ PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const static inline bool isKeyboardOptionTab(KeyboardEvent* event) { return event - && (event->type() == keydownEvent || event->type() == keypressEvent) - && event->altKey() - && event->keyIdentifier() == "U+0009"; + && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) + && event->altKey() + && event->keyIdentifier() == "U+0009"; } bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const @@ -115,7 +107,11 @@ bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const bool EventHandler::tabsToAllControls(KeyboardEvent* event) const { - KeyboardUIMode keyboardUIMode = [m_frame->bridge() keyboardUIMode]; + Page* page = m_frame->page(); + if (!page) + return false; + + KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode(); bool handlingOptionTab = isKeyboardOptionTab(event); // If tab-to-links is off, option-tab always highlights all controls @@ -148,12 +144,21 @@ bool EventHandler::needsKeyboardEventDisambiguationQuirks() const return false; // RSS view needs arrow key keypress events. - if (isSafari && document->url().startsWith("feed:", false) || document->url().startsWith("feeds:", false)) + if (isSafari && document->url().protocolIs("feed") || document->url().protocolIs("feeds")) return true; Settings* settings = m_frame->settings(); if (!settings) return false; - return settings->usesDashboardBackwardCompatibilityMode() || settings->needsKeyboardEventDisambiguationQuirks(); + +#if ENABLE(DASHBOARD_SUPPORT) + if (settings->usesDashboardBackwardCompatibilityMode()) + return true; +#endif + + if (settings->needsKeyboardEventDisambiguationQuirks()) + return true; + + return false; } bool EventHandler::keyEvent(NSEvent *event) @@ -184,10 +189,11 @@ void EventHandler::focusDocumentView() if (!page) return; - if (FrameView* frameView = m_frame->view()) - if (NSView *documentView = frameView->getDocumentView()) + if (FrameView* frameView = m_frame->view()) { + if (NSView *documentView = frameView->documentView()) page->chrome()->focusNSView(documentView); - + } + page->focusController()->setFocusedFrame(m_frame); } @@ -239,7 +245,7 @@ bool EventHandler::passMouseDownEventToWidget(Widget* widget) BEGIN_BLOCK_OBJC_EXCEPTIONS; - NSView *nodeView = widget->getView(); + NSView *nodeView = widget->platformWidget(); ASSERT(nodeView); ASSERT([nodeView superview]); NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]]; @@ -248,11 +254,15 @@ bool EventHandler::passMouseDownEventToWidget(Widget* widget) return true; } - if ([m_frame->bridge() firstResponder] != view) { + Page* page = m_frame->page(); + if (!page) + return true; + + if (page->chrome()->client()->firstResponder() != view) { // Normally [NSWindow sendEvent:] handles setting the first responder. // But in our case, the event was sent to the view representing the entire web page. if ([currentEvent().get() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) - [m_frame->bridge() makeFirstResponder:view]; + page->chrome()->client()->makeFirstResponder(view); } // We need to "defer loading" while tracking the mouse, because tearing down the @@ -262,9 +272,9 @@ bool EventHandler::passMouseDownEventToWidget(Widget* widget) // mouse. We should confirm that, and then remove the deferrsLoading // hack entirely. - bool wasDeferringLoading = m_frame->page()->defersLoading(); + bool wasDeferringLoading = page->defersLoading(); if (!wasDeferringLoading) - m_frame->page()->setDefersLoading(true); + page->setDefersLoading(true); ASSERT(!m_sendingEventToSubview); m_sendingEventToSubview = true; @@ -272,7 +282,7 @@ bool EventHandler::passMouseDownEventToWidget(Widget* widget) m_sendingEventToSubview = false; if (!wasDeferringLoading) - m_frame->page()->setDefersLoading(false); + page->setDefersLoading(false); // Remember which view we sent the event to, so we can direct the release event properly. m_mouseDownView = view; @@ -319,7 +329,7 @@ NSView *EventHandler::mouseDownViewIfStillGood() return nil; } FrameView* topFrameView = m_frame->view(); - NSView *topView = topFrameView ? topFrameView->getView() : nil; + NSView *topView = topFrameView ? topFrameView->platformWidget() : nil; if (!topView || !findViewInSubviews(topView, mouseDownView)) { m_mouseDownView = nil; return nil; @@ -350,13 +360,13 @@ bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResult return true; } -Clipboard* EventHandler::createDraggingClipboard() const +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; // Must be done before ondragstart adds types and data to the pboard, // also done for security, as it erases data from the last drag [pasteboard declareTypes:[NSArray array] owner:nil]; - return new ClipboardMac(true, pasteboard, ClipboardWritable, m_frame); + return ClipboardMac::create(true, pasteboard, ClipboardWritable, m_frame); } bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&) @@ -442,7 +452,7 @@ bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget* widget) if ([currentEvent().get() type] != NSScrollWheel || m_sendingEventToSubview || !widget) return false; - NSView *nodeView = widget->getView(); + NSView* nodeView = widget->platformWidget(); ASSERT(nodeView); ASSERT([nodeView superview]); NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]]; @@ -545,6 +555,10 @@ void EventHandler::mouseUp(NSEvent *event) */ void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent) { + FrameView* view = m_frame->view(); + if (!view) + return; + BEGIN_BLOCK_OBJC_EXCEPTIONS; m_sendingEventToSubview = false; @@ -553,34 +567,34 @@ void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent) NSEvent *fakeEvent = nil; if (eventType == NSLeftMouseDown) { fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp - location:[initiatingEvent locationInWindow] - modifierFlags:[initiatingEvent modifierFlags] - timestamp:[initiatingEvent timestamp] - windowNumber:[initiatingEvent windowNumber] - context:[initiatingEvent context] - eventNumber:[initiatingEvent eventNumber] - clickCount:[initiatingEvent clickCount] - pressure:[initiatingEvent pressure]]; + location:[initiatingEvent locationInWindow] + modifierFlags:[initiatingEvent modifierFlags] + timestamp:[initiatingEvent timestamp] + windowNumber:[initiatingEvent windowNumber] + context:[initiatingEvent context] + eventNumber:[initiatingEvent eventNumber] + clickCount:[initiatingEvent clickCount] + pressure:[initiatingEvent pressure]]; [NSApp postEvent:fakeEvent atStart:YES]; } else { // eventType == NSKeyDown fakeEvent = [NSEvent keyEventWithType:NSKeyUp - location:[initiatingEvent locationInWindow] - modifierFlags:[initiatingEvent modifierFlags] - timestamp:[initiatingEvent timestamp] - windowNumber:[initiatingEvent windowNumber] - context:[initiatingEvent context] - characters:[initiatingEvent characters] - charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] - isARepeat:[initiatingEvent isARepeat] - keyCode:[initiatingEvent keyCode]]; + location:[initiatingEvent locationInWindow] + modifierFlags:[initiatingEvent modifierFlags] + timestamp:[initiatingEvent timestamp] + windowNumber:[initiatingEvent windowNumber] + context:[initiatingEvent context] + characters:[initiatingEvent characters] + charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] + isARepeat:[initiatingEvent isARepeat] + keyCode:[initiatingEvent keyCode]]; [NSApp postEvent:fakeEvent atStart:YES]; } - // FIXME: We should really get the current modifierFlags here, but there's no way to poll + // FIXME: We should really get the current modifierFlags here, but there's no way to poll // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have // no up-to-date cache of them anywhere. fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved - location:[[m_frame->bridge() window] convertScreenToBase:[NSEvent mouseLocation]] + location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]] modifierFlags:[initiatingEvent modifierFlags] timestamp:[initiatingEvent timestamp] windowNumber:[initiatingEvent windowNumber] @@ -629,9 +643,4 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& return passSubframeEventToSubframe(mev, subframe); } -bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults&, PlatformScrollbar* scrollbar) -{ - return passMouseDownEventToWidget(scrollbar); -} - } diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index 8a75797..66e2d04 100644 --- a/WebCore/page/mac/FrameMac.mm +++ b/WebCore/page/mac/FrameMac.mm @@ -1,7 +1,7 @@ /* - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) - * Copyright (C) 2007 Trolltech ASA + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,35 +28,17 @@ #import "config.h" #import "Frame.h" -#import "AXObjectCache.h" -#import "BeforeUnloadEvent.h" #import "BlockExceptions.h" -#import "CSSHelper.h" -#import "Cache.h" -#import "Chrome.h" -#import "ClipboardEvent.h" -#import "ClipboardMac.h" #import "ColorMac.h" #import "Cursor.h" #import "DOMInternal.h" #import "DocumentLoader.h" -#import "EditCommand.h" #import "EditorClient.h" #import "Event.h" -#import "EventNames.h" -#import "FloatRect.h" -#import "FoundationExtras.h" -#import "FrameLoadRequest.h" -#import "FrameLoader.h" #import "FrameLoaderClient.h" -#import "FrameLoaderTypes.h" #import "FramePrivate.h" #import "FrameView.h" #import "GraphicsContext.h" -#import "HTMLDocument.h" -#import "HTMLFormElement.h" -#import "HTMLGenericFormElement.h" -#import "HTMLInputElement.h" #import "HTMLNames.h" #import "HTMLTableCellElement.h" #import "HitTestRequest.h" @@ -66,76 +48,34 @@ #import "MouseEventWithHitTestResults.h" #import "Page.h" #import "PlatformKeyboardEvent.h" -#import "PlatformScrollBar.h" #import "PlatformWheelEvent.h" -#import "Plugin.h" #import "RegularExpression.h" -#import "RenderImage.h" -#import "RenderListItem.h" -#import "RenderPart.h" #import "RenderTableCell.h" -#import "RenderTheme.h" -#import "RenderView.h" -#import "ResourceHandle.h" -#import "Settings.h" +#import "Scrollbar.h" #import "SimpleFontData.h" -#import "SystemTime.h" -#import "TextResourceDecoder.h" #import "UserStyleSheetLoader.h" -#import "WebCoreFrameBridge.h" -#import "WebCoreSystemInterface.h" #import "WebCoreViewFactory.h" -#import "WebDashboardRegion.h" -#import "WebScriptObjectPrivate.h" -#import "kjs_proxy.h" -#import "kjs_window.h" #import "visible_units.h" -#import <Carbon/Carbon.h> -#import <JavaScriptCore/NP_jsobject.h> -#import <JavaScriptCore/npruntime_impl.h> -#undef _webcore_TIMING +#import <Carbon/Carbon.h> +#import <runtime/JSLock.h> -@interface NSObject (WebPlugIn) -- (id)objectForWebScript; -- (NPObject *)createPluginScriptableObject; -@end +#if ENABLE(DASHBOARD_SUPPORT) +#import "WebDashboardRegion.h" +#endif @interface NSView (WebCoreHTMLDocumentView) - (void)drawSingleRect:(NSRect)rect; @end using namespace std; -using namespace KJS::Bindings; -using KJS::JSLock; +using JSC::JSLock; namespace WebCore { -using namespace EventNames; using namespace HTMLNames; -void Frame::setBridge(WebCoreFrameBridge* bridge) -{ - if (d->m_bridge == bridge) - return; - - if (!bridge) { - [d->m_bridge clearFrame]; - HardRelease(d->m_bridge); - d->m_bridge = nil; - return; - } - HardRetain(bridge); - HardRelease(d->m_bridge); - d->m_bridge = bridge; -} - -WebCoreFrameBridge* Frame::bridge() const -{ - return d->m_bridge; -} - // Either get cached regexp or build one that matches any of the labels. // The regexp we build is of the form: (STR1|STR2|STRN) RegularExpression* regExpForLabels(NSArray* labels) @@ -158,17 +98,17 @@ RegularExpression* regExpForLabels(NSArray* labels) if (cacheHit != NSNotFound) result = regExps.at(cacheHit); else { - DeprecatedString pattern("("); + String pattern("("); unsigned int numLabels = [labels count]; unsigned int i; for (i = 0; i < numLabels; i++) { - DeprecatedString label = DeprecatedString::fromNSString((NSString*)[labels objectAtIndex:i]); + String label = [labels objectAtIndex:i]; bool startsWithWordChar = false; bool endsWithWordChar = false; if (label.length() != 0) { - startsWithWordChar = wordRegExp.search(label.at(0)) >= 0; - endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0; + startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0; + endsWithWordChar = wordRegExp.search(label.substring(label.length() - 1, 1)) >= 0; } if (i != 0) @@ -176,13 +116,11 @@ RegularExpression* regExpForLabels(NSArray* labels) // Search for word boundaries only if label starts/ends with "word characters". // If we always searched for word boundaries, this wouldn't work for languages // such as Japanese. - if (startsWithWordChar) { + if (startsWithWordChar) pattern.append("\\b"); - } pattern.append(label); - if (endsWithWordChar) { + if (endsWithWordChar) pattern.append("\\b"); - } } pattern.append(")"); result = new RegularExpression(pattern, false); @@ -225,10 +163,10 @@ NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTable for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) { if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { // For each text chunk, run the regexp - DeprecatedString nodeString = n->nodeValue().deprecatedString(); + String nodeString = n->nodeValue(); int pos = regExp->searchRev(nodeString); if (pos >= 0) - return nodeString.mid(pos, regExp->matchedLength()).getNSString(); + return nodeString.substring(pos, regExp->matchedLength()); } } } @@ -272,13 +210,13 @@ NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element) searchedCellAbove = true; } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { // For each text chunk, run the regexp - DeprecatedString nodeString = n->nodeValue().deprecatedString(); + String nodeString = n->nodeValue(); // add 100 for slop, to make it more likely that we'll search whole nodes if (lengthSearched + nodeString.length() > maxCharsSearched) nodeString = nodeString.right(charsSearchedThreshold - lengthSearched); int pos = regExp->searchRev(nodeString); if (pos >= 0) - return nodeString.mid(pos, regExp->matchedLength()).getNSString(); + return nodeString.substring(pos, regExp->matchedLength()); lengthSearched += nodeString.length(); } @@ -297,11 +235,14 @@ NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element) NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element) { - DeprecatedString name = element->getAttribute(nameAttr).deprecatedString(); + String name = element->getAttribute(nameAttr); + if (name.isEmpty()) + return nil; + // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" - name.replace(RegularExpression("\\d"), " "); + replace(name, RegularExpression("\\d"), " "); name.replace('_', ' '); - + RegularExpression* regExp = regExpForLabels(labels); // Use the largest match we can find in the whole name string int pos; @@ -317,18 +258,18 @@ NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element) bestPos = pos; bestLength = length; } - start = pos+1; + start = pos + 1; } } while (pos != -1); if (bestPos != -1) - return name.mid(bestPos, bestLength).getNSString(); + return name.substring(bestPos, bestLength); return nil; } NSImage* Frame::imageFromRect(NSRect rect) const { - NSView* view = d->m_view->getDocumentView(); + NSView* view = d->m_view->documentView(); if (!view) return nil; if (![view respondsToSelector:@selector(drawSingleRect:)]) @@ -373,10 +314,10 @@ NSImage* Frame::imageFromRect(NSRect rect) const NSImage* Frame::selectionImage(bool forceBlackText) const { - d->m_paintRestriction = forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly; + d->m_view->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); d->m_doc->updateLayout(); NSImage* result = imageFromRect(selectionRect()); - d->m_paintRestriction = PaintRestrictionNone; + d->m_view->setPaintRestriction(PaintRestrictionNone); return result; } @@ -392,11 +333,11 @@ NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* element IntRect topLevelRect; NSRect paintingRect = renderer->paintingRootRect(topLevelRect); - d->m_elementToDraw = node; // invoke special sub-tree drawing mode + d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode NSImage* result = imageFromRect(paintingRect); renderer->updateDragState(false); d->m_doc->updateLayout(); - d->m_elementToDraw = 0; + d->m_view->setNodeToDraw(0); if (elementRect) *elementRect = topLevelRect; @@ -405,6 +346,24 @@ NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* element return result; } +NSImage* Frame::nodeImage(Node* node) const +{ + RenderObject* renderer = node->renderer(); + if (!renderer) + return nil; + + d->m_doc->updateLayout(); // forces style recalc + + IntRect topLevelRect; + NSRect paintingRect = renderer->paintingRootRect(topLevelRect); + + d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode + NSImage* result = imageFromRect(paintingRect); + d->m_view->setNodeToDraw(0); + + return result; +} + NSDictionary* Frame::fontAttributesForSelectionStart() const { Node* nodeToRemove; @@ -473,11 +432,22 @@ NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const { NSWritingDirection result = NSWritingDirectionLeftToRight; - Position pos = selectionController()->selection().visibleStart().deepEquivalent(); + Position pos = selection()->selection().visibleStart().deepEquivalent(); Node* node = pos.node(); - if (!node || !node->renderer() || !node->renderer()->containingBlock()) + if (!node) return result; - RenderStyle* style = node->renderer()->containingBlock()->style(); + + RenderObject* renderer = node->renderer(); + if (!renderer) + return result; + + if (!renderer->isBlockFlow()) { + renderer = renderer->containingBlock(); + if (!renderer) + return result; + } + + RenderStyle* style = renderer->style(); if (!style) return result; @@ -493,11 +463,6 @@ NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const return result; } -void Frame::issuePasteCommand() -{ - [d->m_bridge issuePasteCommand]; -} - const short enableRomanKeyboardsOnly = -23; void Frame::setUseSecureKeyboardEntry(bool enable) { @@ -522,6 +487,7 @@ void Frame::setUseSecureKeyboardEntry(bool enable) } } +#if ENABLE(DASHBOARD_SUPPORT) NSMutableDictionary* Frame::dashboardRegionsDictionary() { Document* doc = document(); @@ -559,106 +525,15 @@ NSMutableDictionary* Frame::dashboardRegionsDictionary() return webRegions; } - -void Frame::dashboardRegionsChanged() -{ - NSMutableDictionary *webRegions = dashboardRegionsDictionary(); - [d->m_bridge dashboardRegionsChanged:webRegions]; -} - -void Frame::willPopupMenu(NSMenu * menu) -{ - [d->m_bridge willPopupMenu:menu]; -} - -FloatRect Frame::customHighlightLineRect(const AtomicString& type, const FloatRect& lineRect, Node* node) -{ - return [d->m_bridge customHighlightRect:type forLine:lineRect representedNode:node]; -} - -void Frame::paintCustomHighlight(const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, bool text, bool line, Node* node) -{ - [d->m_bridge paintCustomHighlight:type forBox:boxRect onLine:lineRect behindText:text entireLine:line representedNode:node]; -} +#endif DragImageRef Frame::dragImageForSelection() { - if (!selectionController()->isRange()) + if (!selection()->isRange()) return nil; return selectionImage(); } - -KJS::Bindings::Instance* Frame::createScriptInstanceForWidget(WebCore::Widget* widget) -{ - NSView* aView = widget->getView(); - if (!aView) - return 0; - - void* nativeHandle = aView; - CreateRootObjectFunction createRootObject = RootObject::createRootObject(); - RefPtr<RootObject> rootObject = createRootObject(nativeHandle); - - if ([aView respondsToSelector:@selector(objectForWebScript)]) { - id objectForWebScript = [aView objectForWebScript]; - if (objectForWebScript) - return Instance::createBindingForLanguageInstance(Instance::ObjectiveCLanguage, objectForWebScript, rootObject.release()); - return 0; - } else if ([aView respondsToSelector:@selector(createPluginScriptableObject)]) { -#if USE(NPOBJECT) - NPObject* npObject = [aView createPluginScriptableObject]; - if (npObject) { - Instance* instance = Instance::createBindingForLanguageInstance(Instance::CLanguage, npObject, rootObject.release()); - - // -createPluginScriptableObject returns a retained NPObject. The caller is expected to release it. - _NPN_ReleaseObject(npObject); - return instance; - } -#endif - return 0; - } - - jobject applet; - - // Get a pointer to the actual Java applet instance. - if ([d->m_bridge respondsToSelector:@selector(getAppletInView:)]) - applet = [d->m_bridge getAppletInView:aView]; - else - applet = [d->m_bridge pollForAppletInView:aView]; - - if (applet) { - // Wrap the Java instance in a language neutral binding and hand - // off ownership to the APPLET element. - Instance* instance = Instance::createBindingForLanguageInstance(Instance::JavaLanguage, applet, rootObject.release()); - return instance; - } - - return 0; -} - -WebScriptObject* Frame::windowScriptObject() -{ - if (!scriptProxy()->isEnabled()) - return 0; - - if (!d->m_windowScriptObject) { - KJS::JSLock lock; - KJS::JSObject* win = KJS::Window::retrieveWindow(this); - KJS::Bindings::RootObject *root = bindingRootObject(); - d->m_windowScriptObject = [WebScriptObject scriptObjectForJSObject:toRef(win) originRootObject:root rootObject:root]; - } - - return d->m_windowScriptObject.get(); -} - -void Frame::clearPlatformScriptObjects() -{ - if (d->m_windowScriptObject) { - KJS::Bindings::RootObject* root = bindingRootObject(); - [d->m_windowScriptObject.get() _setOriginRootObject:root andRootObject:root]; - } -} - void Frame::setUserStyleSheetLocation(const KURL& url) { delete d->m_userStyleSheetLoader; diff --git a/WebCore/page/mac/PageMac.cpp b/WebCore/page/mac/PageMac.cpp new file mode 100644 index 0000000..7386eea --- /dev/null +++ b/WebCore/page/mac/PageMac.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DocumentLoader.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "Page.h" + +namespace WebCore { + +void Page::addSchedulePair(PassRefPtr<SchedulePair> prpPair) +{ + RefPtr<SchedulePair> pair = prpPair; + + if (!m_scheduledRunLoopPairs) + m_scheduledRunLoopPairs.set(new SchedulePairHashSet); + m_scheduledRunLoopPairs->add(pair); + +#ifndef BUILDING_ON_TIGER + for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { + if (DocumentLoader* documentLoader = frame->loader()->documentLoader()) + documentLoader->schedule(pair.get()); + if (DocumentLoader* documentLoader = frame->loader()->provisionalDocumentLoader()) + documentLoader->schedule(pair.get()); + } +#endif + + // FIXME: make SharedTimerMac use these SchedulePairs. +} + +void Page::removeSchedulePair(PassRefPtr<SchedulePair> prpPair) +{ + ASSERT(m_scheduledRunLoopPairs); + if (!m_scheduledRunLoopPairs) + return; + + RefPtr<SchedulePair> pair = prpPair; + m_scheduledRunLoopPairs->remove(pair); + +#ifndef BUILDING_ON_TIGER + for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { + if (DocumentLoader* documentLoader = frame->loader()->documentLoader()) + documentLoader->unschedule(pair.get()); + if (DocumentLoader* documentLoader = frame->loader()->provisionalDocumentLoader()) + documentLoader->unschedule(pair.get()); + } +#endif +} + +} // namespace diff --git a/WebCore/page/mac/WebCoreFrameBridge.h b/WebCore/page/mac/WebCoreFrameBridge.h deleted file mode 100644 index a67f1b3..0000000 --- a/WebCore/page/mac/WebCoreFrameBridge.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006, 2007 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 <Cocoa/Cocoa.h> -#import <JavaVM/jni.h> -#import <WebCore/WebCoreKeyboardUIMode.h> -#import <WebCore/EditAction.h> -#import <WebCore/FrameLoaderTypes.h> -#import <WebCore/SelectionController.h> -#import <WebCore/TextAffinity.h> -#import <WebCore/TextGranularity.h> - -#if USE(NPOBJECT) -#import <JavaScriptCore/npruntime.h> -#endif - -namespace WebCore { - class Frame; - class HTMLFrameOwnerElement; - class Page; - class String; -} - -@class DOMCSSStyleDeclaration; -@class DOMDocument; -@class DOMDocumentFragment; -@class DOMElement; -@class DOMHTMLInputElement; -@class DOMHTMLTextAreaElement; -@class DOMNode; -@class DOMRange; -@class NSMenu; - -@protocol WebCoreRenderTreeCopier; - -enum WebCoreDeviceType { - WebCoreDeviceScreen, - WebCoreDevicePrinter -}; - -enum WebScrollDirection { - WebScrollUp, - WebScrollDown, - WebScrollLeft, - WebScrollRight -}; - -enum WebScrollGranularity { - WebScrollLine, - WebScrollPage, - WebScrollDocument, - WebScrollWheel -}; - -@protocol WebCoreOpenPanelResultListener <NSObject> -- (void)chooseFilename:(NSString *)fileName; -- (void)cancel; -@end - -// WebCoreFrameBridge objects are used by WebCore to abstract away operations that need -// to be implemented by library clients, for example WebKit. The objects are also -// used in the opposite direction, for simple access to WebCore functions without dealing -// directly with the KHTML C++ classes. - -// A WebCoreFrameBridge creates and holds a reference to a Frame. - -// The WebCoreFrameBridge interface contains methods for use by the non-WebCore side of the bridge. - -@interface WebCoreFrameBridge : NSObject -{ -@public - WebCore::Frame* m_frame; - BOOL _shouldCreateRenderers; - BOOL _closed; -} - -- (WebCore::Frame*)_frame; // underscore to prevent conflict with -[NSView frame] - -+ (WebCoreFrameBridge *)bridgeForDOMDocument:(DOMDocument *)document; - -- (id)init; -- (void)close; - -- (void)clearFrame; - -- (NSURL *)baseURL; - -- (void)installInFrame:(NSView *)view; - -- (BOOL)scrollOverflowInDirection:(WebScrollDirection)direction granularity:(WebScrollGranularity)granularity; - -- (void)createFrameViewWithNSView:(NSView *)view marginWidth:(int)mw marginHeight:(int)mh; - -- (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType; -- (void)forceLayoutAdjustingViewSize:(BOOL)adjustSizeFlag; -- (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)adjustSizeFlag; -- (void)sendScrollEvent; -- (BOOL)needsLayout; -- (void)drawRect:(NSRect)rect; -- (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit; -- (NSArray*)computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight; - -- (NSObject *)copyRenderTree:(id <WebCoreRenderTreeCopier>)copier; -- (NSString *)renderTreeAsExternalRepresentation; - -- (NSURL *)URLWithAttributeString:(NSString *)string; - -- (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form; -- (BOOL)elementDoesAutoComplete:(DOMElement *)element; -- (BOOL)elementIsPassword:(DOMElement *)element; -- (DOMElement *)formForElement:(DOMElement *)element; -- (DOMElement *)currentForm; -- (NSArray *)controlsInForm:(DOMElement *)form; -- (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element; -- (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element; - -- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection; -- (unsigned)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag limit:(unsigned)limit; -- (BOOL)markedTextMatchesAreHighlighted; -- (void)setMarkedTextMatchesAreHighlighted:(BOOL)doHighlight; -- (void)unmarkAllTextMatches; -- (NSArray *)rectsForTextMatches; - -- (void)setTextSizeMultiplier:(float)multiplier; - -- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string; -- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture; -- (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)string; - -- (NSString *)selectedString; - -- (NSString *)stringForRange:(DOMRange *)range; - -- (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes; -- (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes; - -- (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity; -- (NSRect)firstRectForDOMRange:(DOMRange *)range; -- (void)scrollDOMRangeToVisible:(DOMRange *)range; - -- (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts; - -- (NSString *)stringWithData:(NSData *)data; // using the encoding of the frame's main resource -+ (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName; // nil for textEncodingName means Latin-1 - -- (void)setShouldCreateRenderers:(BOOL)shouldCreateRenderers; - -- (void)setBaseBackgroundColor:(NSColor *)backgroundColor; -- (void)setDrawsBackground:(BOOL)drawsBackround; - -- (id)accessibilityTree; - -- (DOMRange *)rangeByAlteringCurrentSelection:(WebCore::SelectionController::EAlteration)alteration direction:(WebCore::SelectionController::EDirection)direction granularity:(WebCore::TextGranularity)granularity; -- (WebCore::TextGranularity)selectionGranularity; -- (void)smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)charRangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString; -- (void)selectNSRange:(NSRange)range; -- (NSRange)selectedNSRange; -- (NSRange)markedTextNSRange; -- (DOMRange *)convertNSRangeToDOMRange:(NSRange)range; -- (NSRange)convertDOMRangeToNSRange:(DOMRange *)range; - -- (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString; -- (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text inContext:(DOMRange *)context; -- (DOMDocumentFragment *)documentFragmentWithNodesAsParagraphs:(NSArray *)nodes; - -- (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle; -- (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle; -- (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace; -- (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace; - -- (void)insertParagraphSeparatorInQuotedContent; - -- (DOMRange *)characterRangeAtPoint:(NSPoint)point; - -- (DOMCSSStyleDeclaration *)typingStyle; -- (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(WebCore::EditAction)undoAction; - -- (void)dragSourceMovedTo:(NSPoint)windowLoc; -- (void)dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation; - -- (BOOL)getData:(NSData **)data andResponse:(NSURLResponse **)response forURL:(NSString *)URL; -- (void)getAllResourceDatas:(NSArray **)datas andResponses:(NSArray **)responses; - -- (BOOL)canProvideDocumentSource; -- (BOOL)canSaveAsWebArchive; - -- (void)receivedData:(NSData *)data textEncodingName:(NSString *)textEncodingName; - -@end - -// The WebCoreFrameBridge protocol contains methods for use by the WebCore side of the bridge. - -@protocol WebCoreFrameBridge - -- (NSWindow *)window; - -- (NSResponder *)firstResponder; -- (void)makeFirstResponder:(NSResponder *)responder; - -- (void)runOpenPanelForFileButtonWithResultListener:(id <WebCoreOpenPanelResultListener>)resultListener; - -- (jobject)getAppletInView:(NSView *)view; - -// Deprecated, use getAppletInView: instead. -- (jobject)pollForAppletInView:(NSView *)view; - -- (void)issuePasteCommand; - -- (void)setIsSelected:(BOOL)isSelected forView:(NSView *)view; - -- (void)dashboardRegionsChanged:(NSMutableDictionary *)regions; -- (void)willPopupMenu:(NSMenu *)menu; - -- (NSRect)customHighlightRect:(NSString*)type forLine:(NSRect)lineRect representedNode:(WebCore::Node *)node; -- (void)paintCustomHighlight:(NSString*)type forBox:(NSRect)boxRect onLine:(NSRect)lineRect behindText:(BOOL)text entireLine:(BOOL)line representedNode:(WebCore::Node *)node; - -- (WebCore::KeyboardUIMode)keyboardUIMode; - -- (NSString*)imageTitleForFilename:(NSString*)filename size:(NSSize)size; - -@end - -// This interface definition allows those who hold a WebCoreFrameBridge * to call all the methods -// in the WebCoreFrameBridge protocol without requiring the base implementation to supply the methods. -// This idiom is appropriate because WebCoreFrameBridge is an abstract class. - -@interface WebCoreFrameBridge (SubclassResponsibility) <WebCoreFrameBridge> -@end - -// Protocols that make up part of the interfaces above. - -@protocol WebCoreRenderTreeCopier <NSObject> -- (NSObject *)nodeWithName:(NSString *)name position:(NSPoint)p rect:(NSRect)rect view:(NSView *)view children:(NSArray *)children; -@end diff --git a/WebCore/page/mac/WebCoreFrameBridge.mm b/WebCore/page/mac/WebCoreFrameBridge.mm deleted file mode 100644 index d280bcb..0000000 --- a/WebCore/page/mac/WebCoreFrameBridge.mm +++ /dev/null @@ -1,1244 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2005, 2006 Alexey Proskuryakov (ap@nypop.com) - * Copyright (C) 2006 David Smith (catfish.man@gmail.com) - * - * 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 "WebCoreFrameBridge.h" - -#import "AXObjectCache.h" -#import "CSSHelper.h" -#import "Cache.h" -#import "ClipboardMac.h" -#import "ColorMac.h" -#import "DOMImplementation.h" -#import "DOMInternal.h" -#import "DOMWindow.h" -#import "DeleteSelectionCommand.h" -#import "DocLoader.h" -#import "DocumentFragment.h" -#import "DocumentLoader.h" -#import "DocumentType.h" -#import "Editor.h" -#import "EditorClient.h" -#import "EventHandler.h" -#import "FloatRect.h" -#import "FormDataStreamMac.h" -#import "Frame.h" -#import "FrameLoader.h" -#import "FrameLoaderClient.h" -#import "FrameTree.h" -#import "FrameView.h" -#import "GraphicsContext.h" -#import "HTMLDocument.h" -#import "HTMLFormElement.h" -#import "HTMLInputElement.h" -#import "HTMLNames.h" -#import "HitTestResult.h" -#import "Image.h" -#import "LoaderNSURLExtras.h" -#import "MoveSelectionCommand.h" -#import "Page.h" -#import "PlatformMouseEvent.h" -#import "PlatformScreen.h" -#import "PluginInfoStore.h" -#import "RenderImage.h" -#import "RenderPart.h" -#import "RenderTreeAsText.h" -#import "RenderView.h" -#import "RenderWidget.h" -#import "ReplaceSelectionCommand.h" -#import "ResourceRequest.h" -#import "SelectionController.h" -#import "SimpleFontData.h" -#import "SmartReplace.h" -#import "SubresourceLoader.h" -#import "SystemTime.h" -#import "Text.h" -#import "TextEncoding.h" -#import "TextIterator.h" -#import "TextResourceDecoder.h" -#import "TypingCommand.h" -#import "WebCoreSystemInterface.h" -#import "WebCoreViewFactory.h" -#import "XMLTokenizer.h" -#import "htmlediting.h" -#import "kjs_proxy.h" -#import "kjs_window.h" -#import "markup.h" -#import "visible_units.h" -#import <OpenScripting/ASRegistry.h> -#import <JavaScriptCore/array_instance.h> -#import <JavaScriptCore/date_object.h> -#import <JavaScriptCore/runtime_root.h> -#import <wtf/RetainPtr.h> - -@class NSView; - -using namespace std; -using namespace WebCore; -using namespace HTMLNames; - -using KJS::ArrayInstance; -using KJS::BooleanType; -using KJS::DateInstance; -using KJS::ExecState; -using KJS::GetterSetterType; -using KJS::JSImmediate; -using KJS::JSLock; -using KJS::JSObject; -using KJS::JSValue; -using KJS::NullType; -using KJS::NumberType; -using KJS::ObjectType; -using KJS::SavedBuiltins; -using KJS::SavedProperties; -using KJS::StringType; -using KJS::UndefinedType; -using KJS::UnspecifiedType; -using KJS::Window; - -using KJS::Bindings::RootObject; - -static PassRefPtr<RootObject> createRootObject(void* nativeHandle) -{ - NSView *view = (NSView *)nativeHandle; - WebCoreFrameBridge *bridge = [[WebCoreViewFactory sharedFactory] bridgeForView:view]; - if (!bridge) - return 0; - - Frame* frame = [bridge _frame]; - return frame->createRootObject(nativeHandle, frame->scriptProxy()->globalObject()); -} - -static pthread_t mainThread = 0; - -static void updateRenderingForBindings(ExecState* exec, JSObject* rootObject) -{ - if (pthread_self() != mainThread) - return; - - if (!rootObject) - return; - - Window* window = static_cast<Window*>(rootObject); - if (!window) - return; - - if (Frame* frame = window->impl()->frame()) - if (Document* doc = frame->document()) - doc->updateRendering(); -} - -static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue* jsValue) -{ - NSAppleEventDescriptor* aeDesc = 0; - switch (jsValue->type()) { - case BooleanType: - aeDesc = [NSAppleEventDescriptor descriptorWithBoolean:jsValue->getBoolean()]; - break; - case StringType: - aeDesc = [NSAppleEventDescriptor descriptorWithString:String(jsValue->getString())]; - break; - case NumberType: { - double value = jsValue->getNumber(); - int intValue = (int)value; - if (value == intValue) - aeDesc = [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)]; - else - aeDesc = [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)]; - break; - } - case ObjectType: { - JSObject* object = jsValue->getObject(); - if (object->inherits(&DateInstance::info)) { - DateInstance* date = static_cast<DateInstance*>(object); - double ms = 0; - int tzOffset = 0; - if (date->getTime(ms, tzOffset)) { - CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970; - LongDateTime ldt; - if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt)) - aeDesc = [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)]; - } - } - else if (object->inherits(&ArrayInstance::info)) { - static HashSet<JSObject*> visitedElems; - if (!visitedElems.contains(object)) { - visitedElems.add(object); - - ArrayInstance* array = static_cast<ArrayInstance*>(object); - aeDesc = [NSAppleEventDescriptor listDescriptor]; - unsigned numItems = array->getLength(); - for (unsigned i = 0; i < numItems; ++i) - [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->getItem(i)) atIndex:0]; - - visitedElems.remove(object); - } - } - if (!aeDesc) { - JSValue* primitive = object->toPrimitive(exec); - if (exec->hadException()) { - exec->clearException(); - return [NSAppleEventDescriptor nullDescriptor]; - } - return aeDescFromJSValue(exec, primitive); - } - break; - } - case UndefinedType: - aeDesc = [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue]; - break; - default: - LOG_ERROR("Unknown JavaScript type: %d", jsValue->type()); - // no break; - case UnspecifiedType: - case NullType: - case GetterSetterType: - aeDesc = [NSAppleEventDescriptor nullDescriptor]; - break; - } - - return aeDesc; -} - -@implementation WebCoreFrameBridge - -static inline WebCoreFrameBridge *bridge(Frame *frame) -{ - if (!frame) - return nil; - return frame->bridge(); -} - -- (NSString *)domain -{ - Document *doc = m_frame->document(); - if (doc) - return doc->domain(); - return nil; -} - -+ (WebCoreFrameBridge *)bridgeForDOMDocument:(DOMDocument *)document -{ - return bridge([document _document]->frame()); -} - -- (id)init -{ - static bool initializedKJS; - if (!initializedKJS) { - initializedKJS = true; - - mainThread = pthread_self(); - RootObject::setCreateRootObject(createRootObject); - KJS::Bindings::Instance::setDidExecuteFunction(updateRenderingForBindings); - } - - if (!(self = [super init])) - return nil; - - _shouldCreateRenderers = YES; - return self; -} - -- (void)dealloc -{ - ASSERT(_closed); - [super dealloc]; -} - -- (void)finalize -{ - ASSERT(_closed); - [super finalize]; -} - -- (void)close -{ - [self clearFrame]; - _closed = YES; -} - -- (void)addData:(NSData *)data -{ - Document *doc = m_frame->document(); - - // Document may be nil if the part is about to redirect - // as a result of JS executing during load, i.e. one frame - // changing another's location before the frame's document - // has been created. - if (doc) { - doc->setShouldCreateRenderers(_shouldCreateRenderers); - m_frame->loader()->addData((const char *)[data bytes], [data length]); - } -} - -- (BOOL)scrollOverflowInDirection:(WebScrollDirection)direction granularity:(WebScrollGranularity)granularity -{ - if (!m_frame) - return NO; - return m_frame->eventHandler()->scrollOverflow((ScrollDirection)direction, (ScrollGranularity)granularity); -} - -- (void)clearFrame -{ - m_frame = 0; -} - -- (void)createFrameViewWithNSView:(NSView *)view marginWidth:(int)mw marginHeight:(int)mh -{ - // If we own the view, delete the old one - otherwise the render m_frame will take care of deleting the view. - if (m_frame) - m_frame->setView(0); - - FrameView* frameView = new FrameView(m_frame); - m_frame->setView(frameView); - frameView->deref(); - - frameView->setView(view); - if (mw >= 0) - frameView->setMarginWidth(mw); - if (mh >= 0) - frameView->setMarginHeight(mh); -} - -- (NSString *)_stringWithDocumentTypeStringAndMarkupString:(NSString *)markupString -{ - return m_frame->documentTypeString() + markupString; -} - -- (NSArray *)nodesFromList:(Vector<Node*> *)nodesVector -{ - size_t size = nodesVector->size(); - NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size]; - for (size_t i = 0; i < size; ++i) - [nodes addObject:[DOMNode _wrapNode:(*nodesVector)[i]]]; - return nodes; -} - -- (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes -{ - // FIXME: This is never "for interchange". Is that right? See the next method. - Vector<Node*> nodeList; - NSString *markupString = createMarkup([node _node], IncludeNode, nodes ? &nodeList : 0); - if (nodes) - *nodes = [self nodesFromList:&nodeList]; - - return [self _stringWithDocumentTypeStringAndMarkupString:markupString]; -} - -- (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes -{ - // FIXME: This is always "for interchange". Is that right? See the previous method. - Vector<Node*> nodeList; - NSString *markupString = createMarkup([range _range], nodes ? &nodeList : 0, AnnotateForInterchange); - if (nodes) - *nodes = [self nodesFromList:&nodeList]; - - return [self _stringWithDocumentTypeStringAndMarkupString:markupString]; -} - -- (NSString *)selectedString -{ - String text = m_frame->selectedText(); - text.replace('\\', m_frame->backslashAsCurrencySymbol()); - return text; -} - -- (NSString *)stringForRange:(DOMRange *)range -{ - // This will give a system malloc'd buffer that can be turned directly into an NSString - unsigned length; - UChar* buf = plainTextToMallocAllocatedBuffer([range _range], length); - - if (!buf) - return [NSString string]; - - UChar backslashAsCurrencySymbol = m_frame->backslashAsCurrencySymbol(); - if (backslashAsCurrencySymbol != '\\') - for (unsigned n = 0; n < length; n++) - if (buf[n] == '\\') - buf[n] = backslashAsCurrencySymbol; - - // Transfer buffer ownership to NSString - return [[[NSString alloc] initWithCharactersNoCopy:buf length:length freeWhenDone:YES] autorelease]; -} - -- (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType -{ - if (m_frame->view()) - m_frame->view()->setMediaType(deviceType == WebCoreDeviceScreen ? "screen" : "print"); - Document *doc = m_frame->document(); - if (doc) - doc->setPrinting(deviceType == WebCoreDevicePrinter); - m_frame->reapplyStyles(); -} - -- (void)forceLayoutAdjustingViewSize:(BOOL)flag -{ - m_frame->forceLayout(!flag); - if (flag) - m_frame->view()->adjustViewSize(); -} - -- (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)flag -{ - m_frame->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, flag); -} - -- (void)sendScrollEvent -{ - m_frame->sendScrollEvent(); -} - -- (void)drawRect:(NSRect)rect -{ - PlatformGraphicsContext* platformContext = static_cast<PlatformGraphicsContext*>([[NSGraphicsContext currentContext] graphicsPort]); - ASSERT([[NSGraphicsContext currentContext] isFlipped]); - GraphicsContext context(platformContext); - - m_frame->paint(&context, enclosingIntRect(rect)); -} - -// Used by pagination code called from AppKit when a standalone web page is printed. -- (NSArray*)computePageRectsWithPrintWidthScaleFactor:(float)printWidthScaleFactor printHeight:(float)printHeight -{ - NSMutableArray* pages = [NSMutableArray arrayWithCapacity:5]; - if (printWidthScaleFactor <= 0) { - LOG_ERROR("printWidthScaleFactor has bad value %.2f", printWidthScaleFactor); - return pages; - } - - if (printHeight <= 0) { - LOG_ERROR("printHeight has bad value %.2f", printHeight); - return pages; - } - - if (!m_frame || !m_frame->document() || !m_frame->view()) return pages; - RenderView* root = static_cast<RenderView *>(m_frame->document()->renderer()); - if (!root) return pages; - - FrameView* view = m_frame->view(); - if (!view) - return pages; - - NSView* documentView = view->getDocumentView(); - if (!documentView) - return pages; - - float currPageHeight = printHeight; - float docHeight = root->layer()->height(); - float docWidth = root->layer()->width(); - float printWidth = docWidth/printWidthScaleFactor; - - // We need to give the part the opportunity to adjust the page height at each step. - for (float i = 0; i < docHeight; i += currPageHeight) { - float proposedBottom = min(docHeight, i + printHeight); - m_frame->adjustPageHeight(&proposedBottom, i, proposedBottom, i); - currPageHeight = max(1.0f, proposedBottom - i); - for (float j = 0; j < docWidth; j += printWidth) { - NSValue* val = [NSValue valueWithRect: NSMakeRect(j, i, printWidth, currPageHeight)]; - [pages addObject: val]; - } - } - - return pages; -} - -// This is to support the case where a webview is embedded in the view that's being printed -- (void)adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit -{ - m_frame->adjustPageHeight(newBottom, oldTop, oldBottom, bottomLimit); -} - -- (NSObject *)copyRenderNode:(RenderObject *)node copier:(id <WebCoreRenderTreeCopier>)copier -{ - NSMutableArray *children = [[NSMutableArray alloc] init]; - for (RenderObject *child = node->firstChild(); child; child = child->nextSibling()) { - [children addObject:[self copyRenderNode:child copier:copier]]; - } - - NSString *name = [[NSString alloc] initWithUTF8String:node->renderName()]; - - RenderWidget* renderWidget = node->isWidget() ? static_cast<RenderWidget*>(node) : 0; - Widget* widget = renderWidget ? renderWidget->widget() : 0; - NSView *view = widget ? widget->getView() : nil; - - int nx, ny; - node->absolutePosition(nx, ny); - NSObject *copiedNode = [copier nodeWithName:name - position:NSMakePoint(nx,ny) - rect:NSMakeRect(node->xPos(), node->yPos(), node->width(), node->height()) - view:view - children:children]; - - [name release]; - [children release]; - - return copiedNode; -} - -- (NSObject *)copyRenderTree:(id <WebCoreRenderTreeCopier>)copier -{ - RenderObject *renderer = m_frame->renderer(); - if (!renderer) { - return nil; - } - return [self copyRenderNode:renderer copier:copier]; -} - -- (void)installInFrame:(NSView *)view -{ - // If this isn't the main frame, it must have a render m_frame set, or it - // won't ever get installed in the view hierarchy. - ASSERT(m_frame == m_frame->page()->mainFrame() || m_frame->ownerElement()); - - m_frame->view()->setView(view); - // FIXME: frame tries to do this too, is it needed? - if (m_frame->ownerRenderer()) { - m_frame->ownerRenderer()->setWidget(m_frame->view()); - // Now the render part owns the view, so we don't any more. - } - - m_frame->view()->initScrollbars(); -} - -static HTMLInputElement* inputElementFromDOMElement(DOMElement* element) -{ - Node* node = [element _node]; - if (node->hasTagName(inputTag)) - return static_cast<HTMLInputElement*>(node); - return nil; -} - -static HTMLFormElement *formElementFromDOMElement(DOMElement *element) -{ - Node *node = [element _node]; - // This should not be necessary, but an XSL file on - // maps.google.com crashes otherwise because it is an xslt file - // that contains <form> elements that aren't in any namespace, so - // they come out as generic CML elements - if (node && node->hasTagName(formTag)) { - return static_cast<HTMLFormElement *>(node); - } - return nil; -} - -- (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form -{ - HTMLFormElement *formElement = formElementFromDOMElement(form); - if (formElement) { - Vector<HTMLGenericFormElement*>& elements = formElement->formElements; - AtomicString targetName = name; - for (unsigned int i = 0; i < elements.size(); i++) { - HTMLGenericFormElement *elt = elements[i]; - // Skip option elements, other duds - if (elt->name() == targetName) - return [DOMElement _wrapElement:elt]; - } - } - return nil; -} - -- (BOOL)elementDoesAutoComplete:(DOMElement *)element -{ - HTMLInputElement *inputElement = inputElementFromDOMElement(element); - return inputElement != nil - && inputElement->inputType() == HTMLInputElement::TEXT - && inputElement->autoComplete(); -} - -- (BOOL)elementIsPassword:(DOMElement *)element -{ - HTMLInputElement *inputElement = inputElementFromDOMElement(element); - return inputElement != nil - && inputElement->inputType() == HTMLInputElement::PASSWORD; -} - -- (DOMElement *)formForElement:(DOMElement *)element; -{ - HTMLInputElement *inputElement = inputElementFromDOMElement(element); - if (inputElement) { - HTMLFormElement *formElement = inputElement->form(); - if (formElement) { - return [DOMElement _wrapElement:formElement]; - } - } - return nil; -} - -- (DOMElement *)currentForm -{ - return [DOMElement _wrapElement:m_frame->currentForm()]; -} - -- (NSArray *)controlsInForm:(DOMElement *)form -{ - NSMutableArray *results = nil; - HTMLFormElement *formElement = formElementFromDOMElement(form); - if (formElement) { - Vector<HTMLGenericFormElement*>& elements = formElement->formElements; - for (unsigned int i = 0; i < elements.size(); i++) { - if (elements.at(i)->isEnumeratable()) { // Skip option elements, other duds - DOMElement *de = [DOMElement _wrapElement:elements.at(i)]; - if (!results) { - results = [NSMutableArray arrayWithObject:de]; - } else { - [results addObject:de]; - } - } - } - } - return results; -} - -- (NSString *)searchForLabels:(NSArray *)labels beforeElement:(DOMElement *)element -{ - return m_frame->searchForLabelsBeforeElement(labels, [element _element]); -} - -- (NSString *)matchLabels:(NSArray *)labels againstElement:(DOMElement *)element -{ - return m_frame->matchLabelsAgainstElement(labels, [element _element]); -} - -- (NSURL *)URLWithAttributeString:(NSString *)string -{ - Document *doc = m_frame->document(); - if (!doc) - return nil; - // FIXME: is parseURL appropriate here? - DeprecatedString rel = parseURL(string).deprecatedString(); - return KURL(doc->completeURL(rel)).getNSURL(); -} - -- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection -{ - return m_frame->findString(string, forward, caseFlag, wrapFlag, startInSelection); -} - -- (unsigned)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag limit:(unsigned)limit -{ - return m_frame->markAllMatchesForText(string, caseFlag, limit); -} - -- (BOOL)markedTextMatchesAreHighlighted -{ - return m_frame->markedTextMatchesAreHighlighted(); -} - -- (void)setMarkedTextMatchesAreHighlighted:(BOOL)doHighlight -{ - m_frame->setMarkedTextMatchesAreHighlighted(doHighlight); -} - -- (void)unmarkAllTextMatches -{ - Document *doc = m_frame->document(); - if (!doc) { - return; - } - doc->removeMarkers(DocumentMarker::TextMatch); -} - -- (NSArray *)rectsForTextMatches -{ - Document *doc = m_frame->document(); - if (!doc) - return [NSArray array]; - - NSMutableArray *result = [NSMutableArray array]; - Vector<IntRect> rects = doc->renderedRectsForMarkers(DocumentMarker::TextMatch); - unsigned count = rects.size(); - for (unsigned index = 0; index < count; ++index) - [result addObject:[NSValue valueWithRect:rects[index]]]; - - return result; -} - -- (void)setTextSizeMultiplier:(float)multiplier -{ - int newZoomFactor = (int)rint(multiplier * 100); - if (m_frame->zoomFactor() == newZoomFactor) { - return; - } - m_frame->setZoomFactor(newZoomFactor); -} - -- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string -{ - return [self stringByEvaluatingJavaScriptFromString:string forceUserGesture:true]; -} - -- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)string forceUserGesture:(BOOL)forceUserGesture -{ - ASSERT(m_frame->document()); - - JSValue* result = m_frame->loader()->executeScript(string, forceUserGesture); - - if (!m_frame) // In case the script removed our frame from the page. - return @""; - - // This bizarre set of rules matches behavior from WebKit for Safari 2.0. - // If you don't like it, use -[WebScriptObject evaluateWebScript:] or - // JSEvaluateScript instead, since they have less surprising semantics. - if (!result || !result->isBoolean() && !result->isString() && !result->isNumber()) - return @""; - - JSLock lock; - return String(result->toString(m_frame->scriptProxy()->globalObject()->globalExec())); -} - -- (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)string -{ - ASSERT(m_frame->document()); - ASSERT(m_frame == m_frame->page()->mainFrame()); - JSValue* result = m_frame->loader()->executeScript(string, true); - if (!result) // FIXME: pass errors - return 0; - JSLock lock; - return aeDescFromJSValue(m_frame->scriptProxy()->globalObject()->globalExec(), result); -} - -- (NSRect)caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity -{ - return [node _node]->renderer()->caretRect(offset, static_cast<EAffinity>(affinity)); -} - -- (NSRect)firstRectForDOMRange:(DOMRange *)range -{ - return m_frame->firstRectForRange([range _range]); -} - -- (void)scrollDOMRangeToVisible:(DOMRange *)range -{ - NSRect rangeRect = [self firstRectForDOMRange:range]; - Node *startNode = [[range startContainer] _node]; - - if (startNode && startNode->renderer()) { - RenderLayer *layer = startNode->renderer()->enclosingLayer(); - if (layer) - layer->scrollRectToVisible(enclosingIntRect(rangeRect), RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignToEdgeIfNeeded); - } -} - -- (NSURL *)baseURL -{ - return m_frame->loader()->completeURL(m_frame->document()->baseURL()).getNSURL(); -} - -- (NSString *)stringWithData:(NSData *)data -{ - Document* doc = m_frame->document(); - if (!doc) - return nil; - TextResourceDecoder* decoder = doc->decoder(); - if (!decoder) - return nil; - return decoder->encoding().decode(reinterpret_cast<const char*>([data bytes]), [data length]); -} - -+ (NSString *)stringWithData:(NSData *)data textEncodingName:(NSString *)textEncodingName -{ - WebCore::TextEncoding encoding(textEncodingName); - if (!encoding.isValid()) - encoding = WindowsLatin1Encoding(); - return encoding.decode(reinterpret_cast<const char*>([data bytes]), [data length]); -} - -- (BOOL)needsLayout -{ - return m_frame->view() ? m_frame->view()->needsLayout() : false; -} - -- (NSString *)renderTreeAsExternalRepresentation -{ - return externalRepresentation(m_frame->renderer()).getNSString(); -} - -- (void)setShouldCreateRenderers:(BOOL)f -{ - _shouldCreateRenderers = f; -} - -- (id)accessibilityTree -{ - AXObjectCache::enableAccessibility(); - if (!m_frame || !m_frame->document()) - return nil; - RenderView* root = static_cast<RenderView *>(m_frame->document()->renderer()); - if (!root) - return nil; - return m_frame->document()->axObjectCache()->get(root); -} - -- (void)setBaseBackgroundColor:(NSColor *)backgroundColor -{ - if (m_frame && m_frame->view()) { - Color color = colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]); - m_frame->view()->setBaseBackgroundColor(color); - } -} - -- (void)setDrawsBackground:(BOOL)drawsBackground -{ - if (m_frame && m_frame->view()) - m_frame->view()->setTransparent(!drawsBackground); -} - -- (DOMRange *)rangeByAlteringCurrentSelection:(SelectionController::EAlteration)alteration direction:(SelectionController::EDirection)direction granularity:(TextGranularity)granularity -{ - if (m_frame->selectionController()->isNone()) - return nil; - - SelectionController selectionController; - selectionController.setSelection(m_frame->selectionController()->selection()); - selectionController.modify(alteration, direction, granularity); - return [DOMRange _wrapRange:selectionController.toRange().get()]; -} - -- (TextGranularity)selectionGranularity -{ - return m_frame->selectionGranularity(); -} - -- (NSRange)convertToNSRange:(Range *)range -{ - int exception = 0; - - if (!range || range->isDetached()) - return NSMakeRange(NSNotFound, 0); - - Element* selectionRoot = m_frame->selectionController()->rootEditableElement(); - Element* scope = selectionRoot ? selectionRoot : m_frame->document()->documentElement(); - - // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view - // that is not inside the current editable region. These checks ensure we don't produce - // potentially invalid data when responding to such requests. - if (range->startContainer(exception) != scope && !range->startContainer(exception)->isDescendantOf(scope)) - return NSMakeRange(NSNotFound, 0); - if(range->endContainer(exception) != scope && !range->endContainer(exception)->isDescendantOf(scope)) - return NSMakeRange(NSNotFound, 0); - - RefPtr<Range> testRange = new Range(scope->document(), scope, 0, range->startContainer(exception), range->startOffset(exception)); - ASSERT(testRange->startContainer(exception) == scope); - int startPosition = TextIterator::rangeLength(testRange.get()); - - testRange->setEnd(range->endContainer(exception), range->endOffset(exception), exception); - ASSERT(testRange->startContainer(exception) == scope); - int endPosition = TextIterator::rangeLength(testRange.get()); - - return NSMakeRange(startPosition, endPosition - startPosition); -} - -- (PassRefPtr<Range>)convertToDOMRange:(NSRange)nsrange -{ - if (nsrange.location > INT_MAX) - return 0; - if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX) - nsrange.length = INT_MAX - nsrange.location; - - // our critical assumption is that we are only called by input methods that - // concentrate on a given area containing the selection - // We have to do this because of text fields and textareas. The DOM for those is not - // directly in the document DOM, so serialization is problematic. Our solution is - // to use the root editable element of the selection start as the positional base. - // That fits with AppKit's idea of an input context. - Element* selectionRoot = m_frame->selectionController()->rootEditableElement(); - Element* scope = selectionRoot ? selectionRoot : m_frame->document()->documentElement(); - return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length); -} - -- (DOMRange *)convertNSRangeToDOMRange:(NSRange)nsrange -{ - return [DOMRange _wrapRange:[self convertToDOMRange:nsrange].get()]; -} - -- (NSRange)convertDOMRangeToNSRange:(DOMRange *)range -{ - return [self convertToNSRange:[range _range]]; -} - -- (void)selectNSRange:(NSRange)range -{ - RefPtr<Range> domRange = [self convertToDOMRange:range]; - if (domRange) - m_frame->selectionController()->setSelection(Selection(domRange.get(), SEL_DEFAULT_AFFINITY)); -} - -- (NSRange)selectedNSRange -{ - return [self convertToNSRange:m_frame->selectionController()->toRange().get()]; -} - -- (DOMRange *)markDOMRange -{ - return [DOMRange _wrapRange:m_frame->mark().toRange().get()]; -} - -- (NSRange)markedTextNSRange -{ - return [self convertToNSRange:m_frame->editor()->compositionRange().get()]; -} - -// Given proposedRange, returns an extended range that includes adjacent whitespace that should -// be deleted along with the proposed range in order to preserve proper spacing and punctuation of -// the text surrounding the deletion. -- (DOMRange *)smartDeleteRangeForProposedRange:(DOMRange *)proposedRange -{ - Node *startContainer = [[proposedRange startContainer] _node]; - Node *endContainer = [[proposedRange endContainer] _node]; - if (startContainer == nil || endContainer == nil) - return nil; - - ASSERT(startContainer->document() == endContainer->document()); - - m_frame->document()->updateLayoutIgnorePendingStylesheets(); - - Position start(startContainer, [proposedRange startOffset]); - Position end(endContainer, [proposedRange endOffset]); - Position newStart = start.upstream().leadingWhitespacePosition(DOWNSTREAM, true); - if (newStart.isNull()) - newStart = start; - Position newEnd = end.downstream().trailingWhitespacePosition(DOWNSTREAM, true); - if (newEnd.isNull()) - newEnd = end; - - newStart = rangeCompliantEquivalent(newStart); - newEnd = rangeCompliantEquivalent(newEnd); - - RefPtr<Range> range = m_frame->document()->createRange(); - int exception = 0; - range->setStart(newStart.node(), newStart.offset(), exception); - range->setEnd(newStart.node(), newStart.offset(), exception); - return [DOMRange _wrapRange:range.get()]; -} - -// Determines whether whitespace needs to be added around aString to preserve proper spacing and -// punctuation when it’s inserted into the receiver’s text over charRange. Returns by reference -// in beforeString and afterString any whitespace that should be added, unless either or both are -// nil. Both are returned as nil if aString is nil or if smart insertion and deletion are disabled. -- (void)smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString -{ - // give back nil pointers in case of early returns - if (beforeString) - *beforeString = nil; - if (afterString) - *afterString = nil; - - // inspect destination - Node *startContainer = [[rangeToReplace startContainer] _node]; - Node *endContainer = [[rangeToReplace endContainer] _node]; - - Position startPos(startContainer, [rangeToReplace startOffset]); - Position endPos(endContainer, [rangeToReplace endOffset]); - - VisiblePosition startVisiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY); - VisiblePosition endVisiblePos = VisiblePosition(endPos, VP_DEFAULT_AFFINITY); - - // this check also ensures startContainer, startPos, endContainer, and endPos are non-null - if (startVisiblePos.isNull() || endVisiblePos.isNull()) - return; - - bool addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfParagraph(startVisiblePos); - if (addLeadingSpace) - if (UChar previousChar = startVisiblePos.previous().characterAfter()) - addLeadingSpace = !isCharacterSmartReplaceExempt(previousChar, true); - - bool addTrailingSpace = endPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfParagraph(endVisiblePos); - if (addTrailingSpace) - if (UChar thisChar = endVisiblePos.characterAfter()) - addTrailingSpace = !isCharacterSmartReplaceExempt(thisChar, false); - - // inspect source - bool hasWhitespaceAtStart = false; - bool hasWhitespaceAtEnd = false; - unsigned pasteLength = [pasteString length]; - if (pasteLength > 0) { - NSCharacterSet *whiteSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - - if ([whiteSet characterIsMember:[pasteString characterAtIndex:0]]) { - hasWhitespaceAtStart = YES; - } - if ([whiteSet characterIsMember:[pasteString characterAtIndex:(pasteLength - 1)]]) { - hasWhitespaceAtEnd = YES; - } - } - - // issue the verdict - if (beforeString && addLeadingSpace && !hasWhitespaceAtStart) - *beforeString = @" "; - if (afterString && addTrailingSpace && !hasWhitespaceAtEnd) - *afterString = @" "; -} - -- (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString -{ - if (!m_frame || !m_frame->document()) - return 0; - - return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromMarkup(m_frame->document(), markupString, baseURLString).get()]; -} - -- (DOMDocumentFragment *)documentFragmentWithText:(NSString *)text inContext:(DOMRange *)context -{ - return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromText([context _range], text).get()]; -} - -- (DOMDocumentFragment *)documentFragmentWithNodesAsParagraphs:(NSArray *)nodes -{ - if (!m_frame || !m_frame->document()) - return 0; - - NSEnumerator *nodeEnum = [nodes objectEnumerator]; - Vector<Node*> nodesVector; - DOMNode *node; - while ((node = [nodeEnum nextObject])) - nodesVector.append([node _node]); - - return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromNodes(m_frame->document(), nodesVector).get()]; -} - -- (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle -{ - if (m_frame->selectionController()->isNone() || !fragment) - return; - - applyCommand(new ReplaceSelectionCommand(m_frame->document(), [fragment _documentFragment], selectReplacement, smartReplace, matchStyle)); - m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded); -} - -- (void)replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle -{ - DOMDocumentFragment *fragment = [DOMDocumentFragment _wrapDocumentFragment:m_frame->document()->createDocumentFragment().get()]; - [fragment appendChild:node]; - [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle]; -} - -- (void)replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace -{ - DOMDocumentFragment *fragment = [self documentFragmentWithMarkupString:markupString baseURLString:baseURLString]; - [self replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO]; -} - -- (void)replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace -{ - [self replaceSelectionWithFragment:[self documentFragmentWithText:text - inContext:[DOMRange _wrapRange:m_frame->selectionController()->toRange().get()]] - selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:YES]; -} - -- (void)insertParagraphSeparatorInQuotedContent -{ - if (m_frame->selectionController()->isNone()) - return; - - TypingCommand::insertParagraphSeparatorInQuotedContent(m_frame->document()); - m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded); -} - -- (VisiblePosition)_visiblePositionForPoint:(NSPoint)point -{ - IntPoint outerPoint(point); - HitTestResult result = m_frame->eventHandler()->hitTestResultAtPoint(outerPoint, true); - Node* node = result.innerNode(); - if (!node) - return VisiblePosition(); - RenderObject* renderer = node->renderer(); - if (!renderer) - return VisiblePosition(); - VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y()); - if (visiblePos.isNull()) - visiblePos = VisiblePosition(Position(node, 0)); - return visiblePos; -} - -- (DOMRange *)characterRangeAtPoint:(NSPoint)point -{ - VisiblePosition position = [self _visiblePositionForPoint:point]; - if (position.isNull()) - return nil; - - VisiblePosition previous = position.previous(); - if (previous.isNotNull()) { - DOMRange *previousCharacterRange = [DOMRange _wrapRange:makeRange(previous, position).get()]; - NSRect rect = [self firstRectForDOMRange:previousCharacterRange]; - if (NSPointInRect(point, rect)) - return previousCharacterRange; - } - - VisiblePosition next = position.next(); - if (next.isNotNull()) { - DOMRange *nextCharacterRange = [DOMRange _wrapRange:makeRange(position, next).get()]; - NSRect rect = [self firstRectForDOMRange:nextCharacterRange]; - if (NSPointInRect(point, rect)) - return nextCharacterRange; - } - - return nil; -} - -- (DOMCSSStyleDeclaration *)typingStyle -{ - if (!m_frame || !m_frame->typingStyle()) - return nil; - return [DOMCSSStyleDeclaration _wrapCSSStyleDeclaration:m_frame->typingStyle()->copy().get()]; -} - -- (void)setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction -{ - if (!m_frame) - return; - m_frame->computeAndSetTypingStyle([style _CSSStyleDeclaration], undoAction); -} - -- (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts -{ - bool multipleFonts = false; - NSFont *font = nil; - if (m_frame) { - const SimpleFontData* fd = m_frame->editor()->fontForSelection(multipleFonts); - if (fd) - font = fd->getNSFont(); - } - - if (hasMultipleFonts) - *hasMultipleFonts = multipleFonts; - return font; -} - -- (void)dragSourceMovedTo:(NSPoint)windowLoc -{ - if (m_frame) { - // FIXME: Fake modifier keys here. - PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [self window]), - LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); - m_frame->eventHandler()->dragSourceMovedTo(event); - } -} - -- (void)dragSourceEndedAt:(NSPoint)windowLoc operation:(NSDragOperation)operation -{ - if (m_frame) { - // FIXME: Fake modifier keys here. - PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [self window]), - LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); - m_frame->eventHandler()->dragSourceEndedAt(event, (DragOperation)operation); - } -} - -- (BOOL)getData:(NSData **)data andResponse:(NSURLResponse **)response forURL:(NSString *)url -{ - Document* doc = m_frame->document(); - if (!doc) - return NO; - - CachedResource* resource = doc->docLoader()->cachedResource(url); - if (!resource) - return NO; - - SharedBuffer* buffer = resource->data(); - if (buffer) - *data = [buffer->createNSData() autorelease]; - else - *data = nil; - - *response = resource->response().nsURLResponse(); - return YES; -} - -- (void)getAllResourceDatas:(NSArray **)datas andResponses:(NSArray **)responses -{ - Document* doc = m_frame->document(); - if (!doc) { - NSArray* emptyArray = [NSArray array]; - *datas = emptyArray; - *responses = emptyArray; - return; - } - - const HashMap<String, CachedResource*>& allResources = doc->docLoader()->allCachedResources(); - - NSMutableArray *d = [[NSMutableArray alloc] initWithCapacity:allResources.size()]; - NSMutableArray *r = [[NSMutableArray alloc] initWithCapacity:allResources.size()]; - - HashMap<String, CachedResource*>::const_iterator end = allResources.end(); - for (HashMap<String, CachedResource*>::const_iterator it = allResources.begin(); it != end; ++it) { - SharedBuffer* buffer = it->second->data(); - NSData *data; - if (buffer) - data = buffer->createNSData(); - else - data = [[NSData alloc] init]; - [d addObject:data]; - [data release]; - [r addObject:it->second->response().nsURLResponse()]; - } - - *datas = [d autorelease]; - *responses = [r autorelease]; -} - -- (BOOL)canProvideDocumentSource -{ - String mimeType = m_frame->loader()->responseMIMEType(); - - if (WebCore::DOMImplementation::isTextMIMEType(mimeType) || - Image::supportsType(mimeType) || - PluginInfoStore::supportsMIMEType(mimeType)) - return NO; - - return YES; -} - -- (BOOL)canSaveAsWebArchive -{ - // Currently, all documents that we can view source for - // (HTML and XML documents) can also be saved as web archives - return [self canProvideDocumentSource]; -} - -- (void)receivedData:(NSData *)data textEncodingName:(NSString *)textEncodingName -{ - // Set the encoding. This only needs to be done once, but it's harmless to do it again later. - String encoding; - if (m_frame) - encoding = m_frame->loader()->documentLoader()->overrideEncoding(); - bool userChosen = !encoding.isNull(); - if (encoding.isNull()) - encoding = textEncodingName; - m_frame->loader()->setEncoding(encoding, userChosen); - [self addData:data]; -} - -// ------------------- - -- (Frame*)_frame -{ - return m_frame; -} - -@end diff --git a/WebCore/page/mac/WebCoreFrameView.h b/WebCore/page/mac/WebCoreFrameView.h index a478dca..977b1a7 100644 --- a/WebCore/page/mac/WebCoreFrameView.h +++ b/WebCore/page/mac/WebCoreFrameView.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * 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 @@ -23,32 +23,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@class WebCoreFrameBridge; +#include "ScrollTypes.h" -// This protocol is a way for an NSScrollView to detect -// that the view it's embedded in is one that should be resized when the -// scroll view is resized. - -typedef enum { - WebCoreScrollbarAuto, - WebCoreScrollbarAlwaysOff, - WebCoreScrollbarAlwaysOn -} WebCoreScrollbarMode; - -@protocol WebCoreFrameView -- (void)setHorizontalScrollingMode:(WebCoreScrollbarMode)mode; -- (void)setVerticalScrollingMode:(WebCoreScrollbarMode)mode; -- (void)setScrollingMode:(WebCoreScrollbarMode)mode; - -- (WebCoreScrollbarMode)horizontalScrollingMode; -- (WebCoreScrollbarMode)verticalScrollingMode; +namespace WebCore { + class Frame; +} +@protocol WebCoreFrameScrollView +- (void)setScrollingModes:(WebCore::ScrollbarMode)hMode vertical:(WebCore::ScrollbarMode)vMode andLock:(BOOL)lock; +- (void)scrollingModes:(WebCore::ScrollbarMode*)hMode vertical:(WebCore::ScrollbarMode*)vMode; - (void)setScrollBarsSuppressed:(BOOL)suppressed repaintOnUnsuppress:(BOOL)repaint; - @end -// This protocol is a way for WebCore to gain access to its information -// about WebKit subclasses of NSView -@protocol WebCoreBridgeHolder -- (WebCoreFrameBridge *) webCoreBridge; +@protocol WebCoreFrameView +- (WebCore::Frame*)_web_frame; @end diff --git a/WebCore/page/mac/WebCoreViewFactory.h b/WebCore/page/mac/WebCoreViewFactory.h index 55514ed..4caef54 100644 --- a/WebCore/page/mac/WebCoreViewFactory.h +++ b/WebCore/page/mac/WebCoreViewFactory.h @@ -23,21 +23,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@class NSArray; -@class NSDictionary; -@class NSMenu; -@class NSString; -@class NSView; -@class WebCoreFrameBridge; @class WebCoreTextMarker; @class WebCoreTextMarkerRange; @protocol WebCoreViewFactory - (NSArray *)pluginsInfo; // array of id <WebCorePluginInfo> -- (void)refreshPlugins:(BOOL)reloadPages; -- (NSString *)pluginNameForMIMEType:(NSString *)MIMEType; -- (BOOL)pluginSupportsMIMEType:(NSString *)MIMEType; +- (void)refreshPlugins; - (NSString *)inputElementAltText; - (NSString *)resetButtonDefaultLabel; @@ -98,6 +90,8 @@ - (NSString *)defaultLanguageCode; +- (NSString *)imageTitleForFilename:(NSString *)filename width:(int)width height:(int)height; + - (BOOL)objectIsTextMarker:(id)object; - (BOOL)objectIsTextMarkerRange:(id)object; @@ -113,25 +107,29 @@ - (AXUIElementRef)AXUIElementForElement:(id)element; - (void)unregisterUniqueIdForUIElement:(id)element; -- (WebCoreFrameBridge *)bridgeForView:(NSView *)aView; - - (NSString *)AXWebAreaText; - (NSString *)AXLinkText; - (NSString *)AXListMarkerText; - (NSString *)AXImageMapText; - (NSString *)AXHeadingText; +- (NSString *)AXDefinitionListTermText; +- (NSString *)AXDefinitionListDefinitionText; + +- (NSString *)AXButtonActionVerb; +- (NSString *)AXRadioButtonActionVerb; +- (NSString *)AXTextFieldActionVerb; +- (NSString *)AXCheckedCheckBoxActionVerb; +- (NSString *)AXUncheckedCheckBoxActionVerb; +- (NSString *)AXLinkActionVerb; +- (NSString *)multipleFileUploadTextForNumberOfFiles:(unsigned)numberOfFiles; // FTP Directory Related - (NSString *)unknownFileSizeText; @end @interface WebCoreViewFactory : NSObject -{ -} - + (WebCoreViewFactory *)sharedFactory; - @end @interface WebCoreViewFactory (SubclassResponsibility) <WebCoreViewFactory> diff --git a/WebCore/page/mac/WebDashboardRegion.h b/WebCore/page/mac/WebDashboardRegion.h index 81113e9..4963d04 100644 --- a/WebCore/page/mac/WebDashboardRegion.h +++ b/WebCore/page/mac/WebDashboardRegion.h @@ -23,6 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if !defined(ENABLE_DASHBOARD_SUPPORT) +#define ENABLE_DASHBOARD_SUPPORT 1 +#endif + +#if ENABLE_DASHBOARD_SUPPORT + typedef enum { WebDashboardRegionTypeNone, WebDashboardRegionTypeCircle, @@ -41,3 +47,5 @@ typedef enum { - (NSRect)dashboardRegionRect; - (WebDashboardRegionType)dashboardRegionType; @end + +#endif diff --git a/WebCore/page/mac/WebDashboardRegion.m b/WebCore/page/mac/WebDashboardRegion.m index 958e599..d2eb07f 100644 --- a/WebCore/page/mac/WebDashboardRegion.m +++ b/WebCore/page/mac/WebDashboardRegion.m @@ -25,6 +25,7 @@ #include "config.h" #import "WebDashboardRegion.h" +#if ENABLE(DASHBOARD_SUPPORT) @implementation WebDashboardRegion - initWithRect:(NSRect)r clip:(NSRect)c type:(WebDashboardRegionType)t { @@ -73,3 +74,4 @@ } @end +#endif |