From df25a46b0c04be35a4301b4e0bce5133d89dfad2 Mon Sep 17 00:00:00 2001 From: Fedor Date: Wed, 9 Sep 2020 17:28:39 +0300 Subject: [PATCH] [libeditor] Performance improvements. --- editor/libeditor/CSSEditUtils.cpp | 259 ++++++++++--------- editor/libeditor/CSSEditUtils.h | 65 ++--- editor/libeditor/EditorBase.cpp | 95 ++++--- editor/libeditor/EditorBase.h | 13 + editor/libeditor/HTMLEditRules.cpp | 83 +++--- editor/libeditor/HTMLEditor.cpp | 136 +++++----- editor/libeditor/HTMLEditor.h | 18 +- editor/libeditor/HTMLEditorObjectResizer.cpp | 29 +-- editor/libeditor/HTMLStyleEditor.cpp | 30 +-- editor/libeditor/TextEditRules.cpp | 4 +- editor/libeditor/TextEditor.cpp | 12 +- editor/libeditor/TextEditor.h | 19 +- 12 files changed, 417 insertions(+), 346 deletions(-) diff --git a/editor/libeditor/CSSEditUtils.cpp b/editor/libeditor/CSSEditUtils.cpp index dd15a8730..e15bc278f 100644 --- a/editor/libeditor/CSSEditUtils.cpp +++ b/editor/libeditor/CSSEditUtils.cpp @@ -322,6 +322,15 @@ bool CSSEditUtils::IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty, const nsAString* aAttribute) +{ + nsCOMPtr attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr; + return IsCSSEditableProperty(aNode, aProperty, attribute); +} + +bool +CSSEditUtils::IsCSSEditableProperty(nsINode* aNode, + nsIAtom* aProperty, + nsIAtom* aAttribute) { MOZ_ASSERT(aNode); @@ -339,13 +348,12 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode, nsGkAtoms::u == aProperty || nsGkAtoms::strike == aProperty || (nsGkAtoms::font == aProperty && aAttribute && - (aAttribute->EqualsLiteral("color") || - aAttribute->EqualsLiteral("face")))) { + (aAttribute == nsGkAtoms::color || aAttribute == nsGkAtoms::face))) { return true; } // ALIGN attribute on elements supporting it - if (aAttribute && (aAttribute->EqualsLiteral("align")) && + if (aAttribute == nsGkAtoms::align && node->IsAnyOfHTMLElements(nsGkAtoms::div, nsGkAtoms::p, nsGkAtoms::h1, @@ -368,7 +376,7 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode, return true; } - if (aAttribute && (aAttribute->EqualsLiteral("valign")) && + if (aAttribute == nsGkAtoms::valign && node->IsAnyOfHTMLElements(nsGkAtoms::col, nsGkAtoms::colgroup, nsGkAtoms::tbody, @@ -381,59 +389,52 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode, } // attributes TEXT, BACKGROUND and BGCOLOR on BODY - if (aAttribute && node->IsHTMLElement(nsGkAtoms::body) && - (aAttribute->EqualsLiteral("text") - || aAttribute->EqualsLiteral("background") - || aAttribute->EqualsLiteral("bgcolor"))) { + if (node->IsHTMLElement(nsGkAtoms::body) && + (aAttribute == nsGkAtoms::text || aAttribute == nsGkAtoms::background || + aAttribute == nsGkAtoms::bgcolor)) { return true; } // attribute BGCOLOR on other elements - if (aAttribute && aAttribute->EqualsLiteral("bgcolor")) { + if (aAttribute == nsGkAtoms::bgcolor) { return true; } // attributes HEIGHT, WIDTH and NOWRAP on TD and TH - if (aAttribute && - node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) && - (aAttribute->EqualsLiteral("height") - || aAttribute->EqualsLiteral("width") - || aAttribute->EqualsLiteral("nowrap"))) { + if (node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) && + (aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width || + aAttribute == nsGkAtoms::nowrap)) { return true; } // attributes HEIGHT and WIDTH on TABLE - if (aAttribute && node->IsHTMLElement(nsGkAtoms::table) && - (aAttribute->EqualsLiteral("height") - || aAttribute->EqualsLiteral("width"))) { + if (node->IsHTMLElement(nsGkAtoms::table) && + (aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width)) { return true; } // attributes SIZE and WIDTH on HR - if (aAttribute && node->IsHTMLElement(nsGkAtoms::hr) && - (aAttribute->EqualsLiteral("size") - || aAttribute->EqualsLiteral("width"))) { + if (node->IsHTMLElement(nsGkAtoms::hr) && + (aAttribute == nsGkAtoms::size || aAttribute == nsGkAtoms::width)) { return true; } // attribute TYPE on OL UL LI - if (aAttribute && - node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul, + if (node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul, nsGkAtoms::li) && - aAttribute->EqualsLiteral("type")) { + aAttribute == nsGkAtoms::type) { return true; } - if (aAttribute && node->IsHTMLElement(nsGkAtoms::img) && - (aAttribute->EqualsLiteral("border") - || aAttribute->EqualsLiteral("width") - || aAttribute->EqualsLiteral("height"))) { + if (node->IsHTMLElement(nsGkAtoms::img) && + (aAttribute == nsGkAtoms::border || aAttribute == nsGkAtoms::width || + aAttribute == nsGkAtoms::height)) { return true; } // other elements that we can align using CSS even if they // can't carry the html ALIGN attribute - if (aAttribute && aAttribute->EqualsLiteral("align") && + if (aAttribute == nsGkAtoms::align && node->IsAnyOfHTMLElements(nsGkAtoms::ul, nsGkAtoms::ol, nsGkAtoms::dl, @@ -818,7 +819,7 @@ void CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle( Element* aElement, nsIAtom* aHTMLProperty, - const nsAString* aAttribute, + nsIAtom* aAttribute, const nsAString* aValue, nsTArray& cssPropertyArray, nsTArray& cssValueArray, @@ -838,21 +839,20 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle( } else if (nsGkAtoms::tt == aHTMLProperty) { equivTable = ttEquivTable; } else if (aAttribute) { - if (nsGkAtoms::font == aHTMLProperty && - aAttribute->EqualsLiteral("color")) { + if (nsGkAtoms::font == aHTMLProperty && aAttribute == nsGkAtoms::color) { equivTable = fontColorEquivTable; } else if (nsGkAtoms::font == aHTMLProperty && - aAttribute->EqualsLiteral("face")) { + aAttribute == nsGkAtoms::face) { equivTable = fontFaceEquivTable; - } else if (aAttribute->EqualsLiteral("bgcolor")) { + } else if (aAttribute == nsGkAtoms::bgcolor) { equivTable = bgcolorEquivTable; - } else if (aAttribute->EqualsLiteral("background")) { + } else if (aAttribute == nsGkAtoms::background) { equivTable = backgroundImageEquivTable; - } else if (aAttribute->EqualsLiteral("text")) { + } else if (aAttribute == nsGkAtoms::text) { equivTable = textColorEquivTable; - } else if (aAttribute->EqualsLiteral("border")) { + } else if (aAttribute == nsGkAtoms::border) { equivTable = borderEquivTable; - } else if (aAttribute->EqualsLiteral("align")) { + } else if (aAttribute == nsGkAtoms::align) { if (aElement->IsHTMLElement(nsGkAtoms::table)) { equivTable = tableAlignEquivTable; } else if (aElement->IsHTMLElement(nsGkAtoms::hr)) { @@ -863,17 +863,17 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle( } else { equivTable = textAlignEquivTable; } - } else if (aAttribute->EqualsLiteral("valign")) { + } else if (aAttribute == nsGkAtoms::valign) { equivTable = verticalAlignEquivTable; - } else if (aAttribute->EqualsLiteral("nowrap")) { + } else if (aAttribute == nsGkAtoms::nowrap) { equivTable = nowrapEquivTable; - } else if (aAttribute->EqualsLiteral("width")) { + } else if (aAttribute == nsGkAtoms::width) { equivTable = widthEquivTable; - } else if (aAttribute->EqualsLiteral("height") || + } else if (aAttribute == nsGkAtoms::height || (aElement->IsHTMLElement(nsGkAtoms::hr) && - aAttribute->EqualsLiteral("size"))) { + aAttribute == nsGkAtoms::size)) { equivTable = heightEquivTable; - } else if (aAttribute->EqualsLiteral("type") && + } else if (aAttribute == nsGkAtoms::type && aElement->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul, nsGkAtoms::li)) { @@ -890,40 +890,46 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle( // aValue for the node, and return in aCount the number of CSS properties set // by the call. The Element version returns aCount instead. int32_t -CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement, +CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode, nsIAtom* aProperty, const nsAString* aAttribute, const nsAString* aValue, bool aSuppressTransaction) { - MOZ_ASSERT(aElement && aProperty); MOZ_ASSERT_IF(aAttribute, aValue); - int32_t count; // This can only fail if SetCSSProperty fails, which should only happen if // something is pretty badly wrong. In this case we assert so that hopefully // someone will notice, but there's nothing more sensible to do than just // return the count and carry on. - nsresult rv = SetCSSEquivalentToHTMLStyle(aElement->AsDOMNode(), - aProperty, aAttribute, - aValue, &count, - aSuppressTransaction); - NS_ASSERTION(NS_SUCCEEDED(rv), "SetCSSEquivalentToHTMLStyle failed"); - NS_ENSURE_SUCCESS(rv, count); - return count; + nsCOMPtr element = do_QueryInterface(aNode); + return SetCSSEquivalentToHTMLStyle(element, + aProperty, aAttribute, + aValue, aSuppressTransaction); } -nsresult -CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode, +int32_t +CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement, nsIAtom* aHTMLProperty, const nsAString* aAttribute, const nsAString* aValue, - int32_t* aCount, bool aSuppressTransaction) { - nsCOMPtr element = do_QueryInterface(aNode); - *aCount = 0; - if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) { - return NS_OK; + nsCOMPtr attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr; + return SetCSSEquivalentToHTMLStyle(aElement, aHTMLProperty, attribute, + aValue, aSuppressTransaction); +} + +int32_t +CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement, + nsIAtom* aHTMLProperty, + nsIAtom* aAttribute, + const nsAString* aValue, + bool aSuppressTransaction) +{ + MOZ_ASSERT(aElement); + + if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) { + return 0; } // we can apply the styles only if the node is an element and if we have @@ -932,18 +938,20 @@ CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode, // Find the CSS equivalence to the HTML style nsTArray cssPropertyArray; nsTArray cssValueArray; - GenerateCSSDeclarationsFromHTMLStyle(element, aHTMLProperty, aAttribute, + GenerateCSSDeclarationsFromHTMLStyle(aElement, aHTMLProperty, aAttribute, aValue, cssPropertyArray, cssValueArray, false); // set the individual CSS inline styles - *aCount = cssPropertyArray.Length(); - for (int32_t index = 0; index < *aCount; index++) { - nsresult rv = SetCSSProperty(*element, *cssPropertyArray[index], + size_t count = cssPropertyArray.Length(); + for (size_t index = 0; index < count; index++) { + nsresult rv = SetCSSProperty(*aElement, *cssPropertyArray[index], cssValueArray[index], aSuppressTransaction); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return 0; + } } - return NS_OK; + return count; } // Remove from aNode the CSS inline style equivalent to HTMLProperty/aAttribute/aValue for the node @@ -955,20 +963,22 @@ CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(nsIDOMNode* aNode, bool aSuppressTransaction) { nsCOMPtr element = do_QueryInterface(aNode); - NS_ENSURE_TRUE(element, NS_OK); + nsCOMPtr attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr; - return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, aAttribute, + return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, attribute, aValue, aSuppressTransaction); } nsresult CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement, nsIAtom* aHTMLProperty, - const nsAString* aAttribute, + nsIAtom* aAttribute, const nsAString* aValue, bool aSuppressTransaction) { - MOZ_ASSERT(aElement); + if (NS_WARN_IF(!aElement)) { + return NS_OK; + } if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) { return NS_OK; @@ -1003,7 +1013,7 @@ CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement, nsresult CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode, nsIAtom* aHTMLProperty, - const nsAString* aAttribute, + nsIAtom* aAttribute, nsAString& aValueString, StyleType aStyleType) { @@ -1020,7 +1030,8 @@ CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode, nsTArray cssValueArray; // get the CSS equivalence with last param true indicating we want only the // "gettable" properties - GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, nullptr, + GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, + nullptr, cssPropertyArray, cssValueArray, true); int32_t count = cssPropertyArray.Length(); for (int32_t index = 0; index < count; index++) { @@ -1066,48 +1077,58 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode, StyleType aStyleType) { MOZ_ASSERT(aNode && aProperty); - bool isSet; - nsresult rv = IsCSSEquivalentToHTMLInlineStyleSet(aNode->AsDOMNode(), - aProperty, aAttribute, - isSet, aValue, aStyleType); - NS_ENSURE_SUCCESS(rv, false); - return isSet; + nsCOMPtr attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr; + return IsCSSEquivalentToHTMLInlineStyleSet(aNode, + aProperty, attribute, + aValue, aStyleType); } -nsresult +bool +CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode, + nsIAtom* aProperty, + const nsAString* aAttribute, + nsAString& aValue, + StyleType aStyleType) +{ + MOZ_ASSERT(aNode && aProperty); + nsCOMPtr node = do_QueryInterface(aNode); + nsCOMPtr attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr; + return IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, attribute, + aValue, aStyleType); +} + +bool CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet( - nsIDOMNode* aNode, + nsINode* aNode, nsIAtom* aHTMLProperty, - const nsAString* aHTMLAttribute, - bool& aIsSet, + nsIAtom* aHTMLAttribute, nsAString& valueString, StyleType aStyleType) { - NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); + NS_ENSURE_TRUE(aNode, false); nsAutoString htmlValueString(valueString); - aIsSet = false; - nsCOMPtr node = do_QueryInterface(aNode); + bool isSet = false; do { valueString.Assign(htmlValueString); // get the value of the CSS equivalent styles nsresult rv = - GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute, + GetCSSEquivalentToHTMLInlineStyleSet(aNode, aHTMLProperty, aHTMLAttribute, valueString, aStyleType); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_SUCCESS(rv, false); // early way out if we can if (valueString.IsEmpty()) { - return NS_OK; + return isSet; } if (nsGkAtoms::b == aHTMLProperty) { if (valueString.EqualsLiteral("bold")) { - aIsSet = true; + isSet = true; } else if (valueString.EqualsLiteral("normal")) { - aIsSet = false; + isSet = false; } else if (valueString.EqualsLiteral("bolder")) { - aIsSet = true; + isSet = true; valueString.AssignLiteral("bold"); } else { int32_t weight = 0; @@ -1115,32 +1136,31 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet( nsAutoString value(valueString); weight = value.ToInteger(&errorCode); if (400 < weight) { - aIsSet = true; + isSet = true; valueString.AssignLiteral("bold"); } else { - aIsSet = false; + isSet = false; valueString.AssignLiteral("normal"); } } } else if (nsGkAtoms::i == aHTMLProperty) { if (valueString.EqualsLiteral("italic") || valueString.EqualsLiteral("oblique")) { - aIsSet = true; + isSet = true; } } else if (nsGkAtoms::u == aHTMLProperty) { nsAutoString val; val.AssignLiteral("underline"); - aIsSet = ChangeStyleTransaction::ValueIncludes(valueString, val); + isSet = ChangeStyleTransaction::ValueIncludes(valueString, val); } else if (nsGkAtoms::strike == aHTMLProperty) { nsAutoString val; val.AssignLiteral("line-through"); - aIsSet = ChangeStyleTransaction::ValueIncludes(valueString, val); - } else if (aHTMLAttribute && - ((nsGkAtoms::font == aHTMLProperty && - aHTMLAttribute->EqualsLiteral("color")) || - aHTMLAttribute->EqualsLiteral("bgcolor"))) { + isSet = ChangeStyleTransaction::ValueIncludes(valueString, val); + } else if ((nsGkAtoms::font == aHTMLProperty && + aHTMLAttribute == nsGkAtoms::color) || + aHTMLAttribute == nsGkAtoms::bgcolor) { if (htmlValueString.IsEmpty()) { - aIsSet = true; + isSet = true; } else { nscolor rgba; nsAutoString subStr; @@ -1174,54 +1194,53 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet( htmlColor.Append(char16_t(')')); } - aIsSet = htmlColor.Equals(valueString, - nsCaseInsensitiveStringComparator()); + isSet = htmlColor.Equals(valueString, + nsCaseInsensitiveStringComparator()); } else { - aIsSet = htmlValueString.Equals(valueString, - nsCaseInsensitiveStringComparator()); + isSet = htmlValueString.Equals(valueString, + nsCaseInsensitiveStringComparator()); } } } else if (nsGkAtoms::tt == aHTMLProperty) { - aIsSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace")); + isSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace")); } else if (nsGkAtoms::font == aHTMLProperty && aHTMLAttribute && - aHTMLAttribute->EqualsLiteral("face")) { + aHTMLAttribute == nsGkAtoms::face) { if (!htmlValueString.IsEmpty()) { const char16_t commaSpace[] = { char16_t(','), char16_t(' '), 0 }; const char16_t comma[] = { char16_t(','), 0 }; htmlValueString.ReplaceSubstring(commaSpace, comma); nsAutoString valueStringNorm(valueString); valueStringNorm.ReplaceSubstring(commaSpace, comma); - aIsSet = htmlValueString.Equals(valueStringNorm, - nsCaseInsensitiveStringComparator()); + isSet = htmlValueString.Equals(valueStringNorm, + nsCaseInsensitiveStringComparator()); } else { - aIsSet = true; + isSet = true; } - return NS_OK; - } else if (aHTMLAttribute && aHTMLAttribute->EqualsLiteral("align")) { - aIsSet = true; + return isSet; + } else if (aHTMLAttribute == nsGkAtoms::align) { + isSet = true; } else { - aIsSet = false; - return NS_OK; + return false; } if (!htmlValueString.IsEmpty() && htmlValueString.Equals(valueString, nsCaseInsensitiveStringComparator())) { - aIsSet = true; + isSet = true; } if (htmlValueString.EqualsLiteral("-moz-editor-invert-value")) { - aIsSet = !aIsSet; + isSet = !isSet; } if (nsGkAtoms::u == aHTMLProperty || nsGkAtoms::strike == aHTMLProperty) { // unfortunately, the value of the text-decoration property is not inherited. // that means that we have to look at ancestors of node to see if they are underlined - node = node->GetParentElement(); // set to null if it's not a dom element + aNode = aNode->GetParentElement(); // set to null if it's not a dom element } } while ((nsGkAtoms::u == aHTMLProperty || - nsGkAtoms::strike == aHTMLProperty) && !aIsSet && node); - return NS_OK; + nsGkAtoms::strike == aHTMLProperty) && !isSet && aNode); + return isSet; } void diff --git a/editor/libeditor/CSSEditUtils.h b/editor/libeditor/CSSEditUtils.h index 0b9a12952..5129ab88d 100644 --- a/editor/libeditor/CSSEditUtils.h +++ b/editor/libeditor/CSSEditUtils.h @@ -90,6 +90,8 @@ public: */ bool IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty, const nsAString* aAttribute); + bool IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty, + nsIAtom* aAttribute); /** * Adds/remove a CSS declaration to the STYLE atrribute carried by a given @@ -188,14 +190,14 @@ public: * * @param aNode [IN] A DOM node. * @param aHTMLProperty [IN] An atom containing an HTML property. - * @param aAttribute [IN] A pointer to an attribute name or nullptr if + * @param aAttribute [IN] An atom of attribute name or nullptr if * irrelevant. * @param aValueString [OUT] The list of CSS values. * @param aStyleType [IN] eSpecified or eComputed. */ nsresult GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode, nsIAtom* aHTMLProperty, - const nsAString* aAttribute, + nsIAtom* aAttribute, nsAString& aValueString, StyleType aStyleType); @@ -205,16 +207,20 @@ public: * * @param aNode [IN] A DOM node. * @param aHTMLProperty [IN] An atom containing an HTML property. - * @param aAttribute [IN] A pointer to an attribute name or nullptr if - * irrelevant. - * @param aIsSet [OUT] A boolean being true if the css properties are - * set. + * @param aAttribute [IN] A pointer/atom to an attribute name or nullptr + * if irrelevant. * @param aValueString [IN/OUT] The attribute value (in) the list of CSS * values (out). * @param aStyleType [IN] eSpecified or eComputed. - * - * The nsIContent variant returns aIsSet instead of using an out parameter. + * @return A boolean being true if the css properties are + * set. */ + bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent, + nsIAtom* aProperty, + nsIAtom* aAttribute, + nsAString& aValue, + StyleType aStyleType); + bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent, nsIAtom* aProperty, const nsAString* aAttribute, @@ -227,12 +233,11 @@ public: nsAString& aValue, StyleType aStyleType); - nsresult IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode, - nsIAtom* aHTMLProperty, - const nsAString* aAttribute, - bool& aIsSet, - nsAString& aValueString, - StyleType aStyleType); + bool IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode, + nsIAtom* aProperty, + const nsAString* aAttribute, + nsAString& aValue, + StyleType aStyleType); /** * Adds to the node the CSS inline styles equivalent to the HTML style @@ -240,27 +245,29 @@ public: * * @param aNode [IN] A DOM node. * @param aHTMLProperty [IN] An atom containing an HTML property. - * @param aAttribute [IN] A pointer to an attribute name or nullptr if - * irrelevant. + * @param aAttribute [IN] A pointer/atom to an attribute name or nullptr + * if irrelevant. * @param aValue [IN] The attribute value. - * @param aCount [OUT] The number of CSS properties set by the call. * @param aSuppressTransaction [IN] A boolean indicating, when true, * that no transaction should be recorded. * - * aCount is returned by the dom::Element variant instead of being an out - * parameter. + * @return The number of CSS properties set by the call. */ + int32_t SetCSSEquivalentToHTMLStyle(dom::Element* aElement, + nsIAtom* aProperty, + nsIAtom* aAttribute, + const nsAString* aValue, + bool aSuppressTransaction); int32_t SetCSSEquivalentToHTMLStyle(dom::Element* aElement, nsIAtom* aProperty, const nsAString* aAttribute, const nsAString* aValue, bool aSuppressTransaction); - nsresult SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode, - nsIAtom* aHTMLProperty, - const nsAString* aAttribute, - const nsAString* aValue, - int32_t* aCount, - bool aSuppressTransaction); + int32_t SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode, + nsIAtom* aHTMLProperty, + const nsAString* aAttribute, + const nsAString* aValue, + bool aSuppressTransaction); /** * Removes from the node the CSS inline styles equivalent to the HTML style. @@ -284,7 +291,7 @@ public: * * @param aElement [IN] A DOM Element (must not be null). * @param aHTMLProperty [IN] An atom containing an HTML property. - * @param aAttribute [IN] A pointer to an attribute name or nullptr if + * @param aAttribute [IN] An atom to an attribute name or nullptr if * irrelevant. * @param aValue [IN] The attribute value. * @param aSuppressTransaction [IN] A boolean indicating, when true, @@ -292,7 +299,7 @@ public: */ nsresult RemoveCSSEquivalentToHTMLStyle(dom::Element* aElement, nsIAtom* aHTMLProperty, - const nsAString* aAttribute, + nsIAtom* aAttribute, const nsAString* aValue, bool aSuppressTransaction); @@ -409,7 +416,7 @@ private: * * @param aNode [IN] The DOM node. * @param aHTMLProperty [IN] An atom containing an HTML property. - * @param aAttribute [IN] A pointer to an attribute name or nullptr + * @param aAttribute [IN] An atom to an attribute name or nullptr * if irrelevant * @param aValue [IN] The attribute value. * @param aPropertyArray [OUT] The array of CSS properties. @@ -422,7 +429,7 @@ private: */ void GenerateCSSDeclarationsFromHTMLStyle(dom::Element* aNode, nsIAtom* aHTMLProperty, - const nsAString* aAttribute, + nsIAtom* aAttribute, const nsAString* aValue, nsTArray& aPropertyArray, nsTArray& aValueArray, diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index 3f419a74e..60df3571e 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -1235,12 +1235,23 @@ EditorBase::SetAttribute(nsIDOMElement* aElement, const nsAString& aAttribute, const nsAString& aValue) { + if (NS_WARN_IF(aAttribute.IsEmpty())) { + return NS_ERROR_FAILURE; + } nsCOMPtr element = do_QueryInterface(aElement); NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER); nsCOMPtr attribute = NS_Atomize(aAttribute); + return SetAttribute(element, attribute, aValue); +} + +nsresult +EditorBase::SetAttribute(Element* aElement, + nsIAtom* aAttribute, + const nsAString& aValue) +{ RefPtr transaction = - CreateTxnForSetAttribute(*element, *attribute, aValue); + CreateTxnForSetAttribute(*aElement, *aAttribute, aValue); return DoTransaction(transaction); } @@ -1269,12 +1280,22 @@ NS_IMETHODIMP EditorBase::RemoveAttribute(nsIDOMElement* aElement, const nsAString& aAttribute) { + if (NS_WARN_IF(aAttribute.IsEmpty())) { + return NS_ERROR_FAILURE; + } nsCOMPtr element = do_QueryInterface(aElement); NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER); nsCOMPtr attribute = NS_Atomize(aAttribute); + return RemoveAttribute(element, attribute); +} + +nsresult +EditorBase::RemoveAttribute(Element* aElement, + nsIAtom* aAttribute) +{ RefPtr transaction = - CreateTxnForRemoveAttribute(*element, *attribute); + CreateTxnForRemoveAttribute(*aElement, *aAttribute); return DoTransaction(transaction); } @@ -2249,25 +2270,28 @@ EditorBase::CloneAttribute(const nsAString& aAttribute, nsIDOMNode* aSourceNode) { NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER); - - nsCOMPtr destElement = do_QueryInterface(aDestNode); - nsCOMPtr sourceElement = do_QueryInterface(aSourceNode); - NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE); - - nsAutoString attrValue; - bool isAttrSet; - nsresult rv = GetAttributeValue(sourceElement, - aAttribute, - attrValue, - &isAttrSet); - NS_ENSURE_SUCCESS(rv, rv); - if (isAttrSet) { - rv = SetAttribute(destElement, aAttribute, attrValue); - } else { - rv = RemoveAttribute(destElement, aAttribute); + if (NS_WARN_IF(aAttribute.IsEmpty())) { + return NS_ERROR_FAILURE; } - return rv; + nsCOMPtr destElement = do_QueryInterface(aDestNode); + nsCOMPtr sourceElement = do_QueryInterface(aSourceNode); + NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE); + + nsCOMPtr attribute = NS_Atomize(aAttribute); + return CloneAttribute(attribute, destElement, sourceElement); +} + +nsresult +EditorBase::CloneAttribute(nsIAtom* aAttribute, + Element* aDestElement, + Element* aSourceElement) +{ + nsAutoString attrValue; + if (aSourceElement->GetAttr(kNameSpaceID_None, aAttribute, attrValue)) { + return SetAttribute(aDestElement, aAttribute, attrValue); + } + return RemoveAttribute(aDestElement, aAttribute); } /** @@ -2306,11 +2330,9 @@ EditorBase::CloneAttributes(Element* aDest, RefPtr destAttributes = aDest->Attributes(); while (RefPtr attr = destAttributes->Item(0)) { if (destInBody) { - RemoveAttribute(static_cast(GetAsDOMNode(aDest)), - attr->NodeName()); + RemoveAttribute(aDest, attr->NodeInfo()->NameAtom()); } else { - ErrorResult ignored; - aDest->RemoveAttribute(attr->NodeName(), ignored); + aDest->UnsetAttr(kNameSpaceID_None, attr->NodeInfo()->NameAtom(), true); } } @@ -2322,13 +2344,13 @@ EditorBase::CloneAttributes(Element* aDest, nsAutoString value; attr->GetValue(value); if (destInBody) { - SetAttributeOrEquivalent(static_cast(GetAsDOMNode(aDest)), - attr->NodeName(), value, false); + SetAttributeOrEquivalent(aDest, attr->NodeInfo()->NameAtom(), value, + false); } else { // The element is not inserted in the document yet, we don't want to put // a transaction on the UndoStack - SetAttributeOrEquivalent(static_cast(GetAsDOMNode(aDest)), - attr->NodeName(), value, true); + SetAttributeOrEquivalent(aDest, attr->NodeInfo()->NameAtom(), value, + true); } } } @@ -4678,21 +4700,32 @@ EditorBase::CreateHTMLContent(nsIAtom* aTag) kNameSpaceID_XHTML); } -nsresult +NS_IMETHODIMP EditorBase::SetAttributeOrEquivalent(nsIDOMElement* aElement, const nsAString& aAttribute, const nsAString& aValue, bool aSuppressTransaction) { - return SetAttribute(aElement, aAttribute, aValue); + nsCOMPtr element = do_QueryInterface(aElement); + if (NS_WARN_IF(!element)) { + return NS_ERROR_NULL_POINTER; + } + nsCOMPtr attribute = NS_Atomize(aAttribute); + return SetAttributeOrEquivalent(element, attribute, aValue, + aSuppressTransaction); } -nsresult +NS_IMETHODIMP EditorBase::RemoveAttributeOrEquivalent(nsIDOMElement* aElement, const nsAString& aAttribute, bool aSuppressTransaction) { - return RemoveAttribute(aElement, aAttribute); + nsCOMPtr element = do_QueryInterface(aElement); + if (NS_WARN_IF(!element)) { + return NS_ERROR_NULL_POINTER; + } + nsCOMPtr attribute = NS_Atomize(aAttribute); + return RemoveAttributeOrEquivalent(element, attribute, aSuppressTransaction); } nsresult diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h index 618da12a8..08a895dcd 100644 --- a/editor/libeditor/EditorBase.h +++ b/editor/libeditor/EditorBase.h @@ -291,6 +291,19 @@ public: nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode); nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset); + nsresult CloneAttribute(nsIAtom* aAttribute, Element* aDestElement, + Element* aSourceElement); + nsresult RemoveAttribute(Element* aElement, nsIAtom* aAttribute); + virtual nsresult RemoveAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, + bool aSuppressTransaction) = 0; + nsresult SetAttribute(Element* aElement, nsIAtom* aAttribute, + const nsAString& aValue); + virtual nsresult SetAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, + const nsAString& aValue, + bool aSuppressTransaction) = 0; + /** * Method to replace certain CreateElementNS() calls. * diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index af4a43ab9..f24d0131d 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -840,19 +840,18 @@ HTMLEditRules::GetAlignment(bool* aMixed, NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER); - NS_NAMED_LITERAL_STRING(typeAttrName, "align"); nsCOMPtr blockParent = htmlEditor->GetBlock(*nodeToExamine); NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE); if (htmlEditor->IsCSSEnabled() && htmlEditor->mCSSEditUtils->IsCSSEditableProperty(blockParent, nullptr, - &typeAttrName)) { + nsGkAtoms::align)) { // We are in CSS mode and we know how to align this element with CSS nsAutoString value; // Let's get the value(s) of text-align or margin-left/margin-right htmlEditor->mCSSEditUtils->GetCSSEquivalentToHTMLInlineStyleSet( - blockParent, nullptr, &typeAttrName, value, CSSEditUtils::eComputed); + blockParent, nullptr, nsGkAtoms::align, value, CSSEditUtils::eComputed); if (value.EqualsLiteral("center") || value.EqualsLiteral("-moz-center") || value.EqualsLiteral("auto auto")) { @@ -1510,10 +1509,11 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection, nsCOMPtr blockParent = htmlEditor->GetBlock(node); NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE); - // If the active editing host is an inline element, or if the active editing - // host is the block parent itself, just append a br. + // When there is an active editing host (the if it's in designMode) + // and a block which becomes the parent of line breaker is in it, do the + // standard thing. nsCOMPtr host = htmlEditor->GetActiveEditingHost(); - if (!EditorUtils::IsDescendantOf(blockParent, host)) { + if (host && !EditorUtils::IsDescendantOf(blockParent, host)) { nsresult rv = StandardBreakImpl(node, offset, aSelection); NS_ENSURE_SUCCESS(rv, rv); *aHandled = true; @@ -3303,15 +3303,15 @@ HTMLEditRules::WillMakeList(Selection* aSelection, } } NS_ENSURE_STATE(mHTMLEditor); - nsCOMPtr curElement = do_QueryInterface(curNode); - NS_NAMED_LITERAL_STRING(typestr, "type"); + nsCOMPtr curElement = do_QueryInterface(curNode); if (aBulletType && !aBulletType->IsEmpty()) { - rv = mHTMLEditor->SetAttribute(curElement, typestr, *aBulletType); + rv = mHTMLEditor->SetAttribute(curElement, nsGkAtoms::type, + *aBulletType); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { - rv = mHTMLEditor->RemoveAttribute(curElement, typestr); + rv = mHTMLEditor->RemoveAttribute(curElement, nsGkAtoms::type); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -4756,7 +4756,7 @@ HTMLEditRules::WillAlign(Selection& aSelection, NS_ENSURE_SUCCESS(rv, rv); if (useCSS) { htmlEditor->mCSSEditUtils->SetCSSEquivalentToHTMLStyle( - curNode->AsElement(), nullptr, &NS_LITERAL_STRING("align"), + curNode->AsElement(), nullptr, nsGkAtoms::align, &aAlignType, false); curDiv = nullptr; continue; @@ -4837,7 +4837,6 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode, nsCOMPtr node = do_QueryInterface(aNode); NS_ENSURE_TRUE(node && alignType, NS_ERROR_NULL_POINTER); nsCOMPtr firstChild, lastChild; - nsCOMPtr divNode; bool useCSS = mHTMLEditor->IsCSSEnabled(); @@ -4845,24 +4844,25 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode, firstChild = mHTMLEditor->GetFirstEditableChild(*node); NS_ENSURE_STATE(mHTMLEditor); lastChild = mHTMLEditor->GetLastEditableChild(*node); - NS_NAMED_LITERAL_STRING(attr, "align"); if (!firstChild) { // this cell has no content, nothing to align } else if (firstChild == lastChild && firstChild->IsHTMLElement(nsGkAtoms::div)) { // the cell already has a div containing all of its content: just // act on this div. - nsCOMPtr divElem = do_QueryInterface(firstChild); + RefPtr divElem = firstChild->AsElement(); if (useCSS) { NS_ENSURE_STATE(mHTMLEditor); - nsresult rv = mHTMLEditor->SetAttributeOrEquivalent(divElem, attr, + nsresult rv = mHTMLEditor->SetAttributeOrEquivalent(divElem, + nsGkAtoms::align, *alignType, false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { NS_ENSURE_STATE(mHTMLEditor); - nsresult rv = mHTMLEditor->SetAttribute(divElem, attr, *alignType); + nsresult rv = mHTMLEditor->SetAttribute(divElem, nsGkAtoms::align, + *alignType); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -4870,28 +4870,29 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode, } else { // else we need to put in a div, set the alignment, and toss in all the children NS_ENSURE_STATE(mHTMLEditor); - divNode = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0); - NS_ENSURE_STATE(divNode); + RefPtr divElem = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0); + NS_ENSURE_STATE(divElem); // set up the alignment on the div - nsCOMPtr divElem = do_QueryInterface(divNode); if (useCSS) { NS_ENSURE_STATE(mHTMLEditor); nsresult rv = - mHTMLEditor->SetAttributeOrEquivalent(divElem, attr, *alignType, false); + mHTMLEditor->SetAttributeOrEquivalent(divElem, nsGkAtoms::align, + *alignType, false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { NS_ENSURE_STATE(mHTMLEditor); - nsresult rv = mHTMLEditor->SetAttribute(divElem, attr, *alignType); + nsresult rv = + mHTMLEditor->SetAttribute(divElem, nsGkAtoms::align, *alignType); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } // tuck the children into the end of the active div - while (lastChild && (lastChild != divNode)) { + while (lastChild && (lastChild != divElem)) { NS_ENSURE_STATE(mHTMLEditor); - nsresult rv = mHTMLEditor->MoveNode(lastChild, divNode, 0); + nsresult rv = mHTMLEditor->MoveNode(lastChild, divElem, 0); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_STATE(mHTMLEditor); lastChild = mHTMLEditor->GetLastEditableChild(*node); @@ -6498,10 +6499,14 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara, // split the paragraph NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(selNode->IsContent()); - mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset, - HTMLEditor::EmptyContainers::yes, - getter_AddRefs(leftPara), - getter_AddRefs(rightPara)); + int32_t offset = + mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset, + HTMLEditor::EmptyContainers::yes, + getter_AddRefs(leftPara), + getter_AddRefs(rightPara)); + if (NS_WARN_IF(offset == -1)) { + return NS_ERROR_FAILURE; + } // get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p) NS_ENSURE_STATE(mHTMLEditor); if (mHTMLEditor->IsVisBreak(aBRNode)) { @@ -6511,9 +6516,9 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara, } // remove ID attribute on the paragraph we just created - nsCOMPtr rightElt = do_QueryInterface(rightPara); + RefPtr rightElt = rightPara->AsElement(); NS_ENSURE_STATE(mHTMLEditor); - rv = mHTMLEditor->RemoveAttribute(rightElt, NS_LITERAL_STRING("id")); + rv = mHTMLEditor->RemoveAttribute(rightElt, nsGkAtoms::id); NS_ENSURE_SUCCESS(rv, rv); // check both halves of para to see if we need mozBR @@ -7143,9 +7148,9 @@ HTMLEditRules::CacheInlineStyles(nsIDOMNode* aNode) isSet, &outValue); } else { NS_ENSURE_STATE(mHTMLEditor); - mHTMLEditor->mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(aNode, - mCachedStyles[j].tag, &(mCachedStyles[j].attr), isSet, outValue, - CSSEditUtils::eComputed); + isSet = mHTMLEditor->mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet( + aNode, mCachedStyles[j].tag, &(mCachedStyles[j].attr), outValue, + CSSEditUtils::eComputed); } if (isSet) { mCachedStyles[j].mPresent = true; @@ -8388,18 +8393,18 @@ HTMLEditRules::RemoveAlignment(nsIDOMNode* aNode, NS_ENSURE_SUCCESS(rv, rv); } else if (isBlock || HTMLEditUtils::IsHR(child)) { // the current node is a block element - nsCOMPtr curElem = do_QueryInterface(child); + nsCOMPtr curElem = do_QueryInterface(child); if (HTMLEditUtils::SupportsAlignAttr(child)) { // remove the ALIGN attribute if this element can have it NS_ENSURE_STATE(mHTMLEditor); - rv = mHTMLEditor->RemoveAttribute(curElem, NS_LITERAL_STRING("align")); + rv = mHTMLEditor->RemoveAttribute(curElem, nsGkAtoms::align); NS_ENSURE_SUCCESS(rv, rv); } if (useCSS) { if (HTMLEditUtils::IsTable(child) || HTMLEditUtils::IsHR(child)) { NS_ENSURE_STATE(mHTMLEditor); rv = mHTMLEditor->SetAttributeOrEquivalent(curElem, - NS_LITERAL_STRING("align"), + nsGkAtoms::align, aAlignType, false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -8519,21 +8524,17 @@ HTMLEditRules::AlignBlock(Element& aElement, nsresult rv = RemoveAlignment(aElement.AsDOMNode(), aAlignType, aContentsOnly == ContentsOnly::yes); NS_ENSURE_SUCCESS(rv, rv); - NS_NAMED_LITERAL_STRING(attr, "align"); if (htmlEditor->IsCSSEnabled()) { // Let's use CSS alignment; we use margin-left and margin-right for tables // and text-align for other block-level elements rv = htmlEditor->SetAttributeOrEquivalent( - static_cast(aElement.AsDOMNode()), - attr, aAlignType, false); + &aElement, nsGkAtoms::align, aAlignType, false); NS_ENSURE_SUCCESS(rv, rv); } else { // HTML case; this code is supposed to be called ONLY if the element // supports the align attribute but we'll never know... if (HTMLEditUtils::SupportsAlignAttr(aElement.AsDOMNode())) { - rv = htmlEditor->SetAttribute( - static_cast(aElement.AsDOMNode()), - attr, aAlignType); + rv = htmlEditor->SetAttribute(&aElement, nsGkAtoms::align, aAlignType); NS_ENSURE_SUCCESS(rv, rv); } } diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index c2f0bdc6d..6a630cb1c 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -2529,7 +2529,7 @@ HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName) // New call to use instead to get proper HTML element, bug 39919 nsCOMPtr realTagAtom = NS_Atomize(realTagName); - nsCOMPtr newElement = CreateHTMLContent(realTagAtom); + RefPtr newElement = CreateHTMLContent(realTagAtom); if (!newElement) { return nullptr; } @@ -2561,8 +2561,7 @@ HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName) } else if (tagName.EqualsLiteral("td")) { nsresult rv = SetAttributeOrEquivalent( - static_cast(newElement->AsDOMNode()), - NS_LITERAL_STRING("valign"), NS_LITERAL_STRING("top"), true); + newElement, nsGkAtoms::valign, NS_LITERAL_STRING("top"), true); NS_ENSURE_SUCCESS(rv, nullptr); } // ADD OTHER TAGS HERE @@ -4390,87 +4389,83 @@ HTMLEditor::IsEmptyNodeImpl(nsINode* aNode, // add to aElement the CSS inline styles corresponding to the HTML attribute // aAttribute with its value aValue nsresult -HTMLEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, +HTMLEditor::SetAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, const nsAString& aValue, bool aSuppressTransaction) { + MOZ_ASSERT(aElement); + MOZ_ASSERT(aAttribute); + nsAutoScriptBlocker scriptBlocker; - if (IsCSSEnabled() && mCSSEditUtils) { - int32_t count; - nsresult rv = - mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr, - &aAttribute, &aValue, - &count, - aSuppressTransaction); - NS_ENSURE_SUCCESS(rv, rv); - if (count) { - // we found an equivalence ; let's remove the HTML attribute itself if it is set - nsAutoString existingValue; - bool wasSet = false; - rv = GetAttributeValue(aElement, aAttribute, existingValue, &wasSet); - NS_ENSURE_SUCCESS(rv, rv); - if (!wasSet) { - return NS_OK; - } - return aSuppressTransaction ? aElement->RemoveAttribute(aAttribute) : - RemoveAttribute(aElement, aAttribute); - } - - // count is an integer that represents the number of CSS declarations applied to the - // element. If it is zero, we found no equivalence in this implementation for the - // attribute - if (aAttribute.EqualsLiteral("style")) { - // if it is the style attribute, just add the new value to the existing style - // attribute's value - nsAutoString existingValue; - bool wasSet = false; - nsresult rv = GetAttributeValue(aElement, NS_LITERAL_STRING("style"), - existingValue, &wasSet); - NS_ENSURE_SUCCESS(rv, rv); - existingValue.Append(' '); - existingValue.Append(aValue); - return aSuppressTransaction ? - aElement->SetAttribute(aAttribute, existingValue) : - SetAttribute(aElement, aAttribute, existingValue); - } - - // we have no CSS equivalence for this attribute and it is not the style - // attribute; let's set it the good'n'old HTML way - return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) : - SetAttribute(aElement, aAttribute, aValue); + if (!IsCSSEnabled() || !mCSSEditUtils) { + // we are not in an HTML+CSS editor; let's set the attribute the HTML way + return aSuppressTransaction ? + aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) : + SetAttribute(aElement, aAttribute, aValue); } - // we are not in an HTML+CSS editor; let's set the attribute the HTML way - return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) : - SetAttribute(aElement, aAttribute, aValue); + int32_t count = + mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr, + aAttribute, &aValue, + aSuppressTransaction); + if (count) { + // we found an equivalence ; let's remove the HTML attribute itself if it + // is set + nsAutoString existingValue; + if (!aElement->GetAttr(kNameSpaceID_None, aAttribute, existingValue)) { + return NS_OK; + } + + return aSuppressTransaction ? + aElement->UnsetAttr(kNameSpaceID_None, aAttribute, true) : + RemoveAttribute(aElement, aAttribute); + } + + // count is an integer that represents the number of CSS declarations applied + // to the element. If it is zero, we found no equivalence in this + // implementation for the attribute + if (aAttribute == nsGkAtoms::style) { + // if it is the style attribute, just add the new value to the existing + // style attribute's value + nsAutoString existingValue; + aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::style, existingValue); + existingValue.Append(' '); + existingValue.Append(aValue); + return aSuppressTransaction ? + aElement->SetAttr(kNameSpaceID_None, aAttribute, existingValue, true) : + SetAttribute(aElement, aAttribute, existingValue); + } + + // we have no CSS equivalence for this attribute and it is not the style + // attribute; let's set it the good'n'old HTML way + return aSuppressTransaction ? + aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) : + SetAttribute(aElement, aAttribute, aValue); } nsresult -HTMLEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, +HTMLEditor::RemoveAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, bool aSuppressTransaction) { - nsCOMPtr element = do_QueryInterface(aElement); - NS_ENSURE_TRUE(element, NS_OK); - - nsCOMPtr attribute = NS_Atomize(aAttribute); - MOZ_ASSERT(attribute); + MOZ_ASSERT(aElement); + MOZ_ASSERT(aAttribute); if (IsCSSEnabled() && mCSSEditUtils) { nsresult rv = mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle( - element, nullptr, &aAttribute, nullptr, aSuppressTransaction); + aElement, nullptr, aAttribute, nullptr, aSuppressTransaction); NS_ENSURE_SUCCESS(rv, rv); } - if (!element->HasAttr(kNameSpaceID_None, attribute)) { + if (!aElement->HasAttr(kNameSpaceID_None, aAttribute)) { return NS_OK; } return aSuppressTransaction ? - element->UnsetAttr(kNameSpaceID_None, attribute, /* aNotify = */ true) : + aElement->UnsetAttr(kNameSpaceID_None, aAttribute, /* aNotify = */ true) : RemoveAttribute(aElement, aAttribute); } @@ -4523,7 +4518,6 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor) NS_ENSURE_SUCCESS(rv, rv); if (!cancel && !handled) { // Loop through the ranges in the selection - NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor"); for (uint32_t i = 0; i < selection->RangeCount(); i++) { RefPtr range = selection->GetRangeAt(i); NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); @@ -4542,13 +4536,15 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor) if (blockParent && cachedBlockParent != blockParent) { cachedBlockParent = blockParent; mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr, - &bgcolor, &aColor, false); + nsGkAtoms::bgcolor, + &aColor, false); } } else if (startNode == endNode && startNode->IsHTMLElement(nsGkAtoms::body) && isCollapsed) { // No block in the document, let's apply the background to the body mCSSEditUtils->SetCSSEquivalentToHTMLStyle(startNode->AsElement(), - nullptr, &bgcolor, &aColor, + nullptr, nsGkAtoms::bgcolor, + &aColor, false); } else if (startNode == endNode && (endOffset - startOffset == 1 || (!startOffset && !endOffset))) { @@ -4559,7 +4555,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor) if (blockParent && cachedBlockParent != blockParent) { cachedBlockParent = blockParent; mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr, - &bgcolor, &aColor, false); + nsGkAtoms::bgcolor, + &aColor, false); } } else { // Not the easy case. Range not contained in single text node. There @@ -4602,7 +4599,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor) if (blockParent && cachedBlockParent != blockParent) { cachedBlockParent = blockParent; mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr, - &bgcolor, &aColor, + nsGkAtoms::bgcolor, + &aColor, false); } } @@ -4613,7 +4611,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor) if (blockParent && cachedBlockParent != blockParent) { cachedBlockParent = blockParent; mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr, - &bgcolor, &aColor, + nsGkAtoms::bgcolor, + &aColor, false); } } @@ -4627,7 +4626,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor) if (blockParent && cachedBlockParent != blockParent) { cachedBlockParent = blockParent; mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr, - &bgcolor, &aColor, + nsGkAtoms::bgcolor, + &aColor, false); } } diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index dc1a41b70..494e7c383 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -118,6 +118,16 @@ public: virtual already_AddRefed GetInputEventTargetContent() override; virtual bool IsEditable(nsINode* aNode) override; using EditorBase::IsEditable; + virtual nsresult RemoveAttributeOrEquivalent( + Element* aElement, + nsIAtom* aAttribute, + bool aSuppressTransaction) override; + virtual nsresult SetAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, + const nsAString& aValue, + bool aSuppressTransaction) override; + using EditorBase::RemoveAttributeOrEquivalent; + using EditorBase::SetAttributeOrEquivalent; // nsStubMutationObserver overrides NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED @@ -329,14 +339,6 @@ public: */ virtual nsresult SelectEntireDocument(Selection* aSelection) override; - NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, - const nsAString& aValue, - bool aSuppressTransaction) override; - NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, - bool aSuppressTransaction) override; - /** * Join together any adjacent editable text nodes in the range. */ diff --git a/editor/libeditor/HTMLEditorObjectResizer.cpp b/editor/libeditor/HTMLEditorObjectResizer.cpp index 111a3f975..8ed5b6e4d 100644 --- a/editor/libeditor/HTMLEditorObjectResizer.cpp +++ b/editor/libeditor/HTMLEditorObjectResizer.cpp @@ -926,35 +926,30 @@ HTMLEditor::SetFinalSize(int32_t aX, // we want one transaction only from a user's point of view AutoEditBatch batchIt(this); - NS_NAMED_LITERAL_STRING(widthStr, "width"); - NS_NAMED_LITERAL_STRING(heightStr, "height"); - - nsCOMPtr resizedObject = do_QueryInterface(mResizedObject); - NS_ENSURE_TRUE(resizedObject, ); if (mResizedObjectIsAbsolutelyPositioned) { if (setHeight) { - mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::top, y); + mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::top, y); } if (setWidth) { - mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::left, x); + mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::left, x); } } if (IsCSSEnabled() || mResizedObjectIsAbsolutelyPositioned) { if (setWidth && mResizedObject->HasAttr(kNameSpaceID_None, nsGkAtoms::width)) { - RemoveAttribute(static_cast(GetAsDOMNode(mResizedObject)), widthStr); + RemoveAttribute(mResizedObject, nsGkAtoms::width); } if (setHeight && mResizedObject->HasAttr(kNameSpaceID_None, nsGkAtoms::height)) { - RemoveAttribute(static_cast(GetAsDOMNode(mResizedObject)), heightStr); + RemoveAttribute(mResizedObject, nsGkAtoms::height); } if (setWidth) { - mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::width, + mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::width, width); } if (setHeight) { - mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::height, + mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::height, height); } } else { @@ -964,30 +959,30 @@ HTMLEditor::SetFinalSize(int32_t aX, // triggering an immediate reflow; otherwise, we have problems // with asynchronous reflow if (setWidth) { - mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::width, + mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::width, width); } if (setHeight) { - mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::height, + mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::height, height); } if (setWidth) { nsAutoString w; w.AppendInt(width); - SetAttribute(static_cast(GetAsDOMNode(mResizedObject)), widthStr, w); + SetAttribute(mResizedObject, nsGkAtoms::width, w); } if (setHeight) { nsAutoString h; h.AppendInt(height); - SetAttribute(static_cast(GetAsDOMNode(mResizedObject)), heightStr, h); + SetAttribute(mResizedObject, nsGkAtoms::height, h); } if (setWidth) { - mCSSEditUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::width, + mCSSEditUtils->RemoveCSSProperty(*mResizedObject, *nsGkAtoms::width, EmptyString()); } if (setHeight) { - mCSSEditUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::height, + mCSSEditUtils->RemoveCSSProperty(*mResizedObject, *nsGkAtoms::height, EmptyString()); } } diff --git a/editor/libeditor/HTMLStyleEditor.cpp b/editor/libeditor/HTMLStyleEditor.cpp index 72eb1d690..c41f0a05c 100644 --- a/editor/libeditor/HTMLStyleEditor.cpp +++ b/editor/libeditor/HTMLStyleEditor.cpp @@ -429,7 +429,7 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode, mCSSEditUtils->IsCSSEditableProperty(&aNode, &aProperty, aAttribute)) || // bgcolor is always done using CSS - aAttribute->EqualsLiteral("bgcolor"); + attrAtom == nsGkAtoms::bgcolor; if (useCSS) { nsCOMPtr tmp; @@ -444,12 +444,9 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode, } // Add the CSS styles corresponding to the HTML style request - int32_t count; - nsresult rv = - mCSSEditUtils->SetCSSEquivalentToHTMLStyle(tmp->AsDOMNode(), - &aProperty, aAttribute, - &aValue, &count, false); - NS_ENSURE_SUCCESS(rv, rv); + mCSSEditUtils->SetCSSEquivalentToHTMLStyle(tmp, + &aProperty, attrAtom, + &aValue, false); return NS_OK; } @@ -576,8 +573,9 @@ HTMLEditor::SplitStyleAbovePoint(nsCOMPtr* aNode, // in this implementation for the node; let's check if it carries those // CSS styles nsAutoString firstValue; - mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(GetAsDOMNode(node), - aProperty, aAttribute, isSet, firstValue, CSSEditUtils::eSpecified); + isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet( + node, aProperty, aAttribute, firstValue, + CSSEditUtils::eSpecified); } if (// node is the correct inline prop (aProperty && node->IsHTMLElement(aProperty)) || @@ -746,8 +744,6 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode, // if we weren't passed an attribute, then we want to // remove any matching inlinestyles entirely if (!aAttribute || aAttribute->IsEmpty()) { - NS_NAMED_LITERAL_STRING(styleAttr, "style"); - NS_NAMED_LITERAL_STRING(classAttr, "class"); bool hasStyleAttr = aNode.HasAttr(kNameSpaceID_None, nsGkAtoms::style); bool hasClassAttr = aNode.HasAttr(kNameSpaceID_None, nsGkAtoms::_class); @@ -756,14 +752,14 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode, // just remove the element... We need to create above the element // a span that will carry those styles or class, then we can delete // the node. - nsCOMPtr spanNode = + RefPtr spanNode = InsertContainerAbove(&aNode, nsGkAtoms::span); NS_ENSURE_STATE(spanNode); nsresult rv = - CloneAttribute(styleAttr, spanNode->AsDOMNode(), aNode.AsDOMNode()); + CloneAttribute(nsGkAtoms::style, spanNode, aNode.AsElement()); NS_ENSURE_SUCCESS(rv, rv); rv = - CloneAttribute(classAttr, spanNode->AsDOMNode(), aNode.AsDOMNode()); + CloneAttribute(nsGkAtoms::_class, spanNode, aNode.AsElement()); NS_ENSURE_SUCCESS(rv, rv); } nsresult rv = RemoveContainer(&aNode); @@ -796,15 +792,17 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode, // the HTML style defined by aProperty/aAttribute has a CSS equivalence in // this implementation for the node aNode; let's check if it carries those // css styles + nsCOMPtr attribute = + aAttribute ? NS_Atomize(*aAttribute) : nullptr; nsAutoString propertyValue; bool isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(&aNode, - aProperty, aAttribute, propertyValue, CSSEditUtils::eSpecified); + aProperty, attribute, propertyValue, CSSEditUtils::eSpecified); if (isSet && aNode.IsElement()) { // yes, tmp has the corresponding css declarations in its style attribute // let's remove them mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(aNode.AsElement(), aProperty, - aAttribute, + attribute, &propertyValue, false); // remove the node if it is a span or font, if its style attribute is diff --git a/editor/libeditor/TextEditRules.cpp b/editor/libeditor/TextEditRules.cpp index 4ecaff722..e98d36dd3 100644 --- a/editor/libeditor/TextEditRules.cpp +++ b/editor/libeditor/TextEditRules.cpp @@ -1422,9 +1422,9 @@ TextEditRules::CreateMozBR(nsIDOMNode* inParent, NS_ENSURE_SUCCESS(rv, rv); // give it special moz attr - nsCOMPtr brElem = do_QueryInterface(brNode); + nsCOMPtr brElem = do_QueryInterface(brNode); if (brElem) { - rv = mTextEditor->SetAttribute(brElem, NS_LITERAL_STRING("type"), + rv = mTextEditor->SetAttribute(brElem, nsGkAtoms::type, NS_LITERAL_STRING("_moz")); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp index 07b06a96a..3bee7843c 100644 --- a/editor/libeditor/TextEditor.cpp +++ b/editor/libeditor/TextEditor.cpp @@ -311,9 +311,9 @@ TextEditor::UpdateMetaCharset(nsIDOMDocument* aDocument, } // set attribute to charset=text/html - nsCOMPtr metaElement = do_QueryInterface(metaNode); + RefPtr metaElement = metaNode->AsElement(); MOZ_ASSERT(metaElement); - rv = EditorBase::SetAttribute(metaElement, NS_LITERAL_STRING("content"), + rv = EditorBase::SetAttribute(metaElement, nsGkAtoms::content, Substring(originalStart, start) + charsetEquals + NS_ConvertASCIItoUTF16(aCharacterSet)); @@ -1622,8 +1622,8 @@ TextEditor::GetDOMEventTarget() nsresult -TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, +TextEditor::SetAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, const nsAString& aValue, bool aSuppressTransaction) { @@ -1631,8 +1631,8 @@ TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement, } nsresult -TextEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, +TextEditor::RemoveAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, bool aSuppressTransaction) { return EditorBase::RemoveAttribute(aElement, aAttribute); diff --git a/editor/libeditor/TextEditor.h b/editor/libeditor/TextEditor.h index 31c551f85..7bb594931 100644 --- a/editor/libeditor/TextEditor.h +++ b/editor/libeditor/TextEditor.h @@ -63,14 +63,17 @@ public: // nsIEditorMailSupport overrides NS_DECL_NSIEDITORMAILSUPPORT - // Overrides of EditorBase interface methods - NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, - const nsAString& aValue, - bool aSuppressTransaction) override; - NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement, - const nsAString& aAttribute, - bool aSuppressTransaction) override; + // Overrides of EditorBase + virtual nsresult RemoveAttributeOrEquivalent( + Element* aElement, + nsIAtom* aAttribute, + bool aSuppressTransaction) override; + virtual nsresult SetAttributeOrEquivalent(Element* aElement, + nsIAtom* aAttribute, + const nsAString& aValue, + bool aSuppressTransaction) override; + using EditorBase::RemoveAttributeOrEquivalent; + using EditorBase::SetAttributeOrEquivalent; NS_IMETHOD Init(nsIDOMDocument* aDoc, nsIContent* aRoot, nsISelectionController* aSelCon, uint32_t aFlags,