Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLTableCellElement.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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsIDOMHTMLTableCellElement.h"
00038 #include "nsIDOMHTMLTableRowElement.h"
00039 #include "nsIDOMHTMLCollection.h"
00040 #include "nsIDOMEventReceiver.h"
00041 #include "nsMappedAttributes.h"
00042 #include "nsGenericHTMLElement.h"
00043 #include "nsHTMLAtoms.h"
00044 #include "nsStyleConsts.h"
00045 #include "nsPresContext.h"
00046 #include "nsRuleData.h"
00047 #include "nsIDocument.h"
00048 #include "celldata.h"
00049 
00050 class nsHTMLTableCellElement : public nsGenericHTMLElement,
00051                                public nsIDOMHTMLTableCellElement
00052 {
00053 public:
00054   nsHTMLTableCellElement(nsINodeInfo *aNodeInfo);
00055   virtual ~nsHTMLTableCellElement();
00056 
00057   // nsISupports
00058   NS_DECL_ISUPPORTS_INHERITED
00059 
00060   // nsIDOMNode
00061   NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsGenericHTMLElement::)
00062 
00063   // nsIDOMElement
00064   NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
00065 
00066   // nsIDOMHTMLElement
00067   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
00068 
00069   // nsIDOMHTMLTableCellElement
00070   NS_DECL_NSIDOMHTMLTABLECELLELEMENT
00071 
00072   virtual PRBool ParseAttribute(nsIAtom* aAttribute,
00073                                 const nsAString& aValue,
00074                                 nsAttrValue& aResult);
00075   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
00076   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
00077   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
00078 
00079 protected:
00080   // This does not return a nsresult since all we care about is if we
00081   // found the row element that this cell is in or not.
00082   void GetRow(nsIDOMHTMLTableRowElement** aRow);
00083   nsIContent * GetTable();
00084 };
00085 
00086 
00087 NS_IMPL_NS_NEW_HTML_ELEMENT(TableCell)
00088 
00089 
00090 nsHTMLTableCellElement::nsHTMLTableCellElement(nsINodeInfo *aNodeInfo)
00091   : nsGenericHTMLElement(aNodeInfo)
00092 {
00093 }
00094 
00095 nsHTMLTableCellElement::~nsHTMLTableCellElement()
00096 {
00097 }
00098 
00099 
00100 NS_IMPL_ADDREF_INHERITED(nsHTMLTableCellElement, nsGenericElement) 
00101 NS_IMPL_RELEASE_INHERITED(nsHTMLTableCellElement, nsGenericElement) 
00102 
00103 
00104 // QueryInterface implementation for nsHTMLTableCellElement
00105 NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLTableCellElement, nsGenericHTMLElement)
00106   NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLTableCellElement)
00107   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLTableCellElement)
00108 NS_HTML_CONTENT_INTERFACE_MAP_END
00109 
00110 
00111 NS_IMPL_DOM_CLONENODE(nsHTMLTableCellElement)
00112 
00113 
00114 // protected method
00115 void
00116 nsHTMLTableCellElement::GetRow(nsIDOMHTMLTableRowElement** aRow)
00117 {
00118   *aRow = nsnull;
00119 
00120   nsCOMPtr<nsIDOMNode> rowNode;
00121   GetParentNode(getter_AddRefs(rowNode));
00122 
00123   if (rowNode) {
00124     CallQueryInterface(rowNode, aRow);
00125   }
00126 }
00127 
00128 // protected method
00129 nsIContent*
00130 nsHTMLTableCellElement::GetTable()
00131 {
00132   nsIContent *result = nsnull;
00133 
00134   nsIContent *parent = GetParent();
00135   if (parent) {  // GetParent() should be a row
00136     nsIContent* section = parent->GetParent();
00137     if (section) {
00138       if (section->IsContentOfType(eHTML) &&
00139           section->GetNodeInfo()->Equals(nsHTMLAtoms::table)) {
00140         // XHTML, without a row group
00141         result = section;
00142       } else {
00143         // we have a row group.
00144         result = section->GetParent();
00145       }
00146     }
00147   }
00148   return result;
00149 }
00150 
00151 NS_IMETHODIMP
00152 nsHTMLTableCellElement::GetCellIndex(PRInt32* aCellIndex)
00153 {
00154   *aCellIndex = -1;
00155 
00156   nsCOMPtr<nsIDOMHTMLTableRowElement> row;
00157 
00158   GetRow(getter_AddRefs(row));
00159 
00160   if (!row) {
00161     return NS_OK;
00162   }
00163 
00164   nsCOMPtr<nsIDOMHTMLCollection> cells;
00165 
00166   row->GetCells(getter_AddRefs(cells));
00167 
00168   if (!cells) {
00169     return NS_OK;
00170   }
00171 
00172   PRUint32 numCells;
00173   cells->GetLength(&numCells);
00174 
00175   PRBool found = PR_FALSE;
00176   PRUint32 i;
00177 
00178   for (i = 0; (i < numCells) && !found; i++) {
00179     nsCOMPtr<nsIDOMNode> node;
00180     cells->Item(i, getter_AddRefs(node));
00181 
00182     if (node.get() == NS_STATIC_CAST(nsIDOMNode *, this)) {
00183       *aCellIndex = i;
00184       found = PR_TRUE;
00185     }
00186   }
00187 
00188   return NS_OK;
00189 }
00190 
00191 
00192 NS_IMETHODIMP
00193 nsHTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
00194 {
00195   nsresult rv = nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
00196   NS_ENSURE_SUCCESS(rv, rv);
00197 
00198   // Add style information from the mapped attributes of the table
00199   // element.  This depends on the strange behavior of the
00200   // |MapAttributesIntoRule| in nsHTMLTableElement.cpp, which is
00201   // technically incorrect since it's violating the nsIStyleRule
00202   // contract.  However, things are OK (except for the incorrect
00203   // dependence on display type rather than tag) since tables and cells
00204   // match different, less specific, rules.
00205   nsCOMPtr<nsIStyledContent> styledTable = do_QueryInterface(GetTable());
00206   if (styledTable) {
00207     rv = styledTable->WalkContentStyleRules(aRuleWalker);
00208   }
00209 
00210   return rv;
00211 }
00212 
00213 
00214 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Abbr, abbr)
00215 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Axis, axis)
00216 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, BgColor, bgcolor)
00217 NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, Ch, _char, ".")
00218 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, ChOff, charoff)
00219 NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, ColSpan, colspan, 1)
00220 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Headers, headers)
00221 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Height, height)
00222 NS_IMPL_BOOL_ATTR(nsHTMLTableCellElement, NoWrap, nowrap)
00223 NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, RowSpan, rowspan, 1)
00224 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Scope, scope)
00225 NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, VAlign, valign, "middle")
00226 NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Width, width)
00227 
00228 
00229 NS_IMETHODIMP
00230 nsHTMLTableCellElement::GetAlign(nsAString& aValue)
00231 {
00232   nsresult rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::align, aValue);
00233 
00234   if (rv == NS_CONTENT_ATTR_NOT_THERE) {
00235     // There's no align attribute, ask the row for the alignment.
00236 
00237     nsCOMPtr<nsIDOMHTMLTableRowElement> row;
00238     GetRow(getter_AddRefs(row));
00239 
00240     if (row) {
00241       return row->GetAlign(aValue);
00242     }
00243   }
00244 
00245   return NS_OK;
00246 }
00247 
00248 NS_IMETHODIMP
00249 nsHTMLTableCellElement::SetAlign(const nsAString& aValue)
00250 {
00251   return SetAttr(kNameSpaceID_None, nsHTMLAtoms::align, aValue, PR_TRUE);
00252 }
00253 
00254 
00255 static const nsAttrValue::EnumTable kCellScopeTable[] = {
00256   { "row",      NS_STYLE_CELL_SCOPE_ROW },
00257   { "col",      NS_STYLE_CELL_SCOPE_COL },
00258   { "rowgroup", NS_STYLE_CELL_SCOPE_ROWGROUP },
00259   { "colgroup", NS_STYLE_CELL_SCOPE_COLGROUP },
00260   { 0 }
00261 };
00262 
00263 PRBool
00264 nsHTMLTableCellElement::ParseAttribute(nsIAtom* aAttribute,
00265                                        const nsAString& aValue,
00266                                        nsAttrValue& aResult)
00267 {
00268   /* ignore these attributes, stored simply as strings
00269      abbr, axis, ch, headers
00270    */
00271   if (aAttribute == nsHTMLAtoms::charoff) {
00272     /* attributes that resolve to integers with a min of 0 */
00273     return aResult.ParseIntWithBounds(aValue, 0);
00274   }
00275   if (aAttribute == nsHTMLAtoms::colspan) {
00276     PRBool res = aResult.ParseIntWithBounds(aValue, -1);
00277     if (res) {
00278       PRInt32 val = aResult.GetIntegerValue();
00279       // reset large colspan values as IE and opera do
00280       // quirks mode does not honor the special html 4 value of 0
00281       if (val > MAX_COLSPAN || val < 0 || (0 == val && InNavQuirksMode(GetOwnerDoc()))) {
00282         aResult.SetTo(1);
00283       }
00284     }
00285     return res;
00286   }
00287   if (aAttribute == nsHTMLAtoms::rowspan) {
00288     PRBool res = aResult.ParseIntWithBounds(aValue, -1, MAX_ROWSPAN);
00289     if (res) {
00290       PRInt32 val = aResult.GetIntegerValue();
00291       // quirks mode does not honor the special html 4 value of 0
00292       if (val < 0 || (0 == val && InNavQuirksMode(GetOwnerDoc()))) {
00293         aResult.SetTo(1);
00294       }
00295     }
00296     return res;
00297   }
00298   if (aAttribute == nsHTMLAtoms::height) {
00299     return aResult.ParseSpecialIntValue(aValue, PR_TRUE, PR_FALSE);
00300   }
00301   if (aAttribute == nsHTMLAtoms::width) {
00302     return aResult.ParseSpecialIntValue(aValue, PR_TRUE, PR_FALSE);
00303   }
00304   if (aAttribute == nsHTMLAtoms::align) {
00305     return ParseTableCellHAlignValue(aValue, aResult);
00306   }
00307   if (aAttribute == nsHTMLAtoms::bgcolor) {
00308     return aResult.ParseColor(aValue, GetOwnerDoc());
00309   }
00310   if (aAttribute == nsHTMLAtoms::scope) {
00311     return aResult.ParseEnumValue(aValue, kCellScopeTable);
00312   }
00313   if (aAttribute == nsHTMLAtoms::valign) {
00314     return ParseTableVAlignValue(aValue, aResult);
00315   }
00316 
00317   return nsGenericHTMLElement::ParseAttribute(aAttribute, aValue, aResult);
00318 }
00319 
00320 static 
00321 void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
00322                            nsRuleData* aData)
00323 {
00324   if (aData->mSID == eStyleStruct_Position) {
00325     // width: value
00326     if (aData->mPositionData->mWidth.GetUnit() == eCSSUnit_Null) {
00327       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::width);
00328       if (value && value->Type() == nsAttrValue::eInteger) {
00329         if (value->GetIntegerValue() > 0)
00330           aData->mPositionData->mWidth.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel); 
00331         // else 0 implies auto for compatibility.
00332       }
00333       else if (value && value->Type() == nsAttrValue::ePercent) {
00334         if (value->GetPercentValue() > 0.0f)
00335           aData->mPositionData->mWidth.SetPercentValue(value->GetPercentValue());
00336         // else 0 implies auto for compatibility
00337       }
00338     }
00339 
00340     // height: value
00341     if (aData->mPositionData->mHeight.GetUnit() == eCSSUnit_Null) {
00342       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::height);
00343       if (value && value->Type() == nsAttrValue::eInteger) {
00344         if (value->GetIntegerValue() > 0)
00345           aData->mPositionData->mHeight.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
00346         // else 0 implies auto for compatibility.
00347       }
00348       else if (value && value->Type() == nsAttrValue::ePercent) {
00349         if (value->GetPercentValue() > 0.0f)
00350           aData->mPositionData->mHeight.SetPercentValue(value->GetPercentValue());
00351         // else 0 implies auto for compatibility
00352       }
00353     }
00354   }
00355   else if (aData->mSID == eStyleStruct_Text) {
00356     if (aData->mTextData->mTextAlign.GetUnit() == eCSSUnit_Null) {
00357       // align: enum
00358       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::align);
00359       if (value && value->Type() == nsAttrValue::eEnum)
00360         aData->mTextData->mTextAlign.SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
00361     }
00362 
00363     if (aData->mTextData->mWhiteSpace.GetUnit() == eCSSUnit_Null) {
00364       // nowrap: enum
00365       if (aAttributes->GetAttr(nsHTMLAtoms::nowrap)) {
00366         // See if our width is not a integer width.
00367         const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::width);
00368         nsCompatibility mode = aData->mPresContext->CompatibilityMode();
00369         if (!value || value->Type() != nsAttrValue::eInteger || eCompatibility_NavQuirks != mode)
00370           aData->mTextData->mWhiteSpace.SetIntValue(NS_STYLE_WHITESPACE_NOWRAP, eCSSUnit_Enumerated);
00371       }
00372     }
00373   }
00374   else if (aData->mSID == eStyleStruct_TextReset) {
00375     if (aData->mTextData->mVerticalAlign.GetUnit() == eCSSUnit_Null) {
00376       // valign: enum
00377       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::valign);
00378       if (value && value->Type() == nsAttrValue::eEnum)
00379         aData->mTextData->mVerticalAlign.SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
00380     }
00381   }
00382   
00383   nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
00384   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
00385 }
00386 
00387 NS_IMETHODIMP_(PRBool)
00388 nsHTMLTableCellElement::IsAttributeMapped(const nsIAtom* aAttribute) const
00389 {
00390   static const MappedAttributeEntry attributes[] = {
00391     { &nsHTMLAtoms::align }, 
00392     { &nsHTMLAtoms::valign },
00393     { &nsHTMLAtoms::nowrap },
00394 #if 0
00395     // XXXldb If these are implemented, they might need to move to
00396     // GetAttributeChangeHint (depending on how, and preferably not).
00397     { &nsHTMLAtoms::abbr },
00398     { &nsHTMLAtoms::axis },
00399     { &nsHTMLAtoms::headers },
00400     { &nsHTMLAtoms::scope },
00401 #endif
00402     { &nsHTMLAtoms::width },
00403     { &nsHTMLAtoms::height },
00404     { nsnull }
00405   };
00406 
00407   static const MappedAttributeEntry* const map[] = {
00408     attributes,
00409     sCommonAttributeMap,
00410     sBackgroundAttributeMap,
00411   };
00412 
00413   return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map));
00414 }
00415 
00416 nsMapRuleToAttributesFunc
00417 nsHTMLTableCellElement::GetAttributeMappingFunction() const
00418 {
00419   return &MapAttributesIntoRule;
00420 }