Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #import "PluginProcessShim.h"
     27 
     28 #import <AppKit/AppKit.h>
     29 #import <Carbon/Carbon.h>
     30 #import <WebKitSystemInterface.h>
     31 #import <stdio.h>
     32 #import <objc/objc-runtime.h>
     33 
     34 #define DYLD_INTERPOSE(_replacement,_replacee) \
     35     __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \
     36     __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
     37 
     38 namespace WebKit {
     39 
     40 extern "C" void WebKitPluginProcessShimInitialize(const PluginProcessShimCallbacks& callbacks);
     41 
     42 static PluginProcessShimCallbacks pluginProcessShimCallbacks;
     43 
     44 static IMP NSApplication_RunModalForWindow;
     45 static unsigned modalCount = 0;
     46 
     47 static void beginModal()
     48 {
     49     // Make sure to make ourselves the front process
     50     ProcessSerialNumber psn;
     51     GetCurrentProcess(&psn);
     52     SetFrontProcess(&psn);
     53 
     54     if (!modalCount++)
     55         pluginProcessShimCallbacks.setModal(true);
     56 }
     57 
     58 static void endModal()
     59 {
     60     if (!--modalCount)
     61         pluginProcessShimCallbacks.setModal(false);
     62 }
     63 
     64 static NSInteger shim_NSApplication_RunModalForWindow(id self, SEL _cmd, NSWindow* window)
     65 {
     66     beginModal();
     67     NSInteger result = ((NSInteger (*)(id, SEL, NSWindow *))NSApplication_RunModalForWindow)(self, _cmd, window);
     68     endModal();
     69 
     70     return result;
     71 }
     72 
     73 #ifndef __LP64__
     74 static void shimDebugger(void)
     75 {
     76     if (!pluginProcessShimCallbacks.shouldCallRealDebugger())
     77         return;
     78 
     79     Debugger();
     80 }
     81 
     82 static UInt32 shimGetCurrentEventButtonState()
     83 {
     84     return pluginProcessShimCallbacks.getCurrentEventButtonState();
     85 }
     86 
     87 static Boolean shimIsWindowActive(WindowRef window)
     88 {
     89     bool result;
     90     if (pluginProcessShimCallbacks.isWindowActive(window, result))
     91         return result;
     92 
     93     return IsWindowActive(window);
     94 }
     95 
     96 static void shimModalDialog(ModalFilterUPP modalFilter, DialogItemIndex *itemHit)
     97 {
     98     beginModal();
     99     ModalDialog(modalFilter, itemHit);
    100     endModal();
    101 }
    102 
    103 static DialogItemIndex shimAlert(SInt16 alertID, ModalFilterUPP modalFilter)
    104 {
    105     beginModal();
    106     DialogItemIndex index = Alert(alertID, modalFilter);
    107     endModal();
    108 
    109     return index;
    110 }
    111 
    112 static void shimShowWindow(WindowRef window)
    113 {
    114     pluginProcessShimCallbacks.carbonWindowShown(window);
    115     ShowWindow(window);
    116 }
    117 
    118 static void shimHideWindow(WindowRef window)
    119 {
    120     pluginProcessShimCallbacks.carbonWindowHidden(window);
    121     HideWindow(window);
    122 }
    123 
    124 DYLD_INTERPOSE(shimDebugger, Debugger);
    125 DYLD_INTERPOSE(shimGetCurrentEventButtonState, GetCurrentEventButtonState);
    126 DYLD_INTERPOSE(shimIsWindowActive, IsWindowActive);
    127 DYLD_INTERPOSE(shimModalDialog, ModalDialog);
    128 DYLD_INTERPOSE(shimAlert, Alert);
    129 DYLD_INTERPOSE(shimShowWindow, ShowWindow);
    130 DYLD_INTERPOSE(shimHideWindow, HideWindow);
    131 
    132 #endif
    133 
    134 __attribute__((visibility("default")))
    135 void WebKitPluginProcessShimInitialize(const PluginProcessShimCallbacks& callbacks)
    136 {
    137     pluginProcessShimCallbacks = callbacks;
    138 
    139     // Override -[NSApplication runModalForWindow:]
    140     Method runModalForWindowMethod = class_getInstanceMethod(objc_getClass("NSApplication"), @selector(runModalForWindow:));
    141     NSApplication_RunModalForWindow = method_setImplementation(runModalForWindowMethod, reinterpret_cast<IMP>(shim_NSApplication_RunModalForWindow));
    142 
    143     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
    144 
    145     // Track when any Cocoa window is about to be be shown.
    146     id orderOnScreenObserver = [defaultCenter addObserverForName:WKWindowWillOrderOnScreenNotification()
    147                                                           object:nil
    148                                                            queue:nil
    149                                                            usingBlock:^(NSNotification *notification) { pluginProcessShimCallbacks.cocoaWindowShown([notification object]); }];
    150     // Track when any cocoa window is about to be hidden.
    151     id orderOffScreenObserver = [defaultCenter addObserverForName:WKWindowWillOrderOffScreenNotification()
    152                                                            object:nil
    153                                                             queue:nil
    154                                                        usingBlock:^(NSNotification *notification) { pluginProcessShimCallbacks.cocoaWindowHidden([notification object]); }];
    155 
    156     // Leak the two observers so that they observe notifications for the lifetime of the process.
    157     CFRetain(orderOnScreenObserver);
    158     CFRetain(orderOffScreenObserver);
    159 }
    160 
    161 } // namespace WebKit
    162