NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
        nsIDOMElement *aOriginalElement,
        nsAString& aStr)
{
    NS_ENSURE_ARG(aElement);

    nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
    if (!content) return NS_ERROR_FAILURE;

    // The _moz_dirty attribute is emitted by the editor to
    // indicate that this element should be pretty printed
    // even if we're not in pretty printing mode
    PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
                                           nsGkAtoms::mozdirty);

    nsIAtom *name = content->Tag();

    if (name == nsGkAtoms::br && mPreLevel > 0
            && (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre)) {
        AppendToString(mLineBreak, aStr);
        mMayIgnoreLineBreakSequence = PR_TRUE;
        mColPos = 0;
        return NS_OK;
    }

    if (name == nsGkAtoms::body) {
        mInBody = PR_TRUE;
    }

    if (LineBreakBeforeOpen(name, hasDirtyAttr)) {
        AppendToString(mLineBreak, aStr);
        mMayIgnoreLineBreakSequence = PR_TRUE;
        mColPos = 0;
        mAddSpace = PR_FALSE;
    }
    else if (mAddSpace) {
        AppendToString(PRUnichar(' '), aStr);
        mAddSpace = PR_FALSE;
    }
    else {
        MaybeAddNewline(aStr);
    }
    // Always reset to avoid false newlines in case MaybeAddNewline wasn't
    // called
    mAddNewline = PR_FALSE;

    StartIndentation(name, hasDirtyAttr, aStr);

    if (name == nsGkAtoms::pre ||
            name == nsGkAtoms::script ||
            name == nsGkAtoms::style) {
        mPreLevel++;
    }

    AppendToString(kLessThan, aStr);

    nsAutoString nameStr;
    name->ToString(nameStr);
    AppendToString(nameStr.get(), -1, aStr);

    // Need to keep track of OL and LI elements in order to get ordinal number
    // for the LI.
    if (mIsCopying && name == nsGkAtoms::ol) {
        // We are copying and current node is an OL;
        // Store it's start attribute value in olState->startVal.
        nsAutoString start;
        PRInt32 startAttrVal = 0;
        aElement->GetAttribute(NS_LITERAL_STRING("start"), start);
        if (!start.IsEmpty()) {
            PRInt32 rv = 0;
            startAttrVal = start.ToInteger(&rv);
            //If OL has "start" attribute, first LI element has to start with that value
            //Therefore subtracting 1 as all the LI elements are incrementing it before using it;
            //In failure of ToInteger(), default StartAttrValue to 0.
            if (NS_SUCCEEDED(rv))
                startAttrVal--;
            else
                startAttrVal = 0;
        }
        olState* state = new olState(startAttrVal, PR_TRUE);
        if (state)
            mOLStateStack.AppendElement(state);
    }

    if (mIsCopying && name == nsGkAtoms::li) {
        mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
        if (mIsFirstChildOfOL) {
            // If OL is parent of this LI, serialize attributes in different manner.
            SerializeLIValueAttribute(aElement, aStr);
        }
    }

    // Even LI passed above have to go through this
    // for serializing attributes other than "value".
    SerializeAttributes(content, name, aStr);

    AppendToString(kGreaterThan, aStr);

    if (LineBreakAfterOpen(name, hasDirtyAttr)) {
        AppendToString(mLineBreak, aStr);
        mMayIgnoreLineBreakSequence = PR_TRUE;
        mColPos = 0;
    }

    if (name == nsGkAtoms::script ||
            name == nsGkAtoms::style ||
            name == nsGkAtoms::noscript ||
            name == nsGkAtoms::noframes) {
        mInCDATA = PR_TRUE;
    }

    if (mIsWholeDocument && name == nsGkAtoms::head) {
        // Check if there already are any content-type meta children.
        // If there are, they will be modified to use the correct charset.
        // If there aren't, we'll insert one here.
        PRBool hasMeta = PR_FALSE;
        PRUint32 i, childCount = content->GetChildCount();
        for (i = 0; i < childCount; ++i) {
            nsIContent* child = content->GetChildAt(i);
            if (child->IsNodeOfType(nsINode::eHTML) &&
                    child->Tag() == nsGkAtoms::meta &&
                    child->HasAttr(kNameSpaceID_None, nsGkAtoms::content)) {
                nsAutoString header;
                child->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);

                if (header.LowerCaseEqualsLiteral("content-type")) {
                    hasMeta = PR_TRUE;
                    break;
                }
            }
        }

        if (!hasMeta) {
            AppendToString(mLineBreak, aStr);
            AppendToString(NS_LITERAL_STRING("<meta http-equiv=\"content-type\""),
                           aStr);
            AppendToString(NS_LITERAL_STRING(" content=\"text/html; charset="), aStr);
            AppendToString(NS_ConvertASCIItoUTF16(mCharset), aStr);
            AppendToString(NS_LITERAL_STRING("\">"), aStr);
        }
    }

    return NS_OK;
}
NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
                                            nsIDOMElement *aOriginalElement,
                                            nsAString& aStr)
{
  NS_ENSURE_ARG(aElement);

  nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
  if (!content) return NS_ERROR_FAILURE;

  PRBool forceFormat = PR_FALSE;
  if (!CheckElementStart(content, forceFormat, aStr)) {
    return NS_OK;
  }

  nsIAtom *name = content->Tag();
  PRBool lineBreakBeforeOpen = LineBreakBeforeOpen(content->GetNameSpaceID(), name);

  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw) {
    if (mColPos && lineBreakBeforeOpen) {
      AppendNewLineToString(aStr);
    }
    else {
      MaybeAddNewlineForRootNode(aStr);
    }
    if (!mColPos) {
      AppendIndentation(aStr);
    }
    else if (mAddSpace) {
      AppendToString(PRUnichar(' '), aStr);
      mAddSpace = PR_FALSE;
    }
  }
  else if (mAddSpace) {
    AppendToString(PRUnichar(' '), aStr);
    mAddSpace = PR_FALSE;
  }
  else {
    MaybeAddNewlineForRootNode(aStr);
  }
  // Always reset to avoid false newlines in case MaybeAddNewlineForRootNode wasn't
  // called
  mAddNewlineForRootNode = PR_FALSE;
  
  AppendToString(kLessThan, aStr);

  nsAutoString nameStr;
  name->ToString(nameStr);
  AppendToString(nameStr.get(), -1, aStr);

  MaybeEnterInPreContent(content);

  // for block elements, we increase the indentation
  if ((mDoFormat || forceFormat) && !mPreLevel && !mDoRaw)
    IncrIndentation(name);

  // Need to keep track of OL and LI elements in order to get ordinal number 
  // for the LI.
  if (mIsCopying && name == nsGkAtoms::ol){
    // We are copying and current node is an OL;
    // Store its start attribute value in olState->startVal.
    nsAutoString start;
    PRInt32 startAttrVal = 0;
    aElement->GetAttribute(NS_LITERAL_STRING("start"), start);
    if (!start.IsEmpty()){
      PRInt32 rv = 0;
      startAttrVal = start.ToInteger(&rv);
      //If OL has "start" attribute, first LI element has to start with that value
      //Therefore subtracting 1 as all the LI elements are incrementing it before using it;
      //In failure of ToInteger(), default StartAttrValue to 0.
      if (NS_SUCCEEDED(rv))
        startAttrVal--; 
      else
        startAttrVal = 0;
    }
    mOLStateStack.AppendElement(olState(startAttrVal, PR_TRUE));
  }

  if (mIsCopying && name == nsGkAtoms::li) {
    mIsFirstChildOfOL = IsFirstChildOfOL(aOriginalElement);
    if (mIsFirstChildOfOL){
      // If OL is parent of this LI, serialize attributes in different manner.
      SerializeLIValueAttribute(aElement, aStr);
    }
  }

  // Even LI passed above have to go through this 
  // for serializing attributes other than "value".
  nsAutoString dummyPrefix;
  SerializeAttributes(content, aOriginalElement, dummyPrefix, EmptyString(), name, aStr);

  AppendToString(kGreaterThan, aStr);

  if (name == nsGkAtoms::script ||
      name == nsGkAtoms::style ||
      name == nsGkAtoms::noscript ||
      name == nsGkAtoms::noframes) {
    ++mDisableEntityEncoding;
  }

  if ((mDoFormat || forceFormat) && !mPreLevel &&
    !mDoRaw && LineBreakAfterOpen(content->GetNameSpaceID(), name)) {
    AppendNewLineToString(aStr);
  }

  AfterElementStart(content, aOriginalElement, aStr);

  return NS_OK;
}
NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
                                            PRBool aHasChildren,
                                            nsAString& aStr)
{
  NS_ENSURE_ARG(aElement);
  
  nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
  if (!content) return NS_ERROR_FAILURE;
  
  // The _moz_dirty attribute is emitted by the editor to
  // indicate that this element should be pretty printed
  // even if we're not in pretty printing mode
  PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
                                         nsLayoutAtoms::mozdirty);

  nsIAtom *name = content->Tag();

  if (name == nsHTMLAtoms::br && mPreLevel > 0
      && (mFlags & nsIDocumentEncoder::OutputNoFormattingInPre)) {
    AppendToString(mLineBreak, aStr);
    mMayIgnoreLineBreakSequence = PR_TRUE;
    mColPos = 0;
    return NS_OK;
  }

  if (name == nsHTMLAtoms::body) {
    mInBody = PR_TRUE;
  }

  if (LineBreakBeforeOpen(name, hasDirtyAttr)) {
    AppendToString(mLineBreak, aStr);
    mMayIgnoreLineBreakSequence = PR_TRUE;
    mColPos = 0;
    mAddSpace = PR_FALSE;
  }
  else if (mAddSpace) {
    AppendToString(PRUnichar(' '), aStr);
    mAddSpace = PR_FALSE;
  }
  else {
    MaybeAddNewline(aStr);
  }
  // Always reset to avoid false newlines in case MaybeAddNewline wasn't
  // called
  mAddNewline = PR_FALSE;

  StartIndentation(name, hasDirtyAttr, aStr);

  if (name == nsHTMLAtoms::pre ||
      name == nsHTMLAtoms::script ||
      name == nsHTMLAtoms::style) {
    mPreLevel++;
  }
  
  AppendToString(kLessThan, aStr);

  nsAutoString nameStr;
  name->ToString(nameStr);
  AppendToString(nameStr.get(), -1, aStr);

  // Need to keep track of OL and LI elements in order to get ordinal number 
  // for the LI.
  if (mIsCopying && name == nsHTMLAtoms::ol){
    // We are copying and current node is an OL;
    // Store it's start attribute value in olState->startVal.
    nsAutoString start;
    PRInt32 startAttrVal = 0;
    aElement->GetAttribute(NS_LITERAL_STRING("start"), start);
    if (!start.IsEmpty()){
      PRInt32 rv = 0;
      startAttrVal = start.ToInteger(&rv);
      //If OL has "start" attribute, first LI element has to start with that value
      //Therefore subtracting 1 as all the LI elements are incrementing it before using it;
      //In failure of ToInteger(), default StartAttrValue to 0.
      if (NS_SUCCEEDED(rv))
        startAttrVal--; 
      else
        startAttrVal = 0;
    }
    olState* state = new olState(startAttrVal, PR_TRUE);
    if (state)
      mOLStateStack.AppendElement(state);
  }

  if (mIsCopying && name == nsHTMLAtoms::li) {
    mIsFirstChildOfOL = IsFirstChildOfOL(aElement);
    if (mIsFirstChildOfOL){
      // If OL is parent of this LI, serialize attributes in different manner.
      SerializeLIValueAttribute(aElement, aStr);
    }
  }

  // Even LI passed above have to go through this 
  // for serializing attributes other than "value".
  SerializeAttributes(content, name, aStr);

  AppendToString(kGreaterThan, aStr);

  if (LineBreakAfterOpen(name, hasDirtyAttr)) {
    AppendToString(mLineBreak, aStr);
    mMayIgnoreLineBreakSequence = PR_TRUE;
    mColPos = 0;
  }

  if (name == nsHTMLAtoms::script ||
      name == nsHTMLAtoms::style ||
      name == nsHTMLAtoms::noscript ||
      name == nsHTMLAtoms::noframes) {
    mInCDATA = PR_TRUE;
  }

  return NS_OK;
}