void nsMsgCompose::TagConvertible()

in mailnews/compose/src/nsMsgCompose.cpp [4629:4796]


void nsMsgCompose::TagConvertible(Element* node, int32_t* _retval) {
  *_retval = nsIMsgCompConvertible::No;

  nsAutoString element;
  element = node->NodeName();

  // A style attribute on any element can change layout in any way,
  // so that is not convertible.
  nsAutoString attribValue;
  node->GetAttribute(u"style"_ns, attribValue);
  if (!attribValue.IsEmpty()) {
    *_retval = nsIMsgCompConvertible::No;
    return;
  }

  // moz-* classes are used internally by the editor and mail composition
  // (like moz-cite-prefix or moz-signature). Those can be discarded.
  // But any other ones are unconvertible. Style can be attached to them or any
  // other context (e.g. in microformats).
  node->GetAttribute(u"class"_ns, attribValue);
  if (!attribValue.IsEmpty()) {
    if (StringBeginsWith(attribValue, u"moz-"_ns,
                         nsCaseInsensitiveStringComparator)) {
      // We assume that anything with a moz-* class is convertible regardless of
      // the tag, because we add, for example, class="moz-signature" to HTML
      // messages and we still want to be able to downgrade them.
      *_retval = nsIMsgCompConvertible::Plain;
    } else {
      *_retval = nsIMsgCompConvertible::No;
    }

    return;
  }

  // ID attributes can contain attached style/context or be target of links
  // so we should preserve them.
  node->GetAttribute(u"id"_ns, attribValue);
  if (!attribValue.IsEmpty()) {
    *_retval = nsIMsgCompConvertible::No;
    return;
  }

  // Alignment is not convertible to plaintext; editor currently uses this.
  node->GetAttribute(u"align"_ns, attribValue);
  if (!attribValue.IsEmpty()) {
    *_retval = nsIMsgCompConvertible::No;
    return;
  }

  // Title attribute is not convertible to plaintext;
  // this also preserves any links with titles.
  node->GetAttribute(u"title"_ns, attribValue);
  if (!attribValue.IsEmpty()) {
    *_retval = nsIMsgCompConvertible::No;
    return;
  }

  // Treat <font face="monospace"> as converible to plaintext.
  if (element.LowerCaseEqualsLiteral("font")) {
    node->GetAttribute(u"size"_ns, attribValue);
    if (!attribValue.IsEmpty()) {
      *_retval = nsIMsgCompConvertible::No;
      return;
    }
    node->GetAttribute(u"face"_ns, attribValue);
    if (attribValue.LowerCaseEqualsLiteral("monospace")) {
      *_retval = nsIMsgCompConvertible::Plain;
    }
  }

  if (  // Considered convertible to plaintext: Some "simple" elements
        // without non-convertible attributes like style, class, id,
        // or align (see above).
      element.LowerCaseEqualsLiteral("br") ||
      element.LowerCaseEqualsLiteral("p") ||
      element.LowerCaseEqualsLiteral("tt") ||
      element.LowerCaseEqualsLiteral("html") ||
      element.LowerCaseEqualsLiteral("head") ||
      element.LowerCaseEqualsLiteral("meta") ||
      element.LowerCaseEqualsLiteral("title")) {
    *_retval = nsIMsgCompConvertible::Plain;
  } else if (
      // element.LowerCaseEqualsLiteral("blockquote") || // see below
      element.LowerCaseEqualsLiteral("ul") ||
      element.LowerCaseEqualsLiteral("ol") ||
      element.LowerCaseEqualsLiteral("li") ||
      element.LowerCaseEqualsLiteral("dl") ||
      element.LowerCaseEqualsLiteral("dt") ||
      element.LowerCaseEqualsLiteral("dd")) {
    *_retval = nsIMsgCompConvertible::Yes;
  } else if (
      // element.LowerCaseEqualsLiteral("a") || // see below
      element.LowerCaseEqualsLiteral("h1") ||
      element.LowerCaseEqualsLiteral("h2") ||
      element.LowerCaseEqualsLiteral("h3") ||
      element.LowerCaseEqualsLiteral("h4") ||
      element.LowerCaseEqualsLiteral("h5") ||
      element.LowerCaseEqualsLiteral("h6") ||
      element.LowerCaseEqualsLiteral("hr") ||
      element.LowerCaseEqualsLiteral("pre") ||
      (mConvertStructs && (element.LowerCaseEqualsLiteral("em") ||
                           element.LowerCaseEqualsLiteral("strong") ||
                           element.LowerCaseEqualsLiteral("code") ||
                           element.LowerCaseEqualsLiteral("b") ||
                           element.LowerCaseEqualsLiteral("i") ||
                           element.LowerCaseEqualsLiteral("u")))) {
    *_retval = nsIMsgCompConvertible::Altering;
  } else if (element.LowerCaseEqualsLiteral("body")) {
    *_retval = nsIMsgCompConvertible::Plain;

    if (node->HasAttribute(u"background"_ns) ||  // There is a background image
        node->HasAttribute(
            u"dir"_ns)) {  // dir=rtl attributes should not downconvert
      *_retval = nsIMsgCompConvertible::No;
    } else {
      nsAutoString color;
      if (node->HasAttribute(u"text"_ns)) {
        node->GetAttribute(u"text"_ns, color);
        if (!color.EqualsLiteral("#000000"))
          *_retval = nsIMsgCompConvertible::Altering;
      }
      if (*_retval != nsIMsgCompConvertible::Altering &&  // small optimization
          node->HasAttribute(u"bgcolor"_ns)) {
        node->GetAttribute(u"bgcolor"_ns, color);
        if (!color.LowerCaseEqualsLiteral("#ffffff"))
          *_retval = nsIMsgCompConvertible::Altering;
      }
    }

    // ignore special color setting for link, vlink and alink at this point.
  } else if (element.LowerCaseEqualsLiteral("blockquote")) {
    // Skip <blockquote type="cite">
    *_retval = nsIMsgCompConvertible::Yes;

    node->GetAttribute(u"type"_ns, attribValue);
    if (attribValue.LowerCaseEqualsLiteral("cite")) {
      *_retval = nsIMsgCompConvertible::Plain;
    }
  } else if (element.LowerCaseEqualsLiteral("div") ||
             element.LowerCaseEqualsLiteral("span") ||
             element.LowerCaseEqualsLiteral("a")) {
    // Do some special checks for these tags. They are inside this |else if|
    // for performance reasons.

    // Maybe, it's an <a> element inserted by another recognizer (e.g. 4.x')
    if (element.LowerCaseEqualsLiteral("a")) {
      // Ignore anchor tag, if the URI is the same as the text
      // (as inserted by recognizers).
      *_retval = nsIMsgCompConvertible::Altering;

      nsAutoString hrefValue;
      node->GetAttribute(u"href"_ns, hrefValue);
      nsINodeList* children = node->ChildNodes();
      if (children->Length() > 0) {
        nsINode* pItem = children->Item(0);
        nsAutoString textValue;
        pItem->GetNodeValue(textValue);
        if (textValue == hrefValue) *_retval = nsIMsgCompConvertible::Plain;
      }
    }

    // Lastly, test, if it is just a "simple" <div> or <span>
    else if (element.LowerCaseEqualsLiteral("div") ||
             element.LowerCaseEqualsLiteral("span")) {
      *_retval = nsIMsgCompConvertible::Plain;
    }
  }
}