Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLHRElement.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 "nsIDOMHTMLHRElement.h"
00038 #include "nsIDOMNSHTMLHRElement.h"
00039 #include "nsIDOMEventReceiver.h"
00040 #include "nsGenericHTMLElement.h"
00041 #include "nsHTMLAtoms.h"
00042 #include "nsStyleConsts.h"
00043 #include "nsPresContext.h"
00044 #include "nsMappedAttributes.h"
00045 #include "nsRuleData.h"
00046 
00047 class nsHTMLHRElement : public nsGenericHTMLElement,
00048                         public nsIDOMHTMLHRElement,
00049                         public nsIDOMNSHTMLHRElement
00050 {
00051 public:
00052   nsHTMLHRElement(nsINodeInfo *aNodeInfo);
00053   virtual ~nsHTMLHRElement();
00054 
00055   // nsISupports
00056   NS_DECL_ISUPPORTS_INHERITED
00057 
00058   // nsIDOMNode
00059   NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsGenericHTMLElement::)
00060 
00061   // nsIDOMElement
00062   NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
00063 
00064   // nsIDOMHTMLElement
00065   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
00066 
00067   // nsIDOMHTMLHRElement
00068   NS_DECL_NSIDOMHTMLHRELEMENT
00069 
00070   // nsIDOMNSHTMLHRElement
00071   NS_DECL_NSIDOMNSHTMLHRELEMENT
00072 
00073   virtual PRBool ParseAttribute(nsIAtom* aAttribute,
00074                                 const nsAString& aValue,
00075                                 nsAttrValue& aResult);
00076   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
00077   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
00078 };
00079 
00080 
00081 NS_IMPL_NS_NEW_HTML_ELEMENT(HR)
00082 
00083 
00084 nsHTMLHRElement::nsHTMLHRElement(nsINodeInfo *aNodeInfo)
00085   : nsGenericHTMLElement(aNodeInfo)
00086 {
00087 }
00088 
00089 nsHTMLHRElement::~nsHTMLHRElement()
00090 {
00091 }
00092 
00093 
00094 NS_IMPL_ADDREF_INHERITED(nsHTMLHRElement, nsGenericElement) 
00095 NS_IMPL_RELEASE_INHERITED(nsHTMLHRElement, nsGenericElement) 
00096 
00097 
00098 // QueryInterface implementation for nsHTMLHRElement
00099 NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLHRElement, nsGenericHTMLElement)
00100   NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLHRElement)
00101   NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLHRElement)
00102   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLHRElement)
00103 NS_HTML_CONTENT_INTERFACE_MAP_END
00104 
00105 
00106 NS_IMPL_DOM_CLONENODE(nsHTMLHRElement)
00107 
00108 
00109 NS_IMPL_STRING_ATTR(nsHTMLHRElement, Align, align)
00110 NS_IMPL_BOOL_ATTR(nsHTMLHRElement, NoShade, noshade)
00111 NS_IMPL_STRING_ATTR(nsHTMLHRElement, Size, size)
00112 NS_IMPL_STRING_ATTR(nsHTMLHRElement, Width, width)
00113 NS_IMPL_STRING_ATTR(nsHTMLHRElement, Color, color)
00114 
00115 static const nsAttrValue::EnumTable kAlignTable[] = {
00116   { "left", NS_STYLE_TEXT_ALIGN_LEFT },
00117   { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
00118   { "center", NS_STYLE_TEXT_ALIGN_CENTER },
00119   { 0 }
00120 };
00121 
00122 PRBool
00123 nsHTMLHRElement::ParseAttribute(nsIAtom* aAttribute,
00124                                 const nsAString& aValue,
00125                                 nsAttrValue& aResult)
00126 {
00127   if (aAttribute == nsHTMLAtoms::width) {
00128     return aResult.ParseSpecialIntValue(aValue, PR_TRUE, PR_FALSE);
00129   }
00130   if (aAttribute == nsHTMLAtoms::size) {
00131     return aResult.ParseIntWithBounds(aValue, 1, 1000);
00132   }
00133   if (aAttribute == nsHTMLAtoms::align) {
00134     return aResult.ParseEnumValue(aValue, kAlignTable);
00135   }
00136   if (aAttribute == nsHTMLAtoms::color) {
00137     return aResult.ParseColor(aValue, GetOwnerDoc());
00138   }
00139 
00140   return nsGenericHTMLElement::ParseAttribute(aAttribute, aValue, aResult);
00141 }
00142 
00143 static void
00144 MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
00145                       nsRuleData* aData)
00146 {
00147   PRBool noshade = PR_FALSE;
00148 
00149   const nsAttrValue* colorValue = aAttributes->GetAttr(nsHTMLAtoms::color);
00150   nscolor color;
00151   PRBool colorIsSet = colorValue && colorValue->GetColorValue(color);
00152 
00153   if (aData->mSID == eStyleStruct_Position ||
00154       aData->mSID == eStyleStruct_Border) {
00155     if (colorIsSet) {
00156       noshade = PR_TRUE;
00157     } else {
00158       noshade = !!aAttributes->GetAttr(nsHTMLAtoms::noshade);
00159     }
00160   }
00161 
00162   if (aData->mSID == eStyleStruct_Margin) {
00163     // align: enum
00164     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::align);
00165     if (value && value->Type() == nsAttrValue::eEnum) {
00166       // Map align attribute into auto side margins
00167       nsCSSRect& margin = aData->mMarginData->mMargin;
00168       switch (value->GetEnumValue()) {
00169       case NS_STYLE_TEXT_ALIGN_LEFT:
00170         if (margin.mLeft.GetUnit() == eCSSUnit_Null)
00171           margin.mLeft.SetFloatValue(0.0f, eCSSUnit_Pixel);
00172         if (margin.mRight.GetUnit() == eCSSUnit_Null)
00173           margin.mRight.SetAutoValue();
00174         break;
00175       case NS_STYLE_TEXT_ALIGN_RIGHT:
00176         if (margin.mLeft.GetUnit() == eCSSUnit_Null)
00177           margin.mLeft.SetAutoValue();
00178         if (margin.mRight.GetUnit() == eCSSUnit_Null)
00179           margin.mRight.SetFloatValue(0.0f, eCSSUnit_Pixel);
00180         break;
00181       case NS_STYLE_TEXT_ALIGN_CENTER:
00182         if (margin.mLeft.GetUnit() == eCSSUnit_Null)
00183           margin.mLeft.SetAutoValue();
00184         if (margin.mRight.GetUnit() == eCSSUnit_Null)
00185           margin.mRight.SetAutoValue();
00186         break;
00187       }
00188     }
00189   }
00190   else if (aData->mSID == eStyleStruct_Position) {
00191     // width: integer, percent
00192     if (aData->mPositionData->mWidth.GetUnit() == eCSSUnit_Null) {
00193       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::width);
00194       if (value && value->Type() == nsAttrValue::eInteger) {
00195         aData->mPositionData->mWidth.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
00196       } else if (value && value->Type() == nsAttrValue::ePercent) {
00197         aData->mPositionData->mWidth.SetPercentValue(value->GetPercentValue());
00198       }
00199     }
00200 
00201     if (aData->mPositionData->mHeight.GetUnit() == eCSSUnit_Null) {
00202       // size: integer
00203       if (noshade) {
00204         // noshade case: size is set using the border
00205         aData->mPositionData->mHeight.SetAutoValue();
00206       } else {
00207         // normal case
00208         // the height includes the top and bottom borders that are initially 1px.
00209         // for size=1, html.css has a special case rule that makes this work by
00210         // removing all but the top border.
00211         const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::size);
00212         if (value && value->Type() == nsAttrValue::eInteger) {
00213           aData->mPositionData->mHeight.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
00214         } // else use default value from html.css
00215       }
00216     }
00217   }
00218   else if (aData->mSID == eStyleStruct_Border && noshade) { // if not noshade, border styles are dealt with by html.css
00219     // size: integer
00220     // if a size is set, use half of it per side, otherwise, use 1px per side
00221     float sizePerSide;
00222     PRBool allSides = PR_TRUE;
00223     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::size);
00224     if (value && value->Type() == nsAttrValue::eInteger) {
00225       sizePerSide = (float)value->GetIntegerValue() / 2.0f;
00226       if (sizePerSide < 1.0f) {
00227         // XXX When the pixel bug is fixed, all the special casing for
00228         // subpixel borders should be removed.
00229         // In the meantime, this makes http://www.microsoft.com/ look right.
00230         sizePerSide = 1.0f;
00231         allSides = PR_FALSE;
00232       }
00233     } else {
00234       sizePerSide = 1.0f; // default to a 2px high line
00235     }
00236     nsCSSRect& borderWidth = aData->mMarginData->mBorderWidth;
00237     if (borderWidth.mTop.GetUnit() == eCSSUnit_Null) {
00238       borderWidth.mTop.SetFloatValue(sizePerSide, eCSSUnit_Pixel);
00239     }
00240     if (allSides) {
00241       if (borderWidth.mRight.GetUnit() == eCSSUnit_Null) {
00242         borderWidth.mRight.SetFloatValue(sizePerSide, eCSSUnit_Pixel);
00243       }
00244       if (borderWidth.mBottom.GetUnit() == eCSSUnit_Null) {
00245         borderWidth.mBottom.SetFloatValue(sizePerSide, eCSSUnit_Pixel);
00246       }
00247       if (borderWidth.mLeft.GetUnit() == eCSSUnit_Null) {
00248         borderWidth.mLeft.SetFloatValue(sizePerSide, eCSSUnit_Pixel);
00249       }
00250     }
00251 
00252     // if a color is set, set the border-style to 'solid' so that the
00253     // 'color' property takes effect, otherwise, use '-moz-bg-solid'.
00254     // (we got the color attribute earlier)
00255     PRInt32 style = colorIsSet ? NS_STYLE_BORDER_STYLE_SOLID :
00256                                  NS_STYLE_BORDER_STYLE_BG_SOLID;
00257 
00258     nsCSSRect& borderStyle = aData->mMarginData->mBorderStyle;
00259     if (borderStyle.mTop.GetUnit() == eCSSUnit_Null) {
00260       borderStyle.mTop.SetIntValue(style, eCSSUnit_Enumerated);
00261     }
00262     if (allSides) {
00263       if (borderStyle.mRight.GetUnit() == eCSSUnit_Null) {
00264         borderStyle.mRight.SetIntValue(style, eCSSUnit_Enumerated);
00265       }
00266       if (borderStyle.mBottom.GetUnit() == eCSSUnit_Null) {
00267         borderStyle.mBottom.SetIntValue(style, eCSSUnit_Enumerated);
00268       }
00269       if (borderStyle.mLeft.GetUnit() == eCSSUnit_Null) {
00270         borderStyle.mLeft.SetIntValue(style, eCSSUnit_Enumerated);
00271       }
00272 
00273       // If it would be noticeable, set the border radius to
00274       // 100% on all corners
00275       nsCSSRect& borderRadius = aData->mMarginData->mBorderRadius;
00276       if (borderRadius.mTop.GetUnit() == eCSSUnit_Null) {
00277         borderRadius.mTop.SetPercentValue(1.0f);
00278       }
00279       if (borderRadius.mRight.GetUnit() == eCSSUnit_Null) {
00280         borderRadius.mRight.SetPercentValue(1.0f);
00281       }
00282       if (borderRadius.mBottom.GetUnit() == eCSSUnit_Null) {
00283         borderRadius.mBottom.SetPercentValue(1.0f);
00284       }
00285       if (borderRadius.mLeft.GetUnit() == eCSSUnit_Null) {
00286         borderRadius.mLeft.SetPercentValue(1.0f);
00287       }
00288     }
00289   }
00290   else if (aData->mSID == eStyleStruct_Color) {
00291     // color: a color
00292     // (we got the color attribute earlier)
00293     if (colorIsSet &&
00294         aData->mColorData->mColor.GetUnit() == eCSSUnit_Null) {
00295       aData->mColorData->mColor.SetColorValue(color);
00296     }
00297   }
00298 
00299   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
00300 }
00301 
00302 NS_IMETHODIMP_(PRBool)
00303 nsHTMLHRElement::IsAttributeMapped(const nsIAtom* aAttribute) const
00304 {
00305   static const MappedAttributeEntry attributes[] = {
00306     { &nsHTMLAtoms::align },
00307     { &nsHTMLAtoms::width },
00308     { &nsHTMLAtoms::size },
00309     { &nsHTMLAtoms::color },
00310     { &nsHTMLAtoms::noshade },
00311     { nsnull },
00312   };
00313   
00314   static const MappedAttributeEntry* const map[] = {
00315     attributes,
00316     sCommonAttributeMap,
00317   };
00318 
00319   return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map));
00320 }
00321 
00322 
00323 nsMapRuleToAttributesFunc
00324 nsHTMLHRElement::GetAttributeMappingFunction() const
00325 {
00326   return &MapAttributesIntoRule;
00327 }