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