LCOV - code coverage report
Current view: top level - editor/libeditor - CSSEditUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 635 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 50 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/CSSEditUtils.h"
       7             : 
       8             : #include "mozilla/Assertions.h"
       9             : #include "mozilla/ChangeStyleTransaction.h"
      10             : #include "mozilla/HTMLEditor.h"
      11             : #include "mozilla/Preferences.h"
      12             : #include "mozilla/DeclarationBlockInlines.h"
      13             : #include "mozilla/css/StyleRule.h"
      14             : #include "mozilla/dom/Element.h"
      15             : #include "mozilla/mozalloc.h"
      16             : #include "nsAString.h"
      17             : #include "nsCOMPtr.h"
      18             : #include "nsColor.h"
      19             : #include "nsComputedDOMStyle.h"
      20             : #include "nsDebug.h"
      21             : #include "nsDependentSubstring.h"
      22             : #include "nsError.h"
      23             : #include "nsGkAtoms.h"
      24             : #include "nsIAtom.h"
      25             : #include "nsIContent.h"
      26             : #include "nsIDOMCSSStyleDeclaration.h"
      27             : #include "nsIDOMElement.h"
      28             : #include "nsIDOMNode.h"
      29             : #include "nsIDOMWindow.h"
      30             : #include "nsIDocument.h"
      31             : #include "nsIEditor.h"
      32             : #include "nsINode.h"
      33             : #include "nsISupportsImpl.h"
      34             : #include "nsISupportsUtils.h"
      35             : #include "nsLiteralString.h"
      36             : #include "nsPIDOMWindow.h"
      37             : #include "nsReadableUtils.h"
      38             : #include "nsString.h"
      39             : #include "nsStringFwd.h"
      40             : #include "nsStringIterator.h"
      41             : #include "nsStyledElement.h"
      42             : #include "nsSubstringTuple.h"
      43             : #include "nsUnicharUtils.h"
      44             : 
      45             : namespace mozilla {
      46             : 
      47             : using namespace dom;
      48             : 
      49             : static
      50           0 : void ProcessBValue(const nsAString* aInputString,
      51             :                    nsAString& aOutputString,
      52             :                    const char* aDefaultValueString,
      53             :                    const char* aPrependString,
      54             :                    const char* aAppendString)
      55             : {
      56           0 :   if (aInputString && aInputString->EqualsLiteral("-moz-editor-invert-value")) {
      57           0 :       aOutputString.AssignLiteral("normal");
      58             :   }
      59             :   else {
      60           0 :     aOutputString.AssignLiteral("bold");
      61             :   }
      62           0 : }
      63             : 
      64             : static
      65           0 : void ProcessDefaultValue(const nsAString* aInputString,
      66             :                          nsAString& aOutputString,
      67             :                          const char* aDefaultValueString,
      68             :                          const char* aPrependString,
      69             :                          const char* aAppendString)
      70             : {
      71           0 :   CopyASCIItoUTF16(aDefaultValueString, aOutputString);
      72           0 : }
      73             : 
      74             : static
      75           0 : void ProcessSameValue(const nsAString* aInputString,
      76             :                       nsAString & aOutputString,
      77             :                       const char* aDefaultValueString,
      78             :                       const char* aPrependString,
      79             :                       const char* aAppendString)
      80             : {
      81           0 :   if (aInputString) {
      82           0 :     aOutputString.Assign(*aInputString);
      83             :   }
      84             :   else
      85           0 :     aOutputString.Truncate();
      86           0 : }
      87             : 
      88             : static
      89           0 : void ProcessExtendedValue(const nsAString* aInputString,
      90             :                           nsAString& aOutputString,
      91             :                           const char* aDefaultValueString,
      92             :                           const char* aPrependString,
      93             :                           const char* aAppendString)
      94             : {
      95           0 :   aOutputString.Truncate();
      96           0 :   if (aInputString) {
      97           0 :     if (aPrependString) {
      98           0 :       AppendASCIItoUTF16(aPrependString, aOutputString);
      99             :     }
     100           0 :     aOutputString.Append(*aInputString);
     101           0 :     if (aAppendString) {
     102           0 :       AppendASCIItoUTF16(aAppendString, aOutputString);
     103             :     }
     104             :   }
     105           0 : }
     106             : 
     107             : static
     108           0 : void ProcessLengthValue(const nsAString* aInputString,
     109             :                         nsAString& aOutputString,
     110             :                         const char* aDefaultValueString,
     111             :                         const char* aPrependString,
     112             :                         const char* aAppendString)
     113             : {
     114           0 :   aOutputString.Truncate();
     115           0 :   if (aInputString) {
     116           0 :     aOutputString.Append(*aInputString);
     117           0 :     if (-1 == aOutputString.FindChar(char16_t('%'))) {
     118           0 :       aOutputString.AppendLiteral("px");
     119             :     }
     120             :   }
     121           0 : }
     122             : 
     123             : static
     124           0 : void ProcessListStyleTypeValue(const nsAString* aInputString,
     125             :                                nsAString& aOutputString,
     126             :                                const char* aDefaultValueString,
     127             :                                const char* aPrependString,
     128             :                                const char* aAppendString)
     129             : {
     130           0 :   aOutputString.Truncate();
     131           0 :   if (aInputString) {
     132           0 :     if (aInputString->EqualsLiteral("1")) {
     133           0 :       aOutputString.AppendLiteral("decimal");
     134             :     }
     135           0 :     else if (aInputString->EqualsLiteral("a")) {
     136           0 :       aOutputString.AppendLiteral("lower-alpha");
     137             :     }
     138           0 :     else if (aInputString->EqualsLiteral("A")) {
     139           0 :       aOutputString.AppendLiteral("upper-alpha");
     140             :     }
     141           0 :     else if (aInputString->EqualsLiteral("i")) {
     142           0 :       aOutputString.AppendLiteral("lower-roman");
     143             :     }
     144           0 :     else if (aInputString->EqualsLiteral("I")) {
     145           0 :       aOutputString.AppendLiteral("upper-roman");
     146             :     }
     147           0 :     else if (aInputString->EqualsLiteral("square")
     148           0 :              || aInputString->EqualsLiteral("circle")
     149           0 :              || aInputString->EqualsLiteral("disc")) {
     150           0 :       aOutputString.Append(*aInputString);
     151             :     }
     152             :   }
     153           0 : }
     154             : 
     155             : static
     156           0 : void ProcessMarginLeftValue(const nsAString* aInputString,
     157             :                             nsAString& aOutputString,
     158             :                             const char* aDefaultValueString,
     159             :                             const char* aPrependString,
     160             :                             const char* aAppendString)
     161             : {
     162           0 :   aOutputString.Truncate();
     163           0 :   if (aInputString) {
     164           0 :     if (aInputString->EqualsLiteral("center") ||
     165           0 :         aInputString->EqualsLiteral("-moz-center")) {
     166           0 :       aOutputString.AppendLiteral("auto");
     167             :     }
     168           0 :     else if (aInputString->EqualsLiteral("right") ||
     169           0 :              aInputString->EqualsLiteral("-moz-right")) {
     170           0 :       aOutputString.AppendLiteral("auto");
     171             :     }
     172             :     else {
     173           0 :       aOutputString.AppendLiteral("0px");
     174             :     }
     175             :   }
     176           0 : }
     177             : 
     178             : static
     179           0 : void ProcessMarginRightValue(const nsAString* aInputString,
     180             :                              nsAString& aOutputString,
     181             :                              const char* aDefaultValueString,
     182             :                              const char* aPrependString,
     183             :                              const char* aAppendString)
     184             : {
     185           0 :   aOutputString.Truncate();
     186           0 :   if (aInputString) {
     187           0 :     if (aInputString->EqualsLiteral("center") ||
     188           0 :         aInputString->EqualsLiteral("-moz-center")) {
     189           0 :       aOutputString.AppendLiteral("auto");
     190             :     }
     191           0 :     else if (aInputString->EqualsLiteral("left") ||
     192           0 :              aInputString->EqualsLiteral("-moz-left")) {
     193           0 :       aOutputString.AppendLiteral("auto");
     194             :     }
     195             :     else {
     196           0 :       aOutputString.AppendLiteral("0px");
     197             :     }
     198             :   }
     199           0 : }
     200             : 
     201             : const CSSEditUtils::CSSEquivTable boldEquivTable[] = {
     202             :   { CSSEditUtils::eCSSEditableProperty_font_weight, ProcessBValue, nullptr, nullptr, nullptr, true, false },
     203             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     204             : };
     205             : 
     206             : const CSSEditUtils::CSSEquivTable italicEquivTable[] = {
     207             :   { CSSEditUtils::eCSSEditableProperty_font_style, ProcessDefaultValue, "italic", nullptr, nullptr, true, false },
     208             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     209             : };
     210             : 
     211             : const CSSEditUtils::CSSEquivTable underlineEquivTable[] = {
     212             :   { CSSEditUtils::eCSSEditableProperty_text_decoration, ProcessDefaultValue, "underline", nullptr, nullptr, true, false },
     213             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     214             : };
     215             : 
     216             : const CSSEditUtils::CSSEquivTable strikeEquivTable[] = {
     217             :   { CSSEditUtils::eCSSEditableProperty_text_decoration, ProcessDefaultValue, "line-through", nullptr, nullptr, true, false },
     218             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     219             : };
     220             : 
     221             : const CSSEditUtils::CSSEquivTable ttEquivTable[] = {
     222             :   { CSSEditUtils::eCSSEditableProperty_font_family, ProcessDefaultValue, "monospace", nullptr, nullptr, true, false },
     223             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     224             : };
     225             : 
     226             : const CSSEditUtils::CSSEquivTable fontColorEquivTable[] = {
     227             :   { CSSEditUtils::eCSSEditableProperty_color, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     228             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     229             : };
     230             : 
     231             : const CSSEditUtils::CSSEquivTable fontFaceEquivTable[] = {
     232             :   { CSSEditUtils::eCSSEditableProperty_font_family, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     233             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     234             : };
     235             : 
     236             : const CSSEditUtils::CSSEquivTable bgcolorEquivTable[] = {
     237             :   { CSSEditUtils::eCSSEditableProperty_background_color, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     238             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     239             : };
     240             : 
     241             : const CSSEditUtils::CSSEquivTable backgroundImageEquivTable[] = {
     242             :   { CSSEditUtils::eCSSEditableProperty_background_image, ProcessExtendedValue, nullptr, "url(", ")", true, true },
     243             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     244             : };
     245             : 
     246             : const CSSEditUtils::CSSEquivTable textColorEquivTable[] = {
     247             :   { CSSEditUtils::eCSSEditableProperty_color, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     248             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     249             : };
     250             : 
     251             : const CSSEditUtils::CSSEquivTable borderEquivTable[] = {
     252             :   { CSSEditUtils::eCSSEditableProperty_border, ProcessExtendedValue, nullptr, nullptr, "px solid", true, false },
     253             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     254             : };
     255             : 
     256             : const CSSEditUtils::CSSEquivTable textAlignEquivTable[] = {
     257             :   { CSSEditUtils::eCSSEditableProperty_text_align, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     258             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     259             : };
     260             : 
     261             : const CSSEditUtils::CSSEquivTable captionAlignEquivTable[] = {
     262             :   { CSSEditUtils::eCSSEditableProperty_caption_side, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     263             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     264             : };
     265             : 
     266             : const CSSEditUtils::CSSEquivTable verticalAlignEquivTable[] = {
     267             :   { CSSEditUtils::eCSSEditableProperty_vertical_align, ProcessSameValue, nullptr, nullptr, nullptr, true, false },
     268             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     269             : };
     270             : 
     271             : const CSSEditUtils::CSSEquivTable nowrapEquivTable[] = {
     272             :   { CSSEditUtils::eCSSEditableProperty_whitespace, ProcessDefaultValue, "nowrap", nullptr, nullptr, true, false },
     273             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     274             : };
     275             : 
     276             : const CSSEditUtils::CSSEquivTable widthEquivTable[] = {
     277             :   { CSSEditUtils::eCSSEditableProperty_width, ProcessLengthValue, nullptr, nullptr, nullptr, true, false },
     278             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     279             : };
     280             : 
     281             : const CSSEditUtils::CSSEquivTable heightEquivTable[] = {
     282             :   { CSSEditUtils::eCSSEditableProperty_height, ProcessLengthValue, nullptr, nullptr, nullptr, true, false },
     283             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     284             : };
     285             : 
     286             : const CSSEditUtils::CSSEquivTable listStyleTypeEquivTable[] = {
     287             :   { CSSEditUtils::eCSSEditableProperty_list_style_type, ProcessListStyleTypeValue, nullptr, nullptr, nullptr, true, true },
     288             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     289             : };
     290             : 
     291             : const CSSEditUtils::CSSEquivTable tableAlignEquivTable[] = {
     292             :   { CSSEditUtils::eCSSEditableProperty_text_align, ProcessDefaultValue, "left", nullptr, nullptr, false, false },
     293             :   { CSSEditUtils::eCSSEditableProperty_margin_left, ProcessMarginLeftValue, nullptr, nullptr, nullptr, true, false },
     294             :   { CSSEditUtils::eCSSEditableProperty_margin_right, ProcessMarginRightValue, nullptr, nullptr, nullptr, true, false },
     295             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     296             : };
     297             : 
     298             : const CSSEditUtils::CSSEquivTable hrAlignEquivTable[] = {
     299             :   { CSSEditUtils::eCSSEditableProperty_margin_left, ProcessMarginLeftValue, nullptr, nullptr, nullptr, true, false },
     300             :   { CSSEditUtils::eCSSEditableProperty_margin_right, ProcessMarginRightValue, nullptr, nullptr, nullptr, true, false },
     301             :   { CSSEditUtils::eCSSEditableProperty_NONE, 0 }
     302             : };
     303             : 
     304           0 : CSSEditUtils::CSSEditUtils(HTMLEditor* aHTMLEditor)
     305             :   : mHTMLEditor(aHTMLEditor)
     306           0 :   , mIsCSSPrefChecked(true)
     307             : {
     308             :   // let's retrieve the value of the "CSS editing" pref
     309           0 :   mIsCSSPrefChecked = Preferences::GetBool("editor.use_css", mIsCSSPrefChecked);
     310           0 : }
     311             : 
     312           0 : CSSEditUtils::~CSSEditUtils()
     313             : {
     314           0 : }
     315             : 
     316             : // Answers true if we have some CSS equivalence for the HTML style defined
     317             : // by aProperty and/or aAttribute for the node aNode
     318             : bool
     319           0 : CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
     320             :                                     nsIAtom* aProperty,
     321             :                                     const nsAString* aAttribute)
     322             : {
     323           0 :   nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
     324           0 :   return IsCSSEditableProperty(aNode, aProperty, attribute);
     325             : }
     326             : 
     327             : bool
     328           0 : CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
     329             :                                     nsIAtom* aProperty,
     330             :                                     nsIAtom* aAttribute)
     331             : {
     332           0 :   MOZ_ASSERT(aNode);
     333             : 
     334           0 :   nsINode* node = aNode;
     335             :   // we need an element node here
     336           0 :   if (node->NodeType() == nsIDOMNode::TEXT_NODE) {
     337           0 :     node = node->GetParentNode();
     338           0 :     NS_ENSURE_TRUE(node, false);
     339             :   }
     340             : 
     341             :   // html inline styles B I TT U STRIKE and COLOR/FACE on FONT
     342           0 :   if (nsGkAtoms::b == aProperty ||
     343           0 :       nsGkAtoms::i == aProperty ||
     344           0 :       nsGkAtoms::tt == aProperty ||
     345           0 :       nsGkAtoms::u == aProperty ||
     346           0 :       nsGkAtoms::strike == aProperty ||
     347           0 :       (nsGkAtoms::font == aProperty && aAttribute &&
     348           0 :        (aAttribute == nsGkAtoms::color || aAttribute == nsGkAtoms::face))) {
     349           0 :     return true;
     350             :   }
     351             : 
     352             :   // ALIGN attribute on elements supporting it
     353           0 :   if (aAttribute == nsGkAtoms::align &&
     354           0 :       node->IsAnyOfHTMLElements(nsGkAtoms::div,
     355             :                                 nsGkAtoms::p,
     356             :                                 nsGkAtoms::h1,
     357             :                                 nsGkAtoms::h2,
     358             :                                 nsGkAtoms::h3,
     359             :                                 nsGkAtoms::h4,
     360             :                                 nsGkAtoms::h5,
     361             :                                 nsGkAtoms::h6,
     362             :                                 nsGkAtoms::td,
     363             :                                 nsGkAtoms::th,
     364             :                                 nsGkAtoms::table,
     365             :                                 nsGkAtoms::hr,
     366             :                                 // For the above, why not use
     367             :                                 // HTMLEditUtils::SupportsAlignAttr?
     368             :                                 // It also checks for tbody, tfoot, thead.
     369             :                                 // Let's add the following elements here even
     370             :                                 // if "align" has a different meaning for them
     371             :                                 nsGkAtoms::legend,
     372             :                                 nsGkAtoms::caption)) {
     373           0 :     return true;
     374             :   }
     375             : 
     376           0 :   if (aAttribute == nsGkAtoms::valign &&
     377           0 :       node->IsAnyOfHTMLElements(nsGkAtoms::col,
     378             :                                 nsGkAtoms::colgroup,
     379             :                                 nsGkAtoms::tbody,
     380             :                                 nsGkAtoms::td,
     381             :                                 nsGkAtoms::th,
     382             :                                 nsGkAtoms::tfoot,
     383             :                                 nsGkAtoms::thead,
     384             :                                 nsGkAtoms::tr)) {
     385           0 :     return true;
     386             :   }
     387             : 
     388             :   // attributes TEXT, BACKGROUND and BGCOLOR on BODY
     389           0 :   if (node->IsHTMLElement(nsGkAtoms::body) &&
     390           0 :       (aAttribute == nsGkAtoms::text || aAttribute == nsGkAtoms::background ||
     391           0 :        aAttribute == nsGkAtoms::bgcolor)) {
     392           0 :     return true;
     393             :   }
     394             : 
     395             :   // attribute BGCOLOR on other elements
     396           0 :   if (aAttribute == nsGkAtoms::bgcolor) {
     397           0 :     return true;
     398             :   }
     399             : 
     400             :   // attributes HEIGHT, WIDTH and NOWRAP on TD and TH
     401           0 :   if (node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) &&
     402           0 :       (aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width ||
     403           0 :        aAttribute == nsGkAtoms::nowrap)) {
     404           0 :     return true;
     405             :   }
     406             : 
     407             :   // attributes HEIGHT and WIDTH on TABLE
     408           0 :   if (node->IsHTMLElement(nsGkAtoms::table) &&
     409           0 :       (aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width)) {
     410           0 :     return true;
     411             :   }
     412             : 
     413             :   // attributes SIZE and WIDTH on HR
     414           0 :   if (node->IsHTMLElement(nsGkAtoms::hr) &&
     415           0 :       (aAttribute == nsGkAtoms::size || aAttribute == nsGkAtoms::width)) {
     416           0 :     return true;
     417             :   }
     418             : 
     419             :   // attribute TYPE on OL UL LI
     420           0 :   if (node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul,
     421           0 :                                 nsGkAtoms::li) &&
     422           0 :       aAttribute == nsGkAtoms::type) {
     423           0 :     return true;
     424             :   }
     425             : 
     426           0 :   if (node->IsHTMLElement(nsGkAtoms::img) &&
     427           0 :       (aAttribute == nsGkAtoms::border || aAttribute == nsGkAtoms::width ||
     428           0 :        aAttribute == nsGkAtoms::height)) {
     429           0 :     return true;
     430             :   }
     431             : 
     432             :   // other elements that we can align using CSS even if they
     433             :   // can't carry the html ALIGN attribute
     434           0 :   if (aAttribute == nsGkAtoms::align &&
     435           0 :       node->IsAnyOfHTMLElements(nsGkAtoms::ul,
     436             :                                 nsGkAtoms::ol,
     437             :                                 nsGkAtoms::dl,
     438             :                                 nsGkAtoms::li,
     439             :                                 nsGkAtoms::dd,
     440             :                                 nsGkAtoms::dt,
     441             :                                 nsGkAtoms::address,
     442             :                                 nsGkAtoms::pre)) {
     443           0 :     return true;
     444             :   }
     445             : 
     446           0 :   return false;
     447             : }
     448             : 
     449             : // The lowest level above the transaction; adds the CSS declaration
     450             : // "aProperty : aValue" to the inline styles carried by aElement
     451             : nsresult
     452           0 : CSSEditUtils::SetCSSProperty(Element& aElement,
     453             :                              nsIAtom& aProperty,
     454             :                              const nsAString& aValue,
     455             :                              bool aSuppressTxn)
     456             : {
     457             :   RefPtr<ChangeStyleTransaction> transaction =
     458           0 :     CreateCSSPropertyTxn(aElement, aProperty, aValue,
     459           0 :                          ChangeStyleTransaction::eSet);
     460           0 :   if (aSuppressTxn) {
     461           0 :     return transaction->DoTransaction();
     462             :   }
     463           0 :   return mHTMLEditor->DoTransaction(transaction);
     464             : }
     465             : 
     466             : nsresult
     467           0 : CSSEditUtils::SetCSSPropertyPixels(Element& aElement,
     468             :                                    nsIAtom& aProperty,
     469             :                                    int32_t aIntValue)
     470             : {
     471           0 :   nsAutoString s;
     472           0 :   s.AppendInt(aIntValue);
     473           0 :   return SetCSSProperty(aElement, aProperty, s + NS_LITERAL_STRING("px"),
     474           0 :                         /* suppress txn */ false);
     475             : }
     476             : 
     477             : // The lowest level above the transaction; removes the value aValue from the
     478             : // list of values specified for the CSS property aProperty, or totally remove
     479             : // the declaration if this property accepts only one value
     480             : nsresult
     481           0 : CSSEditUtils::RemoveCSSProperty(Element& aElement,
     482             :                                 nsIAtom& aProperty,
     483             :                                 const nsAString& aValue,
     484             :                                 bool aSuppressTxn)
     485             : {
     486             :   RefPtr<ChangeStyleTransaction> transaction =
     487           0 :     CreateCSSPropertyTxn(aElement, aProperty, aValue,
     488           0 :                          ChangeStyleTransaction::eRemove);
     489           0 :   if (aSuppressTxn) {
     490           0 :     return transaction->DoTransaction();
     491             :   }
     492           0 :   return mHTMLEditor->DoTransaction(transaction);
     493             : }
     494             : 
     495             : already_AddRefed<ChangeStyleTransaction>
     496           0 : CSSEditUtils::CreateCSSPropertyTxn(
     497             :                 Element& aElement,
     498             :                 nsIAtom& aAttribute,
     499             :                 const nsAString& aValue,
     500             :                 ChangeStyleTransaction::EChangeType aChangeType)
     501             : {
     502             :   RefPtr<ChangeStyleTransaction> transaction =
     503           0 :     new ChangeStyleTransaction(aElement, aAttribute, aValue, aChangeType);
     504           0 :   return transaction.forget();
     505             : }
     506             : 
     507             : nsresult
     508           0 : CSSEditUtils::GetSpecifiedProperty(nsINode& aNode,
     509             :                                    nsIAtom& aProperty,
     510             :                                    nsAString& aValue)
     511             : {
     512           0 :   return GetCSSInlinePropertyBase(&aNode, &aProperty, aValue, eSpecified);
     513             : }
     514             : 
     515             : nsresult
     516           0 : CSSEditUtils::GetComputedProperty(nsINode& aNode,
     517             :                                   nsIAtom& aProperty,
     518             :                                   nsAString& aValue)
     519             : {
     520           0 :   return GetCSSInlinePropertyBase(&aNode, &aProperty, aValue, eComputed);
     521             : }
     522             : 
     523             : nsresult
     524           0 : CSSEditUtils::GetCSSInlinePropertyBase(nsINode* aNode,
     525             :                                        nsIAtom* aProperty,
     526             :                                        nsAString& aValue,
     527             :                                        StyleType aStyleType)
     528             : {
     529           0 :   MOZ_ASSERT(aNode && aProperty);
     530           0 :   aValue.Truncate();
     531             : 
     532           0 :   nsCOMPtr<Element> element = GetElementContainerOrSelf(aNode);
     533           0 :   NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
     534             : 
     535           0 :   if (aStyleType == eComputed) {
     536             :     // Get the all the computed css styles attached to the element node
     537           0 :     RefPtr<nsComputedDOMStyle> cssDecl = GetComputedStyle(element);
     538           0 :     NS_ENSURE_STATE(cssDecl);
     539             : 
     540             :     // from these declarations, get the one we want and that one only
     541           0 :     MOZ_ALWAYS_SUCCEEDS(
     542             :       cssDecl->GetPropertyValue(nsDependentAtomString(aProperty), aValue));
     543             : 
     544           0 :     return NS_OK;
     545             :   }
     546             : 
     547           0 :   MOZ_ASSERT(aStyleType == eSpecified);
     548           0 :   RefPtr<DeclarationBlock> decl = element->GetInlineStyleDeclaration();
     549           0 :   if (!decl) {
     550           0 :     return NS_OK;
     551             :   }
     552             : 
     553             :   nsCSSPropertyID prop =
     554           0 :     nsCSSProps::LookupProperty(nsDependentAtomString(aProperty),
     555           0 :                                CSSEnabledState::eForAllContent);
     556           0 :   MOZ_ASSERT(prop != eCSSProperty_UNKNOWN);
     557             : 
     558           0 :   decl->GetPropertyValueByID(prop, aValue);
     559             : 
     560           0 :   return NS_OK;
     561             : }
     562             : 
     563             : already_AddRefed<nsComputedDOMStyle>
     564           0 : CSSEditUtils::GetComputedStyle(Element* aElement)
     565             : {
     566           0 :   MOZ_ASSERT(aElement);
     567             : 
     568           0 :   nsIDocument* doc = aElement->GetUncomposedDoc();
     569           0 :   NS_ENSURE_TRUE(doc, nullptr);
     570             : 
     571           0 :   nsIPresShell* presShell = doc->GetShell();
     572           0 :   NS_ENSURE_TRUE(presShell, nullptr);
     573             : 
     574             :   RefPtr<nsComputedDOMStyle> style =
     575           0 :     NS_NewComputedDOMStyle(aElement, EmptyString(), presShell);
     576             : 
     577           0 :   return style.forget();
     578             : }
     579             : 
     580             : // remove the CSS style "aProperty : aPropertyValue" and possibly remove the whole node
     581             : // if it is a span and if its only attribute is _moz_dirty
     582             : nsresult
     583           0 : CSSEditUtils::RemoveCSSInlineStyle(nsINode& aNode,
     584             :                                    nsIAtom* aProperty,
     585             :                                    const nsAString& aPropertyValue)
     586             : {
     587           0 :   RefPtr<Element> element = aNode.AsElement();
     588           0 :   NS_ENSURE_STATE(element);
     589             : 
     590             :   // remove the property from the style attribute
     591           0 :   nsresult rv = RemoveCSSProperty(*element, *aProperty, aPropertyValue);
     592           0 :   NS_ENSURE_SUCCESS(rv, rv);
     593             : 
     594           0 :   if (!element->IsHTMLElement(nsGkAtoms::span) ||
     595           0 :       HTMLEditor::HasAttributes(element)) {
     596           0 :     return NS_OK;
     597             :   }
     598             : 
     599           0 :   return mHTMLEditor->RemoveContainer(element);
     600             : }
     601             : 
     602             : // Answers true if the property can be removed by setting a "none" CSS value
     603             : // on a node
     604             : bool
     605           0 : CSSEditUtils::IsCSSInvertible(nsIAtom& aProperty,
     606             :                               const nsAString* aAttribute)
     607             : {
     608           0 :   return nsGkAtoms::b == &aProperty;
     609             : }
     610             : 
     611             : // Get the default browser background color if we need it for GetCSSBackgroundColorState
     612             : void
     613           0 : CSSEditUtils::GetDefaultBackgroundColor(nsAString& aColor)
     614             : {
     615           0 :   if (Preferences::GetBool("editor.use_custom_colors", false)) {
     616           0 :     nsresult rv = Preferences::GetString("editor.background_color", &aColor);
     617             :     // XXX Why don't you validate the pref value?
     618           0 :     if (NS_FAILED(rv)) {
     619           0 :       NS_WARNING("failed to get editor.background_color");
     620           0 :       aColor.AssignLiteral("#ffffff");  // Default to white
     621             :     }
     622           0 :     return;
     623             :   }
     624             : 
     625           0 :   if (Preferences::GetBool("browser.display.use_system_colors", false)) {
     626           0 :     return;
     627             :   }
     628             : 
     629             :   nsresult rv =
     630           0 :     Preferences::GetString("browser.display.background_color", &aColor);
     631             :   // XXX Why don't you validate the pref value?
     632           0 :   if (NS_FAILED(rv)) {
     633           0 :     NS_WARNING("failed to get browser.display.background_color");
     634           0 :     aColor.AssignLiteral("#ffffff");  // Default to white
     635             :   }
     636             : }
     637             : 
     638             : // Get the default length unit used for CSS Indent/Outdent
     639             : void
     640           0 : CSSEditUtils::GetDefaultLengthUnit(nsAString& aLengthUnit)
     641             : {
     642             :   nsresult rv =
     643           0 :     Preferences::GetString("editor.css.default_length_unit", &aLengthUnit);
     644             :   // XXX Why don't you validate the pref value?
     645           0 :   if (NS_FAILED(rv)) {
     646           0 :     aLengthUnit.AssignLiteral("px");
     647             :   }
     648           0 : }
     649             : 
     650             : // Unfortunately, CSSStyleDeclaration::GetPropertyCSSValue is not yet
     651             : // implemented... We need then a way to determine the number part and the unit
     652             : // from aString, aString being the result of a GetPropertyValue query...
     653             : void
     654           0 : CSSEditUtils::ParseLength(const nsAString& aString,
     655             :                           float* aValue,
     656             :                           nsIAtom** aUnit)
     657             : {
     658           0 :   if (aString.IsEmpty()) {
     659           0 :     *aValue = 0;
     660           0 :     *aUnit = NS_Atomize(aString).take();
     661           0 :     return;
     662             :   }
     663             : 
     664           0 :   nsAString::const_iterator iter;
     665           0 :   aString.BeginReading(iter);
     666             : 
     667           0 :   float a = 10.0f , b = 1.0f, value = 0;
     668           0 :   int8_t sign = 1;
     669           0 :   int32_t i = 0, j = aString.Length();
     670             :   char16_t c;
     671           0 :   bool floatingPointFound = false;
     672           0 :   c = *iter;
     673           0 :   if (char16_t('-') == c) { sign = -1; iter++; i++; }
     674           0 :   else if (char16_t('+') == c) { iter++; i++; }
     675           0 :   while (i < j) {
     676           0 :     c = *iter;
     677           0 :     if ((char16_t('0') == c) ||
     678           0 :         (char16_t('1') == c) ||
     679           0 :         (char16_t('2') == c) ||
     680           0 :         (char16_t('3') == c) ||
     681           0 :         (char16_t('4') == c) ||
     682           0 :         (char16_t('5') == c) ||
     683           0 :         (char16_t('6') == c) ||
     684           0 :         (char16_t('7') == c) ||
     685           0 :         (char16_t('8') == c) ||
     686             :         (char16_t('9') == c)) {
     687           0 :       value = (value * a) + (b * (c - char16_t('0')));
     688           0 :       b = b / 10 * a;
     689             :     }
     690           0 :     else if (!floatingPointFound && (char16_t('.') == c)) {
     691           0 :       floatingPointFound = true;
     692           0 :       a = 1.0f; b = 0.1f;
     693             :     }
     694             :     else break;
     695           0 :     iter++;
     696           0 :     i++;
     697             :   }
     698           0 :   *aValue = value * sign;
     699           0 :   *aUnit = NS_Atomize(StringTail(aString, j-i)).take();
     700             : }
     701             : 
     702             : void
     703           0 : CSSEditUtils::GetCSSPropertyAtom(nsCSSEditableProperty aProperty,
     704             :                                  nsIAtom** aAtom)
     705             : {
     706           0 :   *aAtom = nullptr;
     707           0 :   switch (aProperty) {
     708             :     case eCSSEditableProperty_background_color:
     709           0 :       *aAtom = nsGkAtoms::backgroundColor;
     710           0 :       break;
     711             :     case eCSSEditableProperty_background_image:
     712           0 :       *aAtom = nsGkAtoms::background_image;
     713           0 :       break;
     714             :     case eCSSEditableProperty_border:
     715           0 :       *aAtom = nsGkAtoms::border;
     716           0 :       break;
     717             :     case eCSSEditableProperty_caption_side:
     718           0 :       *aAtom = nsGkAtoms::caption_side;
     719           0 :       break;
     720             :     case eCSSEditableProperty_color:
     721           0 :       *aAtom = nsGkAtoms::color;
     722           0 :       break;
     723             :     case eCSSEditableProperty_float:
     724           0 :       *aAtom = nsGkAtoms::_float;
     725           0 :       break;
     726             :     case eCSSEditableProperty_font_family:
     727           0 :       *aAtom = nsGkAtoms::font_family;
     728           0 :       break;
     729             :     case eCSSEditableProperty_font_size:
     730           0 :       *aAtom = nsGkAtoms::font_size;
     731           0 :       break;
     732             :     case eCSSEditableProperty_font_style:
     733           0 :       *aAtom = nsGkAtoms::font_style;
     734           0 :       break;
     735             :     case eCSSEditableProperty_font_weight:
     736           0 :       *aAtom = nsGkAtoms::fontWeight;
     737           0 :       break;
     738             :     case eCSSEditableProperty_height:
     739           0 :       *aAtom = nsGkAtoms::height;
     740           0 :       break;
     741             :     case eCSSEditableProperty_list_style_type:
     742           0 :       *aAtom = nsGkAtoms::list_style_type;
     743           0 :       break;
     744             :     case eCSSEditableProperty_margin_left:
     745           0 :       *aAtom = nsGkAtoms::marginLeft;
     746           0 :       break;
     747             :     case eCSSEditableProperty_margin_right:
     748           0 :       *aAtom = nsGkAtoms::marginRight;
     749           0 :       break;
     750             :     case eCSSEditableProperty_text_align:
     751           0 :       *aAtom = nsGkAtoms::textAlign;
     752           0 :       break;
     753             :     case eCSSEditableProperty_text_decoration:
     754           0 :       *aAtom = nsGkAtoms::text_decoration;
     755           0 :       break;
     756             :     case eCSSEditableProperty_vertical_align:
     757           0 :       *aAtom = nsGkAtoms::vertical_align;
     758           0 :       break;
     759             :     case eCSSEditableProperty_whitespace:
     760           0 :       *aAtom = nsGkAtoms::white_space;
     761           0 :       break;
     762             :     case eCSSEditableProperty_width:
     763           0 :       *aAtom = nsGkAtoms::width;
     764           0 :       break;
     765             :     case eCSSEditableProperty_NONE:
     766             :       // intentionally empty
     767           0 :       break;
     768             :   }
     769           0 : }
     770             : 
     771             : // Populate aProperty and aValueArray with the CSS declarations equivalent to the
     772             : // value aValue according to the equivalence table aEquivTable
     773             : void
     774           0 : CSSEditUtils::BuildCSSDeclarations(nsTArray<nsIAtom*>& aPropertyArray,
     775             :                                    nsTArray<nsString>& aValueArray,
     776             :                                    const CSSEquivTable* aEquivTable,
     777             :                                    const nsAString* aValue,
     778             :                                    bool aGetOrRemoveRequest)
     779             : {
     780             :   // clear arrays
     781           0 :   aPropertyArray.Clear();
     782           0 :   aValueArray.Clear();
     783             : 
     784             :   // if we have an input value, let's use it
     785           0 :   nsAutoString value, lowerCasedValue;
     786           0 :   if (aValue) {
     787           0 :     value.Assign(*aValue);
     788           0 :     lowerCasedValue.Assign(*aValue);
     789           0 :     ToLowerCase(lowerCasedValue);
     790             :   }
     791             : 
     792           0 :   int8_t index = 0;
     793           0 :   nsCSSEditableProperty cssProperty = aEquivTable[index].cssProperty;
     794           0 :   while (cssProperty) {
     795           0 :     if (!aGetOrRemoveRequest|| aEquivTable[index].gettable) {
     796           0 :       nsAutoString cssValue, cssPropertyString;
     797             :       nsIAtom * cssPropertyAtom;
     798             :       // find the equivalent css value for the index-th property in
     799             :       // the equivalence table
     800           0 :       (*aEquivTable[index].processValueFunctor) ((!aGetOrRemoveRequest || aEquivTable[index].caseSensitiveValue) ? &value : &lowerCasedValue,
     801             :                                                  cssValue,
     802           0 :                                                  aEquivTable[index].defaultValue,
     803           0 :                                                  aEquivTable[index].prependValue,
     804           0 :                                                  aEquivTable[index].appendValue);
     805           0 :       GetCSSPropertyAtom(cssProperty, &cssPropertyAtom);
     806           0 :       aPropertyArray.AppendElement(cssPropertyAtom);
     807           0 :       aValueArray.AppendElement(cssValue);
     808             :     }
     809           0 :     index++;
     810           0 :     cssProperty = aEquivTable[index].cssProperty;
     811             :   }
     812           0 : }
     813             : 
     814             : // Populate cssPropertyArray and cssValueArray with the declarations equivalent
     815             : // to aHTMLProperty/aAttribute/aValue for the node aNode
     816             : void
     817           0 : CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
     818             :                 Element* aElement,
     819             :                 nsIAtom* aHTMLProperty,
     820             :                 nsIAtom* aAttribute,
     821             :                 const nsAString* aValue,
     822             :                 nsTArray<nsIAtom*>& cssPropertyArray,
     823             :                 nsTArray<nsString>& cssValueArray,
     824             :                 bool aGetOrRemoveRequest)
     825             : {
     826           0 :   MOZ_ASSERT(aElement);
     827           0 :   const CSSEditUtils::CSSEquivTable* equivTable = nullptr;
     828             : 
     829           0 :   if (nsGkAtoms::b == aHTMLProperty) {
     830           0 :     equivTable = boldEquivTable;
     831           0 :   } else if (nsGkAtoms::i == aHTMLProperty) {
     832           0 :     equivTable = italicEquivTable;
     833           0 :   } else if (nsGkAtoms::u == aHTMLProperty) {
     834           0 :     equivTable = underlineEquivTable;
     835           0 :   } else if (nsGkAtoms::strike == aHTMLProperty) {
     836           0 :     equivTable = strikeEquivTable;
     837           0 :   } else if (nsGkAtoms::tt == aHTMLProperty) {
     838           0 :     equivTable = ttEquivTable;
     839           0 :   } else if (aAttribute) {
     840           0 :     if (nsGkAtoms::font == aHTMLProperty && aAttribute == nsGkAtoms::color) {
     841           0 :       equivTable = fontColorEquivTable;
     842           0 :     } else if (nsGkAtoms::font == aHTMLProperty &&
     843           0 :                aAttribute == nsGkAtoms::face) {
     844           0 :       equivTable = fontFaceEquivTable;
     845           0 :     } else if (aAttribute == nsGkAtoms::bgcolor) {
     846           0 :       equivTable = bgcolorEquivTable;
     847           0 :     } else if (aAttribute == nsGkAtoms::background) {
     848           0 :       equivTable = backgroundImageEquivTable;
     849           0 :     } else if (aAttribute == nsGkAtoms::text) {
     850           0 :       equivTable = textColorEquivTable;
     851           0 :     } else if (aAttribute == nsGkAtoms::border) {
     852           0 :       equivTable = borderEquivTable;
     853           0 :     } else if (aAttribute == nsGkAtoms::align) {
     854           0 :       if (aElement->IsHTMLElement(nsGkAtoms::table)) {
     855           0 :         equivTable = tableAlignEquivTable;
     856           0 :       } else if (aElement->IsHTMLElement(nsGkAtoms::hr)) {
     857           0 :         equivTable = hrAlignEquivTable;
     858           0 :       } else if (aElement->IsAnyOfHTMLElements(nsGkAtoms::legend,
     859             :                                                nsGkAtoms::caption)) {
     860           0 :         equivTable = captionAlignEquivTable;
     861             :       } else {
     862           0 :         equivTable = textAlignEquivTable;
     863             :       }
     864           0 :     } else if (aAttribute == nsGkAtoms::valign) {
     865           0 :       equivTable = verticalAlignEquivTable;
     866           0 :     } else if (aAttribute == nsGkAtoms::nowrap) {
     867           0 :       equivTable = nowrapEquivTable;
     868           0 :     } else if (aAttribute == nsGkAtoms::width) {
     869           0 :       equivTable = widthEquivTable;
     870           0 :     } else if (aAttribute == nsGkAtoms::height ||
     871           0 :                (aElement->IsHTMLElement(nsGkAtoms::hr) &&
     872           0 :                 aAttribute == nsGkAtoms::size)) {
     873           0 :       equivTable = heightEquivTable;
     874           0 :     } else if (aAttribute == nsGkAtoms::type &&
     875           0 :                aElement->IsAnyOfHTMLElements(nsGkAtoms::ol,
     876             :                                              nsGkAtoms::ul,
     877             :                                              nsGkAtoms::li)) {
     878           0 :       equivTable = listStyleTypeEquivTable;
     879             :     }
     880             :   }
     881           0 :   if (equivTable) {
     882           0 :     BuildCSSDeclarations(cssPropertyArray, cssValueArray, equivTable,
     883           0 :                          aValue, aGetOrRemoveRequest);
     884             :   }
     885           0 : }
     886             : 
     887             : // Add to aNode the CSS inline style equivalent to HTMLProperty/aAttribute/
     888             : // aValue for the node, and return in aCount the number of CSS properties set
     889             : // by the call.  The Element version returns aCount instead.
     890             : int32_t
     891           0 : CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
     892             :                                           nsIAtom* aProperty,
     893             :                                           const nsAString* aAttribute,
     894             :                                           const nsAString* aValue,
     895             :                                           bool aSuppressTransaction)
     896             : {
     897           0 :   MOZ_ASSERT_IF(aAttribute, aValue);
     898             :   // This can only fail if SetCSSProperty fails, which should only happen if
     899             :   // something is pretty badly wrong.  In this case we assert so that hopefully
     900             :   // someone will notice, but there's nothing more sensible to do than just
     901             :   // return the count and carry on.
     902           0 :   nsCOMPtr<Element> element = do_QueryInterface(aNode);
     903           0 :   return SetCSSEquivalentToHTMLStyle(element,
     904             :                                      aProperty, aAttribute,
     905           0 :                                      aValue, aSuppressTransaction);
     906             : }
     907             : 
     908             : int32_t
     909           0 : CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
     910             :                                           nsIAtom* aHTMLProperty,
     911             :                                           const nsAString* aAttribute,
     912             :                                           const nsAString* aValue,
     913             :                                           bool aSuppressTransaction)
     914             : {
     915           0 :   nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
     916           0 :   return SetCSSEquivalentToHTMLStyle(aElement, aHTMLProperty, attribute,
     917           0 :                                      aValue, aSuppressTransaction);
     918             : }
     919             : 
     920             : int32_t
     921           0 : CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
     922             :                                           nsIAtom* aHTMLProperty,
     923             :                                           nsIAtom* aAttribute,
     924             :                                           const nsAString* aValue,
     925             :                                           bool aSuppressTransaction)
     926             : {
     927           0 :   MOZ_ASSERT(aElement);
     928             : 
     929           0 :   if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
     930           0 :     return 0;
     931             :   }
     932             : 
     933             :   // we can apply the styles only if the node is an element and if we have
     934             :   // an equivalence for the requested HTML style in this implementation
     935             : 
     936             :   // Find the CSS equivalence to the HTML style
     937           0 :   nsTArray<nsIAtom*> cssPropertyArray;
     938           0 :   nsTArray<nsString> cssValueArray;
     939             :   GenerateCSSDeclarationsFromHTMLStyle(aElement, aHTMLProperty, aAttribute,
     940             :                                        aValue, cssPropertyArray, cssValueArray,
     941           0 :                                        false);
     942             : 
     943             :   // set the individual CSS inline styles
     944           0 :   size_t count = cssPropertyArray.Length();
     945           0 :   for (size_t index = 0; index < count; index++) {
     946           0 :     nsresult rv = SetCSSProperty(*aElement, *cssPropertyArray[index],
     947           0 :                                  cssValueArray[index], aSuppressTransaction);
     948           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     949           0 :       return 0;
     950             :     }
     951             :   }
     952           0 :   return count;
     953             : }
     954             : 
     955             : // Remove from aNode the CSS inline style equivalent to HTMLProperty/aAttribute/aValue for the node
     956             : nsresult
     957           0 : CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
     958             :                                              nsIAtom* aHTMLProperty,
     959             :                                              const nsAString* aAttribute,
     960             :                                              const nsAString* aValue,
     961             :                                              bool aSuppressTransaction)
     962             : {
     963           0 :   nsCOMPtr<Element> element = do_QueryInterface(aNode);
     964           0 :   nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
     965             : 
     966           0 :   return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, attribute,
     967           0 :                                         aValue, aSuppressTransaction);
     968             : }
     969             : 
     970             : nsresult
     971           0 : CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement,
     972             :                                              nsIAtom* aHTMLProperty,
     973             :                                              nsIAtom* aAttribute,
     974             :                                              const nsAString* aValue,
     975             :                                              bool aSuppressTransaction)
     976             : {
     977           0 :   if (NS_WARN_IF(!aElement)) {
     978           0 :     return NS_OK;
     979             :   }
     980             : 
     981           0 :   if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
     982           0 :     return NS_OK;
     983             :   }
     984             : 
     985             :   // we can apply the styles only if the node is an element and if we have
     986             :   // an equivalence for the requested HTML style in this implementation
     987             : 
     988             :   // Find the CSS equivalence to the HTML style
     989           0 :   nsTArray<nsIAtom*> cssPropertyArray;
     990           0 :   nsTArray<nsString> cssValueArray;
     991             :   GenerateCSSDeclarationsFromHTMLStyle(aElement, aHTMLProperty, aAttribute,
     992             :                                        aValue, cssPropertyArray, cssValueArray,
     993           0 :                                        true);
     994             : 
     995             :   // remove the individual CSS inline styles
     996           0 :   int32_t count = cssPropertyArray.Length();
     997           0 :   for (int32_t index = 0; index < count; index++) {
     998           0 :     nsresult rv = RemoveCSSProperty(*aElement,
     999           0 :                                     *cssPropertyArray[index],
    1000           0 :                                     cssValueArray[index],
    1001           0 :                                     aSuppressTransaction);
    1002           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1003             :   }
    1004           0 :   return NS_OK;
    1005             : }
    1006             : 
    1007             : // returns in aValueString the list of values for the CSS equivalences to
    1008             : // the HTML style aHTMLProperty/aAttribute/aValueString for the node aNode;
    1009             : // the value of aStyleType controls the styles we retrieve : specified or
    1010             : // computed.
    1011             : nsresult
    1012           0 : CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
    1013             :                                                    nsIAtom* aHTMLProperty,
    1014             :                                                    nsIAtom* aAttribute,
    1015             :                                                    nsAString& aValueString,
    1016             :                                                    StyleType aStyleType)
    1017             : {
    1018           0 :   aValueString.Truncate();
    1019           0 :   nsCOMPtr<Element> theElement = GetElementContainerOrSelf(aNode);
    1020           0 :   NS_ENSURE_TRUE(theElement, NS_ERROR_NULL_POINTER);
    1021             : 
    1022           0 :   if (!theElement || !IsCSSEditableProperty(theElement, aHTMLProperty, aAttribute)) {
    1023           0 :     return NS_OK;
    1024             :   }
    1025             : 
    1026             :   // Yes, the requested HTML style has a CSS equivalence in this implementation
    1027           0 :   nsTArray<nsIAtom*> cssPropertyArray;
    1028           0 :   nsTArray<nsString> cssValueArray;
    1029             :   // get the CSS equivalence with last param true indicating we want only the
    1030             :   // "gettable" properties
    1031           0 :   GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute,
    1032             :                                        nullptr,
    1033           0 :                                        cssPropertyArray, cssValueArray, true);
    1034           0 :   int32_t count = cssPropertyArray.Length();
    1035           0 :   for (int32_t index = 0; index < count; index++) {
    1036           0 :     nsAutoString valueString;
    1037             :     // retrieve the specified/computed value of the property
    1038           0 :     nsresult rv = GetCSSInlinePropertyBase(theElement, cssPropertyArray[index],
    1039           0 :                                            valueString, aStyleType);
    1040           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1041             :     // append the value to aValueString (possibly with a leading whitespace)
    1042           0 :     if (index) {
    1043           0 :       aValueString.Append(char16_t(' '));
    1044             :     }
    1045           0 :     aValueString.Append(valueString);
    1046             :   }
    1047           0 :   return NS_OK;
    1048             : }
    1049             : 
    1050             : // Does the node aNode (or its parent, if it's not an element node) have a CSS
    1051             : // style equivalent to the HTML style aHTMLProperty/aHTMLAttribute/valueString?
    1052             : // The value of aStyleType controls the styles we retrieve: specified or
    1053             : // computed. The return value aIsSet is true if the CSS styles are set.
    1054             : //
    1055             : // The nsIContent variant returns aIsSet instead of using an out parameter, and
    1056             : // does not modify aValue.
    1057             : bool
    1058           0 : CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
    1059             :                                                   nsIAtom* aProperty,
    1060             :                                                   const nsAString* aAttribute,
    1061             :                                                   const nsAString& aValue,
    1062             :                                                   StyleType aStyleType)
    1063             : {
    1064             :   // Use aValue as only an in param, not in-out
    1065           0 :   nsAutoString value(aValue);
    1066             :   return IsCSSEquivalentToHTMLInlineStyleSet(aNode, aProperty, aAttribute,
    1067           0 :                                              value, aStyleType);
    1068             : }
    1069             : 
    1070             : bool
    1071           0 : CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
    1072             :                                                   nsIAtom* aProperty,
    1073             :                                                   const nsAString* aAttribute,
    1074             :                                                   nsAString& aValue,
    1075             :                                                   StyleType aStyleType)
    1076             : {
    1077           0 :   MOZ_ASSERT(aNode && aProperty);
    1078           0 :   nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
    1079           0 :   return IsCSSEquivalentToHTMLInlineStyleSet(aNode,
    1080             :                                              aProperty, attribute,
    1081           0 :                                              aValue, aStyleType);
    1082             : }
    1083             : 
    1084             : bool
    1085           0 : CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
    1086             :                                                   nsIAtom* aProperty,
    1087             :                                                   const nsAString* aAttribute,
    1088             :                                                   nsAString& aValue,
    1089             :                                                   StyleType aStyleType)
    1090             : {
    1091           0 :   MOZ_ASSERT(aNode && aProperty);
    1092           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    1093           0 :   nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
    1094           0 :   return IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, attribute,
    1095           0 :                                              aValue, aStyleType);
    1096             : }
    1097             : 
    1098             : bool
    1099           0 : CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
    1100             :                 nsINode* aNode,
    1101             :                 nsIAtom* aHTMLProperty,
    1102             :                 nsIAtom* aHTMLAttribute,
    1103             :                 nsAString& valueString,
    1104             :                 StyleType aStyleType)
    1105             : {
    1106           0 :   NS_ENSURE_TRUE(aNode, false);
    1107             : 
    1108           0 :   nsAutoString htmlValueString(valueString);
    1109           0 :   bool isSet = false;
    1110           0 :   do {
    1111           0 :     valueString.Assign(htmlValueString);
    1112             :     // get the value of the CSS equivalent styles
    1113             :     nsresult rv =
    1114             :       GetCSSEquivalentToHTMLInlineStyleSet(aNode, aHTMLProperty, aHTMLAttribute,
    1115           0 :                                            valueString, aStyleType);
    1116           0 :     NS_ENSURE_SUCCESS(rv, false);
    1117             : 
    1118             :     // early way out if we can
    1119           0 :     if (valueString.IsEmpty()) {
    1120           0 :       return isSet;
    1121             :     }
    1122             : 
    1123           0 :     if (nsGkAtoms::b == aHTMLProperty) {
    1124           0 :       if (valueString.EqualsLiteral("bold")) {
    1125           0 :         isSet = true;
    1126           0 :       } else if (valueString.EqualsLiteral("normal")) {
    1127           0 :         isSet = false;
    1128           0 :       } else if (valueString.EqualsLiteral("bolder")) {
    1129           0 :         isSet = true;
    1130           0 :         valueString.AssignLiteral("bold");
    1131             :       } else {
    1132           0 :         int32_t weight = 0;
    1133             :         nsresult errorCode;
    1134           0 :         nsAutoString value(valueString);
    1135           0 :         weight = value.ToInteger(&errorCode);
    1136           0 :         if (400 < weight) {
    1137           0 :           isSet = true;
    1138           0 :           valueString.AssignLiteral("bold");
    1139             :         } else {
    1140           0 :           isSet = false;
    1141           0 :           valueString.AssignLiteral("normal");
    1142             :         }
    1143             :       }
    1144           0 :     } else if (nsGkAtoms::i == aHTMLProperty) {
    1145           0 :       if (valueString.EqualsLiteral("italic") ||
    1146           0 :           valueString.EqualsLiteral("oblique")) {
    1147           0 :         isSet = true;
    1148             :       }
    1149           0 :     } else if (nsGkAtoms::u == aHTMLProperty) {
    1150           0 :       nsAutoString val;
    1151           0 :       val.AssignLiteral("underline");
    1152           0 :       isSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
    1153           0 :     } else if (nsGkAtoms::strike == aHTMLProperty) {
    1154           0 :       nsAutoString val;
    1155           0 :       val.AssignLiteral("line-through");
    1156           0 :       isSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
    1157           0 :     } else if ((nsGkAtoms::font == aHTMLProperty &&
    1158           0 :                 aHTMLAttribute == nsGkAtoms::color) ||
    1159           0 :                aHTMLAttribute == nsGkAtoms::bgcolor) {
    1160           0 :       if (htmlValueString.IsEmpty()) {
    1161           0 :         isSet = true;
    1162             :       } else {
    1163             :         nscolor rgba;
    1164           0 :         nsAutoString subStr;
    1165           0 :         htmlValueString.Right(subStr, htmlValueString.Length() - 1);
    1166           0 :         if (NS_ColorNameToRGB(htmlValueString, &rgba) ||
    1167           0 :             NS_HexToRGBA(subStr, nsHexColorType::NoAlpha, &rgba)) {
    1168           0 :           nsAutoString htmlColor, tmpStr;
    1169             : 
    1170           0 :           if (NS_GET_A(rgba) != 255) {
    1171             :             // This should only be hit by the "transparent" keyword, which
    1172             :             // currently serializes to "transparent" (not "rgba(0, 0, 0, 0)").
    1173           0 :             MOZ_ASSERT(NS_GET_R(rgba) == 0 && NS_GET_G(rgba) == 0 &&
    1174             :                        NS_GET_B(rgba) == 0 && NS_GET_A(rgba) == 0);
    1175           0 :             htmlColor.AppendLiteral("transparent");
    1176             :           } else {
    1177           0 :             htmlColor.AppendLiteral("rgb(");
    1178             : 
    1179           0 :             NS_NAMED_LITERAL_STRING(comma, ", ");
    1180             : 
    1181           0 :             tmpStr.AppendInt(NS_GET_R(rgba), 10);
    1182           0 :             htmlColor.Append(tmpStr + comma);
    1183             : 
    1184           0 :             tmpStr.Truncate();
    1185           0 :             tmpStr.AppendInt(NS_GET_G(rgba), 10);
    1186           0 :             htmlColor.Append(tmpStr + comma);
    1187             : 
    1188           0 :             tmpStr.Truncate();
    1189           0 :             tmpStr.AppendInt(NS_GET_B(rgba), 10);
    1190           0 :             htmlColor.Append(tmpStr);
    1191             : 
    1192           0 :             htmlColor.Append(char16_t(')'));
    1193             :           }
    1194             : 
    1195           0 :           isSet = htmlColor.Equals(valueString,
    1196           0 :                                    nsCaseInsensitiveStringComparator());
    1197             :         } else {
    1198           0 :           isSet = htmlValueString.Equals(valueString,
    1199           0 :                                          nsCaseInsensitiveStringComparator());
    1200             :         }
    1201           0 :       }
    1202           0 :     } else if (nsGkAtoms::tt == aHTMLProperty) {
    1203           0 :       isSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace"));
    1204           0 :     } else if (nsGkAtoms::font == aHTMLProperty && aHTMLAttribute &&
    1205           0 :                aHTMLAttribute == nsGkAtoms::face) {
    1206           0 :       if (!htmlValueString.IsEmpty()) {
    1207           0 :         const char16_t commaSpace[] = { char16_t(','), char16_t(' '), 0 };
    1208           0 :         const char16_t comma[] = { char16_t(','), 0 };
    1209           0 :         htmlValueString.ReplaceSubstring(commaSpace, comma);
    1210           0 :         nsAutoString valueStringNorm(valueString);
    1211           0 :         valueStringNorm.ReplaceSubstring(commaSpace, comma);
    1212             :         isSet = htmlValueString.Equals(valueStringNorm,
    1213           0 :                                        nsCaseInsensitiveStringComparator());
    1214             :       } else {
    1215           0 :         isSet = true;
    1216             :       }
    1217           0 :       return isSet;
    1218           0 :     } else if (aHTMLAttribute == nsGkAtoms::align) {
    1219           0 :       isSet = true;
    1220             :     } else {
    1221           0 :       return false;
    1222             :     }
    1223             : 
    1224           0 :     if (!htmlValueString.IsEmpty() &&
    1225           0 :         htmlValueString.Equals(valueString,
    1226           0 :                                nsCaseInsensitiveStringComparator())) {
    1227           0 :       isSet = true;
    1228             :     }
    1229             : 
    1230           0 :     if (htmlValueString.EqualsLiteral("-moz-editor-invert-value")) {
    1231           0 :       isSet = !isSet;
    1232             :     }
    1233             : 
    1234           0 :     if (nsGkAtoms::u == aHTMLProperty || nsGkAtoms::strike == aHTMLProperty) {
    1235             :       // unfortunately, the value of the text-decoration property is not inherited.
    1236             :       // that means that we have to look at ancestors of node to see if they are underlined
    1237           0 :       aNode = aNode->GetParentElement(); // set to null if it's not a dom element
    1238             :     }
    1239           0 :   } while ((nsGkAtoms::u == aHTMLProperty ||
    1240           0 :             nsGkAtoms::strike == aHTMLProperty) && !isSet && aNode);
    1241           0 :   return isSet;
    1242             : }
    1243             : 
    1244             : bool
    1245           0 : CSSEditUtils::HaveCSSEquivalentStyles(
    1246             :                 nsINode& aNode,
    1247             :                 nsIAtom* aHTMLProperty,
    1248             :                 nsIAtom* aHTMLAttribute,
    1249             :                 StyleType aStyleType)
    1250             : {
    1251           0 :   nsAutoString valueString;
    1252           0 :   nsCOMPtr<nsINode> node = &aNode;
    1253           0 :   do {
    1254             :     // get the value of the CSS equivalent styles
    1255             :     nsresult rv =
    1256           0 :       GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute,
    1257           0 :                                            valueString, aStyleType);
    1258           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1259           0 :       return false;
    1260             :     }
    1261             : 
    1262           0 :     if (!valueString.IsEmpty()) {
    1263           0 :       return true;
    1264             :     }
    1265             : 
    1266           0 :     if (nsGkAtoms::u != aHTMLProperty && nsGkAtoms::strike != aHTMLProperty) {
    1267           0 :       return false;
    1268             :     }
    1269             : 
    1270             :     // unfortunately, the value of the text-decoration property is not
    1271             :     // inherited.
    1272             :     // that means that we have to look at ancestors of node to see if they
    1273             :     // are underlined
    1274             : 
    1275             :     // set to null if it's not a dom element
    1276           0 :     node = node->GetParentElement();
    1277             :   } while (node);
    1278             : 
    1279           0 :   return false;
    1280             : }
    1281             : 
    1282             : void
    1283           0 : CSSEditUtils::SetCSSEnabled(bool aIsCSSPrefChecked)
    1284             : {
    1285           0 :   mIsCSSPrefChecked = aIsCSSPrefChecked;
    1286           0 : }
    1287             : 
    1288             : bool
    1289           0 : CSSEditUtils::IsCSSPrefChecked()
    1290             : {
    1291           0 :   return mIsCSSPrefChecked ;
    1292             : }
    1293             : 
    1294             : // ElementsSameStyle compares two elements and checks if they have the same
    1295             : // specified CSS declarations in the STYLE attribute
    1296             : // The answer is always negative if at least one of them carries an ID or a class
    1297             : bool
    1298           0 : CSSEditUtils::ElementsSameStyle(nsIDOMNode* aFirstNode,
    1299             :                                 nsIDOMNode* aSecondNode)
    1300             : {
    1301           0 :   nsCOMPtr<Element> firstElement  = do_QueryInterface(aFirstNode);
    1302           0 :   nsCOMPtr<Element> secondElement = do_QueryInterface(aSecondNode);
    1303             : 
    1304           0 :   NS_ASSERTION((firstElement && secondElement), "Non element nodes passed to ElementsSameStyle.");
    1305           0 :   NS_ENSURE_TRUE(firstElement, false);
    1306           0 :   NS_ENSURE_TRUE(secondElement, false);
    1307             : 
    1308           0 :   return ElementsSameStyle(firstElement, secondElement);
    1309             : }
    1310             : 
    1311             : bool
    1312           0 : CSSEditUtils::ElementsSameStyle(Element* aFirstElement,
    1313             :                                 Element* aSecondElement)
    1314             : {
    1315           0 :   MOZ_ASSERT(aFirstElement);
    1316           0 :   MOZ_ASSERT(aSecondElement);
    1317             : 
    1318           0 :   if (aFirstElement->HasAttr(kNameSpaceID_None, nsGkAtoms::id) ||
    1319           0 :       aSecondElement->HasAttr(kNameSpaceID_None, nsGkAtoms::id)) {
    1320             :     // at least one of the spans carries an ID ; suspect a CSS rule applies to it and
    1321             :     // refuse to merge the nodes
    1322           0 :     return false;
    1323             :   }
    1324             : 
    1325           0 :   nsAutoString firstClass, secondClass;
    1326           0 :   bool isFirstClassSet = aFirstElement->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, firstClass);
    1327           0 :   bool isSecondClassSet = aSecondElement->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, secondClass);
    1328           0 :   if (isFirstClassSet && isSecondClassSet) {
    1329             :     // both spans carry a class, let's compare them
    1330           0 :     if (!firstClass.Equals(secondClass)) {
    1331             :       // WARNING : technically, the comparison just above is questionable :
    1332             :       // from a pure HTML/CSS point of view class="a b" is NOT the same than
    1333             :       // class="b a" because a CSS rule could test the exact value of the class
    1334             :       // attribute to be "a b" for instance ; from a user's point of view, a
    1335             :       // wysiwyg editor should probably NOT make any difference. CSS people
    1336             :       // need to discuss this issue before any modification.
    1337           0 :       return false;
    1338             :     }
    1339           0 :   } else if (isFirstClassSet || isSecondClassSet) {
    1340             :     // one span only carries a class, early way out
    1341           0 :     return false;
    1342             :   }
    1343             : 
    1344           0 :   nsCOMPtr<nsIDOMCSSStyleDeclaration> firstCSSDecl, secondCSSDecl;
    1345             :   uint32_t firstLength, secondLength;
    1346           0 :   nsresult rv = GetInlineStyles(aFirstElement,  getter_AddRefs(firstCSSDecl),  &firstLength);
    1347           0 :   if (NS_FAILED(rv) || !firstCSSDecl) {
    1348           0 :     return false;
    1349             :   }
    1350           0 :   rv = GetInlineStyles(aSecondElement, getter_AddRefs(secondCSSDecl), &secondLength);
    1351           0 :   if (NS_FAILED(rv) || !secondCSSDecl) {
    1352           0 :     return false;
    1353             :   }
    1354             : 
    1355           0 :   if (firstLength != secondLength) {
    1356             :     // early way out if we can
    1357           0 :     return false;
    1358             :   }
    1359             : 
    1360           0 :   if (!firstLength) {
    1361             :     // no inline style !
    1362           0 :     return true;
    1363             :   }
    1364             : 
    1365           0 :   nsAutoString propertyNameString;
    1366           0 :   nsAutoString firstValue, secondValue;
    1367           0 :   for (uint32_t i = 0; i < firstLength; i++) {
    1368           0 :     firstCSSDecl->Item(i, propertyNameString);
    1369           0 :     firstCSSDecl->GetPropertyValue(propertyNameString, firstValue);
    1370           0 :     secondCSSDecl->GetPropertyValue(propertyNameString, secondValue);
    1371           0 :     if (!firstValue.Equals(secondValue)) {
    1372           0 :       return false;
    1373             :     }
    1374             :   }
    1375           0 :   for (uint32_t i = 0; i < secondLength; i++) {
    1376           0 :     secondCSSDecl->Item(i, propertyNameString);
    1377           0 :     secondCSSDecl->GetPropertyValue(propertyNameString, secondValue);
    1378           0 :     firstCSSDecl->GetPropertyValue(propertyNameString, firstValue);
    1379           0 :     if (!firstValue.Equals(secondValue)) {
    1380           0 :       return false;
    1381             :     }
    1382             :   }
    1383             : 
    1384           0 :   return true;
    1385             : }
    1386             : 
    1387             : nsresult
    1388           0 : CSSEditUtils::GetInlineStyles(Element* aElement,
    1389             :                               nsIDOMCSSStyleDeclaration** aCssDecl,
    1390             :                               uint32_t* aLength)
    1391             : {
    1392           0 :   return GetInlineStyles(static_cast<nsISupports*>(aElement), aCssDecl, aLength);
    1393             : }
    1394             : 
    1395             : nsresult
    1396           0 : CSSEditUtils::GetInlineStyles(nsIDOMElement* aElement,
    1397             :                               nsIDOMCSSStyleDeclaration** aCssDecl,
    1398             :                               uint32_t* aLength)
    1399             : {
    1400           0 :   return GetInlineStyles(static_cast<nsISupports*>(aElement), aCssDecl, aLength);
    1401             : }
    1402             : 
    1403             : nsresult
    1404           0 : CSSEditUtils::GetInlineStyles(nsISupports* aElement,
    1405             :                               nsIDOMCSSStyleDeclaration** aCssDecl,
    1406             :                               uint32_t* aLength)
    1407             : {
    1408           0 :   NS_ENSURE_TRUE(aElement && aLength, NS_ERROR_NULL_POINTER);
    1409           0 :   *aLength = 0;
    1410           0 :   nsCOMPtr<nsStyledElement> inlineStyles = do_QueryInterface(aElement);
    1411           0 :   NS_ENSURE_TRUE(inlineStyles, NS_ERROR_NULL_POINTER);
    1412             : 
    1413             :   nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
    1414           0 :     do_QueryInterface(inlineStyles->Style());
    1415           0 :   MOZ_ASSERT(cssDecl);
    1416             : 
    1417           0 :   cssDecl.forget(aCssDecl);
    1418           0 :   (*aCssDecl)->GetLength(aLength);
    1419           0 :   return NS_OK;
    1420             : }
    1421             : 
    1422             : already_AddRefed<nsIDOMElement>
    1423           0 : CSSEditUtils::GetElementContainerOrSelf(nsIDOMNode* aNode)
    1424             : {
    1425           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    1426           0 :   NS_ENSURE_TRUE(node, nullptr);
    1427             :   nsCOMPtr<nsIDOMElement> element =
    1428           0 :     do_QueryInterface(GetElementContainerOrSelf(node));
    1429           0 :   return element.forget();
    1430             : }
    1431             : 
    1432             : Element*
    1433           0 : CSSEditUtils::GetElementContainerOrSelf(nsINode* aNode)
    1434             : {
    1435           0 :   MOZ_ASSERT(aNode);
    1436           0 :   if (nsIDOMNode::DOCUMENT_NODE == aNode->NodeType()) {
    1437           0 :     return nullptr;
    1438             :   }
    1439             : 
    1440           0 :   nsINode* node = aNode;
    1441             :   // Loop until we find an element.
    1442           0 :   while (node && !node->IsElement()) {
    1443           0 :     node = node->GetParentNode();
    1444             :   }
    1445             : 
    1446           0 :   NS_ENSURE_TRUE(node, nullptr);
    1447           0 :   return node->AsElement();
    1448             : }
    1449             : 
    1450             : nsresult
    1451           0 : CSSEditUtils::SetCSSProperty(nsIDOMElement* aElement,
    1452             :                              const nsAString& aProperty,
    1453             :                              const nsAString& aValue)
    1454             : {
    1455           0 :   nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
    1456             :   uint32_t length;
    1457           0 :   nsresult rv = GetInlineStyles(aElement, getter_AddRefs(cssDecl), &length);
    1458           0 :   if (NS_FAILED(rv) || !cssDecl) {
    1459           0 :     return rv;
    1460             :   }
    1461             : 
    1462           0 :   return cssDecl->SetProperty(aProperty,
    1463             :                               aValue,
    1464           0 :                               EmptyString());
    1465             : }
    1466             : 
    1467             : nsresult
    1468           0 : CSSEditUtils::SetCSSPropertyPixels(nsIDOMElement* aElement,
    1469             :                                    const nsAString& aProperty,
    1470             :                                    int32_t aIntValue)
    1471             : {
    1472           0 :   nsAutoString s;
    1473           0 :   s.AppendInt(aIntValue);
    1474           0 :   return SetCSSProperty(aElement, aProperty, s + NS_LITERAL_STRING("px"));
    1475             : }
    1476             : 
    1477             : } // namespace mozilla

Generated by: LCOV version 1.13