PageRenderTime 56ms CodeModel.GetById 17ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/extensions/widgetutils/src/nsWidgetUtils.cpp

http://github.com/zpao/v8monkey
C++ | 589 lines | 461 code | 76 blank | 52 comment | 59 complexity | 683ea4bbc8f1f179922bafb268c7c2c3 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2/* vim:set ts=2 sw=2 sts=2 tw=80 et cindent: */
  3/* ***** BEGIN LICENSE BLOCK *****
  4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5 *
  6 * The contents of this file are subject to the Mozilla Public License Version
  7 * 1.1 (the "License"); you may not use this file except in compliance with
  8 * the License. You may obtain a copy of the License at
  9 * http://www.mozilla.org/MPL/
 10 *
 11 * Software distributed under the License is distributed on an "AS IS" basis,
 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 13 * for the specific language governing rights and limitations under the
 14 * License.
 15 *
 16 * The Original Code is Mozilla's Element Optimizeing extension.
 17 *
 18 * The Initial Developer of the Original Code is the Mozilla Foundation.
 19 * Portions created by the Initial Developer are Copyright (C) 2006
 20 * the Initial Developer. All Rights Reserved.
 21 *
 22 * Contributor(s):
 23 *   Oleg Romashin <romaxa@gmail.com> (original author)
 24 *   Brad Lassey <blassey@mozilla.com>
 25 *   Ms2ger <ms2ger@gmail.com>
 26 *
 27 * Alternatively, the contents of this file may be used under the terms of
 28 * either the GNU General Public License Version 2 or later (the "GPL"), or
 29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 30 * in which case the provisions of the GPL or the LGPL are applicable instead
 31 * of those above. If you wish to allow use of your version of this file only
 32 * under the terms of either the GPL or the LGPL, and not to allow others to
 33 * use your version of this file under the terms of the MPL, indicate your
 34 * decision by deleting the provisions above and replace them with the notice
 35 * and other provisions required by the GPL or the LGPL. If you do not delete
 36 * the provisions above, a recipient may use your version of this file under
 37 * the terms of any one of the MPL, the GPL or the LGPL.
 38 *
 39 * ***** END LICENSE BLOCK ***** */
 40
 41#include "nsCURILoader.h"
 42#include "nsICategoryManager.h"
 43#include "nsIDOMDocument.h"
 44#include "nsIDOMHTMLElement.h"
 45#include "nsIDOMHTMLIFrameElement.h"
 46#include "nsIDOMNode.h"
 47#include "nsIDOMNodeList.h"
 48#include "nsIDOMWindow.h"
 49#include "nsIDOMWindowCollection.h"
 50#include "nsIDocument.h"
 51#include "nsIGenericFactory.h"
 52#include "nsIObserver.h"
 53#include "nsIPresShell.h"
 54#include "nsIStyleSheetService.h"
 55#include "nsIWebProgress.h"
 56#include "nsIWebProgressListener.h"
 57#include "nsIWindowWatcher.h"
 58#include "nsNetUtil.h"
 59#include "nsRect.h"
 60#include "nsStringGlue.h"
 61#include "nsWeakReference.h"
 62#include "nsIWebBrowser.h"
 63#include "nsIObserverService.h"
 64#include "nsIDOMEventTarget.h"
 65#include "nsPIDOMWindow.h"
 66#include "nsIDOMWindow.h"
 67#include "nsIDOMCompositionListener.h"
 68#include "nsIDOMTextListener.h"
 69#include "nsIDOMMouseEvent.h"
 70#include "nsIDOMNSEvent.h"
 71#include "nsIView.h"
 72#include "nsGUIEvent.h"
 73#include "nsIViewManager.h"
 74#include "nsIContentPolicy.h"
 75#include "nsIDocShellTreeItem.h"
 76#include "nsIContent.h"
 77#include "nsITimer.h"
 78
 79const int MIN_INT =((int) (1 << (sizeof(int) * 8 - 1)));
 80
 81static int g_lastX=MIN_INT;
 82static int g_lastY=MIN_INT;
 83static PRInt32 g_panning = 0;
 84static bool g_is_scrollable = false;
 85
 86#define EM_MULT 16.
 87#define NS_FRAME_HAS_RELATIVE_SIZE 0x01000000
 88#define NS_FRAME_HAS_OPTIMIZEDVIEW 0x02000000
 89#define BEHAVIOR_ACCEPT nsIPermissionManager::ALLOW_ACTION
 90#define BEHAVIOR_REJECT nsIPermissionManager::DENY_ACTION
 91#define BEHAVIOR_NOFOREIGN 3
 92#define NUMBER_OF_TYPES 13
 93
 94// TODO auto reload nsWidgetUtils in C.
 95class nsWidgetUtils : public nsIObserver,
 96                      public nsIDOMEventListener,
 97                      public nsIContentPolicy,
 98                      public nsSupportsWeakReference
 99{
100public:
101  nsWidgetUtils();
102  virtual ~nsWidgetUtils();
103
104  NS_DECL_ISUPPORTS
105  NS_DECL_NSIDOMEVENTLISTENER
106  NS_DECL_NSIOBSERVER 
107  NS_DECL_NSICONTENTPOLICY
108
109private:
110  nsresult Init(void);
111  void RemoveWindowListeners(nsIDOMWindow *aDOMWin);
112  void GetChromeEventHandler(nsIDOMWindow *aDOMWin, nsIDOMEventTarget **aChromeTarget);
113  void AttachWindowListeners(nsIDOMWindow *aDOMWin);
114  bool IsXULNode(nsIDOMNode *aNode, PRUint32 *aType = 0);
115  nsresult GetDOMWindowByNode(nsIDOMNode *aNode, nsIDOMWindow * *aDOMWindow);
116  nsresult UpdateFromEvent(nsIDOMEvent *aDOMEvent);
117  nsresult MouseDown(nsIDOMEvent* aDOMEvent);
118  nsresult MouseUp(nsIDOMEvent* aDOMEvent);
119  nsresult MouseMove(nsIDOMEvent* aDOMEvent);
120
121  static void StopPanningCallback(nsITimer *timer, void *closure);
122
123  nsCOMPtr<nsIWidget> mWidget;
124  nsCOMPtr<nsIViewManager> mViewManager;
125  nsCOMPtr<nsITimer> mTimer;
126};
127
128nsWidgetUtils::nsWidgetUtils()
129{
130  Init();
131}
132
133NS_IMETHODIMP
134nsWidgetUtils::Init()
135{
136  nsresult rv;
137  nsCOMPtr<nsIObserverService> obsSvc =
138    do_GetService("@mozilla.org/observer-service;1");
139  NS_ENSURE_STATE(obsSvc);
140
141  rv = obsSvc->AddObserver(this, "domwindowopened", false);
142  NS_ENSURE_SUCCESS(rv, rv);
143  rv = obsSvc->AddObserver(this, "domwindowclosed", false);
144  NS_ENSURE_SUCCESS(rv, rv);
145  mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
146}
147
148nsresult
149nsWidgetUtils::UpdateFromEvent(nsIDOMEvent *aDOMEvent)
150{
151  nsCOMPtr <nsIDOMMouseEvent> mouseEvent;
152  mouseEvent = do_QueryInterface(aDOMEvent);
153  if (!mouseEvent)
154    return NS_OK;
155
156  ((nsIDOMMouseEvent*)mouseEvent)->GetScreenX(&g_lastX);
157  ((nsIDOMMouseEvent*)mouseEvent)->GetScreenY(&g_lastY);
158
159  nsCOMPtr<nsIDOMWindow> mWindow;
160  nsCOMPtr<nsIDOMNode> mNode;
161  nsCOMPtr<nsIDOMNode> mOrigNode;
162
163  PRUint32 type = 0;
164  bool isXul = false;
165  {
166    nsCOMPtr <nsIDOMNSEvent> aEvent = do_QueryInterface(aDOMEvent);
167    nsCOMPtr<nsIDOMEventTarget> eventOrigTarget;
168    if (aEvent)
169      aEvent->GetOriginalTarget(getter_AddRefs(eventOrigTarget));
170    if (eventOrigTarget)
171      mOrigNode = do_QueryInterface(eventOrigTarget);
172    isXul = IsXULNode(mOrigNode, &type);
173
174  }
175  if (isXul)
176    return NS_ERROR_FAILURE;
177
178  nsCOMPtr<nsIDOMEventTarget> eventTarget;
179  aDOMEvent->GetTarget(getter_AddRefs(eventTarget));
180  if (eventTarget)
181    mNode = do_QueryInterface(eventTarget);
182
183  if (!mNode)
184    return NS_OK;
185
186  GetDOMWindowByNode(mNode, getter_AddRefs(mWindow));
187  if (!mWindow)
188    return NS_OK;
189  nsCOMPtr<nsIDocument> doc;
190  nsCOMPtr<nsIDOMDocument> domDoc;
191  mWindow->GetDocument(getter_AddRefs(domDoc));
192  doc = do_QueryInterface(domDoc);
193  if (!doc) return NS_OK;
194  // the only case where there could be more shells in printpreview
195  nsIPresShell *shell = doc->GetShell();
196  NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
197  mViewManager = shell->GetViewManager();
198  NS_ENSURE_TRUE(mViewManager, NS_ERROR_FAILURE);
199  mViewManager->GetRootWidget(getter_AddRefs(mWidget));
200  NS_ENSURE_TRUE(mWidget, NS_ERROR_FAILURE);
201  return NS_OK;
202}
203
204nsresult
205nsWidgetUtils::MouseDown(nsIDOMEvent* aDOMEvent)
206{
207  g_is_scrollable = false;
208  // Return TRUE from your signal handler to mark the event as consumed.
209  if (NS_FAILED(UpdateFromEvent(aDOMEvent)))
210    return NS_OK;
211  g_is_scrollable = true;
212  if (g_is_scrollable) {
213     aDOMEvent->StopPropagation();
214     aDOMEvent->PreventDefault();
215  }
216  return NS_OK;
217}
218
219/* static */ void
220nsWidgetUtils::StopPanningCallback(nsITimer *timer, void *closure)
221{
222  g_panning = false;
223}
224
225nsresult
226nsWidgetUtils::MouseUp(nsIDOMEvent* aDOMEvent)
227{
228  nsCOMPtr <nsIDOMMouseEvent> mouseEvent;
229  mouseEvent = do_QueryInterface(aDOMEvent);
230  if (!mouseEvent)
231    return NS_OK;
232  // Return TRUE from your signal handler to mark the event as consumed.
233  g_lastX = MIN_INT;
234  g_lastY = MIN_INT;
235  g_is_scrollable = false;
236  if (g_panning) {
237     aDOMEvent->StopPropagation();
238     aDOMEvent->PreventDefault();
239     nsresult rv;
240     if (mTimer) {
241       rv = mTimer->InitWithFuncCallback(nsWidgetUtils::StopPanningCallback,
242                                        nsnull, 500, nsITimer::TYPE_ONE_SHOT);
243       if (NS_SUCCEEDED(rv))
244         return NS_OK;
245     }
246     g_panning = false;
247  }
248  return NS_OK;
249}
250
251nsresult
252nsWidgetUtils::MouseMove(nsIDOMEvent* aDOMEvent)
253{
254  if (!g_is_scrollable) return NS_OK;
255
256  nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aDOMEvent);
257  if (!mouseEvent)
258    return NS_OK;
259  int x, y;
260  ((nsIDOMMouseEvent*)mouseEvent)->GetScreenX(&x);
261  ((nsIDOMMouseEvent*)mouseEvent)->GetScreenY(&y);
262
263  int dx = g_lastX - x;
264  int dy = g_lastY - y;
265  if(g_lastX == MIN_INT || g_lastY == MIN_INT)
266    return NS_OK;
267
268  nsIView* aView = mViewManager->GetRootView();
269  if (!aView)
270    if (NS_FAILED(UpdateFromEvent(aDOMEvent)))
271      return NS_OK;
272
273  nsEventStatus statusX;
274  nsMouseScrollEvent scrollEventX(true, NS_MOUSE_SCROLL, mWidget);
275  scrollEventX.delta = dx;
276  scrollEventX.scrollFlags = nsMouseScrollEvent::kIsHorizontal | nsMouseScrollEvent::kHasPixels;
277  mViewManager->DispatchEvent(&scrollEventX, aView, &statusX);
278  if(statusX != nsEventStatus_eIgnore ){
279    if (dx > 5)
280      g_panning = true;
281    g_lastX = x;
282  }
283
284  nsEventStatus statusY;
285  nsMouseScrollEvent scrollEventY(true, NS_MOUSE_SCROLL, mWidget);
286  scrollEventY.delta = dy;
287  scrollEventY.scrollFlags = nsMouseScrollEvent::kIsVertical | nsMouseScrollEvent::kHasPixels;
288  mViewManager->DispatchEvent(&scrollEventY, aView, &statusY);
289  if(statusY != nsEventStatus_eIgnore ){
290    if (dy > 5)
291      g_panning = true;
292    g_lastY = y;
293  }
294  if (g_panning) {
295     aDOMEvent->StopPropagation();
296     aDOMEvent->PreventDefault();
297  }
298
299  return NS_OK;
300}
301
302// nsIContentPolicy Implementation
303NS_IMETHODIMP
304nsWidgetUtils::ShouldLoad(PRUint32          aContentType,
305                          nsIURI           *aContentLocation,
306                          nsIURI           *aRequestingLocation,
307                          nsISupports      *aRequestingContext,
308                          const nsACString &aMimeGuess,
309                          nsISupports      *aExtra,
310                          PRInt16          *aDecision)
311{
312    *aDecision = nsIContentPolicy::ACCEPT;
313    nsresult rv;
314
315    if (aContentType != nsIContentPolicy::TYPE_DOCUMENT)
316        return NS_OK;
317
318    // we can't do anything without this
319    if (!aContentLocation)
320        return NS_OK;
321
322    nsCAutoString scheme;
323    rv = aContentLocation->GetScheme(scheme);
324    nsCAutoString lscheme;
325    ToLowerCase(scheme, lscheme);
326    if (!lscheme.EqualsLiteral("ftp") &&
327        !lscheme.EqualsLiteral("http") &&
328        !lscheme.EqualsLiteral("https"))
329        return NS_OK;
330    if (g_panning > 0)
331      *aDecision = nsIContentPolicy::REJECT_REQUEST;
332    return NS_OK;
333}
334
335NS_IMETHODIMP
336nsWidgetUtils::HandleEvent(nsIDOMEvent* aDOMEvent)
337{
338  nsAutoString eventType;
339  aEvent->GetType(eventType);
340
341  if (eventType.EqualsLiteral("mousedown")) {
342    return MouseDown(aEvent);
343  }
344  if (eventType.EqualsLiteral("mouseup")) {
345    return MouseUp(aEvent);
346  }
347  if (eventType.EqualsLiteral("mousemove")) {
348    return MouseMove(aEvent);
349  }
350
351  return NS_OK;
352}
353
354NS_IMETHODIMP
355nsWidgetUtils::ShouldProcess(PRUint32          aContentType,
356                             nsIURI           *aContentLocation,
357                             nsIURI           *aRequestingLocation,
358                             nsISupports      *aRequestingContext,
359                             const nsACString &aMimeGuess,
360                             nsISupports      *aExtra,
361                             PRInt16          *aDecision)
362{
363    *aDecision = nsIContentPolicy::ACCEPT;
364    return NS_OK;
365}
366
367bool
368nsWidgetUtils::IsXULNode(nsIDOMNode *aNode, PRUint32 *aType)
369{
370  bool retval = false;
371  if (!aNode) return retval;
372
373  nsString sorigNode;
374  aNode->GetNodeName(sorigNode);
375  if (sorigNode.EqualsLiteral("#document"))
376    return retval;
377  retval = StringBeginsWith(sorigNode, NS_LITERAL_STRING("xul:"));
378
379  if (!aType) return retval;
380
381  if (sorigNode.EqualsLiteral("xul:thumb")
382      || sorigNode.EqualsLiteral("xul:vbox")
383      || sorigNode.EqualsLiteral("xul:spacer"))
384    *aType = false; // Magic
385  else if (sorigNode.EqualsLiteral("xul:slider"))
386    *aType = 2; // Magic
387  else if (sorigNode.EqualsLiteral("xul:scrollbarbutton"))
388    *aType = 3; // Magic
389
390  return retval;
391}
392
393nsresult
394nsWidgetUtils::GetDOMWindowByNode(nsIDOMNode* aNode, nsIDOMWindow** aDOMWindow)
395{
396  nsCOMPtr<nsIDOMDocument> nodeDoc;
397  nsresult rv = aNode->GetOwnerDocument(getter_AddRefs(nodeDoc));
398  NS_ENSURE_SUCCESS(rv, rv);
399  NS_ENSURE_TRUE(nodeDoc, NS_ERROR_NULL_POINTER);
400
401  nsCOMPtr<nsIDOMWindow> window;
402  rv = nodeDoc->GetDefaultView(getter_AddRefs(window));
403  NS_ENSURE_SUCCESS(rv, rv);
404  NS_ENSURE_TRUE(window, NS_ERROR_NULL_POINTER);
405  window.forget(aDOMWindow);
406  return rv;
407}
408
409void
410nsWidgetUtils::GetChromeEventHandler(nsIDOMWindow *aDOMWin,
411                                     nsIDOMEventTarget **aChromeTarget)
412{
413    nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(aDOMWin));
414    nsIDOMEventTarget* chromeEventHandler = nsnull;
415    if (privateDOMWindow) {
416        chromeEventHandler = privateDOMWindow->GetChromeEventHandler();
417    }
418
419    NS_IF_ADDREF(*aChromeTarget = chromeEventHandler);
420}
421
422void
423nsWidgetUtils::RemoveWindowListeners(nsIDOMWindow *aDOMWin)
424{
425    nsresult rv;
426    nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
427    GetChromeEventHandler(aDOMWin, getter_AddRefs(chromeEventHandler));
428    if (!chromeEventHandler) {
429        return;
430    }
431
432    // Use capturing, otherwise the normal find next will get activated when ours should
433
434    // Remove DOM Text listener for IME text events
435    chromeEventHandler->RemoveEventListener(NS_LITERAL_STRING("mousedown"),
436                                            this, false);
437    chromeEventHandler->RemoveEventListener(NS_LITERAL_STRING("mouseup"),
438                                            this, false);
439    chromeEventHandler->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
440                                            this, false);
441}
442
443void
444nsWidgetUtils::AttachWindowListeners(nsIDOMWindow *aDOMWin)
445{
446    nsresult rv;
447    nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
448    GetChromeEventHandler(aDOMWin, getter_AddRefs(chromeEventHandler));
449    if (!chromeEventHandler) {
450        return;
451    }
452
453    // Use capturing, otherwise the normal find next will get activated when ours should
454
455    // Attach menu listeners, this will help us ignore keystrokes meant for menus
456    chromeEventHandler->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
457                                         false, false);
458    chromeEventHandler->AddEventListener(NS_LITERAL_STRING("mouseup"), this,
459                                         false, false);
460    chromeEventHandler->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
461                                         false, false);
462}
463
464nsWidgetUtils::~nsWidgetUtils()
465{
466}
467
468NS_IMPL_ISUPPORTS4(nsWidgetUtils,
469                   nsIObserver,
470                   nsIDOMEventListener,
471                   nsIContentPolicy,
472                   nsISupportsWeakReference)
473
474NS_IMETHODIMP
475nsWidgetUtils::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
476{
477  nsresult rv;
478  if (!strcmp(aTopic,"domwindowopened")) 
479  {
480    nsCOMPtr<nsIDOMWindow> chromeWindow = do_QueryInterface(aSubject);
481    if (chromeWindow)
482      AttachWindowListeners(chromeWindow);
483    return NS_OK;
484  }
485
486  if (!strcmp(aTopic,"domwindowclosed")) 
487  {
488    nsCOMPtr<nsIDOMWindow> chromeWindow = do_QueryInterface(aSubject);
489    RemoveWindowListeners(chromeWindow);
490    return NS_OK;
491  }
492
493  return NS_OK;
494}
495
496//------------------------------------------------------------------------------
497//  XPCOM REGISTRATION BELOW
498//------------------------------------------------------------------------------
499
500#define WidgetUtils_CID \
501{  0x0ced17b6, 0x96ed, 0x4030, \
502{0xa1, 0x34, 0x77, 0xcb, 0x66, 0x10, 0xa8, 0xf6} }
503
504#define WidgetUtils_ContractID "@mozilla.org/extensions/widgetutils;1"
505
506static NS_METHOD WidgetUtilsRegistration(nsIComponentManager *aCompMgr,
507                                         nsIFile *aPath,
508                                         const char *registryLocation,
509                                         const char *componentType,
510                                         const nsModuleComponentInfo *info)
511{
512    nsresult rv;
513
514    nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
515    if (NS_FAILED(rv))
516        return rv;
517
518    nsCOMPtr<nsICategoryManager> catman;
519    servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
520                                    NS_GET_IID(nsICategoryManager),
521                                    getter_AddRefs(catman));
522
523    if (NS_FAILED(rv))
524        return rv;
525
526    char* previous = nsnull;
527    rv = catman->AddCategoryEntry("app-startup",
528                                  "WidgetUtils",
529                                  WidgetUtils_ContractID,
530                                  true,
531                                  true,
532                                  &previous);
533    if (previous)
534        nsMemory::Free(previous);
535    rv = catman->AddCategoryEntry("content-policy",
536                                  "WidgetUtils",
537                                  WidgetUtils_ContractID,
538                                  true,
539                                  true,
540                                  &previous);
541    if (previous)
542        nsMemory::Free(previous);
543
544    return rv;
545}
546
547static NS_METHOD WidgetUtilsUnregistration(nsIComponentManager *aCompMgr,
548                                           nsIFile *aPath,
549                                           const char *registryLocation,
550                                           const nsModuleComponentInfo *info)
551{
552    nsresult rv;
553
554    nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
555    if (NS_FAILED(rv))
556        return rv;
557
558    nsCOMPtr<nsICategoryManager> catman;
559    servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
560                                    NS_GET_IID(nsICategoryManager),
561                                    getter_AddRefs(catman));
562
563    if (NS_FAILED(rv))
564        return rv;
565
566    rv = catman->DeleteCategoryEntry("app-startup",
567                                     "WidgetUtils",
568                                     true);
569    rv = catman->DeleteCategoryEntry("content-policy",
570                                     "WidgetUtils",
571                                     true);
572
573    return rv;
574}
575
576NS_GENERIC_FACTORY_CONSTRUCTOR(nsWidgetUtils)
577
578  static const nsModuleComponentInfo components[] =
579{
580  { "nsWidgetUtilsService",
581    WidgetUtils_CID,
582    WidgetUtils_ContractID,
583    nsWidgetUtilsConstructor,
584    WidgetUtilsRegistration,
585    WidgetUtilsUnregistration
586  }
587};
588
589NS_IMPL_NSGETMODULE(nsWidgetUtilsModule, components)