summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/page/mac
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/mac')
-rw-r--r--Source/WebCore/page/mac/ChromeMac.mm52
-rw-r--r--Source/WebCore/page/mac/DragControllerMac.mm81
-rw-r--r--Source/WebCore/page/mac/EventHandlerMac.mm790
-rw-r--r--Source/WebCore/page/mac/FrameMac.mm364
-rw-r--r--Source/WebCore/page/mac/PageMac.cpp77
-rw-r--r--Source/WebCore/page/mac/WebCoreFrameView.h42
-rw-r--r--Source/WebCore/page/mac/WebCoreKeyboardUIMode.h40
-rw-r--r--Source/WebCore/page/mac/WebCoreViewFactory.h54
-rw-r--r--Source/WebCore/page/mac/WebCoreViewFactory.m48
9 files changed, 1548 insertions, 0 deletions
diff --git a/Source/WebCore/page/mac/ChromeMac.mm b/Source/WebCore/page/mac/ChromeMac.mm
new file mode 100644
index 0000000..d2ae39d
--- /dev/null
+++ b/Source/WebCore/page/mac/ChromeMac.mm
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import "config.h"
+#import "Chrome.h"
+
+#import "BlockExceptions.h"
+#import "ChromeClient.h"
+
+namespace WebCore {
+
+
+void Chrome::focusNSView(NSView* view)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSResponder *firstResponder = client()->firstResponder();
+ if (firstResponder == view)
+ return;
+
+ if (![view window] || ![view superview] || ![view acceptsFirstResponder])
+ return;
+
+ 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])
+ client()->makeFirstResponder(firstResponder);
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/mac/DragControllerMac.mm b/Source/WebCore/page/mac/DragControllerMac.mm
new file mode 100644
index 0000000..05c8e09
--- /dev/null
+++ b/Source/WebCore/page/mac/DragControllerMac.mm
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 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 "config.h"
+#import "DragController.h"
+
+#if ENABLE(DRAG_SUPPORT)
+#import "DragData.h"
+#import "Frame.h"
+#import "FrameView.h"
+#import "Page.h"
+
+namespace WebCore {
+
+const int DragController::LinkDragBorderInset = -2;
+
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+bool DragController::isCopyKeyDown()
+{
+ return [[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ ASSERT(dragData);
+ if ([NSApp modalWindow] || !dragData->containsURL())
+ return DragOperationNone;
+
+ if (!m_documentUnderMouse || (![[m_page->mainFrame()->view()->getOuterView() window] attachedSheet]
+ && [dragData->platformData() draggingSource] != m_page->mainFrame()->view()->getOuterView()))
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+ // Drag has ended, dragEnded *should* have been called, however it is possible
+ // for the UIDelegate to take over the drag, and fail to send the appropriate
+ // drag termination event. As dragEnded just resets drag variables, we just
+ // call it anyway to be on the safe side
+ dragEnded();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DRAG_SUPPORT)
diff --git a/Source/WebCore/page/mac/EventHandlerMac.mm b/Source/WebCore/page/mac/EventHandlerMac.mm
new file mode 100644
index 0000000..2d4d86b
--- /dev/null
+++ b/Source/WebCore/page/mac/EventHandlerMac.mm
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 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.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "AXObjectCache.h"
+#include "BlockExceptions.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "ClipboardMac.h"
+#include "DragController.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "RuntimeApplicationChecks.h"
+#include "Scrollbar.h"
+#include "Settings.h"
+#include "WebCoreSystemInterface.h"
+#include <objc/objc-runtime.h>
+#include <wtf/StdLibExtras.h>
+
+#if !(defined(OBJC_API_VERSION) && OBJC_API_VERSION > 0)
+static inline IMP method_setImplementation(Method m, IMP i)
+{
+ IMP oi = m->method_imp;
+ m->method_imp = i;
+ return oi;
+}
+#endif
+
+namespace WebCore {
+
+#if ENABLE(DRAG_SUPPORT)
+const double EventHandler::TextDragDelay = 0.15;
+#endif
+
+static RetainPtr<NSEvent>& currentNSEventSlot()
+{
+ DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
+ return event;
+}
+
+NSEvent *EventHandler::currentNSEvent()
+{
+ return currentNSEventSlot().get();
+}
+
+class CurrentEventScope : public Noncopyable {
+public:
+ CurrentEventScope(NSEvent *);
+ ~CurrentEventScope();
+
+private:
+ RetainPtr<NSEvent> m_savedCurrentEvent;
+#ifndef NDEBUG
+ RetainPtr<NSEvent> m_event;
+#endif
+};
+
+inline CurrentEventScope::CurrentEventScope(NSEvent *event)
+ : m_savedCurrentEvent(currentNSEventSlot())
+#ifndef NDEBUG
+ , m_event(event)
+#endif
+{
+ currentNSEventSlot() = event;
+}
+
+inline CurrentEventScope::~CurrentEventScope()
+{
+ ASSERT(currentNSEventSlot() == m_event);
+ currentNSEventSlot() = m_savedCurrentEvent;
+}
+
+bool EventHandler::wheelEvent(NSEvent *event)
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ CurrentEventScope scope(event);
+
+ m_useLatchedWheelEventNode = wkIsLatchingWheelEvent(event);
+
+ PlatformWheelEvent wheelEvent(event, page->chrome()->platformPageClient());
+ handleWheelEvent(wheelEvent);
+
+ return wheelEvent.isAccepted();
+}
+
+PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
+{
+ NSEvent *event = [NSApp currentEvent];
+ if (!event)
+ return 0;
+ switch ([event type]) {
+ case NSKeyDown: {
+ PlatformKeyboardEvent platformEvent(event);
+ platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
+ return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView());
+ }
+ case NSKeyUp:
+ return KeyboardEvent::create(event, m_frame->document()->defaultView());
+ default:
+ return 0;
+ }
+}
+
+bool EventHandler::keyEvent(NSEvent *event)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
+
+ CurrentEventScope scope(event);
+ return keyEvent(PlatformKeyboardEvent(event));
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (FrameView* frameView = m_frame->view()) {
+ if (NSView *documentView = frameView->documentView())
+ page->chrome()->focusNSView(documentView);
+ }
+
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+ if (!target || !target->isWidget())
+ return false;
+
+ // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
+ // just pass currentEvent down to the widget, we don't want to call it for events that
+ // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
+ // part of the pressed/released handling.
+ return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+static bool lastEventIsMouseUp()
+{
+ // Many AppKit widgets run their own event loops and consume events while the mouse is down.
+ // When they finish, currentEvent is the mouseUp that they exited on. We need to update
+ // the WebCore state with this mouseUp, which we never saw. This method lets us detect
+ // that state. Handling this was critical when we used AppKit widgets for form elements.
+ // It's not clear in what cases this is helpful now -- it's possible it can be removed.
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
+ return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
+ && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
+ && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
+{
+ // FIXME: This function always returns true. It should be changed either to return
+ // false in some cases or the return value should be removed.
+
+ RefPtr<Widget> widget = pWidget;
+
+ if (!widget) {
+ LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
+ return true;
+ }
+
+ // In WebKit2 we will never have an NSView. Just return early and let the regular event handler machinery take care of
+ // dispatching the event.
+ if (!widget->platformWidget())
+ return false;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSView *nodeView = widget->platformWidget();
+ ASSERT([nodeView superview]);
+ NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
+ if (!view) {
+ // We probably hit the border of a RenderWidget
+ return true;
+ }
+
+ 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 ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
+ page->chrome()->client()->makeFirstResponder(view);
+ }
+
+ // We need to "defer loading" while tracking the mouse, because tearing down the
+ // page while an AppKit control is tracking the mouse can cause a crash.
+
+ // FIXME: In theory, WebCore now tolerates tear-down while tracking the
+ // mouse. We should confirm that, and then remove the deferrsLoading
+ // hack entirely.
+
+ bool wasDeferringLoading = page->defersLoading();
+ if (!wasDeferringLoading)
+ page->setDefersLoading(true);
+
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ NSView *outerView = widget->getOuterView();
+ widget->beforeMouseDown(outerView, widget.get());
+ [view mouseDown:currentNSEvent()];
+ widget->afterMouseDown(outerView, widget.get());
+ m_sendingEventToSubview = false;
+
+ if (!wasDeferringLoading)
+ page->setDefersLoading(false);
+
+ // Remember which view we sent the event to, so we can direct the release event properly.
+ m_mouseDownView = view;
+ m_mouseDownWasInSubframe = false;
+
+ // Many AppKit widgets run their own event loops and consume events while the mouse is down.
+ // When they finish, currentEvent is the mouseUp that they exited on. We need to update
+ // the EventHandler state with this mouseUp, which we never saw.
+ // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
+ // is a hole here if the widget consumes both the mouseUp and subsequent events.
+ if (lastEventIsMouseUp())
+ m_mousePressed = false;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return true;
+}
+
+// Note that this does the same kind of check as [target isDescendantOf:superview].
+// There are two differences: This is a lot slower because it has to walk the whole
+// tree, and this works in cases where the target has already been deallocated.
+static bool findViewInSubviews(NSView *superview, NSView *target)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSEnumerator *e = [[superview subviews] objectEnumerator];
+ NSView *subview;
+ while ((subview = [e nextObject])) {
+ if (subview == target || findViewInSubviews(subview, target)) {
+ return true;
+ }
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+NSView *EventHandler::mouseDownViewIfStillGood()
+{
+ // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
+ // it could be deallocated already. We search for it in our subview tree; if we don't find
+ // it, we set it to nil.
+ NSView *mouseDownView = m_mouseDownView;
+ if (!mouseDownView) {
+ return nil;
+ }
+ FrameView* topFrameView = m_frame->view();
+ NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
+ if (!topView || !findViewInSubviews(topView, mouseDownView)) {
+ m_mouseDownView = nil;
+ return nil;
+ }
+ return mouseDownView;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
+{
+ NSView *view = mouseDownViewIfStillGood();
+
+ if (!view)
+ return false;
+
+ if (!m_mouseDownWasInSubframe) {
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [view mouseDragged:currentNSEvent()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+ m_sendingEventToSubview = false;
+ }
+
+ return true;
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
+{
+ NSView *view = mouseDownViewIfStillGood();
+ if (!view)
+ return false;
+
+ if (!m_mouseDownWasInSubframe) {
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [view mouseUp:currentNSEvent()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+ m_sendingEventToSubview = false;
+ }
+
+ return true;
+}
+
+bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ switch ([currentNSEvent() type]) {
+ case NSLeftMouseDragged:
+ case NSOtherMouseDragged:
+ case NSRightMouseDragged:
+ // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
+ // layout tests.
+ if (!m_mouseDownWasInSubframe)
+ return false;
+#if ENABLE(DRAG_SUPPORT)
+ if (subframe->page()->dragController()->didInitiateDrag())
+ return false;
+#endif
+ case NSMouseMoved:
+ // Since we're passing in currentNSEvent() here, we can call
+ // handleMouseMoveEvent() directly, since the save/restore of
+ // currentNSEvent() that mouseMoved() does would have no effect.
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
+ m_sendingEventToSubview = false;
+ return true;
+
+ case NSLeftMouseDown: {
+ Node* node = event.targetNode();
+ if (!node)
+ return false;
+ RenderObject* renderer = node->renderer();
+ if (!renderer || !renderer->isWidget())
+ return false;
+ Widget* widget = toRenderWidget(renderer)->widget();
+ if (!widget || !widget->isFrameView())
+ return false;
+ if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
+ return false;
+ m_mouseDownWasInSubframe = true;
+ return true;
+ }
+ case NSLeftMouseUp: {
+ if (!m_mouseDownWasInSubframe)
+ return false;
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
+ m_sendingEventToSubview = false;
+ return true;
+ }
+ default:
+ return false;
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+static IMP originalNSScrollViewScrollWheel;
+static bool _nsScrollViewScrollWheelShouldRetainSelf;
+static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
+
+static bool nsScrollViewScrollWheelShouldRetainSelf()
+{
+ ASSERT(isMainThread());
+
+ return _nsScrollViewScrollWheelShouldRetainSelf;
+}
+
+static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
+{
+ ASSERT(isMainThread());
+
+ if (!originalNSScrollViewScrollWheel) {
+ Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
+ originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
+ }
+
+ _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
+}
+
+static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
+{
+ bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
+
+ if (shouldRetainSelf)
+ [self retain];
+ originalNSScrollViewScrollWheel(self, selector, event);
+ if (shouldRetainSelf)
+ [self release];
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ if (!widget)
+ return false;
+
+ NSView* nodeView = widget->platformWidget();
+ if (!nodeView) {
+ // WebKit2 code path.
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
+ }
+
+ if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview)
+ return false;
+
+ ASSERT(nodeView);
+ ASSERT([nodeView superview]);
+ NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
+ if (!view)
+ // We probably hit the border of a RenderWidget
+ return false;
+
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
+ // crash if the NSScrollView is released during timer or network callback dispatch
+ // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
+ setNSScrollViewScrollWheelShouldRetainSelf(true);
+ [view scrollWheel:currentNSEvent()];
+ setNSScrollViewScrollWheelShouldRetainSelf(false);
+ m_sendingEventToSubview = false;
+ return true;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+ return false;
+}
+
+void EventHandler::mouseDown(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ m_frame->loader()->resetMultipleFormSubmissionProtection();
+
+ m_mouseDownView = nil;
+
+ CurrentEventScope scope(event);
+
+ handleMousePressEvent(currentPlatformMouseEvent());
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseDragged(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ CurrentEventScope scope(event);
+ handleMouseMoveEvent(currentPlatformMouseEvent());
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseUp(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ CurrentEventScope scope(event);
+
+ // Our behavior here is a little different that Qt. Qt always sends
+ // a mouse release event, even for a double click. To correct problems
+ // in khtml's DOM click event handling we do not send a release here
+ // for a double click. Instead we send that event from FrameView's
+ // handleMouseDoubleClickEvent. Note also that the third click of
+ // a triple click is treated as a single click, but the fourth is then
+ // treated as another double click. Hence the "% 2" below.
+ int clickCount = [event clickCount];
+ if (clickCount > 0 && clickCount % 2 == 0)
+ handleMouseDoubleClickEvent(currentPlatformMouseEvent());
+ else
+ handleMouseReleaseEvent(currentPlatformMouseEvent());
+
+ m_mouseDownView = nil;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+/*
+ A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
+ eats all subsequent events after it is starts its modal tracking loop. After the interaction
+ is done, this routine is used to fix things up. When a mouse down started us tracking in
+ the widget, we post a fake mouse up to balance the mouse down we started with. When a
+ key down started us tracking in the widget, we post a fake key up to balance things out.
+ In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to
+ be over after the tracking is done.
+ */
+void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ m_sendingEventToSubview = false;
+ int eventType = [initiatingEvent type];
+ if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
+ 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]];
+
+ [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]];
+ [NSApp postEvent:fakeEvent atStart:YES];
+ }
+ // 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:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
+ modifierFlags:[initiatingEvent modifierFlags]
+ timestamp:[initiatingEvent timestamp]
+ windowNumber:[initiatingEvent windowNumber]
+ context:[initiatingEvent context]
+ eventNumber:0
+ clickCount:0
+ pressure:0];
+ [NSApp postEvent:fakeEvent atStart:YES];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseMoved(NSEvent *event)
+{
+ // Reject a mouse moved if the button is down - screws up tracking during autoscroll
+ // These happen because WebKit sometimes has to fake up moved events.
+ if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ CurrentEventScope scope(event);
+ mouseMoved(currentPlatformMouseEvent());
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+static bool frameHasPlatformWidget(Frame* frame)
+{
+ if (FrameView* frameView = frame->view()) {
+ if (frameView->platformWidget())
+ return true;
+ }
+
+ return false;
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ // WebKit1 code path.
+ if (frameHasPlatformWidget(m_frame))
+ return passSubframeEventToSubframe(mev, subframe);
+
+ // WebKit2 code path.
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ // WebKit1 code path.
+ if (frameHasPlatformWidget(m_frame))
+ return passSubframeEventToSubframe(mev, subframe, hoveredNode);
+
+ // WebKit2 code path.
+ if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
+ return false;
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ // WebKit1 code path.
+ if (frameHasPlatformWidget(m_frame))
+ return passSubframeEventToSubframe(mev, subframe);
+
+ // WebKit2 code path.
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
+{
+ NSView *windowView = nil;
+ if (Page* page = m_frame->page())
+ windowView = page->chrome()->platformPageClient();
+ return PlatformMouseEvent(currentNSEvent(), windowView);
+}
+
+#if ENABLE(CONTEXT_MENUS)
+bool EventHandler::sendContextMenuEvent(NSEvent *event)
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+ return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
+}
+#endif // ENABLE(CONTEXT_MENUS)
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::eventMayStartDrag(NSEvent *event)
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+ return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
+{
+ return m_activationEventNumber == event.eventNumber();
+}
+
+#if ENABLE(DRAG_SUPPORT)
+
+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 ClipboardMac::create(Clipboard::DragAndDrop, pasteboard, ClipboardWritable, m_frame);
+}
+
+#endif
+
+static inline bool isKeyboardOptionTab(KeyboardEvent* event)
+{
+ return event
+ && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
+ && event->altKey()
+ && event->keyIdentifier() == "U+0009";
+}
+
+bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
+{
+ return isKeyboardOptionTab(event);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ 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
+ if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
+ return true;
+
+ // If system preferences say to include all controls, we always include all controls
+ if (keyboardUIMode & KeyboardAccessFull)
+ return true;
+
+ // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
+ if (keyboardUIMode & KeyboardAccessTabsToLinks)
+ return !handlingOptionTab;
+
+ return handlingOptionTab;
+}
+
+bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
+{
+ Document* document = m_frame->document();
+
+ // RSS view needs arrow key keypress events.
+ if (applicationIsSafari() && (document->url().protocolIs("feed") || document->url().protocolIs("feeds")))
+ return true;
+ Settings* settings = m_frame->settings();
+ if (!settings)
+ return false;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ if (settings->usesDashboardBackwardCompatibilityMode())
+ return true;
+#endif
+
+ if (settings->needsKeyboardEventDisambiguationQuirks())
+ return true;
+
+ return false;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
+ // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
+ // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
+ if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
+ return PlatformKeyboardEvent::CtrlKey;
+
+ return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
+}
+
+}
diff --git a/Source/WebCore/page/mac/FrameMac.mm b/Source/WebCore/page/mac/FrameMac.mm
new file mode 100644
index 0000000..d4e4098
--- /dev/null
+++ b/Source/WebCore/page/mac/FrameMac.mm
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * 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
+ * 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 "Frame.h"
+
+#import "BlockExceptions.h"
+#import "ColorMac.h"
+#import "Cursor.h"
+#import "DOMInternal.h"
+#import "Event.h"
+#import "FrameLoaderClient.h"
+#import "FrameView.h"
+#import "GraphicsContext.h"
+#import "HTMLNames.h"
+#import "HTMLTableCellElement.h"
+#import "HitTestRequest.h"
+#import "HitTestResult.h"
+#import "KeyboardEvent.h"
+#import "Logging.h"
+#import "MouseEventWithHitTestResults.h"
+#import "Page.h"
+#import "PlatformKeyboardEvent.h"
+#import "PlatformWheelEvent.h"
+#import "RegularExpression.h"
+#import "RenderTableCell.h"
+#import "Scrollbar.h"
+#import "SimpleFontData.h"
+#import "WebCoreViewFactory.h"
+#import "visible_units.h"
+#import <Carbon/Carbon.h>
+#import <wtf/StdLibExtras.h>
+
+@interface NSView (WebCoreHTMLDocumentView)
+- (void)drawSingleRect:(NSRect)rect;
+@end
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Either get cached regexp or build one that matches any of the labels.
+// The regexp we build is of the form: (STR1|STR2|STRN)
+static RegularExpression* regExpForLabels(NSArray* labels)
+{
+ // All the ObjC calls in this method are simple array and string
+ // calls which we can assume do not raise exceptions
+
+
+ // Parallel arrays that we use to cache regExps. In practice the number of expressions
+ // that the app will use is equal to the number of locales is used in searching.
+ static const unsigned int regExpCacheSize = 4;
+ static NSMutableArray* regExpLabels = nil;
+ DEFINE_STATIC_LOCAL(Vector<RegularExpression*>, regExps, ());
+ DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
+
+ RegularExpression* result;
+ if (!regExpLabels)
+ regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
+ CFIndex cacheHit = [regExpLabels indexOfObject:labels];
+ if (cacheHit != NSNotFound)
+ result = regExps.at(cacheHit);
+ else {
+ String pattern("(");
+ unsigned int numLabels = [labels count];
+ unsigned int i;
+ for (i = 0; i < numLabels; i++) {
+ String label = [labels objectAtIndex:i];
+
+ bool startsWithWordChar = false;
+ bool endsWithWordChar = false;
+ if (label.length() != 0) {
+ startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
+ endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
+ }
+
+ if (i != 0)
+ pattern.append("|");
+ // 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)
+ pattern.append("\\b");
+ pattern.append(label);
+ if (endsWithWordChar)
+ pattern.append("\\b");
+ }
+ pattern.append(")");
+ result = new RegularExpression(pattern, TextCaseInsensitive);
+ }
+
+ // add regexp to the cache, making sure it is at the front for LRU ordering
+ if (cacheHit != 0) {
+ if (cacheHit != NSNotFound) {
+ // remove from old spot
+ [regExpLabels removeObjectAtIndex:cacheHit];
+ regExps.remove(cacheHit);
+ }
+ // add to start
+ [regExpLabels insertObject:labels atIndex:0];
+ regExps.insert(0, result);
+ // trim if too big
+ if ([regExpLabels count] > regExpCacheSize) {
+ [regExpLabels removeObjectAtIndex:regExpCacheSize];
+ RegularExpression* last = regExps.last();
+ regExps.removeLast();
+ delete last;
+ }
+ }
+ return result;
+}
+
+NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
+{
+ RegularExpression* regExp = regExpForLabels(labels);
+ // We stop searching after we've seen this many chars
+ const unsigned int charsSearchedThreshold = 500;
+ // This is the absolute max we search. We allow a little more slop than
+ // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
+ const unsigned int maxCharsSearched = 600;
+ // If the starting element is within a table, the cell that contains it
+ HTMLTableCellElement* startingTableCell = 0;
+ bool searchedCellAbove = false;
+
+ if (resultDistance)
+ *resultDistance = notFound;
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = false;
+
+ // walk backwards in the node tree, until another element, or form, or end of tree
+ unsigned lengthSearched = 0;
+ Node* n;
+ for (n = element->traversePreviousNode();
+ n && lengthSearched < charsSearchedThreshold;
+ n = n->traversePreviousNode())
+ {
+ if (n->hasTagName(formTag)
+ || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
+ {
+ // We hit another form element or the start of the form - bail out
+ break;
+ } else if (n->hasTagName(tdTag) && !startingTableCell) {
+ startingTableCell = static_cast<HTMLTableCellElement*>(n);
+ } else if (n->hasTagName(trTag) && startingTableCell) {
+ NSString* result = searchForLabelsAboveCell(regExp, startingTableCell, resultDistance);
+ if (result && [result length] > 0) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ searchedCellAbove = true;
+ } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
+ // For each text chunk, run the regexp
+ 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) {
+ if (resultDistance)
+ *resultDistance = lengthSearched;
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
+ }
+ }
+
+ // If we started in a cell, but bailed because we found the start of the form or the
+ // previous element, we still might need to search the row above us for a label.
+ if (startingTableCell && !searchedCellAbove) {
+ NSString* result = searchForLabelsAboveCell(regExp, startingTableCell, resultDistance);
+ if (result && [result length] > 0) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ }
+
+ return nil;
+}
+
+static NSString *matchLabelsAgainstString(NSArray *labels, const String& stringToMatch)
+{
+ if (stringToMatch.isEmpty())
+ return nil;
+
+ String mutableStringToMatch = stringToMatch;
+
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
+ mutableStringToMatch.replace('_', ' ');
+
+ RegularExpression* regExp = regExpForLabels(labels);
+ // Use the largest match we can find in the whole string
+ int pos;
+ int length;
+ int bestPos = -1;
+ int bestLength = -1;
+ int start = 0;
+ do {
+ pos = regExp->match(mutableStringToMatch, start);
+ if (pos != -1) {
+ length = regExp->matchedLength();
+ if (length >= bestLength) {
+ bestPos = pos;
+ bestLength = length;
+ }
+ start = pos + 1;
+ }
+ } while (pos != -1);
+
+ if (bestPos != -1)
+ return mutableStringToMatch.substring(bestPos, bestLength);
+ return nil;
+}
+
+NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
+{
+ // Match against the name element, then against the id element if no match is found for the name element.
+ // See 7538330 for one popular site that benefits from the id element check.
+ // FIXME: This code is mirrored in Frame.cpp. It would be nice to make the Mac code call the platform-agnostic
+ // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
+ String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
+ if (!resultFromNameAttribute.isEmpty())
+ return resultFromNameAttribute;
+
+ return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
+}
+
+NSImage* Frame::imageFromRect(NSRect rect) const
+{
+ NSView* view = m_view->documentView();
+ if (!view)
+ return nil;
+ if (![view respondsToSelector:@selector(drawSingleRect:)])
+ return nil;
+
+ PaintBehavior oldPaintBehavior = m_view->paintBehavior();
+ m_view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSRect bounds = [view bounds];
+
+ // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
+ rect = [view convertRect:rect toView:nil];
+ rect.size.height = roundf(rect.size.height);
+ rect.size.width = roundf(rect.size.width);
+ rect = [view convertRect:rect fromView:nil];
+
+ NSImage* resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
+
+ if (rect.size.width != 0 && rect.size.height != 0) {
+ [resultImage setFlipped:YES];
+ [resultImage lockFocus];
+ CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
+
+ // Note: Must not call drawRect: here, because drawRect: assumes that it's called from AppKit's
+ // display machinery. It calls getRectsBeingDrawn:count:, which can only be called inside
+ // when a real AppKit display is underway.
+ [view drawSingleRect:rect];
+
+ CGContextRestoreGState(context);
+ [resultImage unlockFocus];
+ [resultImage setFlipped:NO];
+ }
+
+ m_view->setPaintBehavior(oldPaintBehavior);
+ return resultImage;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ m_view->setPaintBehavior(oldPaintBehavior);
+ return nil;
+}
+
+NSImage* Frame::selectionImage(bool forceBlackText) const
+{
+ m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0));
+ m_doc->updateLayout();
+ NSImage* result = imageFromRect(selection()->bounds());
+ m_view->setPaintBehavior(PaintBehaviorNormal);
+ return result;
+}
+
+NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return nil;
+
+ renderer->updateDragState(true); // mark dragged nodes (so they pick up the right CSS)
+ m_doc->updateLayout(); // forces style recalc - needed since changing the drag state might
+ // imply new styles, plus JS could have changed other things
+ IntRect topLevelRect;
+ NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ NSImage* result = imageFromRect(paintingRect);
+ renderer->updateDragState(false);
+ m_doc->updateLayout();
+ m_view->setNodeToDraw(0);
+
+ if (elementRect)
+ *elementRect = topLevelRect;
+ if (imageRect)
+ *imageRect = paintingRect;
+ return result;
+}
+
+DragImageRef Frame::nodeImage(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return nil;
+
+ m_doc->updateLayout(); // forces style recalc
+
+ IntRect topLevelRect;
+ NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ NSImage* result = imageFromRect(paintingRect);
+ m_view->setNodeToDraw(0);
+
+ return result;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (!selection()->isRange())
+ return nil;
+ return selectionImage();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/mac/PageMac.cpp b/Source/WebCore/page/mac/PageMac.cpp
new file mode 100644
index 0000000..7386eea
--- /dev/null
+++ b/Source/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/Source/WebCore/page/mac/WebCoreFrameView.h b/Source/WebCore/page/mac/WebCoreFrameView.h
new file mode 100644
index 0000000..b76350d
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreFrameView.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ScrollTypes.h"
+
+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;
+- (void)setScrollOrigin:(NSPoint)origin updatePosition:(BOOL)updatePosition;
+- (NSPoint)scrollOrigin;
+@end
+
+@protocol WebCoreFrameView
+- (WebCore::Frame*)_web_frame;
+@end
diff --git a/Source/WebCore/page/mac/WebCoreKeyboardUIMode.h b/Source/WebCore/page/mac/WebCoreKeyboardUIMode.h
new file mode 100644
index 0000000..187cf09
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreKeyboardUIMode.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebCoreKeyboardUIMode_h
+#define WebCoreKeyboardUIMode_h
+
+namespace WebCore {
+
+ enum KeyboardUIMode {
+ KeyboardAccessDefault = 0x00000000,
+ KeyboardAccessFull = 0x00000001,
+ // this flag may be or'ed with either of the two above
+ KeyboardAccessTabsToLinks = 0x10000000
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/page/mac/WebCoreViewFactory.h b/Source/WebCore/page/mac/WebCoreViewFactory.h
new file mode 100644
index 0000000..7af75cb
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreViewFactory.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2003, 2005, 2009, 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 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.
+ */
+
+@class WebCoreTextMarker;
+@class WebCoreTextMarkerRange;
+
+@protocol WebCoreViewFactory
+
+- (BOOL)objectIsTextMarker:(id)object;
+- (BOOL)objectIsTextMarkerRange:(id)object;
+
+- (WebCoreTextMarker *)textMarkerWithBytes:(const void *)bytes length:(size_t)length;
+- (BOOL)getBytes:(void *)bytes fromTextMarker:(WebCoreTextMarker *)textMarker length:(size_t)length;
+
+- (WebCoreTextMarkerRange *)textMarkerRangeWithStart:(WebCoreTextMarker *)start end:(WebCoreTextMarker *)end;
+- (WebCoreTextMarker *)startOfTextMarkerRange:(WebCoreTextMarkerRange *)range;
+- (WebCoreTextMarker *)endOfTextMarkerRange:(WebCoreTextMarkerRange *)range;
+
+- (void)accessibilityHandleFocusChanged;
+- (CGRect)accessibilityConvertScreenRect:(CGRect)bounds;
+
+- (AXUIElementRef)AXUIElementForElement:(id)element;
+- (void)unregisterUniqueIdForUIElement:(id)element;
+
+@end
+
+@interface WebCoreViewFactory : NSObject
++ (WebCoreViewFactory *)sharedFactory;
+@end
+
+@interface WebCoreViewFactory (SubclassResponsibility) <WebCoreViewFactory>
+@end
diff --git a/Source/WebCore/page/mac/WebCoreViewFactory.m b/Source/WebCore/page/mac/WebCoreViewFactory.m
new file mode 100644
index 0000000..5398989
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreViewFactory.m
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#import "WebCoreViewFactory.h"
+#import <wtf/Assertions.h>
+
+@implementation WebCoreViewFactory
+
+static WebCoreViewFactory *sharedFactory;
+
++ (WebCoreViewFactory *)sharedFactory
+{
+ return sharedFactory;
+}
+
+- init
+{
+ [super init];
+
+ ASSERT(!sharedFactory);
+ sharedFactory = [self retain];
+
+ return self;
+}
+
+@end