diff options
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/mac')
6 files changed, 891 insertions, 0 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/mac/AccessibilityWebPageObject.h b/Source/WebKit2/WebProcess/WebPage/mac/AccessibilityWebPageObject.h new file mode 100644 index 0000000..3b331b9 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/mac/AccessibilityWebPageObject.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityWebPageObject_h +#define AccessibilityWebPageObject_h + +namespace WebKit { +class WebPage; +} + +@interface AccessibilityWebPageObject : NSObject { + WebKit::WebPage* m_page; + + id m_parent; + NSArray* m_attributeNames; + NSMutableArray* m_accessibilityChildren; +} + +- (void)setWebPage:(WebKit::WebPage*)page; + +- (void)setRemoteParent:(id)parent; + +@end + +#endif // AccessibilityWebPageObject_h diff --git a/Source/WebKit2/WebProcess/WebPage/mac/AccessibilityWebPageObject.mm b/Source/WebKit2/WebProcess/WebPage/mac/AccessibilityWebPageObject.mm new file mode 100644 index 0000000..fa4aa1a --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/mac/AccessibilityWebPageObject.mm @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "AccessibilityWebPageObject.h" + +#import "WebFrame.h" +#import "WebPage.h" +#import <WebCore/AXObjectCache.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameView.h> +#import <WebCore/ScrollView.h> +#import <WebCore/Scrollbar.h> + +using namespace WebCore; +using namespace WebKit; + +@implementation AccessibilityWebPageObject + +- (id)accessibilityRootObjectWrapper +{ + WebCore::Page* page = m_page->corePage(); + if (!page) + return nil; + + WebCore::Frame* core = page->mainFrame(); + if (!core || !core->document()) + return nil; + + AccessibilityObject* root = core->document()->axObjectCache()->rootObject(); + if (!root) + return nil; + + return root->wrapper(); +} + +- (void)setWebPage:(WebPage*)page +{ + m_page = page; +} + +- (void)setRemoteParent:(id)parent +{ + if (parent != m_parent) { + [m_parent release]; + m_parent = [parent retain]; + } +} + +- (void)dealloc +{ + [m_accessibilityChildren release]; + [m_attributeNames release]; + [m_parent release]; + [super dealloc]; +} + +- (BOOL)accessibilityIsIgnored +{ + return NO; +} + +- (NSArray *)accessibilityAttributeNames +{ + if (!m_attributeNames) + m_attributeNames = [[NSArray alloc] initWithObjects: + NSAccessibilityRoleAttribute, NSAccessibilityRoleDescriptionAttribute, NSAccessibilityFocusedAttribute, + NSAccessibilityParentAttribute, NSAccessibilityWindowAttribute, NSAccessibilityTopLevelUIElementAttribute, + NSAccessibilityPositionAttribute, NSAccessibilitySizeAttribute, NSAccessibilityChildrenAttribute, nil]; + + return m_attributeNames; +} + +- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute +{ + return NO; +} + +- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute +{ + return; +} + +- (NSArray *)accessibilityActionNames +{ + return [NSArray array]; +} + +- (NSArray *)accessibilityChildren +{ + id wrapper = [self accessibilityRootObjectWrapper]; + if (!wrapper) + return [NSArray array]; + + return [NSArray arrayWithObject:wrapper]; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute +{ + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); + + if ([attribute isEqualToString:NSAccessibilityParentAttribute]) + return m_parent; + if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) + return [m_parent accessibilityAttributeValue:NSAccessibilityWindowAttribute]; + if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) + return [m_parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute]; + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) + return NSAccessibilityGroupRole; + if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) + return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil); + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) + return [NSNumber numberWithBool:NO]; + + if (!m_page) + return nil; + + if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) { + WebCore::IntPoint point = m_page->accessibilityPosition(); + return [NSValue valueWithPoint:NSMakePoint(point.x(), point.y())]; + } + if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) { + const IntSize& s = m_page->size(); + return [NSValue valueWithSize:NSMakeSize(s.width(), s.height())]; + } + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) + return [self accessibilityChildren]; + + return [super accessibilityAttributeValue:attribute]; +} + +- (BOOL)accessibilityShouldUseUniqueId +{ + return YES; +} + +- (id)accessibilityHitTest:(NSPoint)point +{ + // Hit-test point comes in as bottom-screen coordinates. Needs to be normalized to the frame of the web page. + NSPoint remotePosition = [[self accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue]; + NSSize remoteSize = [[self accessibilityAttributeValue:NSAccessibilitySizeAttribute] sizeValue]; + + // Get the y position of the WKView (we have to screen-flip and go from bottom left to top left). + CGFloat screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height; + remotePosition.y = (screenHeight - remotePosition.y) - remoteSize.height; + + point.y = screenHeight - point.y; + + // Re-center point into the web page's frame. + point.y -= remotePosition.y; + point.x -= remotePosition.x; + + WebCore::FrameView* fv = m_page->mainFrame()->coreFrame()->view(); + if (fv) { + point.y += fv->scrollPosition().y(); + point.x += fv->scrollPosition().x(); + } + + return [[self accessibilityRootObjectWrapper] accessibilityHitTest:point]; +} + +- (id)accessibilityFocusedUIElement +{ + return NSAccessibilityUnignoredDescendant(self); +} + + +@end diff --git a/Source/WebKit2/WebProcess/WebPage/mac/ChunkedUpdateDrawingAreaMac.cpp b/Source/WebKit2/WebProcess/WebPage/mac/ChunkedUpdateDrawingAreaMac.cpp new file mode 100644 index 0000000..6bcecfd --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/mac/ChunkedUpdateDrawingAreaMac.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ChunkedUpdateDrawingArea.h" + +#include "UpdateChunk.h" +#include "WebFrame.h" +#include "WebPage.h" +#include "WebFrameLoaderClient.h" +#include <WebCore/Frame.h> +#include <WebCore/GraphicsContext.h> +#include <wtf/RetainPtr.h> + +using namespace WebCore; + +namespace WebKit { + +void ChunkedUpdateDrawingArea::paintIntoUpdateChunk(UpdateChunk* updateChunk) +{ + // FIXME: It would be better if we could avoid painting altogether when there is a custom representation. + if (m_webPage->mainFrameHasCustomRepresentation()) + return; + + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGContextRef> bitmapContext(AdoptCF, CGBitmapContextCreate(updateChunk->data(), updateChunk->rect().width(), updateChunk->rect().height(), 8, updateChunk->rect().width() * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + + // WebCore expects a flipped coordinate system. + CGContextTranslateCTM(bitmapContext.get(), 0.0, updateChunk->rect().height()); + CGContextScaleCTM(bitmapContext.get(), 1.0, -1.0); + + // Now paint into the backing store. + GraphicsContext graphicsContext(bitmapContext.get()); + graphicsContext.translate(-updateChunk->rect().x(), -updateChunk->rect().y()); + + m_webPage->drawRect(graphicsContext, updateChunk->rect()); +} + +} // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/mac/LayerBackedDrawingAreaMac.mm b/Source/WebKit2/WebProcess/WebPage/mac/LayerBackedDrawingAreaMac.mm new file mode 100644 index 0000000..f8b7e71 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/mac/LayerBackedDrawingAreaMac.mm @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerBackedDrawingArea.h" + +#include "DrawingAreaProxyMessageKinds.h" +#include "WebKitSystemInterface.h" +#include "WebPage.h" +#include "WebProcess.h" +#include <WebCore/Frame.h> +#include <WebCore/FrameView.h> +#include <WebCore/GraphicsLayer.h> +#include <WebCore/Page.h> + +using namespace WebCore; + +namespace WebKit { + +void LayerBackedDrawingArea::platformInit() +{ + setUpUpdateLayoutRunLoopObserver(); + + [m_backingLayer->platformLayer() setGeometryFlipped:YES]; +#if HAVE(HOSTED_CORE_ANIMATION) + attachCompositingContext(); +#endif + + scheduleCompositingLayerSync(); +} + +void LayerBackedDrawingArea::platformClear() +{ + if (!m_attached) + return; + + if (m_updateLayoutRunLoopObserver) { + CFRunLoopObserverInvalidate(m_updateLayoutRunLoopObserver.get()); + m_updateLayoutRunLoopObserver = 0; + } + +#if HAVE(HOSTED_CORE_ANIMATION) + WKCARemoteLayerClientInvalidate(m_remoteLayerRef.get()); + m_remoteLayerRef = nullptr; +#endif + + m_attached = false; +} + +void LayerBackedDrawingArea::attachCompositingContext() +{ + if (m_attached) + return; + + m_attached = true; + +#if HAVE(HOSTED_CORE_ANIMATION) + mach_port_t serverPort = WebProcess::shared().compositingRenderServerPort(); + m_remoteLayerRef = WKCARemoteLayerClientMakeWithServerPort(serverPort); + WKCARemoteLayerClientSetLayer(m_remoteLayerRef.get(), m_backingLayer->platformLayer()); + + uint32_t contextID = WKCARemoteLayerClientGetClientId(m_remoteLayerRef.get()); + WebProcess::shared().connection()->sendSync(DrawingAreaProxyLegacyMessage::AttachCompositingContext, m_webPage->pageID(), CoreIPC::In(contextID), CoreIPC::Out()); +#endif +} + +void LayerBackedDrawingArea::detachCompositingContext() +{ + m_backingLayer->removeAllChildren(); + + scheduleCompositingLayerSync(); +} + +void LayerBackedDrawingArea::setRootCompositingLayer(WebCore::GraphicsLayer* layer) +{ + m_backingLayer->removeAllChildren(); + if (layer) + m_backingLayer->addChild(layer); + + scheduleCompositingLayerSync(); +} + +void LayerBackedDrawingArea::scheduleCompositingLayerSync() +{ +// if (m_syncTimer.isActive()) +// return; +// +// m_syncTimer.startOneShot(0); + + scheduleUpdateLayoutRunLoopObserver(); +} + +void LayerBackedDrawingArea::syncCompositingLayers() +{ + m_backingLayer->syncCompositingStateForThisLayerOnly(); + + bool didSync = m_webPage->corePage()->mainFrame()->view()->syncCompositingStateRecursive(); + if (!didSync) { + + } +} + +void LayerBackedDrawingArea::setUpUpdateLayoutRunLoopObserver() +{ + if (m_updateLayoutRunLoopObserver) + return; + + // Run before Core Animations commit observer, which has order 2000000. + const CFIndex runLoopOrder = 2000000 - 1; + CFRunLoopObserverContext context = { 0, this, 0, 0, 0 }; + m_updateLayoutRunLoopObserver.adoptCF(CFRunLoopObserverCreate(0, + kCFRunLoopBeforeWaiting | kCFRunLoopExit, true /* repeats */, + runLoopOrder, updateLayoutRunLoopObserverCallback, &context)); +} + +void LayerBackedDrawingArea::scheduleUpdateLayoutRunLoopObserver() +{ + CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent(); + CFRunLoopWakeUp(currentRunLoop); + + if (CFRunLoopContainsObserver(currentRunLoop, m_updateLayoutRunLoopObserver.get(), kCFRunLoopCommonModes)) + return; + + CFRunLoopAddObserver(currentRunLoop, m_updateLayoutRunLoopObserver.get(), kCFRunLoopCommonModes); +} + +void LayerBackedDrawingArea::removeUpdateLayoutRunLoopObserver() +{ + // FIXME: cache the run loop ref? + CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), m_updateLayoutRunLoopObserver.get(), kCFRunLoopCommonModes); +} + +void LayerBackedDrawingArea::updateLayoutRunLoopObserverCallback(CFRunLoopObserverRef, CFRunLoopActivity, void* info) +{ + // Keep the drawing area alive while running the callback, since that does layout, + // which might replace this drawing area with one of another type. + RefPtr<LayerBackedDrawingArea> drawingArea = reinterpret_cast<LayerBackedDrawingArea*>(info); + drawingArea->updateLayoutRunLoopObserverFired(); +} + +void LayerBackedDrawingArea::updateLayoutRunLoopObserverFired() +{ + // Laying out the page can cause the drawing area to change so we keep an extra reference. + RefPtr<LayerBackedDrawingArea> protect(this); + + m_webPage->layoutIfNeeded(); + + if (m_webPage->drawingArea() != this) + return; + + if (m_attached) + syncCompositingLayers(); +} + +void LayerBackedDrawingArea::onPageClose() +{ + platformClear(); +} + +} // namespace WebKit + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebKit2/WebProcess/WebPage/mac/WebInspectorMac.mm b/Source/WebKit2/WebProcess/WebPage/mac/WebInspectorMac.mm new file mode 100644 index 0000000..83909be --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/mac/WebInspectorMac.mm @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebInspector.h" + +#import <wtf/text/WTFString.h> + +namespace WebKit { + +String WebInspector::localizedStringsURL() const +{ + NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"localizedStrings" ofType:@"js"]; + if (path) + return [[NSURL fileURLWithPath:path] absoluteString]; + return String(); +} + +} // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm new file mode 100644 index 0000000..f3211f2 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "WebPage.h" + +#include "AccessibilityWebPageObject.h" +#include "DataReference.h" +#include "PluginView.h" +#include "WebCoreArgumentCoders.h" +#include "WebEvent.h" +#include "WebFrame.h" +#include "WebPageProxyMessages.h" +#include "WebProcess.h" +#include <WebCore/AXObjectCache.h> +#include <WebCore/FocusController.h> +#include <WebCore/Frame.h> +#include <WebCore/FrameView.h> +#include <WebCore/HitTestResult.h> +#include <WebCore/KeyboardEvent.h> +#include <WebCore/Page.h> +#include <WebCore/PlatformKeyboardEvent.h> +#include <WebCore/ScrollView.h> +#include <WebCore/TextIterator.h> +#include <WebCore/WindowsKeyboardCodes.h> +#include <WebKitSystemInterface.h> + +using namespace WebCore; + +namespace WebKit { + +void WebPage::platformInitialize() +{ + m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes)); + +#if !defined(BUILDING_ON_SNOW_LEOPARD) + AccessibilityWebPageObject* mockAccessibilityElement = [[[AccessibilityWebPageObject alloc] init] autorelease]; + + // Get the pid for the starting process. + pid_t pid = WebProcess::shared().presenterApplicationPid(); + WKAXInitializeElementWithPresenterPid(mockAccessibilityElement, pid); + [mockAccessibilityElement setWebPage:this]; + + // send data back over + NSData* remoteToken = (NSData *)WKAXRemoteTokenForElement(mockAccessibilityElement); + CoreIPC::DataReference dataToken = CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]); + send(Messages::WebPageProxy::DidReceiveAccessibilityPageToken(dataToken)); + m_mockAccessibilityElement = mockAccessibilityElement; +#endif +} + +void WebPage::platformPreferencesDidChange(const WebPreferencesStore&) +{ +} + +// FIXME: need to add support for input methods + +bool WebPage::interceptEditingKeyboardEvent(KeyboardEvent* evt, bool shouldSaveCommand) +{ + Node* node = evt->target()->toNode(); + ASSERT(node); + Frame* frame = node->document()->frame(); + ASSERT(frame); + + const PlatformKeyboardEvent* keyEvent = evt->keyEvent(); + if (!keyEvent) + return false; + const Vector<KeypressCommand>& commands = evt->keypressCommands(); + bool hasKeypressCommand = !commands.isEmpty(); + + bool eventWasHandled = false; + + if (shouldSaveCommand || !hasKeypressCommand) { + Vector<KeypressCommand> commandsList; + Vector<CompositionUnderline> underlines; + unsigned start; + unsigned end; + if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(keyEvent->type()), + Messages::WebPageProxy::InterpretKeyEvent::Reply(commandsList, start, end, underlines), + m_pageID, CoreIPC::Connection::NoTimeout)) + return false; + if (commandsList.isEmpty()) + return eventWasHandled; + + if (commandsList[0].commandName == "setMarkedText") { + frame->editor()->setComposition(commandsList[0].text, underlines, start, end); + eventWasHandled = true; + } else if (commandsList[0].commandName == "insertText" && frame->editor()->hasComposition()) { + frame->editor()->confirmComposition(commandsList[0].text); + eventWasHandled = true; + } else if (commandsList[0].commandName == "unmarkText") { + frame->editor()->confirmComposition(); + eventWasHandled = true; + } else { + for (size_t i = 0; i < commandsList.size(); i++) + evt->keypressCommands().append(commandsList[i]); + } + } else { + size_t size = commands.size(); + // Are there commands that would just cause text insertion if executed via Editor? + // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore + // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated + // (e.g. Tab that inserts a Tab character, or Enter). + bool haveTextInsertionCommands = false; + for (size_t i = 0; i < size; ++i) { + if (frame->editor()->command(commands[i].commandName).isTextInsertion()) + haveTextInsertionCommands = true; + } + if (!haveTextInsertionCommands || keyEvent->type() == PlatformKeyboardEvent::Char) { + for (size_t i = 0; i < size; ++i) { + if (commands[i].commandName == "insertText") { + // Don't insert null or control characters as they can result in unexpected behaviour + if (evt->charCode() < ' ') + return false; + eventWasHandled = frame->editor()->insertText(commands[i].text, evt); + } else + if (frame->editor()->command(commands[i].commandName).isSupported()) + eventWasHandled = frame->editor()->command(commands[i].commandName).execute(evt); + } + } + } + return eventWasHandled; +} + +void WebPage::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput) +{ + for (HashSet<PluginView*>::const_iterator it = m_pluginViews.begin(), end = m_pluginViews.end(); it != end; ++it) { + if ((*it)->sendComplexTextInput(pluginComplexTextInputIdentifier, textInput)) + break; + } +} + +void WebPage::getMarkedRange(uint64_t& location, uint64_t& length) +{ + location = NSNotFound; + length = 0; + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return; + + getLocationAndLengthFromRange(frame->editor()->compositionRange().get(), location, length); +} + +static Range *characterRangeAtPoint(Frame* frame, const IntPoint point) +{ + VisiblePosition position = frame->visiblePositionForPoint(point); + if (position.isNull()) + return NULL; + + VisiblePosition previous = position.previous(); + if (previous.isNotNull()) { + Range *previousCharacterRange = makeRange(previous, position).get(); + NSRect rect = frame->editor()->firstRectForRange(previousCharacterRange); + if (NSPointInRect(point, rect)) + return previousCharacterRange; + } + + VisiblePosition next = position.next(); + if (next.isNotNull()) { + Range *nextCharacterRange = makeRange(position, next).get(); + NSRect rect = frame->editor()->firstRectForRange(nextCharacterRange); + if (NSPointInRect(point, rect)) + return nextCharacterRange; + } + + return NULL; +} + +void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index) +{ + index = NSNotFound; + Frame* frame = m_page->mainFrame(); + if (!frame) + return; + + HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false); + frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame(); + + Range *range = characterRangeAtPoint(frame, result.point()); + if (!range) + return; + + uint64_t length; + getLocationAndLengthFromRange(range, index, length); +} + +static PassRefPtr<Range> convertToRange(Frame* frame, 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 = frame->selection()->rootEditableElement(); + Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement(); + return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length); +} + +void WebPage::firstRectForCharacterRange(uint64_t location, uint64_t length, WebCore::IntRect& resultRect) +{ + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + resultRect.setLocation(IntPoint(0, 0)); + resultRect.setSize(IntSize(0, 0)); + + RefPtr<Range> range = convertToRange(frame, NSMakeRange(location, length)); + if (range) { + ASSERT(range->startContainer()); + ASSERT(range->endContainer()); + } + + IntRect rect = frame->editor()->firstRectForRange(range.get()); + resultRect = frame->view()->contentsToWindow(rect); +} + +static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity) +{ + page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity); +} + +static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity) +{ + page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity); +} + +bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent) +{ + if (keyboardEvent.type() != WebEvent::KeyDown) + return false; + + // FIXME: This should be in WebCore. + + switch (keyboardEvent.windowsVirtualKeyCode()) { + case VK_BACK: + if (keyboardEvent.shiftKey()) + m_page->goForward(); + else + m_page->goBack(); + break; + case VK_SPACE: + if (keyboardEvent.shiftKey()) + logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage); + else + logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage); + break; + case VK_PRIOR: + logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage); + break; + case VK_NEXT: + logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage); + break; + case VK_HOME: + logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument); + break; + case VK_END: + logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument); + break; + case VK_UP: + if (keyboardEvent.shiftKey()) + return false; + if (keyboardEvent.metaKey()) { + scroll(m_page.get(), ScrollUp, ScrollByDocument); + scroll(m_page.get(), ScrollLeft, ScrollByDocument); + } else if (keyboardEvent.altKey() || keyboardEvent.controlKey()) + scroll(m_page.get(), ScrollUp, ScrollByPage); + else + scroll(m_page.get(), ScrollUp, ScrollByLine); + break; + case VK_DOWN: + if (keyboardEvent.shiftKey()) + return false; + if (keyboardEvent.metaKey()) { + scroll(m_page.get(), ScrollDown, ScrollByDocument); + scroll(m_page.get(), ScrollLeft, ScrollByDocument); + } else if (keyboardEvent.altKey() || keyboardEvent.controlKey()) + scroll(m_page.get(), ScrollDown, ScrollByPage); + else + scroll(m_page.get(), ScrollDown, ScrollByLine); + break; + case VK_LEFT: + if (keyboardEvent.shiftKey()) + return false; + if (keyboardEvent.metaKey()) + m_page->goBack(); + else { + if (keyboardEvent.altKey() | keyboardEvent.controlKey()) + scroll(m_page.get(), ScrollLeft, ScrollByPage); + else + scroll(m_page.get(), ScrollLeft, ScrollByLine); + } + break; + case VK_RIGHT: + if (keyboardEvent.shiftKey()) + return false; + if (keyboardEvent.metaKey()) + m_page->goForward(); + else { + if (keyboardEvent.altKey() || keyboardEvent.controlKey()) + scroll(m_page.get(), ScrollRight, ScrollByPage); + else + scroll(m_page.get(), ScrollRight, ScrollByLine); + } + break; + default: + return false; + } + + return true; +} + +void WebPage::sendAccessibilityPresenterToken(const CoreIPC::DataReference& data) +{ +#if !defined(BUILDING_ON_SNOW_LEOPARD) + NSData* tokenData = [NSData dataWithBytes:data.data() length:data.size()]; + [m_mockAccessibilityElement.get() setRemoteParent:WKAXRemoteElementForToken((CFDataRef)tokenData)]; +#endif +} + +AccessibilityWebPageObject* WebPage::accessibilityRemoteObject() +{ + return m_mockAccessibilityElement.get(); +} + +bool WebPage::platformHasLocalDataForURL(const WebCore::KURL& url) +{ + NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url]; + [request setValue:(NSString*)userAgent() forHTTPHeaderField:@"User-Agent"]; + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; + [request release]; + + return cachedResponse; +} + +bool WebPage::canHandleRequest(const WebCore::ResourceRequest& request) +{ + if ([NSURLConnection canHandleRequest:request.nsURLRequest()]) + return YES; + + // FIXME: Return true if this scheme is any one WebKit2 knows how to handle. + return request.url().protocolIs("applewebdata"); +} + +} // namespace WebKit |