widget/windows/nsWindowBase.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsWindowBase.h"
     8 #include "mozilla/MiscEvents.h"
     9 #include "nsGkAtoms.h"
    10 #include "WinUtils.h"
    11 #include "npapi.h"
    13 using namespace mozilla;
    14 using namespace mozilla::widget;
    16 static const wchar_t kUser32LibName[] =  L"user32.dll";
    17 bool nsWindowBase::sTouchInjectInitialized = false;
    18 InjectTouchInputPtr nsWindowBase::sInjectTouchFuncPtr;
    20 bool
    21 nsWindowBase::DispatchPluginEvent(const MSG& aMsg)
    22 {
    23   if (!PluginHasFocus()) {
    24     return false;
    25   }
    26   WidgetPluginEvent pluginEvent(true, NS_PLUGIN_INPUT_EVENT, this);
    27   nsIntPoint point(0, 0);
    28   InitEvent(pluginEvent, &point);
    29   NPEvent npEvent;
    30   npEvent.event = aMsg.message;
    31   npEvent.wParam = aMsg.wParam;
    32   npEvent.lParam = aMsg.lParam;
    33   pluginEvent.pluginEvent = &npEvent;
    34   pluginEvent.retargetToFocusedDocument = true;
    35   return DispatchWindowEvent(&pluginEvent);
    36 }
    38 // static
    39 bool
    40 nsWindowBase::InitTouchInjection()
    41 {
    42   if (!sTouchInjectInitialized) {
    43     // Initialize touch injection on the first call
    44     HMODULE hMod = LoadLibraryW(kUser32LibName);
    45     if (!hMod) {
    46       return false;
    47     }
    49     InitializeTouchInjectionPtr func =
    50       (InitializeTouchInjectionPtr)GetProcAddress(hMod, "InitializeTouchInjection");
    51     if (!func) {
    52       WinUtils::Log("InitializeTouchInjection not available.");
    53       return false;
    54     }
    56     if (!func(TOUCH_INJECT_MAX_POINTS, TOUCH_FEEDBACK_DEFAULT)) {
    57       WinUtils::Log("InitializeTouchInjection failure. GetLastError=%d", GetLastError());
    58       return false;
    59     }
    61     sInjectTouchFuncPtr =
    62       (InjectTouchInputPtr)GetProcAddress(hMod, "InjectTouchInput");
    63     if (!sInjectTouchFuncPtr) {
    64       WinUtils::Log("InjectTouchInput not available.");
    65       return false;
    66     }
    67     sTouchInjectInitialized = true;
    68   }
    69   return true;
    70 }
    72 bool
    73 nsWindowBase::InjectTouchPoint(uint32_t aId, nsIntPoint& aPointerScreenPoint,
    74                                POINTER_FLAGS aFlags, uint32_t aPressure,
    75                                uint32_t aOrientation)
    76 {
    77   if (aId > TOUCH_INJECT_MAX_POINTS) {
    78     WinUtils::Log("Pointer ID exceeds maximum. See TOUCH_INJECT_MAX_POINTS.");
    79     return false;
    80   }
    82   POINTER_TOUCH_INFO info;
    83   memset(&info, 0, sizeof(POINTER_TOUCH_INFO));
    85   info.touchFlags = TOUCH_FLAG_NONE;
    86   info.touchMask = TOUCH_MASK_CONTACTAREA|TOUCH_MASK_ORIENTATION|TOUCH_MASK_PRESSURE;
    87   info.pressure = aPressure;
    88   info.orientation = aOrientation;
    90   info.pointerInfo.pointerFlags = aFlags;
    91   info.pointerInfo.pointerType =  PT_TOUCH;
    92   info.pointerInfo.pointerId = aId;
    93   info.pointerInfo.ptPixelLocation.x = WinUtils::LogToPhys(aPointerScreenPoint.x);
    94   info.pointerInfo.ptPixelLocation.y = WinUtils::LogToPhys(aPointerScreenPoint.y);
    96   info.rcContact.top = info.pointerInfo.ptPixelLocation.y - 2;
    97   info.rcContact.bottom = info.pointerInfo.ptPixelLocation.y + 2;
    98   info.rcContact.left = info.pointerInfo.ptPixelLocation.x - 2;
    99   info.rcContact.right = info.pointerInfo.ptPixelLocation.x + 2;
   101   if (!sInjectTouchFuncPtr(1, &info)) {
   102     WinUtils::Log("InjectTouchInput failure. GetLastError=%d", GetLastError());
   103     return false;
   104   }
   105   return true;
   106 }
   108 nsresult
   109 nsWindowBase::SynthesizeNativeTouchPoint(uint32_t aPointerId,
   110                                          nsIWidget::TouchPointerState aPointerState,
   111                                          nsIntPoint aPointerScreenPoint,
   112                                          double aPointerPressure,
   113                                          uint32_t aPointerOrientation)
   114 {
   115   if (!InitTouchInjection()) {
   116     return NS_ERROR_NOT_IMPLEMENTED;
   117   }
   119   bool hover = aPointerState & TOUCH_HOVER;
   120   bool contact = aPointerState & TOUCH_CONTACT;
   121   bool remove = aPointerState & TOUCH_REMOVE;
   122   bool cancel = aPointerState & TOUCH_CANCEL;
   124   // win api expects a value from 0 to 1024. aPointerPressure is a value
   125   // from 0.0 to 1.0.
   126   uint32_t pressure = (uint32_t)ceil(aPointerPressure * 1024);
   128   // If we already know about this pointer id get it's record
   129   PointerInfo* info = mActivePointers.Get(aPointerId);
   131   // We know about this pointer, send an update
   132   if (info) {
   133     POINTER_FLAGS flags = POINTER_FLAG_UPDATE;
   134     if (hover) {
   135       flags |= POINTER_FLAG_INRANGE;
   136     } else if (contact) {
   137       flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_INRANGE;
   138     } else if (remove) {
   139       flags = POINTER_FLAG_UP;
   140       // Remove the pointer from our tracking list. This is nsAutPtr wrapped,
   141       // so shouldn't leak.
   142       mActivePointers.Remove(aPointerId);
   143     }
   145     if (cancel) {
   146       flags |= POINTER_FLAG_CANCELED;
   147     }
   149     return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags,
   150                              pressure, aPointerOrientation) ?
   151       NS_ERROR_UNEXPECTED : NS_OK;
   152   }
   154   // Missing init state, error out
   155   if (remove || cancel) {
   156     return NS_ERROR_INVALID_ARG;
   157   }
   159   // Create a new pointer
   160   info = new PointerInfo(aPointerId, aPointerScreenPoint);
   162   POINTER_FLAGS flags = POINTER_FLAG_INRANGE;
   163   if (contact) {
   164     flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_DOWN;
   165   }
   167   mActivePointers.Put(aPointerId, info);
   168   return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags,
   169                            pressure, aPointerOrientation) ?
   170     NS_ERROR_UNEXPECTED : NS_OK;
   171 }
   173 // static
   174 PLDHashOperator
   175 nsWindowBase::CancelTouchPoints(const unsigned int& aPointerId, nsAutoPtr<PointerInfo>& aInfo, void* aUserArg)
   176 {
   177   nsWindowBase* self = static_cast<nsWindowBase*>(aUserArg);
   178   self->InjectTouchPoint(aInfo.get()->mPointerId, aInfo.get()->mPosition, POINTER_FLAG_CANCELED);
   179   return (PLDHashOperator)(PL_DHASH_NEXT|PL_DHASH_REMOVE);
   180 }
   182 nsresult
   183 nsWindowBase::ClearNativeTouchSequence()
   184 {
   185   if (!sTouchInjectInitialized) {
   186     return NS_OK;
   187   }
   189   // cancel all input points
   190   mActivePointers.Enumerate(CancelTouchPoints, (void*)this);
   192   nsBaseWidget::ClearNativeTouchSequence();
   194   return NS_OK;
   195 }
   197 bool
   198 nsWindowBase::DispatchCommandEvent(uint32_t aEventCommand)
   199 {
   200   nsCOMPtr<nsIAtom> command;
   201   switch (aEventCommand) {
   202     case APPCOMMAND_BROWSER_BACKWARD:
   203       command = nsGkAtoms::Back;
   204       break;
   205     case APPCOMMAND_BROWSER_FORWARD:
   206       command = nsGkAtoms::Forward;
   207       break;
   208     case APPCOMMAND_BROWSER_REFRESH:
   209       command = nsGkAtoms::Reload;
   210       break;
   211     case APPCOMMAND_BROWSER_STOP:
   212       command = nsGkAtoms::Stop;
   213       break;
   214     case APPCOMMAND_BROWSER_SEARCH:
   215       command = nsGkAtoms::Search;
   216       break;
   217     case APPCOMMAND_BROWSER_FAVORITES:
   218       command = nsGkAtoms::Bookmarks;
   219       break;
   220     case APPCOMMAND_BROWSER_HOME:
   221       command = nsGkAtoms::Home;
   222       break;
   223     case APPCOMMAND_CLOSE:
   224       command = nsGkAtoms::Close;
   225       break;
   226     case APPCOMMAND_FIND:
   227       command = nsGkAtoms::Find;
   228       break;
   229     case APPCOMMAND_HELP:
   230       command = nsGkAtoms::Help;
   231       break;
   232     case APPCOMMAND_NEW:
   233       command = nsGkAtoms::New;
   234       break;
   235     case APPCOMMAND_OPEN:
   236       command = nsGkAtoms::Open;
   237       break;
   238     case APPCOMMAND_PRINT:
   239       command = nsGkAtoms::Print;
   240       break;
   241     case APPCOMMAND_SAVE:
   242       command = nsGkAtoms::Save;
   243       break;
   244     case APPCOMMAND_FORWARD_MAIL:
   245       command = nsGkAtoms::ForwardMail;
   246       break;
   247     case APPCOMMAND_REPLY_TO_MAIL:
   248       command = nsGkAtoms::ReplyToMail;
   249       break;
   250     case APPCOMMAND_SEND_MAIL:
   251       command = nsGkAtoms::SendMail;
   252       break;
   253     default:
   254       return false;
   255   }
   256   WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, command, this);
   258   InitEvent(event);
   259   return DispatchWindowEvent(&event);
   260 }
   262 bool
   263 nsWindowBase::HandleAppCommandMsg(WPARAM aWParam,
   264                                   LPARAM aLParam,
   265                                   LRESULT *aRetValue)
   266 {
   267   uint32_t appCommand = GET_APPCOMMAND_LPARAM(aLParam);
   268   uint32_t contentCommandMessage = NS_EVENT_NULL;
   269   // XXX After we implement KeyboardEvent.key, we should dispatch the
   270   //     key event if (GET_DEVICE_LPARAM(lParam) == FAPPCOMMAND_KEY) is.
   271   switch (appCommand)
   272   {
   273     case APPCOMMAND_BROWSER_BACKWARD:
   274     case APPCOMMAND_BROWSER_FORWARD:
   275     case APPCOMMAND_BROWSER_REFRESH:
   276     case APPCOMMAND_BROWSER_STOP:
   277     case APPCOMMAND_BROWSER_SEARCH:
   278     case APPCOMMAND_BROWSER_FAVORITES:
   279     case APPCOMMAND_BROWSER_HOME:
   280     case APPCOMMAND_CLOSE:
   281     case APPCOMMAND_FIND:
   282     case APPCOMMAND_HELP:
   283     case APPCOMMAND_NEW:
   284     case APPCOMMAND_OPEN:
   285     case APPCOMMAND_PRINT:
   286     case APPCOMMAND_SAVE:
   287     case APPCOMMAND_FORWARD_MAIL:
   288     case APPCOMMAND_REPLY_TO_MAIL:
   289     case APPCOMMAND_SEND_MAIL:
   290       // We shouldn't consume the message always because if we don't handle
   291       // the message, the sender (typically, utility of keyboard or mouse)
   292       // may send other key messages which indicate well known shortcut key.
   293       if (DispatchCommandEvent(appCommand)) {
   294         // tell the driver that we handled the event
   295         *aRetValue = 1;
   296         return true;
   297       }
   298       break;
   300     // Use content command for following commands:
   301     case APPCOMMAND_COPY:
   302       contentCommandMessage = NS_CONTENT_COMMAND_COPY;
   303       break;
   304     case APPCOMMAND_CUT:
   305       contentCommandMessage = NS_CONTENT_COMMAND_CUT;
   306       break;
   307     case APPCOMMAND_PASTE:
   308       contentCommandMessage = NS_CONTENT_COMMAND_PASTE;
   309       break;
   310     case APPCOMMAND_REDO:
   311       contentCommandMessage = NS_CONTENT_COMMAND_REDO;
   312       break;
   313     case APPCOMMAND_UNDO:
   314       contentCommandMessage = NS_CONTENT_COMMAND_UNDO;
   315       break;
   316   }
   318   if (contentCommandMessage) {
   319     WidgetContentCommandEvent contentCommand(true, contentCommandMessage,
   320                                               this);
   321     DispatchWindowEvent(&contentCommand);
   322     // tell the driver that we handled the event
   323     *aRetValue = 1;
   324     return true;
   325   }
   327   // default = false - tell the driver that the event was not handled
   328   return false;
   329 }

mercurial