LCOV - code coverage report
Current view: directory - content/events/src - nsXMLEventsManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 191 0 0.0 %
Date: 2012-06-02 Functions: 29 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Olli Pettay.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2004
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Olli Pettay <Olli.Pettay@helsinki.fi> (original author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsIDOMMutationEvent.h"
      40                 : #include "nsXMLEventsManager.h"
      41                 : #include "nsGkAtoms.h"
      42                 : #include "nsIDOMElement.h"
      43                 : #include "nsIDOMDocument.h"
      44                 : #include "nsIDOMEventTarget.h"
      45                 : #include "nsNetUtil.h"
      46                 : #include "nsIURL.h"
      47                 : #include "nsIDOMEventListener.h"
      48                 : #include "nsINameSpaceManager.h"
      49                 : #include "nsINodeInfo.h"
      50                 : #include "mozilla/dom/Element.h"
      51                 : 
      52                 : using namespace mozilla::dom;
      53                 : 
      54               0 : bool nsXMLEventsListener::InitXMLEventsListener(nsIDocument * aDocument,
      55                 :                                                   nsXMLEventsManager * aManager,
      56                 :                                                   nsIContent * aContent)
      57                 : {
      58                 :   nsresult rv;
      59                 :   PRInt32 nameSpaceID;
      60               0 :   if (aContent->GetDocument() != aDocument)
      61               0 :     return false;
      62               0 :   if (aContent->NodeInfo()->Equals(nsGkAtoms::listener,
      63               0 :                                    kNameSpaceID_XMLEvents))
      64               0 :     nameSpaceID = kNameSpaceID_None;
      65                 :   else
      66               0 :     nameSpaceID = kNameSpaceID_XMLEvents;
      67               0 :   nsAutoString eventType;
      68               0 :   aContent->GetAttr(nameSpaceID, nsGkAtoms::event, eventType);
      69               0 :   if (eventType.IsEmpty())
      70               0 :     return false;
      71               0 :   nsAutoString handlerURIStr;
      72               0 :   bool hasHandlerURI = false;
      73               0 :   nsIContent *handler = nsnull;
      74               0 :   nsAutoString observerID;
      75               0 :   nsAutoString targetIdref;
      76                 :   
      77               0 :   if (aContent->GetAttr(nameSpaceID, nsGkAtoms::handler, handlerURIStr)) {
      78               0 :     hasHandlerURI = true;
      79               0 :     nsCAutoString handlerRef;
      80               0 :     nsCOMPtr<nsIURI> handlerURI;
      81               0 :     bool equals = false;
      82               0 :     nsIURI *docURI = aDocument->GetDocumentURI();
      83               0 :     nsIURI *baseURI = aDocument->GetDocBaseURI();
      84               0 :     rv = NS_NewURI( getter_AddRefs(handlerURI), handlerURIStr, nsnull, baseURI);
      85               0 :     if (NS_SUCCEEDED(rv)) {
      86               0 :       handlerURI->GetRef(handlerRef);
      87                 :       // We support only XML Events Basic.
      88               0 :       rv = docURI->EqualsExceptRef(handlerURI, &equals);
      89               0 :       if (NS_SUCCEEDED(rv) && equals) {
      90               0 :         handler = aDocument->GetElementById(NS_ConvertUTF8toUTF16(handlerRef));
      91                 :       }
      92                 :     }
      93                 :   }
      94                 :   else
      95               0 :     handler = aContent;
      96               0 :   if (!handler)
      97               0 :     return false;
      98                 : 
      99               0 :   aContent->GetAttr(nameSpaceID, nsGkAtoms::target, targetIdref);
     100                 : 
     101                 :   bool hasObserver = 
     102               0 :     aContent->GetAttr(nameSpaceID, nsGkAtoms::observer, observerID);
     103                 : 
     104                 :   bool capture =
     105                 :     aContent->AttrValueIs(nameSpaceID, nsGkAtoms::phase,
     106               0 :                           nsGkAtoms::capture, eCaseMatters);
     107                 : 
     108                 :   bool stopPropagation = 
     109                 :     aContent->AttrValueIs(nameSpaceID, nsGkAtoms::propagate,
     110               0 :                           nsGkAtoms::stop, eCaseMatters);
     111                 : 
     112                 :   bool cancelDefault = 
     113                 :     aContent->AttrValueIs(nameSpaceID, nsGkAtoms::defaultAction,
     114               0 :                           nsGkAtoms::cancel, eCaseMatters);
     115                 : 
     116               0 :   nsIContent *observer = nsnull;
     117               0 :   if (!hasObserver) {
     118               0 :     if (!hasHandlerURI) //Parent should be the observer
     119               0 :       observer = aContent->GetParent();
     120                 :     else //We have the handler, so this is the observer
     121               0 :       observer = aContent;
     122                 :   }
     123               0 :   else if (!observerID.IsEmpty()) {
     124               0 :     observer = aDocument->GetElementById(observerID);
     125                 :   }
     126               0 :   nsCOMPtr<nsIDOMEventTarget> eventObserver(do_QueryInterface(observer));
     127               0 :   if (eventObserver) {
     128                 :     nsXMLEventsListener * eli = new nsXMLEventsListener(aManager,
     129                 :                                                         aContent,
     130                 :                                                         observer,
     131                 :                                                         handler,
     132                 :                                                         eventType,
     133                 :                                                         capture,
     134                 :                                                         stopPropagation,
     135                 :                                                         cancelDefault,
     136               0 :                                                         targetIdref);
     137               0 :     if (eli) {
     138               0 :       nsresult rv = eventObserver->AddEventListener(eventType, eli, capture);
     139               0 :       if (NS_SUCCEEDED(rv)) {
     140               0 :         aManager->RemoveXMLEventsContent(aContent);
     141               0 :         aManager->RemoveListener(aContent);
     142               0 :         aManager->AddListener(aContent, eli);
     143               0 :         return true;
     144                 :       }
     145                 :       else
     146               0 :         delete eli;
     147                 :     }
     148                 :   }
     149               0 :   return false;
     150                 : }
     151                 : 
     152               0 : nsXMLEventsListener::nsXMLEventsListener(nsXMLEventsManager * aManager,
     153                 :                                          nsIContent * aElement,
     154                 :                                          nsIContent * aObserver,
     155                 :                                          nsIContent * aHandler,
     156                 :                                          const nsAString& aEvent,
     157                 :                                          bool aPhase,
     158                 :                                          bool aStopPropagation,
     159                 :                                          bool aCancelDefault,
     160                 :                                          const nsAString& aTarget)
     161                 :  : mManager(aManager),
     162                 :    mElement(aElement),
     163                 :    mObserver(aObserver),
     164                 :    mHandler(aHandler),
     165                 :    mEvent(aEvent),
     166                 :    mPhase(aPhase),
     167                 :    mStopPropagation(aStopPropagation),
     168               0 :    mCancelDefault(aCancelDefault)
     169                 : {
     170               0 :   if (!aTarget.IsEmpty())
     171               0 :     mTarget = do_GetAtom(aTarget);
     172               0 : }
     173                 : 
     174               0 : nsXMLEventsListener::~nsXMLEventsListener()
     175                 : {
     176               0 : }
     177                 : 
     178               0 : void nsXMLEventsListener::Unregister()
     179                 : {
     180               0 :   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mObserver);
     181               0 :   if (target) {
     182               0 :     target->RemoveEventListener(mEvent, this, mPhase);
     183                 :   }
     184               0 :   mObserver = nsnull;
     185               0 :   mHandler = nsnull;
     186               0 : }
     187                 : 
     188               0 : void nsXMLEventsListener::SetIncomplete()
     189                 : {
     190               0 :   Unregister();
     191               0 :   mManager->AddXMLEventsContent(mElement);
     192               0 :   mElement = nsnull;
     193               0 : }
     194                 : 
     195               0 : bool nsXMLEventsListener::ObserverEquals(nsIContent * aTarget)
     196                 : {
     197               0 :   return aTarget == mObserver;
     198                 : }
     199                 : 
     200               0 : bool nsXMLEventsListener::HandlerEquals(nsIContent * aTarget)
     201                 : {
     202               0 :   return aTarget == mHandler;
     203                 : }
     204                 : 
     205               0 : NS_IMPL_ISUPPORTS1(nsXMLEventsListener, nsIDOMEventListener)
     206                 : NS_IMETHODIMP
     207               0 : nsXMLEventsListener::HandleEvent(nsIDOMEvent* aEvent)
     208                 : {
     209               0 :   if (!aEvent) 
     210               0 :     return NS_ERROR_INVALID_ARG;
     211               0 :   bool targetMatched = true;
     212               0 :   nsCOMPtr<nsIDOMEvent> event(aEvent);
     213               0 :   if (mTarget) {
     214               0 :     targetMatched = false;
     215               0 :     nsCOMPtr<nsIDOMEventTarget> target;
     216               0 :     aEvent->GetTarget(getter_AddRefs(target));
     217               0 :     nsCOMPtr<nsIContent> targetEl(do_QueryInterface(target));
     218               0 :     if (targetEl && targetEl->GetID() == mTarget) 
     219               0 :         targetMatched = true;
     220                 :   }
     221               0 :   if (!targetMatched)
     222               0 :     return NS_OK;
     223               0 :   nsCOMPtr<nsIDOMEventListener> handler(do_QueryInterface(mHandler));
     224               0 :   if (handler) {
     225               0 :     nsresult rv = handler->HandleEvent(event);
     226               0 :     if (NS_SUCCEEDED(rv)) {
     227               0 :       if (mStopPropagation)
     228               0 :         event->StopPropagation();
     229               0 :       if (mCancelDefault)
     230               0 :         event->PreventDefault();
     231                 :     }
     232               0 :     return rv;
     233                 :   }
     234               0 :   return NS_OK;
     235                 : }
     236                 : 
     237                 : 
     238                 : //XMLEventsManager / DocumentObserver
     239                 : 
     240               0 : static PLDHashOperator EnumAndUnregisterListener(nsISupports * aContent,
     241                 :                                                  nsCOMPtr<nsXMLEventsListener> & aListener,
     242                 :                                                  void * aData)
     243                 : {
     244               0 :   if (aListener)
     245               0 :     aListener->Unregister();
     246               0 :   return PL_DHASH_NEXT;
     247                 : }
     248                 : 
     249               0 : static PLDHashOperator EnumAndSetIncomplete(nsISupports * aContent,
     250                 :                                             nsCOMPtr<nsXMLEventsListener> & aListener,
     251                 :                                             void * aData)
     252                 : {
     253               0 :   if (aListener && aData) {
     254               0 :     nsCOMPtr<nsIContent> content = static_cast<nsIContent *>(aData);
     255               0 :     if (content) { 
     256               0 :       if (aListener->ObserverEquals(content) || aListener->HandlerEquals(content)) {
     257               0 :         aListener->SetIncomplete();
     258               0 :         return PL_DHASH_REMOVE;
     259                 :       }
     260                 :     }
     261                 :   }
     262               0 :   return PL_DHASH_NEXT;
     263                 : }
     264                 : 
     265               0 : nsXMLEventsManager::nsXMLEventsManager()
     266                 : {
     267               0 :   mListeners.Init();
     268               0 : }
     269               0 : nsXMLEventsManager::~nsXMLEventsManager()
     270                 : {
     271               0 : }
     272                 : 
     273               0 : NS_IMPL_ISUPPORTS2(nsXMLEventsManager, nsIDocumentObserver, nsIMutationObserver)
     274                 : 
     275               0 : void nsXMLEventsManager::AddXMLEventsContent(nsIContent * aContent)
     276                 : {
     277               0 :   mIncomplete.RemoveObject(aContent);
     278               0 :   mIncomplete.AppendObject(aContent);
     279               0 : }
     280                 : 
     281               0 : void nsXMLEventsManager::RemoveXMLEventsContent(nsIContent * aContent)
     282                 : {
     283               0 :   mIncomplete.RemoveObject(aContent);
     284               0 : }
     285                 : 
     286               0 : void nsXMLEventsManager::AddListener(nsIContent * aContent, 
     287                 :                                      nsXMLEventsListener * aListener)
     288                 : {
     289               0 :   mListeners.Put(aContent, aListener);
     290               0 : }
     291                 : 
     292               0 : bool nsXMLEventsManager::RemoveListener(nsIContent * aContent)
     293                 : {
     294               0 :   nsCOMPtr<nsXMLEventsListener> listener;
     295               0 :   mListeners.Get(aContent, getter_AddRefs(listener));
     296               0 :   if (listener) {
     297               0 :     listener->Unregister();
     298               0 :     mListeners.Remove(aContent);
     299               0 :     return true;
     300                 :   }
     301               0 :   return false;
     302                 : }
     303                 : 
     304               0 : void nsXMLEventsManager::AddListeners(nsIDocument* aDocument)
     305                 : {
     306               0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     307                 : 
     308                 :   nsIContent *cur;
     309               0 :   for (int i = 0; i < mIncomplete.Count(); ++i) {
     310               0 :     cur = mIncomplete[i];
     311                 :     //If this succeeds, the object will be removed from mIncomplete
     312               0 :     if (nsXMLEventsListener::InitXMLEventsListener(aDocument, this, cur))
     313               0 :       --i;
     314                 :   }
     315               0 : }
     316                 : 
     317                 : void 
     318               0 : nsXMLEventsManager::NodeWillBeDestroyed(const nsINode* aNode)
     319                 : {
     320               0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     321               0 :   mIncomplete.Clear();
     322               0 :   mListeners.Enumerate(EnumAndUnregisterListener, this);
     323               0 :   mListeners.Clear();
     324               0 : }
     325                 : 
     326                 : void 
     327               0 : nsXMLEventsManager::EndLoad(nsIDocument* aDocument)
     328                 : {
     329               0 :   AddListeners(aDocument);
     330               0 : }
     331                 : 
     332                 : void
     333               0 : nsXMLEventsManager::AttributeChanged(nsIDocument* aDocument,
     334                 :                                      Element* aElement,
     335                 :                                      PRInt32 aNameSpaceID,
     336                 :                                      nsIAtom* aAttribute,
     337                 :                                      PRInt32 aModType)
     338                 : {
     339               0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     340                 : 
     341               0 :   if (aNameSpaceID == kNameSpaceID_XMLEvents &&
     342                 :       (aAttribute == nsGkAtoms::event ||
     343                 :        aAttribute == nsGkAtoms::handler ||
     344                 :        aAttribute == nsGkAtoms::target ||
     345                 :        aAttribute == nsGkAtoms::observer ||
     346                 :        aAttribute == nsGkAtoms::phase ||
     347                 :        aAttribute == nsGkAtoms::propagate)) {
     348               0 :     RemoveListener(aElement);
     349               0 :     AddXMLEventsContent(aElement);
     350               0 :     nsXMLEventsListener::InitXMLEventsListener(aDocument, this, aElement);
     351                 :   }
     352                 :   else {
     353               0 :     if (aElement->NodeInfo()->Equals(nsGkAtoms::listener,
     354               0 :                                      kNameSpaceID_XMLEvents)) {
     355               0 :       RemoveListener(aElement);
     356               0 :       AddXMLEventsContent(aElement);
     357               0 :       nsXMLEventsListener::InitXMLEventsListener(aDocument, this, aElement);
     358                 :     }
     359               0 :     else if (aElement->GetIDAttributeName() == aAttribute) {
     360               0 :       if (aModType == nsIDOMMutationEvent::REMOVAL)
     361               0 :         mListeners.Enumerate(EnumAndSetIncomplete, aElement);
     362               0 :       else if (aModType == nsIDOMMutationEvent::MODIFICATION) {
     363                 :         //Remove possible listener
     364               0 :         mListeners.Enumerate(EnumAndSetIncomplete, aElement);
     365                 :         //Add new listeners
     366               0 :         AddListeners(aDocument);
     367                 :       }
     368                 :       else {
     369                 :         //If we are adding the ID attribute, we must check whether we can 
     370                 :         //add new listeners
     371               0 :         AddListeners(aDocument);
     372                 :       }
     373                 :     }
     374                 :   }
     375               0 : }
     376                 : 
     377                 : void
     378               0 : nsXMLEventsManager::ContentAppended(nsIDocument* aDocument,
     379                 :                                     nsIContent* aContainer,
     380                 :                                     nsIContent* aFirstNewContent,
     381                 :                                     PRInt32 aNewIndexInContainer)
     382                 : {
     383               0 :   AddListeners(aDocument);
     384               0 : }
     385                 : 
     386                 : void
     387               0 : nsXMLEventsManager::ContentInserted(nsIDocument* aDocument,
     388                 :                                     nsIContent* aContainer,
     389                 :                                     nsIContent* aChild,
     390                 :                                     PRInt32 aIndexInContainer)
     391                 : {
     392               0 :   AddListeners(aDocument);
     393               0 : }
     394                 : 
     395                 : void
     396               0 : nsXMLEventsManager::ContentRemoved(nsIDocument* aDocument,
     397                 :                                    nsIContent* aContainer,
     398                 :                                    nsIContent* aChild,
     399                 :                                    PRInt32 aIndexInContainer,
     400                 :                                    nsIContent* aPreviousSibling)
     401                 : {
     402               0 :   if (!aChild || !aChild->IsElement())
     403               0 :     return;
     404                 :   //Note, we can't use IDs here, the observer may not always have an ID.
     405                 :   //And to remember: the same observer can be referenced by many 
     406                 :   //XMLEventsListeners
     407                 : 
     408               0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     409                 : 
     410                 :   //If the content was an XML Events observer or handler
     411               0 :   mListeners.Enumerate(EnumAndSetIncomplete, aChild);
     412                 : 
     413                 :   //If the content was an XML Events attributes container
     414               0 :   if (RemoveListener(aChild)) {
     415                 :     //for aContainer.appendChild(aContainer.removeChild(aChild));
     416               0 :     AddXMLEventsContent(aChild);
     417                 :   }
     418                 : 
     419               0 :   PRUint32 count = aChild->GetChildCount();
     420               0 :   for (PRUint32 i = 0; i < count; ++i) {
     421               0 :     ContentRemoved(aDocument, aChild, aChild->GetChildAt(i), i, aChild->GetPreviousSibling());
     422                 :   }
     423                 : }

Generated by: LCOV version 1.7