Back to index

lightning-sunbird  0.9+nobinonly
nsParserService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsDOMError.h"
00040 #include "nsIAtom.h"
00041 #include "nsParserService.h"
00042 #include "nsHTMLEntities.h"
00043 #include "nsElementTable.h"
00044 #include "nsICategoryManager.h"
00045 #include "nsCategoryManagerUtils.h"
00046 
00047 extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
00048                                  int ns_aware, const char** colon);
00049 
00050 nsParserService::nsParserService() : mEntries(0)
00051 {
00052   mHaveNotifiedCategoryObservers = PR_FALSE;
00053 }
00054 
00055 nsParserService::~nsParserService()
00056 {
00057   nsObserverEntry *entry = nsnull;
00058   while( (entry = NS_STATIC_CAST(nsObserverEntry*,mEntries.Pop())) ) {
00059     NS_RELEASE(entry);
00060   }
00061 }
00062 
00063 NS_IMPL_ISUPPORTS2(nsParserService, nsIParserService,
00064                    nsIParserService_MOZILLA_1_8_BRANCH)
00065 
00066 PRInt32
00067 nsParserService::HTMLAtomTagToId(nsIAtom* aAtom) const
00068 {
00069   nsAutoString tagName;
00070   aAtom->ToString(tagName);
00071 
00072   return nsHTMLTags::LookupTag(tagName);
00073 }
00074 
00075 PRInt32
00076 nsParserService::HTMLCaseSensitiveAtomTagToId(nsIAtom* aAtom) const
00077 {
00078   nsAutoString tagName;
00079   aAtom->ToString(tagName);
00080 
00081   return nsHTMLTags::CaseSensitiveLookupTag(tagName.get());
00082 }
00083 
00084 PRInt32
00085 nsParserService::HTMLStringTagToId(const nsAString& aTag) const
00086 {
00087   return nsHTMLTags::LookupTag(aTag);
00088 }
00089 
00090 const PRUnichar*
00091 nsParserService::HTMLIdToStringTag(PRInt32 aId) const
00092 {
00093   return nsHTMLTags::GetStringValue((nsHTMLTag)aId);
00094 }
00095   
00096 nsIAtom*
00097 nsParserService::HTMLIdToAtomTag(PRInt32 aId) const
00098 {
00099   return nsHTMLTags::GetAtom((nsHTMLTag)aId);
00100 }
00101 
00102 NS_IMETHODIMP
00103 nsParserService::HTMLConvertEntityToUnicode(const nsAString& aEntity,
00104                                             PRInt32* aUnicode) const
00105 {
00106   *aUnicode = nsHTMLEntities::EntityToUnicode(aEntity);
00107 
00108   return NS_OK;
00109 }
00110 
00111 NS_IMETHODIMP
00112 nsParserService::HTMLConvertUnicodeToEntity(PRInt32 aUnicode,
00113                                             nsCString& aEntity) const
00114 {
00115   const char* str = nsHTMLEntities::UnicodeToEntity(aUnicode);
00116   if (str) {
00117     aEntity.Assign(str);
00118   }
00119 
00120   return NS_OK;
00121 }
00122 
00123 NS_IMETHODIMP
00124 nsParserService::IsContainer(PRInt32 aId, PRBool& aIsContainer) const
00125 {
00126   aIsContainer = nsHTMLElement::IsContainer((eHTMLTags)aId);
00127 
00128   return NS_OK;
00129 }
00130 
00131 NS_IMETHODIMP
00132 nsParserService::IsBlock(PRInt32 aId, PRBool& aIsBlock) const
00133 {
00134   if((aId>eHTMLTag_unknown) && (aId<eHTMLTag_userdefined)) {
00135     aIsBlock=((gHTMLElements[aId].IsMemberOf(kBlock))       ||
00136               (gHTMLElements[aId].IsMemberOf(kBlockEntity)) ||
00137               (gHTMLElements[aId].IsMemberOf(kHeading))     ||
00138               (gHTMLElements[aId].IsMemberOf(kPreformatted))||
00139               (gHTMLElements[aId].IsMemberOf(kList)));
00140   }
00141   else {
00142     aIsBlock = PR_FALSE;
00143   }
00144 
00145   return NS_OK;
00146 }
00147 
00148 NS_IMETHODIMP
00149 nsParserService::RegisterObserver(nsIElementObserver* aObserver,
00150                                   const nsAString& aTopic,
00151                                   const eHTMLTags* aTags)
00152 {
00153   nsresult result = NS_OK;
00154   nsObserverEntry* entry = GetEntry(aTopic);
00155 
00156   if(!entry) {
00157     result = CreateEntry(aTopic,&entry);
00158     NS_ENSURE_SUCCESS(result,result);
00159   }
00160 
00161   while (*aTags) {
00162     if (*aTags <= NS_HTML_TAG_MAX) {
00163       entry->AddObserver(aObserver,*aTags);
00164     }
00165     ++aTags;
00166   }
00167 
00168   return result;
00169 }
00170 
00171 NS_IMETHODIMP
00172 nsParserService::UnregisterObserver(nsIElementObserver* aObserver,
00173                                     const nsAString& aTopic)
00174 {
00175   PRInt32 count = mEntries.GetSize();
00176 
00177   for (PRInt32 i=0; i < count; ++i) {
00178     nsObserverEntry* entry = NS_STATIC_CAST(nsObserverEntry*,mEntries.ObjectAt(i));
00179     if (entry && entry->Matches(aTopic)) {
00180       entry->RemoveObserver(aObserver);
00181     }
00182   }
00183 
00184   return NS_OK;
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsParserService::GetTopicObservers(const nsAString& aTopic,
00189                                    nsIObserverEntry** aEntry) {
00190   nsresult result = NS_OK;
00191   nsObserverEntry* entry = GetEntry(aTopic);
00192 
00193   if (!entry) {
00194     return NS_ERROR_NULL_POINTER;
00195   }
00196 
00197   NS_ADDREF(*aEntry = entry);
00198 
00199   return result;
00200 }
00201 
00202 nsresult
00203 nsParserService::CheckQName(const nsASingleFragmentString& aQName,
00204                             PRBool aNamespaceAware,
00205                             const PRUnichar** aColon)
00206 {
00207   const char* colon;
00208   const PRUnichar *begin, *end;
00209   aQName.BeginReading(begin);
00210   aQName.EndReading(end);
00211   int result = MOZ_XMLCheckQName(NS_REINTERPRET_CAST(const char*, begin),
00212                                  NS_REINTERPRET_CAST(const char*, end),
00213                                  aNamespaceAware, &colon);
00214   *aColon = NS_REINTERPRET_CAST(const PRUnichar*, colon);
00215 
00216   if (result == 0) {
00217     return NS_OK;
00218   }
00219 
00220   // MOZ_EXPAT_EMPTY_QNAME || MOZ_EXPAT_INVALID_CHARACTER
00221   if (result & (1 << 0) || result & (1 << 1)) {
00222     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
00223   }
00224 
00225   return NS_ERROR_DOM_NAMESPACE_ERR;
00226 }
00227 
00228 class nsMatchesTopic : public nsDequeFunctor{
00229   const nsAString& mString;
00230 public:
00231   PRBool matched;
00232   nsObserverEntry* entry;
00233   nsMatchesTopic(const nsAString& aString):mString(aString),matched(PR_FALSE){};
00234   virtual void* operator()(void* anObject){
00235     entry=NS_STATIC_CAST(nsObserverEntry*, anObject);
00236     matched=mString.Equals(entry->mTopic);
00237     return matched ? nsnull : anObject;
00238   };
00239 };
00240 
00241 // XXX This may be more efficient as a HashTable instead of linear search
00242 nsObserverEntry*
00243 nsParserService::GetEntry(const nsAString& aTopic)
00244 {
00245   if (!mHaveNotifiedCategoryObservers) {
00246     mHaveNotifiedCategoryObservers = PR_TRUE;
00247     NS_CreateServicesFromCategory("parser-service-category",
00248                                   NS_STATIC_CAST(nsISupports*,NS_STATIC_CAST(void*,this)),
00249                                   "parser-service-start"); 
00250   }
00251 
00252   nsMatchesTopic matchesTopic(aTopic);
00253   mEntries.FirstThat(*&matchesTopic);
00254   return matchesTopic.matched?matchesTopic.entry:nsnull;
00255 }
00256 
00257 nsresult
00258 nsParserService::CreateEntry(const nsAString& aTopic, nsObserverEntry** aEntry)
00259 {
00260   *aEntry = new nsObserverEntry(aTopic);
00261 
00262   if (!aEntry) {
00263     return NS_ERROR_OUT_OF_MEMORY;
00264   }
00265 
00266   NS_ADDREF(*aEntry);
00267   mEntries.Push(*aEntry);
00268 
00269   return NS_OK;
00270 }