commit b4366359b738bbcfbd22354e9ac97c980407f702
parent e234d5b921f53a459c6c10e80911f7b6666bb805
Author: Edgar Chen <echen@mozilla.com>
Date: Tue, 28 Oct 2025 09:40:29 +0000
Bug 1993408 - Get rid of nsPlainTextSerializer::mElement; r=masayuki
This is used only for internal method, we could pass it explicitly instead.
Differential Revision: https://phabricator.services.mozilla.com/D268070
Diffstat:
4 files changed, 84 insertions(+), 67 deletions(-)
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
@@ -1816,7 +1816,7 @@ bool FragmentOrElement::TextIsOnlyWhitespace() { return false; }
bool FragmentOrElement::ThreadSafeTextIsOnlyWhitespace() const { return false; }
-static inline bool IsVoidTag(nsAtom* aTag) {
+static inline bool IsVoidTag(const nsAtom* aTag) {
static const nsAtom* voidElements[] = {
nsGkAtoms::area, nsGkAtoms::base, nsGkAtoms::basefont,
nsGkAtoms::bgsound, nsGkAtoms::br, nsGkAtoms::col,
@@ -1845,7 +1845,7 @@ static inline bool IsVoidTag(nsAtom* aTag) {
}
/* static */
-bool FragmentOrElement::IsHTMLVoid(nsAtom* aLocalName) {
+bool FragmentOrElement::IsHTMLVoid(const nsAtom* aLocalName) {
return aLocalName && IsVoidTag(aLocalName);
}
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
@@ -142,7 +142,7 @@ class FragmentOrElement : public nsIContent {
/**
* Is the HTML local name a void element?
*/
- static bool IsHTMLVoid(nsAtom* aLocalName);
+ static bool IsHTMLVoid(const nsAtom* aLocalName);
protected:
virtual ~FragmentOrElement();
diff --git a/dom/serializers/nsPlainTextSerializer.cpp b/dom/serializers/nsPlainTextSerializer.cpp
@@ -80,7 +80,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPlainTextSerializer)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
-NS_IMPL_CYCLE_COLLECTION(nsPlainTextSerializer, mElement)
+NS_IMPL_CYCLE_COLLECTION(nsPlainTextSerializer)
nsresult NS_NewPlainTextSerializer(nsIContentSerializer** aSerializer) {
RefPtr<nsPlainTextSerializer> it = new nsPlainTextSerializer();
@@ -539,21 +539,14 @@ nsPlainTextSerializer::AppendElementStart(Element* aElement,
Element* aOriginalElement) {
NS_ENSURE_ARG(aElement);
- mElement = aElement;
-
- nsresult rv;
- nsAtom* id = GetIdForContent(mElement);
-
- bool isContainer = !FragmentOrElement::IsHTMLVoid(id);
-
- if (isContainer) {
- rv = DoOpenContainer(id);
+ nsresult rv = NS_OK;
+ nsAtom* id = GetIdForContent(aElement);
+ if (!FragmentOrElement::IsHTMLVoid(id)) {
+ rv = DoOpenContainer(aElement, id);
} else {
- rv = DoAddLeaf(id);
+ rv = DoAddLeaf(aElement, id);
}
- mElement = nullptr;
-
if (id == nsGkAtoms::head) {
++mHeadLevel;
}
@@ -566,20 +559,12 @@ nsPlainTextSerializer::AppendElementEnd(Element* aElement,
Element* aOriginalElement) {
NS_ENSURE_ARG(aElement);
- mElement = aElement;
-
- nsresult rv;
- nsAtom* id = GetIdForContent(mElement);
-
- bool isContainer = !FragmentOrElement::IsHTMLVoid(id);
-
- rv = NS_OK;
- if (isContainer) {
- rv = DoCloseContainer(id);
+ nsresult rv = NS_OK;
+ nsAtom* id = GetIdForContent(aElement);
+ if (!FragmentOrElement::IsHTMLVoid(id)) {
+ rv = DoCloseContainer(aElement, id);
}
- mElement = nullptr;
-
if (id == nsGkAtoms::head) {
NS_ASSERTION(mHeadLevel != 0, "mHeadLevel being decremented below 0");
--mHeadLevel;
@@ -619,14 +604,19 @@ nsPlainTextSerializer::AppendDocumentStart(Document* aDocument) {
constexpr int32_t kOlStackDummyValue = 0;
-nsresult nsPlainTextSerializer::DoOpenContainer(const nsAtom* aTag) {
+nsresult nsPlainTextSerializer::DoOpenContainer(Element* aElement,
+ const nsAtom* aTag) {
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(GetIdForContent(aElement) == aTag);
+ MOZ_ASSERT(!FragmentOrElement::IsHTMLVoid(aTag));
+
if (IsIgnorableRubyAnnotation(aTag)) {
// Ignorable ruby annotation shouldn't be replaced by a placeholder
// character, neither any of its descendants.
mIgnoredChildNodeLevel++;
return NS_OK;
}
- if (IsIgnorableScriptOrStyle(mElement)) {
+ if (IsIgnorableScriptOrStyle(aElement)) {
mIgnoredChildNodeLevel++;
return NS_OK;
}
@@ -668,7 +658,7 @@ nsresult nsPlainTextSerializer::DoOpenContainer(const nsAtom* aTag) {
// newlines before the text.
if (aTag == nsGkAtoms::blockquote) {
nsAutoString value;
- nsresult rv = GetAttributeValue(nsGkAtoms::type, value);
+ nsresult rv = GetAttributeValue(aElement, nsGkAtoms::type, value);
isInCiteBlockquote = NS_SUCCEEDED(rv) && value.EqualsIgnoreCase("cite");
}
@@ -694,7 +684,7 @@ nsresult nsPlainTextSerializer::DoOpenContainer(const nsAtom* aTag) {
// it, but better than nothing.
nsAutoString style;
int32_t whitespace;
- if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::style, style)) &&
+ if (NS_SUCCEEDED(GetAttributeValue(aElement, nsGkAtoms::style, style)) &&
(kNotFound != (whitespace = style.Find(u"white-space:")))) {
if (kNotFound != style.LowerCaseFindASCII("pre-wrap", whitespace)) {
#ifdef DEBUG_preformatted
@@ -762,7 +752,8 @@ nsresult nsPlainTextSerializer::DoOpenContainer(const nsAtom* aTag) {
// Must end the current line before we change indention
nsAutoString startAttr;
int32_t startVal = 1;
- if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::start, startAttr))) {
+ if (NS_SUCCEEDED(
+ GetAttributeValue(aElement, nsGkAtoms::start, startAttr))) {
nsresult rv = NS_OK;
startVal = startAttr.ToInteger(&rv);
if (NS_FAILED(rv)) {
@@ -779,7 +770,8 @@ nsresult nsPlainTextSerializer::DoOpenContainer(const nsAtom* aTag) {
if (mTagStackIndex > 1 && IsInOL()) {
if (!mOLStack.IsEmpty()) {
nsAutoString valueAttr;
- if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::value, valueAttr))) {
+ if (NS_SUCCEEDED(
+ GetAttributeValue(aElement, nsGkAtoms::value, valueAttr))) {
nsresult rv = NS_OK;
int32_t valueAttrVal = valueAttr.ToInteger(&rv);
if (NS_SUCCEEDED(rv)) {
@@ -829,19 +821,23 @@ nsresult nsPlainTextSerializer::DoOpenContainer(const nsAtom* aTag) {
// Else make sure we'll separate block level tags,
// even if we're about to leave, before doing any other formatting.
- else if (IsCssBlockLevelElement(mElement)) {
+ else if (IsCssBlockLevelElement(aElement)) {
EnsureVerticalSpace(0);
}
if (mSettings.HasFlag(nsIDocumentEncoder::OutputFormatted)) {
- OpenContainerForOutputFormatted(aTag);
+ OpenContainerForOutputFormatted(aElement, aTag);
}
return NS_OK;
}
void nsPlainTextSerializer::OpenContainerForOutputFormatted(
- const nsAtom* aTag) {
- const bool currentNodeIsConverted = IsCurrentNodeConverted();
+ Element* aElement, const nsAtom* aTag) {
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(GetIdForContent(aElement) == aTag);
+ MOZ_ASSERT(!FragmentOrElement::IsHTMLVoid(aTag));
+
+ const bool currentNodeIsConverted = IsCurrentNodeConverted(aElement);
if (aTag == nsGkAtoms::h1 || aTag == nsGkAtoms::h2 || aTag == nsGkAtoms::h3 ||
aTag == nsGkAtoms::h4 || aTag == nsGkAtoms::h5 || aTag == nsGkAtoms::h6) {
@@ -904,19 +900,24 @@ void nsPlainTextSerializer::OpenContainerForOutputFormatted(
mInWhitespace = true;
}
-nsresult nsPlainTextSerializer::DoCloseContainer(const nsAtom* aTag) {
+nsresult nsPlainTextSerializer::DoCloseContainer(Element* aElement,
+ const nsAtom* aTag) {
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(GetIdForContent(aElement) == aTag);
+ MOZ_ASSERT(!FragmentOrElement::IsHTMLVoid(aTag));
+
if (IsIgnorableRubyAnnotation(aTag)) {
mIgnoredChildNodeLevel--;
return NS_OK;
}
- if (IsIgnorableScriptOrStyle(mElement)) {
+ if (IsIgnorableScriptOrStyle(aElement)) {
mIgnoredChildNodeLevel--;
return NS_OK;
}
if (mSettings.HasFlag(nsIDocumentEncoder::OutputForPlainTextClipboardCopy)) {
if (DoOutput() && IsElementPreformatted() &&
- IsCssBlockLevelElement(mElement)) {
+ IsCssBlockLevelElement(aElement)) {
// If we're closing a preformatted block element, output a line break
// when we find a new container.
mPreformattedBlockBoundary = true;
@@ -1031,7 +1032,7 @@ nsresult nsPlainTextSerializer::DoCloseContainer(const nsAtom* aTag) {
mLineBreakDue = true;
} else if (aTag == nsGkAtoms::q) {
Write(u"\""_ns);
- } else if (IsCssBlockLevelElement(mElement)) {
+ } else if (IsCssBlockLevelElement(aElement)) {
// All other blocks get 1 vertical space after them
// in formatted mode, otherwise 0.
// This is hard. Sometimes 0 is a better number, but
@@ -1045,15 +1046,19 @@ nsresult nsPlainTextSerializer::DoCloseContainer(const nsAtom* aTag) {
}
if (mSettings.HasFlag(nsIDocumentEncoder::OutputFormatted)) {
- CloseContainerForOutputFormatted(aTag);
+ CloseContainerForOutputFormatted(aElement, aTag);
}
return NS_OK;
}
void nsPlainTextSerializer::CloseContainerForOutputFormatted(
- const nsAtom* aTag) {
- const bool currentNodeIsConverted = IsCurrentNodeConverted();
+ Element* aElement, const nsAtom* aTag) {
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(GetIdForContent(aElement) == aTag);
+ MOZ_ASSERT(!FragmentOrElement::IsHTMLVoid(aTag));
+
+ const bool currentNodeIsConverted = IsCurrentNodeConverted(aElement);
if (aTag == nsGkAtoms::h1 || aTag == nsGkAtoms::h2 || aTag == nsGkAtoms::h3 ||
aTag == nsGkAtoms::h4 || aTag == nsGkAtoms::h5 || aTag == nsGkAtoms::h6) {
@@ -1074,7 +1079,7 @@ void nsPlainTextSerializer::CloseContainerForOutputFormatted(
EnsureVerticalSpace(1);
} else if (aTag == nsGkAtoms::a && !currentNodeIsConverted) {
nsAutoString url;
- if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::href, url)) &&
+ if (NS_SUCCEEDED(GetAttributeValue(aElement, nsGkAtoms::href, url)) &&
!url.IsEmpty()) {
nsAutoString temp;
temp.AssignLiteral(" <");
@@ -1162,7 +1167,12 @@ void CreateLineOfDashes(nsAString& aResult, const uint32_t aWrapColumn) {
}
}
-nsresult nsPlainTextSerializer::DoAddLeaf(const nsAtom* aTag) {
+nsresult nsPlainTextSerializer::DoAddLeaf(Element* aElement,
+ const nsAtom* aTag) {
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(GetIdForContent(aElement) == aTag);
+ MOZ_ASSERT(FragmentOrElement::IsHTMLVoid(aTag));
+
mPreformattedBlockBoundary = false;
if (!DoOutput()) {
@@ -1182,7 +1192,7 @@ nsresult nsPlainTextSerializer::DoAddLeaf(const nsAtom* aTag) {
// of non-HTML element.
// XXX Do we need to call `EnsureVerticalSpace()` when the <br> element
// is not an HTML element?
- HTMLBRElement* brElement = HTMLBRElement::FromNodeOrNull(mElement);
+ HTMLBRElement* brElement = HTMLBRElement::FromNodeOrNull(aElement);
if (!brElement || !brElement->IsPaddingForEmptyLastLine()) {
EnsureVerticalSpace(mEmptyLines + 1);
}
@@ -1202,10 +1212,11 @@ nsresult nsPlainTextSerializer::DoAddLeaf(const nsAtom* aTag) {
alt, title or nothing */
// See <http://www.w3.org/TR/REC-html40/struct/objects.html#edef-IMG>
nsAutoString imageDescription;
- if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::alt, imageDescription))) {
+ if (NS_SUCCEEDED(
+ GetAttributeValue(aElement, nsGkAtoms::alt, imageDescription))) {
// If the alt attribute has an empty value (|alt=""|), output nothing
- } else if (NS_SUCCEEDED(
- GetAttributeValue(nsGkAtoms::title, imageDescription)) &&
+ } else if (NS_SUCCEEDED(GetAttributeValue(aElement, nsGkAtoms::title,
+ imageDescription)) &&
!imageDescription.IsEmpty()) {
imageDescription = u" ["_ns + imageDescription + u"] "_ns;
}
@@ -1696,12 +1707,14 @@ void nsPlainTextSerializer::Write(const nsAString& aStr) {
* Gets the value of an attribute in a string. If the function returns
* NS_ERROR_NOT_AVAILABLE, there was none such attribute specified.
*/
-nsresult nsPlainTextSerializer::GetAttributeValue(const nsAtom* aName,
+nsresult nsPlainTextSerializer::GetAttributeValue(Element* aElement,
+ const nsAtom* aName,
nsString& aValueRet) const {
- if (mElement) {
- if (mElement->GetAttr(aName, aValueRet)) {
- return NS_OK;
- }
+ MOZ_ASSERT(aElement);
+ MOZ_ASSERT(aName);
+
+ if (aElement->GetAttr(aName, aValueRet)) {
+ return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
@@ -1711,9 +1724,11 @@ nsresult nsPlainTextSerializer::GetAttributeValue(const nsAtom* aName,
* Returns true, if the element was inserted by Moz' TXT->HTML converter.
* In this case, we should ignore it.
*/
-bool nsPlainTextSerializer::IsCurrentNodeConverted() const {
+bool nsPlainTextSerializer::IsCurrentNodeConverted(Element* aElement) const {
+ MOZ_ASSERT(aElement);
+
nsAutoString value;
- nsresult rv = GetAttributeValue(nsGkAtoms::_class, value);
+ nsresult rv = GetAttributeValue(aElement, nsGkAtoms::_class, value);
return (NS_SUCCEEDED(rv) &&
(StringBeginsWith(value, u"moz-txt"_ns,
nsASCIICaseInsensitiveStringComparator) ||
diff --git a/dom/serializers/nsPlainTextSerializer.h b/dom/serializers/nsPlainTextSerializer.h
@@ -85,7 +85,8 @@ class nsPlainTextSerializer final : public nsIContentSerializer {
private:
~nsPlainTextSerializer();
- nsresult GetAttributeValue(const nsAtom* aName, nsString& aValueRet) const;
+ nsresult GetAttributeValue(mozilla::dom::Element* aElement,
+ const nsAtom* aName, nsString& aValueRet) const;
void AddToLine(const char16_t* aStringToAdd, int32_t aLength);
void MaybeWrapAndOutputCompleteLines();
@@ -109,7 +110,7 @@ class nsPlainTextSerializer final : public nsIContentSerializer {
bool IsElementPreformatted() const;
bool IsInOL() const;
bool IsInOlOrUl() const;
- bool IsCurrentNodeConverted() const;
+ bool IsCurrentNodeConverted(mozilla::dom::Element* aElement) const;
bool MustSuppressLeaf() const;
/**
@@ -117,11 +118,14 @@ class nsPlainTextSerializer final : public nsIContentSerializer {
* HTML element and the atom is a static atom. Otherwise, nullptr is returned.
*/
static nsAtom* GetIdForContent(nsIContent* aContent);
- nsresult DoOpenContainer(const nsAtom* aTag);
- void OpenContainerForOutputFormatted(const nsAtom* aTag);
- nsresult DoCloseContainer(const nsAtom* aTag);
- void CloseContainerForOutputFormatted(const nsAtom* aTag);
- nsresult DoAddLeaf(const nsAtom* aTag);
+ nsresult DoOpenContainer(mozilla::dom::Element* aElement, const nsAtom* aTag);
+ void OpenContainerForOutputFormatted(mozilla::dom::Element* aElement,
+ const nsAtom* aTag);
+ nsresult DoCloseContainer(mozilla::dom::Element* aElement,
+ const nsAtom* aTag);
+ void CloseContainerForOutputFormatted(mozilla::dom::Element* aElement,
+ const nsAtom* aTag);
+ nsresult DoAddLeaf(mozilla::dom::Element* aElement, const nsAtom* aTag);
void DoAddText(const nsAString& aText);
void DoAddLineBreak();
@@ -352,8 +356,6 @@ class nsPlainTextSerializer final : public nsIContentSerializer {
section.
mHeaderCounter[1] for <h1> etc. */
- RefPtr<mozilla::dom::Element> mElement;
-
// For handling table rows
AutoTArray<bool, 8> mHasWrittenCellsForRow;