Issue #1621 - Part 1: CSSEditUtils should use atom for CSS property if possible.

There is a lot of string compare when using CSS property name. We should use nsGkAtoms instead.

Ref: Bug 1323138
This commit is contained in:
Gaming4JC 2020-05-22 17:13:33 -04:00 committed by Roy Tam
commit 5260565a09
5 changed files with 224 additions and 188 deletions

View file

@ -322,6 +322,15 @@ bool
CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute)
{
nsCOMPtr<nsIAtom> 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<nsIAtom*>& cssPropertyArray,
nsTArray<nsString>& 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> 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> element = do_QueryInterface(aNode);
*aCount = 0;
if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) {
return NS_OK;
nsCOMPtr<nsIAtom> 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<nsIAtom*> cssPropertyArray;
nsTArray<nsString> 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> element = do_QueryInterface(aNode);
NS_ENSURE_TRUE(element, NS_OK);
nsCOMPtr<nsIAtom> 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<nsString> 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<nsIAtom> 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<nsINode> node = do_QueryInterface(aNode);
nsCOMPtr<nsIAtom> 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<nsINode> 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