Back to index

lightning-sunbird  0.9+nobinonly
nsMappedAttributes.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * IBM Corporation. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   IBM Corporation
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 "nsMappedAttributes.h"
00040 #include "nsHTMLStyleSheet.h"
00041 #include "nsRuleWalker.h"
00042 #include "prmem.h"
00043 
00044 nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet,
00045                                        nsMapRuleToAttributesFunc aMapRuleFunc)
00046   : mAttrCount(0),
00047     mSheet(aSheet),
00048     mRuleMapper(aMapRuleFunc)
00049 {
00050 }
00051 
00052 nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy)
00053   : mAttrCount(aCopy.mAttrCount),
00054     mSheet(aCopy.mSheet),
00055     mRuleMapper(aCopy.mRuleMapper)
00056 {
00057   NS_ASSERTION(mBufferSize >= aCopy.mAttrCount, "can't fit attributes");
00058 
00059   PRUint32 i;
00060   for (i = 0; i < mAttrCount; ++i) {
00061     new (&Attrs()[i]) InternalAttr(aCopy.Attrs()[i]);
00062   }
00063 }
00064 
00065 nsMappedAttributes::~nsMappedAttributes()
00066 {
00067   if (mSheet) {
00068     mSheet->DropMappedAttributes(this);
00069   }
00070 
00071   PRUint32 i;
00072   for (i = 0; i < mAttrCount; ++i) {
00073     Attrs()[i].~InternalAttr();
00074   }
00075 }
00076 
00077 
00078 nsMappedAttributes*
00079 nsMappedAttributes::Clone(PRBool aWillAddAttr)
00080 {
00081   PRUint32 extra = aWillAddAttr ? 1 : 0;
00082 
00083   // This will call the overridden operator new
00084   return new (mAttrCount + extra) nsMappedAttributes(*this);
00085 }
00086 
00087 void* nsMappedAttributes::operator new(size_t aSize, PRUint32 aAttrCount) CPP_THROW_NEW
00088 {
00089   NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested");
00090 
00091   // aSize will include the mAttrs buffer so subtract that.
00092   void* newAttrs = ::operator new(aSize - sizeof(void*[1]) +
00093                                   aAttrCount * sizeof(InternalAttr));
00094 
00095 #ifdef DEBUG
00096   if (newAttrs) {
00097     NS_STATIC_CAST(nsMappedAttributes*, newAttrs)->mBufferSize = aAttrCount;
00098   }
00099 #endif
00100 
00101   return newAttrs;
00102 }
00103 
00104 NS_IMPL_ISUPPORTS1(nsMappedAttributes,
00105                    nsIStyleRule)
00106 
00107 nsresult
00108 nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
00109 {
00110   NS_PRECONDITION(aAttrName, "null name");
00111 
00112   PRUint32 i;
00113   for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
00114     if (Attrs()[i].mName.Equals(aAttrName)) {
00115       Attrs()[i].mValue.Reset();
00116       Attrs()[i].mValue.SwapValueWith(aValue);
00117 
00118       return NS_OK;
00119     }
00120   }
00121 
00122   NS_ASSERTION(mBufferSize >= mAttrCount + 1, "can't fit attributes");
00123 
00124   if (mAttrCount != i) {
00125     memmove(&Attrs()[i + 1], &Attrs()[i], (mAttrCount - i) * sizeof(InternalAttr));
00126   }
00127 
00128   new (&Attrs()[i].mName) nsAttrName(aAttrName);
00129   new (&Attrs()[i].mValue) nsAttrValue();
00130   Attrs()[i].mValue.SwapValueWith(aValue);
00131   ++mAttrCount;
00132 
00133   return NS_OK;
00134 }
00135 
00136 const nsAttrValue*
00137 nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const
00138 {
00139   NS_PRECONDITION(aAttrName, "null name");
00140 
00141   PRInt32 i = IndexOfAttr(aAttrName, kNameSpaceID_None);
00142   if (i >= 0) {
00143     return &Attrs()[i].mValue;
00144   }
00145 
00146   return nsnull;
00147 }
00148 
00149 PRBool
00150 nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const
00151 {
00152   if (this == aOther) {
00153     return PR_TRUE;
00154   }
00155 
00156   if (mRuleMapper != aOther->mRuleMapper || mAttrCount != aOther->mAttrCount) {
00157     return PR_FALSE;
00158   }
00159 
00160   PRUint32 i;
00161   for (i = 0; i < mAttrCount; ++i) {
00162     if (!Attrs()[i].mName.Equals(aOther->Attrs()[i].mName) ||
00163         !Attrs()[i].mValue.Equals(aOther->Attrs()[i].mValue)) {
00164       return PR_FALSE;
00165     }
00166   }
00167 
00168   return PR_TRUE;
00169 }
00170 
00171 PRUint32
00172 nsMappedAttributes::HashValue() const
00173 {
00174   PRUint32 value = NS_PTR_TO_INT32(mRuleMapper);
00175 
00176   PRUint32 i;
00177   for (i = 0; i < mAttrCount; ++i) {
00178     value ^= Attrs()[i].mName.HashValue() ^ Attrs()[i].mValue.HashValue();
00179   }
00180 
00181   return value;
00182 }
00183 
00184 void
00185 nsMappedAttributes::SetStyleSheet(nsHTMLStyleSheet* aSheet)
00186 {
00187   if (mSheet) {
00188     mSheet->DropMappedAttributes(this);
00189   }
00190   mSheet = aSheet;  // not ref counted
00191 }
00192 
00193 NS_IMETHODIMP
00194 nsMappedAttributes::MapRuleInfoInto(nsRuleData* aRuleData)
00195 {
00196   if (mRuleMapper) {
00197     (*mRuleMapper)(this, aRuleData);
00198   }
00199   return NS_OK;
00200 }
00201 
00202 #ifdef DEBUG
00203 NS_IMETHODIMP
00204 nsMappedAttributes::List(FILE* out, PRInt32 aIndent) const
00205 {
00206   nsAutoString buffer;
00207   PRUint32 i;
00208 
00209   for (i = 0; i < mAttrCount; ++i) {
00210     PRInt32 indent;
00211     for (indent = aIndent; indent > 0; --indent)
00212       fputs("  ", out);
00213 
00214     if (Attrs()[i].mName.IsAtom()) {
00215       Attrs()[i].mName.Atom()->ToString(buffer);
00216     }
00217     else {
00218       Attrs()[i].mName.NodeInfo()->GetQualifiedName(buffer);
00219     }
00220     fputs(NS_LossyConvertUCS2toASCII(buffer).get(), out);
00221 
00222     Attrs()[i].mValue.ToString(buffer);
00223     fputs(NS_LossyConvertUCS2toASCII(buffer).get(), out);
00224     fputs("\n", out);
00225   }
00226 
00227   return NS_OK;
00228 }
00229 #endif
00230 
00231 void
00232 nsMappedAttributes::RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue)
00233 {
00234   Attrs()[aPos].mValue.SwapValueWith(aValue);
00235   Attrs()[aPos].~InternalAttr();
00236   memmove(&Attrs()[aPos], &Attrs()[aPos + 1],
00237           (mAttrCount - aPos - 1) * sizeof(InternalAttr));
00238   mAttrCount--;
00239 }
00240 
00241 const nsAttrName*
00242 nsMappedAttributes::GetExistingAttrNameFromQName(const nsACString& aName) const
00243 {
00244   PRUint32 i;
00245   for (i = 0; i < mAttrCount; ++i) {
00246     if (Attrs()[i].mName.IsAtom()) {
00247       if (Attrs()[i].mName.Atom()->EqualsUTF8(aName)) {
00248         return &Attrs()[i].mName;
00249       }
00250     }
00251     else {
00252       if (Attrs()[i].mName.NodeInfo()->QualifiedNameEquals(aName)) {
00253         return &Attrs()[i].mName;
00254       }
00255     }
00256   }
00257 
00258   return nsnull;
00259 }
00260 
00261 PRInt32
00262 nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const
00263 {
00264   PRUint32 i;
00265   if (aNamespaceID == kNameSpaceID_None) {
00266     // This should be the common case so lets make an optimized loop
00267     for (i = 0; i < mAttrCount; ++i) {
00268       if (Attrs()[i].mName.Equals(aLocalName)) {
00269         return i;
00270       }
00271     }
00272   }
00273   else {
00274     for (i = 0; i < mAttrCount; ++i) {
00275       if (Attrs()[i].mName.Equals(aLocalName, aNamespaceID)) {
00276         return i;
00277       }
00278     }
00279   }
00280 
00281   return -1;
00282 }