Back to index

lightning-sunbird  0.9+nobinonly
nsDOMCSSDeclaration.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 Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mats Palmgren <mats.palmgren@bredband.net>
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 "nsDOMCSSDeclaration.h"
00040 #include "nsIDOMCSSRule.h"
00041 #include "nsICSSParser.h"
00042 #include "nsICSSLoader.h"
00043 #include "nsIStyleRule.h"
00044 #include "nsCSSDeclaration.h"
00045 #include "nsCSSProps.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsIURL.h"
00048 #include "nsReadableUtils.h"
00049 
00050 #include "nsContentUtils.h"
00051 
00052 
00053 nsDOMCSSDeclaration::nsDOMCSSDeclaration()
00054   : mInner(this)
00055 {
00056 }
00057 
00058 nsDOMCSSDeclaration::~nsDOMCSSDeclaration()
00059 {
00060 }
00061 
00062 
00063 // QueryInterface implementation for nsDOMCSSDeclaration
00064 NS_INTERFACE_MAP_BEGIN(nsDOMCSSDeclaration)
00065   NS_INTERFACE_MAP_ENTRY(nsICSSDeclaration)
00066   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleDeclaration)
00067   NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIDOMCSS2Properties, &mInner)
00068   NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIDOMNSCSS2Properties, &mInner)
00069   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMCSSStyleDeclaration)
00070   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSStyleDeclaration)
00071 NS_INTERFACE_MAP_END
00072 
00073 NS_IMETHODIMP
00074 nsDOMCSSDeclaration::GetPropertyValue(const nsCSSProperty aPropID,
00075                                       nsAString& aValue)
00076 {
00077   NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN,
00078                   "Should never pass eCSSProperty_UNKNOWN around");
00079   
00080   nsCSSDeclaration *decl;
00081   nsresult result = GetCSSDeclaration(&decl, PR_FALSE);
00082 
00083   aValue.Truncate();
00084   if (decl) {
00085     result = decl->GetValue(aPropID, aValue);
00086   }
00087 
00088   return result;
00089 }
00090 
00091 NS_IMETHODIMP
00092 nsDOMCSSDeclaration::SetPropertyValue(const nsCSSProperty aPropID,
00093                                       const nsAString& aValue)
00094 {
00095   if (aValue.IsEmpty()) {
00096     // If the new value of the property is an empty string we remove the
00097     // property.
00098     return RemoveProperty(aPropID);
00099   }
00100 
00101   return ParsePropertyValue(aPropID, aValue);
00102 }
00103 
00104 
00105 NS_IMETHODIMP
00106 nsDOMCSSDeclaration::GetCssText(nsAString& aCssText)
00107 {
00108   nsCSSDeclaration* decl;
00109   aCssText.Truncate();
00110   GetCSSDeclaration(&decl, PR_FALSE);
00111 
00112   if (decl) {
00113     decl->ToString(aCssText);
00114   }
00115 
00116   return NS_OK;
00117 }
00118 
00119 NS_IMETHODIMP
00120 nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText)
00121 {
00122   return ParseDeclaration(aCssText, PR_FALSE, PR_TRUE);
00123 }
00124 
00125 NS_IMETHODIMP
00126 nsDOMCSSDeclaration::GetLength(PRUint32* aLength)
00127 {
00128   nsCSSDeclaration *decl;
00129   nsresult result = GetCSSDeclaration(&decl, PR_FALSE);
00130  
00131   if (decl) {
00132     *aLength = decl->Count();
00133   } else {
00134     *aLength = 0;
00135   }
00136 
00137   return result;
00138 }
00139 
00140 NS_IMETHODIMP
00141 nsDOMCSSDeclaration::GetPropertyCSSValue(const nsAString& aPropertyName,
00142                                          nsIDOMCSSValue** aReturn)
00143 {
00144   NS_ENSURE_ARG_POINTER(aReturn);
00145 
00146   // We don't support CSSValue yet so we'll just return null...
00147   *aReturn = nsnull;
00148 
00149   return NS_OK;
00150 }
00151 
00152 NS_IMETHODIMP
00153 nsDOMCSSDeclaration::Item(PRUint32 aIndex, nsAString& aReturn)
00154 {
00155   nsCSSDeclaration *decl;
00156   nsresult result = GetCSSDeclaration(&decl, PR_FALSE);
00157 
00158   aReturn.SetLength(0);
00159   if (decl) {
00160     result = decl->GetNthProperty(aIndex, aReturn);
00161   }
00162 
00163   return result;
00164 }
00165 
00166 NS_IMETHODIMP    
00167 nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName, 
00168                                       nsAString& aReturn)
00169 {
00170   const nsCSSProperty propID = nsCSSProps::LookupProperty(aPropertyName);
00171   if (propID == eCSSProperty_UNKNOWN) {
00172     aReturn.Truncate();
00173     return NS_OK;
00174   }
00175   
00176   return GetPropertyValue(propID, aReturn);
00177 }
00178 
00179 NS_IMETHODIMP    
00180 nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName, 
00181                                          nsAString& aReturn)
00182 {
00183   nsCSSDeclaration *decl;
00184   nsresult result = GetCSSDeclaration(&decl, PR_FALSE);
00185 
00186   aReturn.Truncate();
00187   if (decl && decl->GetValueIsImportant(aPropertyName)) {
00188     aReturn.AssignLiteral("important");    
00189   }
00190 
00191   return result;
00192 }
00193 
00194 NS_IMETHODIMP    
00195 nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName, 
00196                                  const nsAString& aValue, 
00197                                  const nsAString& aPriority)
00198 {
00199   // In the common (and fast) cases we can use the property id
00200   nsCSSProperty propID = nsCSSProps::LookupProperty(aPropertyName);
00201   if (propID == eCSSProperty_UNKNOWN) {
00202     return NS_OK;
00203   }
00204   
00205   if (aValue.IsEmpty()) {
00206     // If the new value of the property is an empty string we remove the
00207     // property.
00208     return RemoveProperty(propID);
00209   }
00210 
00211   if (aPriority.IsEmpty()) {
00212     return ParsePropertyValue(propID, aValue);
00213   }
00214 
00215   // ParsePropertyValue does not handle priorities correctly -- it's
00216   // optimized for speed.  And the priority is not part of the
00217   // property value anyway.... So we have to use the full-blown
00218   // ParseDeclaration()
00219   return ParseDeclaration(aPropertyName + NS_LITERAL_STRING(":") +
00220                           aValue + NS_LITERAL_STRING("!") + aPriority,
00221                           PR_TRUE, PR_FALSE);
00222 }
00223 
00224 NS_IMETHODIMP
00225 nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName,
00226                                     nsAString& aReturn)
00227 {
00228   const nsCSSProperty propID = nsCSSProps::LookupProperty(aPropertyName);
00229   if (propID == eCSSProperty_UNKNOWN) {
00230     aReturn.Truncate();
00231     return NS_OK;
00232   }
00233   
00234   nsresult rv = GetPropertyValue(propID, aReturn);
00235   NS_ENSURE_SUCCESS(rv, rv);
00236   
00237   rv = RemoveProperty(propID);
00238   return rv;
00239 }
00240 
00241 nsresult
00242 nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSProperty aPropID,
00243                                         const nsAString& aPropValue)
00244 {
00245   nsCSSDeclaration* decl;
00246   nsresult result = GetCSSDeclaration(&decl, PR_TRUE);
00247   if (!decl) {
00248     return result;
00249   }
00250   
00251   nsCOMPtr<nsICSSLoader> cssLoader;
00252   nsCOMPtr<nsICSSParser> cssParser;
00253   nsCOMPtr<nsIURI> baseURI, sheetURI;
00254   
00255   result = GetCSSParsingEnvironment(getter_AddRefs(sheetURI),
00256                                     getter_AddRefs(baseURI),
00257                                     getter_AddRefs(cssLoader),
00258                                     getter_AddRefs(cssParser));
00259   if (NS_FAILED(result)) {
00260     return result;
00261   }
00262 
00263   PRBool changed;
00264   result = cssParser->ParseProperty(aPropID, aPropValue, sheetURI, baseURI,
00265                                     decl, &changed);
00266   if (NS_SUCCEEDED(result) && changed) {
00267     result = DeclarationChanged();
00268   }
00269 
00270   if (cssLoader) {
00271     cssLoader->RecycleParser(cssParser);
00272   }
00273 
00274   return result;
00275 }
00276 
00277 nsresult
00278 nsDOMCSSDeclaration::ParseDeclaration(const nsAString& aDecl,
00279                                       PRBool aParseOnlyOneDecl,
00280                                       PRBool aClearOldDecl)
00281 {
00282   nsCSSDeclaration* decl;
00283   nsresult result = GetCSSDeclaration(&decl, PR_TRUE);
00284   if (!decl) {
00285     return result;
00286   }
00287 
00288   nsCOMPtr<nsICSSLoader> cssLoader;
00289   nsCOMPtr<nsICSSParser> cssParser;
00290   nsCOMPtr<nsIURI> baseURI, sheetURI;
00291 
00292   result = GetCSSParsingEnvironment(getter_AddRefs(sheetURI),
00293                                     getter_AddRefs(baseURI),
00294                                     getter_AddRefs(cssLoader),
00295                                     getter_AddRefs(cssParser));
00296 
00297   if (NS_FAILED(result)) {
00298     return result;
00299   }
00300 
00301   PRBool changed;
00302   result = cssParser->ParseAndAppendDeclaration(aDecl, sheetURI, baseURI, decl,
00303                                                 aParseOnlyOneDecl,
00304                                                 &changed,
00305                                                 aClearOldDecl);
00306   
00307   if (NS_SUCCEEDED(result) && changed) {
00308     result = DeclarationChanged();
00309   }
00310 
00311   if (cssLoader) {
00312     cssLoader->RecycleParser(cssParser);
00313   }
00314 
00315   return result;
00316 }
00317 
00318 nsresult
00319 nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
00320 {
00321   nsCSSDeclaration* decl;
00322   nsresult rv = GetCSSDeclaration(&decl, PR_FALSE);
00323   if (!decl) {
00324     return rv;
00325   }
00326 
00327   rv = decl->RemoveProperty(aPropID);
00328 
00329   if (NS_SUCCEEDED(rv)) {
00330     rv = DeclarationChanged();
00331   } else {
00332     // RemoveProperty used to throw in all sorts of situations -- e.g.
00333     // if the property was a shorthand one.  Do not propagate its return
00334     // value to callers.  (XXX or should we propagate it again now?)
00335     rv = NS_OK;
00336   }
00337 
00338   return rv;
00339 }
00340 
00342 
00343 CSS2PropertiesTearoff::CSS2PropertiesTearoff(nsICSSDeclaration *aOuter)
00344   : mOuter(aOuter)
00345 {
00346   NS_ASSERTION(mOuter, "must have outer");
00347 }
00348 
00349 CSS2PropertiesTearoff::~CSS2PropertiesTearoff()
00350 {
00351 }
00352 
00353 NS_IMETHODIMP_(nsrefcnt)
00354 CSS2PropertiesTearoff::AddRef(void)
00355 {
00356   return mOuter->AddRef();
00357 }
00358 
00359 NS_IMETHODIMP_(nsrefcnt)
00360 CSS2PropertiesTearoff::Release(void)
00361 {
00362   return mOuter->Release();
00363 }
00364 
00365 NS_IMETHODIMP
00366 CSS2PropertiesTearoff::QueryInterface(REFNSIID aIID, void** aInstancePtr)
00367 {
00368   return mOuter->QueryInterface(aIID, aInstancePtr);
00369 }
00370 
00371 // nsIDOMCSS2Properties
00372 // nsIDOMNSCSS2Properties
00373 
00374 #define CSS_PROP(name_, id_, method_, datastruct_, member_, type_, kwtable_) \
00375   NS_IMETHODIMP                                                              \
00376   CSS2PropertiesTearoff::Get##method_(nsAString& aValue)                     \
00377   {                                                                          \
00378     return mOuter->GetPropertyValue(eCSSProperty_##id_, aValue);             \
00379   }                                                                          \
00380                                                                              \
00381   NS_IMETHODIMP                                                              \
00382   CSS2PropertiesTearoff::Set##method_(const nsAString& aValue)               \
00383   {                                                                          \
00384     return mOuter->SetPropertyValue(eCSSProperty_##id_, aValue);             \
00385   }
00386 
00387 #define CSS_PROP_NOTIMPLEMENTED(name_, id_, method_)                         \
00388   NS_IMETHODIMP                                                              \
00389   CSS2PropertiesTearoff::Get##method_(nsAString& aValue)                     \
00390   {                                                                          \
00391     aValue.Truncate();                                                       \
00392     return NS_OK;                                                            \
00393   }                                                                          \
00394                                                                              \
00395   NS_IMETHODIMP                                                              \
00396   CSS2PropertiesTearoff::Set##method_(const nsAString& aValue)               \
00397   {                                                                          \
00398     return NS_OK;                                                            \
00399   }
00400 
00401 #define CSS_PROP_LIST_EXCLUDE_INTERNAL
00402 #define CSS_PROP_SHORTHAND(name_, id_, method_) \
00403   CSS_PROP(name_, id_, method_, X, X, X, X)
00404 #include "nsCSSPropList.h"
00405 
00406 // Aliases
00407 CSS_PROP(X, opacity, MozOpacity, X, X, X, X)
00408 CSS_PROP(X, outline, MozOutline, X, X, X, X)
00409 CSS_PROP(X, outline_color, MozOutlineColor, X, X, X, X)
00410 CSS_PROP(X, outline_style, MozOutlineStyle, X, X, X, X)
00411 CSS_PROP(X, outline_width, MozOutlineWidth, X, X, X, X)
00412 CSS_PROP(X, outline_offset, MozOutlineOffset, X, X, X, X)
00413 
00414 #undef CSS_PROP_SHORTHAND
00415 #undef CSS_PROP_NOTIMPLEMENTED
00416 #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
00417 #undef CSS_PROP