tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HTMLEditorCommands.cpp (51408B)


      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/EditorCommands.h"
      7 
      8 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
      9 #include "mozilla/EditorBase.h"  // for EditorBase
     10 #include "mozilla/ErrorResult.h"
     11 #include "mozilla/HTMLEditor.h"  // for HTMLEditor
     12 #include "mozilla/dom/Element.h"
     13 #include "nsAString.h"
     14 #include "nsAtom.h"                   // for nsAtom, nsStaticAtom, etc
     15 #include "nsCommandParams.h"          // for nsCommandParams, etc
     16 #include "nsComponentManagerUtils.h"  // for do_CreateInstance
     17 #include "nsGkAtoms.h"                // for nsGkAtoms, nsGkAtoms::font, etc
     18 #include "nsIClipboard.h"             // for nsIClipboard, etc
     19 #include "nsIEditingSession.h"
     20 #include "nsIPrincipal.h"     // for nsIPrincipal
     21 #include "nsLiteralString.h"  // for NS_LITERAL_STRING
     22 #include "nsReadableUtils.h"  // for EmptyString
     23 #include "nsString.h"         // for nsAutoString, nsString, etc
     24 #include "nsStringFwd.h"      // for nsString
     25 
     26 class nsISupports;
     27 
     28 namespace mozilla {
     29 using dom::Element;
     30 
     31 // prototype
     32 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
     33                             nsAString& aLocalName);
     34 
     35 // defines
     36 #define STATE_ENABLED "state_enabled"
     37 #define STATE_ALL "state_all"
     38 #define STATE_ANY "state_any"
     39 #define STATE_MIXED "state_mixed"
     40 #define STATE_BEGIN "state_begin"
     41 #define STATE_END "state_end"
     42 #define STATE_ATTRIBUTE "state_attribute"
     43 #define STATE_DATA "state_data"
     44 
     45 /*****************************************************************************
     46 * mozilla::StateUpdatingCommandBase
     47 *****************************************************************************/
     48 
     49 bool StateUpdatingCommandBase::IsCommandEnabled(Command aCommand,
     50                                                EditorBase* aEditorBase) const {
     51  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
     52  if (!htmlEditor) {
     53    return false;
     54  }
     55  if (!htmlEditor->IsModifiable() || !htmlEditor->IsSelectionEditable() ||
     56      !htmlEditor->IsStyleEditable()) {
     57    return false;
     58  }
     59  if (aCommand == Command::FormatAbsolutePosition) {
     60    return htmlEditor->IsAbsolutePositionEditorEnabled();
     61  }
     62  return true;
     63 }
     64 
     65 nsresult StateUpdatingCommandBase::DoCommand(Command aCommand,
     66                                             EditorBase& aEditorBase,
     67                                             nsIPrincipal* aPrincipal) const {
     68  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
     69  if (NS_WARN_IF(!htmlEditor)) {
     70    return NS_ERROR_FAILURE;
     71  }
     72  nsStaticAtom* tagName = GetTagName(aCommand);
     73  if (NS_WARN_IF(!tagName)) {
     74    return NS_ERROR_UNEXPECTED;
     75  }
     76  nsresult rv = ToggleState(MOZ_KnownLive(*tagName), MOZ_KnownLive(*htmlEditor),
     77                            aPrincipal);
     78  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     79                       "StateUpdatingCommandBase::ToggleState() failed");
     80  return rv;
     81 }
     82 
     83 nsresult StateUpdatingCommandBase::GetCommandStateParams(
     84    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
     85    nsIEditingSession* aEditingSession) const {
     86  if (!aEditorBase) {
     87    return NS_OK;
     88  }
     89  HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
     90  if (NS_WARN_IF(!htmlEditor)) {
     91    return NS_ERROR_FAILURE;
     92  }
     93  nsStaticAtom* tagName = GetTagName(aCommand);
     94  if (NS_WARN_IF(!tagName)) {
     95    return NS_ERROR_UNEXPECTED;
     96  }
     97  // MOZ_KnownLive(htmlEditor) because the lifetime of aEditorBase is guaranteed
     98  // by the callers.
     99  // MOZ_KnownLive(tagName) because nsStaticAtom instances are alive until
    100  // shutting down.
    101  nsresult rv = GetCurrentState(MOZ_KnownLive(*tagName),
    102                                MOZ_KnownLive(*htmlEditor), aParams);
    103  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    104                       "StateUpdatingCommandBase::GetCurrentState() failed");
    105  return rv;
    106 }
    107 
    108 /*****************************************************************************
    109 * mozilla::PasteNoFormattingCommand
    110 *****************************************************************************/
    111 
    112 StaticRefPtr<PasteNoFormattingCommand> PasteNoFormattingCommand::sInstance;
    113 
    114 bool PasteNoFormattingCommand::IsCommandEnabled(Command aCommand,
    115                                                EditorBase* aEditorBase) const {
    116  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
    117  if (!htmlEditor) {
    118    return false;
    119  }
    120  return htmlEditor->CanPaste(nsIClipboard::kGlobalClipboard);
    121 }
    122 
    123 nsresult PasteNoFormattingCommand::DoCommand(Command aCommand,
    124                                             EditorBase& aEditorBase,
    125                                             nsIPrincipal* aPrincipal) const {
    126  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
    127  if (NS_WARN_IF(!htmlEditor)) {
    128    return NS_ERROR_FAILURE;
    129  }
    130  // Known live because we hold a ref above in "editor"
    131  nsresult rv =
    132      MOZ_KnownLive(htmlEditor)
    133          ->PasteNoFormattingAsAction(nsIClipboard::kGlobalClipboard,
    134                                      EditorBase::DispatchPasteEvent::Yes,
    135                                      nullptr, aPrincipal);
    136  NS_WARNING_ASSERTION(
    137      NS_SUCCEEDED(rv),
    138      "HTMLEditor::PasteNoFormattingAsAction(DispatchPasteEvent::Yes) failed");
    139  return rv;
    140 }
    141 
    142 nsresult PasteNoFormattingCommand::GetCommandStateParams(
    143    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
    144    nsIEditingSession* aEditingSession) const {
    145  return aParams.SetBool(STATE_ENABLED,
    146                         IsCommandEnabled(aCommand, aEditorBase));
    147 }
    148 
    149 /*****************************************************************************
    150 * mozilla::StyleUpdatingCommand
    151 *****************************************************************************/
    152 
    153 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
    154 
    155 nsresult StyleUpdatingCommand::GetCurrentState(nsStaticAtom& aTagName,
    156                                               HTMLEditor& aHTMLEditor,
    157                                               nsCommandParams& aParams) const {
    158  bool firstOfSelectionHasProp = false;
    159  bool anyOfSelectionHasProp = false;
    160  bool allOfSelectionHasProp = false;
    161 
    162  nsresult rv = aHTMLEditor.GetInlineProperty(
    163      aTagName, nullptr, u""_ns, &firstOfSelectionHasProp,
    164      &anyOfSelectionHasProp, &allOfSelectionHasProp);
    165  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    166                       "HTMLEditor::GetInlineProperty() failed");
    167 
    168  aParams.SetBool(STATE_ENABLED, NS_SUCCEEDED(rv));
    169  aParams.SetBool(STATE_ALL, allOfSelectionHasProp);
    170  aParams.SetBool(STATE_ANY, anyOfSelectionHasProp);
    171  aParams.SetBool(STATE_MIXED, anyOfSelectionHasProp && !allOfSelectionHasProp);
    172  aParams.SetBool(STATE_BEGIN, firstOfSelectionHasProp);
    173  aParams.SetBool(STATE_END, allOfSelectionHasProp);  // not completely accurate
    174  return NS_OK;
    175 }
    176 
    177 nsresult StyleUpdatingCommand::ToggleState(nsStaticAtom& aTagName,
    178                                           HTMLEditor& aHTMLEditor,
    179                                           nsIPrincipal* aPrincipal) const {
    180  RefPtr<nsCommandParams> params = new nsCommandParams();
    181 
    182  // tags "href" and "name" are special cases in the core editor
    183  // they are used to remove named anchor/link and shouldn't be used for
    184  // insertion
    185  bool doTagRemoval;
    186  if (&aTagName == nsGkAtoms::href || &aTagName == nsGkAtoms::name) {
    187    doTagRemoval = true;
    188  } else {
    189    // check current selection; set doTagRemoval if formatting should be removed
    190    nsresult rv = GetCurrentState(aTagName, aHTMLEditor, *params);
    191    if (NS_FAILED(rv)) {
    192      NS_WARNING("StyleUpdatingCommand::GetCurrentState() failed");
    193      return rv;
    194    }
    195    ErrorResult error;
    196    doTagRemoval = params->GetBool(STATE_ALL, error);
    197    if (NS_WARN_IF(error.Failed())) {
    198      return error.StealNSResult();
    199    }
    200  }
    201 
    202  if (doTagRemoval) {
    203    nsresult rv =
    204        aHTMLEditor.RemoveInlinePropertyAsAction(aTagName, nullptr, aPrincipal);
    205    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    206                         "HTMLEditor::RemoveInlinePropertyAsAction() failed");
    207    return rv;
    208  }
    209 
    210  nsresult rv = aHTMLEditor.SetInlinePropertyAsAction(aTagName, nullptr, u""_ns,
    211                                                      aPrincipal);
    212  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    213                       "HTMLEditor::SetInlinePropertyAsAction() failed");
    214  return rv;
    215 }
    216 
    217 /*****************************************************************************
    218 * mozilla::ListCommand
    219 *****************************************************************************/
    220 
    221 StaticRefPtr<ListCommand> ListCommand::sInstance;
    222 
    223 nsresult ListCommand::GetCurrentState(nsStaticAtom& aTagName,
    224                                      HTMLEditor& aHTMLEditor,
    225                                      nsCommandParams& aParams) const {
    226  bool bMixed;
    227  nsAutoString localName;
    228  nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
    229  if (NS_FAILED(rv)) {
    230    NS_WARNING("GetListState() failed");
    231    return rv;
    232  }
    233 
    234  bool inList = aTagName.Equals(localName);
    235  aParams.SetBool(STATE_ALL, !bMixed && inList);
    236  aParams.SetBool(STATE_MIXED, bMixed);
    237  aParams.SetBool(STATE_ENABLED, true);
    238  return NS_OK;
    239 }
    240 
    241 nsresult ListCommand::ToggleState(nsStaticAtom& aTagName,
    242                                  HTMLEditor& aHTMLEditor,
    243                                  nsIPrincipal* aPrincipal) const {
    244  RefPtr<nsCommandParams> params = new nsCommandParams();
    245  nsresult rv = GetCurrentState(aTagName, aHTMLEditor, *params);
    246  if (NS_FAILED(rv)) {
    247    NS_WARNING("ListCommand::GetCurrentState() failed");
    248    return rv;
    249  }
    250 
    251  ErrorResult error;
    252  bool inList = params->GetBool(STATE_ALL, error);
    253  if (NS_WARN_IF(error.Failed())) {
    254    return error.StealNSResult();
    255  }
    256 
    257  nsDependentAtomString listType(&aTagName);
    258  if (inList) {
    259    nsresult rv = aHTMLEditor.RemoveListAsAction(listType, aPrincipal);
    260    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    261                         "HTMLEditor::RemoveListAsAction() failed");
    262    return rv;
    263  }
    264 
    265  rv = aHTMLEditor.MakeOrChangeListAsAction(
    266      aTagName, u""_ns, HTMLEditor::SelectAllOfCurrentList::No, aPrincipal);
    267  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    268                       "HTMLEditor::MakeOrChangeListAsAction() failed");
    269  return rv;
    270 }
    271 
    272 /*****************************************************************************
    273 * mozilla::ListItemCommand
    274 *****************************************************************************/
    275 
    276 StaticRefPtr<ListItemCommand> ListItemCommand::sInstance;
    277 
    278 nsresult ListItemCommand::GetCurrentState(nsStaticAtom& aTagName,
    279                                          HTMLEditor& aHTMLEditor,
    280                                          nsCommandParams& aParams) const {
    281  ErrorResult error;
    282  ListItemElementSelectionState state(aHTMLEditor, error);
    283  if (error.Failed()) {
    284    NS_WARNING("ListItemElementSelectionState failed");
    285    return error.StealNSResult();
    286  }
    287 
    288  if (state.IsNotOneTypeDefinitionListItemElementSelected()) {
    289    aParams.SetBool(STATE_ALL, false);
    290    aParams.SetBool(STATE_MIXED, true);
    291    return NS_OK;
    292  }
    293 
    294  nsStaticAtom* selectedListItemTagName = nullptr;
    295  if (state.IsLIElementSelected()) {
    296    selectedListItemTagName = nsGkAtoms::li;
    297  } else if (state.IsDTElementSelected()) {
    298    selectedListItemTagName = nsGkAtoms::dt;
    299  } else if (state.IsDDElementSelected()) {
    300    selectedListItemTagName = nsGkAtoms::dd;
    301  }
    302  aParams.SetBool(STATE_ALL, &aTagName == selectedListItemTagName);
    303  aParams.SetBool(STATE_MIXED, false);
    304  return NS_OK;
    305 }
    306 
    307 nsresult ListItemCommand::ToggleState(nsStaticAtom& aTagName,
    308                                      HTMLEditor& aHTMLEditor,
    309                                      nsIPrincipal* aPrincipal) const {
    310  // Need to use aTagName????
    311  RefPtr<nsCommandParams> params = new nsCommandParams();
    312  GetCurrentState(aTagName, aHTMLEditor, *params);
    313  ErrorResult error;
    314  bool inList = params->GetBool(STATE_ALL, error);
    315  if (NS_WARN_IF(error.Failed())) {
    316    return error.StealNSResult();
    317  }
    318 
    319  if (inList) {
    320    // To remove a list, first get what kind of list we're in
    321    bool bMixed;
    322    nsAutoString localName;
    323    nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
    324    if (NS_FAILED(rv)) {
    325      NS_WARNING("GetListState() failed");
    326      return rv;
    327    }
    328    if (localName.IsEmpty() || bMixed) {
    329      return NS_OK;
    330    }
    331    rv = aHTMLEditor.RemoveListAsAction(localName, aPrincipal);
    332    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    333                         "HTMLEditor::RemoveListAsAction() failed");
    334    return rv;
    335  }
    336 
    337  // Set to the requested paragraph type
    338  // XXX Note: This actually doesn't work for "LI",
    339  //    but we currently don't use this for non DL lists anyway.
    340  // Problem: won't this replace any current block paragraph style?
    341  nsresult rv = aHTMLEditor.SetParagraphStateAsAction(
    342      nsDependentAtomString(&aTagName), aPrincipal);
    343  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    344                       "HTMLEditor::SetParagraphFormatAsAction() failed");
    345  return rv;
    346 }
    347 
    348 /*****************************************************************************
    349 * mozilla::RemoveListCommand
    350 *****************************************************************************/
    351 
    352 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
    353 
    354 bool RemoveListCommand::IsCommandEnabled(Command aCommand,
    355                                         EditorBase* aEditorBase) const {
    356  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
    357  if (!htmlEditor) {
    358    return false;
    359  }
    360  if (!htmlEditor->IsModifiable() || !htmlEditor->IsSelectionEditable() ||
    361      !htmlEditor->IsStyleEditable()) {
    362    return false;
    363  }
    364 
    365  // It is enabled if we are in any list type
    366  bool bMixed;
    367  nsAutoString localName;
    368  nsresult rv = GetListState(MOZ_KnownLive(htmlEditor), &bMixed, localName);
    369  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetListState() failed");
    370  return NS_SUCCEEDED(rv) && (bMixed || !localName.IsEmpty());
    371 }
    372 
    373 nsresult RemoveListCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
    374                                      nsIPrincipal* aPrincipal) const {
    375  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
    376  if (NS_WARN_IF(!htmlEditor)) {
    377    return NS_OK;
    378  }
    379  // This removes any list type
    380  nsresult rv =
    381      MOZ_KnownLive(htmlEditor)->RemoveListAsAction(u""_ns, aPrincipal);
    382  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    383                       "HTMLEditor::RemoveListAsAction() failed");
    384  return rv;
    385 }
    386 
    387 nsresult RemoveListCommand::GetCommandStateParams(
    388    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
    389    nsIEditingSession* aEditingSession) const {
    390  return aParams.SetBool(STATE_ENABLED,
    391                         IsCommandEnabled(aCommand, aEditorBase));
    392 }
    393 
    394 /*****************************************************************************
    395 * mozilla::IndentCommand
    396 *****************************************************************************/
    397 
    398 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
    399 
    400 bool IndentCommand::IsCommandEnabled(Command aCommand,
    401                                     EditorBase* aEditorBase) const {
    402  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
    403  if (!htmlEditor) {
    404    return false;
    405  }
    406  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
    407         htmlEditor->IsStyleEditable();
    408 }
    409 
    410 nsresult IndentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
    411                                  nsIPrincipal* aPrincipal) const {
    412  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
    413  if (NS_WARN_IF(!htmlEditor)) {
    414    return NS_OK;
    415  }
    416  nsresult rv = MOZ_KnownLive(htmlEditor)->IndentAsAction(aPrincipal);
    417  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::IndentAsAction() failed");
    418  return rv;
    419 }
    420 
    421 nsresult IndentCommand::GetCommandStateParams(
    422    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
    423    nsIEditingSession* aEditingSession) const {
    424  return aParams.SetBool(STATE_ENABLED,
    425                         IsCommandEnabled(aCommand, aEditorBase));
    426 }
    427 
    428 /*****************************************************************************
    429 * mozilla::OutdentCommand
    430 *****************************************************************************/
    431 
    432 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
    433 
    434 bool OutdentCommand::IsCommandEnabled(Command aCommand,
    435                                      EditorBase* aEditorBase) const {
    436  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
    437  if (!htmlEditor) {
    438    return false;
    439  }
    440  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
    441         htmlEditor->IsStyleEditable();
    442 }
    443 
    444 nsresult OutdentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
    445                                   nsIPrincipal* aPrincipal) const {
    446  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
    447  if (NS_WARN_IF(!htmlEditor)) {
    448    return NS_OK;
    449  }
    450  nsresult rv = MOZ_KnownLive(htmlEditor)->OutdentAsAction(aPrincipal);
    451  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    452                       "HTMLEditor::OutdentAsAction() failed");
    453  return rv;
    454 }
    455 
    456 nsresult OutdentCommand::GetCommandStateParams(
    457    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
    458    nsIEditingSession* aEditingSession) const {
    459  return aParams.SetBool(STATE_ENABLED,
    460                         IsCommandEnabled(aCommand, aEditorBase));
    461 }
    462 
    463 /*****************************************************************************
    464 * mozilla::MultiStateCommandBase
    465 *****************************************************************************/
    466 
    467 bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
    468                                             EditorBase* aEditorBase) const {
    469  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
    470  if (!htmlEditor) {
    471    return false;
    472  }
    473  // should be disabled sometimes, like if the current selection is an image
    474  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
    475         htmlEditor->IsStyleEditable();
    476 }
    477 
    478 nsresult MultiStateCommandBase::DoCommand(Command aCommand,
    479                                          EditorBase& aEditorBase,
    480                                          nsIPrincipal* aPrincipal) const {
    481  NS_WARNING(
    482      "who is calling MultiStateCommandBase::DoCommand (no implementation)?");
    483  return NS_OK;
    484 }
    485 
    486 nsresult MultiStateCommandBase::DoCommandParam(Command aCommand,
    487                                               const nsAString& aStringParam,
    488                                               EditorBase& aEditorBase,
    489                                               nsIPrincipal* aPrincipal) const {
    490  NS_WARNING_ASSERTION(aCommand != Command::FormatJustify,
    491                       "Command::FormatJustify should be used only for "
    492                       "IsCommandEnabled() and GetCommandStateParams()");
    493  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
    494  if (NS_WARN_IF(!htmlEditor)) {
    495    return NS_ERROR_FAILURE;
    496  }
    497  nsresult rv = SetState(MOZ_KnownLive(htmlEditor), aStringParam, aPrincipal);
    498  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    499                       "MultiStateCommandBase::SetState() failed");
    500  return rv;
    501 }
    502 
    503 nsresult MultiStateCommandBase::GetCommandStateParams(
    504    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
    505    nsIEditingSession* aEditingSession) const {
    506  if (!aEditorBase) {
    507    return NS_OK;
    508  }
    509  HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
    510  if (NS_WARN_IF(!htmlEditor)) {
    511    return NS_ERROR_FAILURE;
    512  }
    513  nsresult rv = GetCurrentState(MOZ_KnownLive(htmlEditor), aParams);
    514  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    515                       "MultiStateCommandBase::GetCurrentState() failed");
    516  return rv;
    517 }
    518 
    519 /*****************************************************************************
    520 * mozilla::FormatBlockStateCommand
    521 *****************************************************************************/
    522 
    523 StaticRefPtr<FormatBlockStateCommand> FormatBlockStateCommand::sInstance;
    524 
    525 nsresult FormatBlockStateCommand::GetCurrentState(
    526    HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
    527  if (NS_WARN_IF(!aHTMLEditor)) {
    528    return NS_ERROR_INVALID_ARG;
    529  }
    530 
    531  ErrorResult error;
    532  ParagraphStateAtSelection state(
    533      *aHTMLEditor,
    534      ParagraphStateAtSelection::FormatBlockMode::HTMLFormatBlockCommand,
    535      error);
    536  if (error.Failed()) {
    537    NS_WARNING("ParagraphStateAtSelection failed");
    538    return error.StealNSResult();
    539  }
    540  aParams.SetBool(STATE_MIXED, state.IsMixed());
    541  if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
    542    aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
    543  } else {
    544    nsCString paragraphState;  // Don't use `nsAutoCString` for avoiding copy.
    545    state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
    546    aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
    547  }
    548  return NS_OK;
    549 }
    550 
    551 nsresult FormatBlockStateCommand::SetState(HTMLEditor* aHTMLEditor,
    552                                           const nsAString& aNewState,
    553                                           nsIPrincipal* aPrincipal) const {
    554  if (NS_WARN_IF(!aHTMLEditor) || NS_WARN_IF(aNewState.IsEmpty())) {
    555    return NS_ERROR_INVALID_ARG;
    556  }
    557  nsresult rv = aHTMLEditor->FormatBlockAsAction(aNewState, aPrincipal);
    558  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    559                       "HTMLEditor::FormatBlockAsAction() failed");
    560  return rv;
    561 }
    562 
    563 /*****************************************************************************
    564 * mozilla::ParagraphStateCommand
    565 *****************************************************************************/
    566 
    567 StaticRefPtr<ParagraphStateCommand> ParagraphStateCommand::sInstance;
    568 
    569 nsresult ParagraphStateCommand::GetCurrentState(
    570    HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
    571  if (NS_WARN_IF(!aHTMLEditor)) {
    572    return NS_ERROR_INVALID_ARG;
    573  }
    574 
    575  ErrorResult error;
    576  ParagraphStateAtSelection state(
    577      *aHTMLEditor,
    578      ParagraphStateAtSelection::FormatBlockMode::XULParagraphStateCommand,
    579      error);
    580  if (error.Failed()) {
    581    NS_WARNING("ParagraphStateAtSelection failed");
    582    return error.StealNSResult();
    583  }
    584  aParams.SetBool(STATE_MIXED, state.IsMixed());
    585  if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
    586    // XXX This is odd behavior, we should fix this later.
    587    aParams.SetCString(STATE_ATTRIBUTE, "x"_ns);
    588  } else {
    589    nsCString paragraphState;  // Don't use `nsAutoCString` for avoiding copy.
    590    state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
    591    aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
    592  }
    593  return NS_OK;
    594 }
    595 
    596 nsresult ParagraphStateCommand::SetState(HTMLEditor* aHTMLEditor,
    597                                         const nsAString& aNewState,
    598                                         nsIPrincipal* aPrincipal) const {
    599  if (NS_WARN_IF(!aHTMLEditor)) {
    600    return NS_ERROR_INVALID_ARG;
    601  }
    602  nsresult rv = aHTMLEditor->SetParagraphStateAsAction(aNewState, aPrincipal);
    603  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    604                       "HTMLEditor::SetParagraphStateAsAction() failed");
    605  return rv;
    606 }
    607 
    608 /*****************************************************************************
    609 * mozilla::FontFaceStateCommand
    610 *****************************************************************************/
    611 
    612 StaticRefPtr<FontFaceStateCommand> FontFaceStateCommand::sInstance;
    613 
    614 nsresult FontFaceStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
    615                                               nsCommandParams& aParams) const {
    616  if (NS_WARN_IF(!aHTMLEditor)) {
    617    return NS_ERROR_INVALID_ARG;
    618  }
    619 
    620  nsAutoString outStateString;
    621  bool outMixed;
    622  nsresult rv = aHTMLEditor->GetFontFaceState(&outMixed, outStateString);
    623  if (NS_FAILED(rv)) {
    624    NS_WARNING("HTMLEditor::GetFontFaceState() failed");
    625    return rv;
    626  }
    627  aParams.SetBool(STATE_MIXED, outMixed);
    628  aParams.SetCString(STATE_ATTRIBUTE, NS_ConvertUTF16toUTF8(outStateString));
    629  return NS_OK;
    630 }
    631 
    632 nsresult FontFaceStateCommand::SetState(HTMLEditor* aHTMLEditor,
    633                                        const nsAString& aNewState,
    634                                        nsIPrincipal* aPrincipal) const {
    635  if (NS_WARN_IF(!aHTMLEditor)) {
    636    return NS_ERROR_INVALID_ARG;
    637  }
    638 
    639  if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
    640    nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
    641        *nsGkAtoms::font, nsGkAtoms::face, aPrincipal);
    642    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    643                         "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
    644                         "font, nsGkAtoms::face) failed");
    645    return rv;
    646  }
    647 
    648  nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
    649      *nsGkAtoms::font, nsGkAtoms::face, aNewState, aPrincipal);
    650  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    651                       "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
    652                       "nsGkAtoms::face) failed");
    653  return rv;
    654 }
    655 
    656 /*****************************************************************************
    657 * mozilla::FontSizeStateCommand
    658 *****************************************************************************/
    659 
    660 StaticRefPtr<FontSizeStateCommand> FontSizeStateCommand::sInstance;
    661 
    662 nsresult FontSizeStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
    663                                               nsCommandParams& aParams) const {
    664  if (NS_WARN_IF(!aHTMLEditor)) {
    665    return NS_ERROR_INVALID_ARG;
    666  }
    667 
    668  nsAutoString outStateString;
    669  bool firstHas, anyHas, allHas;
    670  nsresult rv = aHTMLEditor->GetInlinePropertyWithAttrValue(
    671      *nsGkAtoms::font, nsGkAtoms::size, u""_ns, &firstHas, &anyHas, &allHas,
    672      outStateString);
    673  if (NS_FAILED(rv)) {
    674    NS_WARNING(
    675        "HTMLEditor::GetInlinePropertyWithAttrValue(nsGkAtoms::font, "
    676        "nsGkAtoms::size) failed");
    677    return rv;
    678  }
    679 
    680  nsAutoCString tOutStateString;
    681  LossyCopyUTF16toASCII(outStateString, tOutStateString);
    682  aParams.SetBool(STATE_MIXED, anyHas && !allHas);
    683  aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
    684  aParams.SetBool(STATE_ENABLED, true);
    685 
    686  return NS_OK;
    687 }
    688 
    689 // acceptable values for "aNewState" are:
    690 //   -2
    691 //   -1
    692 //    0
    693 //   +1
    694 //   +2
    695 //   +3
    696 //   medium
    697 //   normal
    698 nsresult FontSizeStateCommand::SetState(HTMLEditor* aHTMLEditor,
    699                                        const nsAString& aNewState,
    700                                        nsIPrincipal* aPrincipal) const {
    701  if (NS_WARN_IF(!aHTMLEditor)) {
    702    return NS_ERROR_INVALID_ARG;
    703  }
    704 
    705  if (!aNewState.IsEmpty() && !aNewState.EqualsLiteral("normal") &&
    706      !aNewState.EqualsLiteral("medium")) {
    707    nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
    708        *nsGkAtoms::font, nsGkAtoms::size, aNewState, aPrincipal);
    709    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    710                         "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::"
    711                         "font, nsGkAtoms::size) failed");
    712    return rv;
    713  }
    714 
    715  // remove any existing font size, big or small
    716  nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
    717      *nsGkAtoms::font, nsGkAtoms::size, aPrincipal);
    718  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    719                       "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
    720                       "font, nsGkAtoms::size) failed");
    721  return rv;
    722 }
    723 
    724 /*****************************************************************************
    725 * mozilla::FontColorStateCommand
    726 *****************************************************************************/
    727 
    728 StaticRefPtr<FontColorStateCommand> FontColorStateCommand::sInstance;
    729 
    730 nsresult FontColorStateCommand::GetCurrentState(
    731    HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
    732  if (NS_WARN_IF(!aHTMLEditor)) {
    733    return NS_ERROR_INVALID_ARG;
    734  }
    735 
    736  bool outMixed;
    737  nsAutoString outStateString;
    738  nsresult rv = aHTMLEditor->GetFontColorState(&outMixed, outStateString);
    739  if (NS_FAILED(rv)) {
    740    NS_WARNING("HTMLEditor::GetFontColorState() failed");
    741    return rv;
    742  }
    743 
    744  nsAutoCString tOutStateString;
    745  LossyCopyUTF16toASCII(outStateString, tOutStateString);
    746  aParams.SetBool(STATE_MIXED, outMixed);
    747  aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
    748  return NS_OK;
    749 }
    750 
    751 nsresult FontColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
    752                                         const nsAString& aNewState,
    753                                         nsIPrincipal* aPrincipal) const {
    754  if (NS_WARN_IF(!aHTMLEditor)) {
    755    return NS_ERROR_INVALID_ARG;
    756  }
    757 
    758  if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
    759    nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
    760        *nsGkAtoms::font, nsGkAtoms::color, aPrincipal);
    761    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    762                         "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
    763                         "font, nsGkAtoms::color) failed");
    764    return rv;
    765  }
    766 
    767  nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
    768      *nsGkAtoms::font, nsGkAtoms::color, aNewState, aPrincipal);
    769  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    770                       "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
    771                       "nsGkAtoms::color) failed");
    772  return rv;
    773 }
    774 
    775 /*****************************************************************************
    776 * mozilla::HighlightColorStateCommand
    777 *****************************************************************************/
    778 
    779 StaticRefPtr<HighlightColorStateCommand> HighlightColorStateCommand::sInstance;
    780 
    781 nsresult HighlightColorStateCommand::GetCurrentState(
    782    HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
    783  if (NS_WARN_IF(!aHTMLEditor)) {
    784    return NS_ERROR_INVALID_ARG;
    785  }
    786 
    787  bool outMixed;
    788  nsAutoString outStateString;
    789  nsresult rv = aHTMLEditor->GetHighlightColorState(&outMixed, outStateString);
    790  if (NS_FAILED(rv)) {
    791    NS_WARNING("HTMLEditor::GetHighlightColorState() failed");
    792    return rv;
    793  }
    794 
    795  nsAutoCString tOutStateString;
    796  LossyCopyUTF16toASCII(outStateString, tOutStateString);
    797  aParams.SetBool(STATE_MIXED, outMixed);
    798  aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
    799  return NS_OK;
    800 }
    801 
    802 nsresult HighlightColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
    803                                              const nsAString& aNewState,
    804                                              nsIPrincipal* aPrincipal) const {
    805  if (NS_WARN_IF(!aHTMLEditor)) {
    806    return NS_ERROR_INVALID_ARG;
    807  }
    808 
    809  if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
    810    nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
    811        *nsGkAtoms::font, nsGkAtoms::bgcolor, aPrincipal);
    812    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    813                         "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
    814                         "font, nsGkAtoms::bgcolor) failed");
    815    return rv;
    816  }
    817 
    818  nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
    819      *nsGkAtoms::font, nsGkAtoms::bgcolor, aNewState, aPrincipal);
    820  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    821                       "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
    822                       "nsGkAtoms::bgcolor) failed");
    823  return rv;
    824 }
    825 
    826 /*****************************************************************************
    827 * mozilla::BackgroundColorStateCommand
    828 *****************************************************************************/
    829 
    830 StaticRefPtr<BackgroundColorStateCommand>
    831    BackgroundColorStateCommand::sInstance;
    832 
    833 nsresult BackgroundColorStateCommand::GetCurrentState(
    834    HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
    835  if (NS_WARN_IF(!aHTMLEditor)) {
    836    return NS_ERROR_INVALID_ARG;
    837  }
    838 
    839  bool outMixed;
    840  nsAutoString outStateString;
    841  nsresult rv = aHTMLEditor->GetBackgroundColorState(&outMixed, outStateString);
    842  if (NS_FAILED(rv)) {
    843    NS_WARNING("HTMLEditor::GetBackgroundColorState() failed");
    844    return rv;
    845  }
    846 
    847  nsAutoCString tOutStateString;
    848  LossyCopyUTF16toASCII(outStateString, tOutStateString);
    849  aParams.SetBool(STATE_MIXED, outMixed);
    850  aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
    851  return NS_OK;
    852 }
    853 
    854 nsresult BackgroundColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
    855                                               const nsAString& aNewState,
    856                                               nsIPrincipal* aPrincipal) const {
    857  if (NS_WARN_IF(!aHTMLEditor)) {
    858    return NS_ERROR_INVALID_ARG;
    859  }
    860  nsresult rv = aHTMLEditor->SetBackgroundColorAsAction(aNewState, aPrincipal);
    861  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    862                       "HTMLEditor::SetBackgroundColorAsAction() failed");
    863  return rv;
    864 }
    865 
    866 /*****************************************************************************
    867 * mozilla::AlignCommand
    868 *****************************************************************************/
    869 
    870 StaticRefPtr<AlignCommand> AlignCommand::sInstance;
    871 
    872 nsresult AlignCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
    873                                       nsCommandParams& aParams) const {
    874  if (NS_WARN_IF(!aHTMLEditor)) {
    875    return NS_ERROR_INVALID_ARG;
    876  }
    877 
    878  ErrorResult error;
    879  AlignStateAtSelection state(*aHTMLEditor, error);
    880  if (error.Failed()) {
    881    if (!state.IsSelectionRangesFound()) {
    882      // If there was no selection ranges, we shouldn't throw exception for
    883      // compatibility with the other browsers, but I have no better idea
    884      // than returning empty string in this case.  Oddly, Blink/WebKit returns
    885      // "true" or "false", but it's different from us and the value does not
    886      // make sense.  Additionally, WPT loves our behavior.
    887      error.SuppressException();
    888      aParams.SetBool(STATE_MIXED, false);
    889      aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
    890      return NS_OK;
    891    }
    892    NS_WARNING("AlignStateAtSelection failed");
    893    return error.StealNSResult();
    894  }
    895  nsCString alignment;  // Don't use `nsAutoCString` to avoid copying string.
    896  switch (state.AlignmentAtSelectionStart()) {
    897    default:
    898    case nsIHTMLEditor::eLeft:
    899      alignment.AssignLiteral("left");
    900      break;
    901    case nsIHTMLEditor::eCenter:
    902      alignment.AssignLiteral("center");
    903      break;
    904    case nsIHTMLEditor::eRight:
    905      alignment.AssignLiteral("right");
    906      break;
    907    case nsIHTMLEditor::eJustify:
    908      alignment.AssignLiteral("justify");
    909      break;
    910  }
    911  aParams.SetBool(STATE_MIXED, false);
    912  aParams.SetCString(STATE_ATTRIBUTE, alignment);
    913  return NS_OK;
    914 }
    915 
    916 nsresult AlignCommand::SetState(HTMLEditor* aHTMLEditor,
    917                                const nsAString& aNewState,
    918                                nsIPrincipal* aPrincipal) const {
    919  if (NS_WARN_IF(!aHTMLEditor)) {
    920    return NS_ERROR_INVALID_ARG;
    921  }
    922  nsresult rv = aHTMLEditor->AlignAsAction(aNewState, aPrincipal);
    923  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::AlignAsAction() failed");
    924  return rv;
    925 }
    926 
    927 /*****************************************************************************
    928 * mozilla::AbsolutePositioningCommand
    929 *****************************************************************************/
    930 
    931 StaticRefPtr<AbsolutePositioningCommand> AbsolutePositioningCommand::sInstance;
    932 
    933 nsresult AbsolutePositioningCommand::GetCurrentState(
    934    nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
    935    nsCommandParams& aParams) const {
    936  if (!aHTMLEditor.IsAbsolutePositionEditorEnabled()) {
    937    aParams.SetBool(STATE_MIXED, false);
    938    aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
    939    return NS_OK;
    940  }
    941 
    942  RefPtr<Element> container =
    943      aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
    944  aParams.SetBool(STATE_MIXED, false);
    945  aParams.SetCString(STATE_ATTRIBUTE, container ? "absolute"_ns : ""_ns);
    946  return NS_OK;
    947 }
    948 
    949 nsresult AbsolutePositioningCommand::ToggleState(
    950    nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
    951    nsIPrincipal* aPrincipal) const {
    952  RefPtr<Element> container =
    953      aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
    954  nsresult rv = aHTMLEditor.SetSelectionToAbsoluteOrStaticAsAction(!container,
    955                                                                   aPrincipal);
    956  NS_WARNING_ASSERTION(
    957      NS_SUCCEEDED(rv),
    958      "HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction() failed");
    959  return rv;
    960 }
    961 
    962 /*****************************************************************************
    963 * mozilla::DecreaseZIndexCommand
    964 *****************************************************************************/
    965 
    966 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
    967 
    968 bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
    969                                             EditorBase* aEditorBase) const {
    970  RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(aEditorBase);
    971  if (!htmlEditor) {
    972    return false;
    973  }
    974  if (!htmlEditor->IsAbsolutePositionEditorEnabled() ||
    975      !htmlEditor->IsStyleEditable()) {
    976    return false;
    977  }
    978  RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
    979  if (!positionedElement) {
    980    return false;
    981  }
    982  return htmlEditor->GetZIndex(*positionedElement) > 0;
    983 }
    984 
    985 nsresult DecreaseZIndexCommand::DoCommand(Command aCommand,
    986                                          EditorBase& aEditorBase,
    987                                          nsIPrincipal* aPrincipal) const {
    988  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
    989  if (NS_WARN_IF(!htmlEditor)) {
    990    return NS_ERROR_FAILURE;
    991  }
    992  nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(-1, aPrincipal);
    993  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
    994                       "HTMLEditor::AddZIndexAsAction(-1) failed");
    995  return rv;
    996 }
    997 
    998 nsresult DecreaseZIndexCommand::GetCommandStateParams(
    999    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1000    nsIEditingSession* aEditingSession) const {
   1001  return aParams.SetBool(STATE_ENABLED,
   1002                         IsCommandEnabled(aCommand, aEditorBase));
   1003 }
   1004 
   1005 /*****************************************************************************
   1006 * mozilla::IncreaseZIndexCommand
   1007 *****************************************************************************/
   1008 
   1009 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
   1010 
   1011 bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
   1012                                             EditorBase* aEditorBase) const {
   1013  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
   1014  if (!htmlEditor) {
   1015    return false;
   1016  }
   1017  if (!htmlEditor->IsAbsolutePositionEditorEnabled() ||
   1018      !htmlEditor->IsStyleEditable()) {
   1019    return false;
   1020  }
   1021  return !!htmlEditor->GetPositionedElement();
   1022 }
   1023 
   1024 nsresult IncreaseZIndexCommand::DoCommand(Command aCommand,
   1025                                          EditorBase& aEditorBase,
   1026                                          nsIPrincipal* aPrincipal) const {
   1027  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1028  if (NS_WARN_IF(!htmlEditor)) {
   1029    return NS_ERROR_FAILURE;
   1030  }
   1031  nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(1, aPrincipal);
   1032  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1033                       "HTMLEditor::AddZIndexAsAction(1) failed");
   1034  return rv;
   1035 }
   1036 
   1037 nsresult IncreaseZIndexCommand::GetCommandStateParams(
   1038    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1039    nsIEditingSession* aEditingSession) const {
   1040  return aParams.SetBool(STATE_ENABLED,
   1041                         IsCommandEnabled(aCommand, aEditorBase));
   1042 }
   1043 
   1044 /*****************************************************************************
   1045 * mozilla::RemoveStylesCommand
   1046 *****************************************************************************/
   1047 
   1048 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
   1049 
   1050 bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
   1051                                           EditorBase* aEditorBase) const {
   1052  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
   1053  if (!htmlEditor) {
   1054    return false;
   1055  }
   1056  // test if we have any styles?
   1057  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
   1058         htmlEditor->IsStyleEditable();
   1059 }
   1060 
   1061 nsresult RemoveStylesCommand::DoCommand(Command aCommand,
   1062                                        EditorBase& aEditorBase,
   1063                                        nsIPrincipal* aPrincipal) const {
   1064  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1065  if (NS_WARN_IF(!htmlEditor)) {
   1066    return NS_OK;
   1067  }
   1068  nsresult rv =
   1069      MOZ_KnownLive(htmlEditor)->RemoveAllInlinePropertiesAsAction(aPrincipal);
   1070  NS_WARNING_ASSERTION(
   1071      NS_SUCCEEDED(rv),
   1072      "HTMLEditor::RemoveAllInlinePropertiesAsAction() failed");
   1073  return rv;
   1074 }
   1075 
   1076 nsresult RemoveStylesCommand::GetCommandStateParams(
   1077    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1078    nsIEditingSession* aEditingSession) const {
   1079  return aParams.SetBool(STATE_ENABLED,
   1080                         IsCommandEnabled(aCommand, aEditorBase));
   1081 }
   1082 
   1083 /*****************************************************************************
   1084 * mozilla::IncreaseFontSizeCommand
   1085 *****************************************************************************/
   1086 
   1087 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
   1088 
   1089 bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
   1090                                               EditorBase* aEditorBase) const {
   1091  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
   1092  if (!htmlEditor) {
   1093    return false;
   1094  }
   1095  // test if we are at max size?
   1096  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
   1097         htmlEditor->IsStyleEditable();
   1098 }
   1099 
   1100 nsresult IncreaseFontSizeCommand::DoCommand(Command aCommand,
   1101                                            EditorBase& aEditorBase,
   1102                                            nsIPrincipal* aPrincipal) const {
   1103  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1104  if (NS_WARN_IF(!htmlEditor)) {
   1105    return NS_OK;
   1106  }
   1107  nsresult rv = MOZ_KnownLive(htmlEditor)->IncreaseFontSizeAsAction(aPrincipal);
   1108  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1109                       "HTMLEditor::IncreaseFontSizeAsAction() failed");
   1110  return rv;
   1111 }
   1112 
   1113 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
   1114    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1115    nsIEditingSession* aEditingSession) const {
   1116  return aParams.SetBool(STATE_ENABLED,
   1117                         IsCommandEnabled(aCommand, aEditorBase));
   1118 }
   1119 
   1120 /*****************************************************************************
   1121 * mozilla::DecreaseFontSizeCommand
   1122 *****************************************************************************/
   1123 
   1124 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
   1125 
   1126 bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
   1127                                               EditorBase* aEditorBase) const {
   1128  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
   1129  if (!htmlEditor) {
   1130    return false;
   1131  }
   1132  // test if we are at min size?
   1133  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
   1134         htmlEditor->IsStyleEditable();
   1135 }
   1136 
   1137 nsresult DecreaseFontSizeCommand::DoCommand(Command aCommand,
   1138                                            EditorBase& aEditorBase,
   1139                                            nsIPrincipal* aPrincipal) const {
   1140  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1141  if (NS_WARN_IF(!htmlEditor)) {
   1142    return NS_OK;
   1143  }
   1144  nsresult rv = MOZ_KnownLive(htmlEditor)->DecreaseFontSizeAsAction(aPrincipal);
   1145  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1146                       "HTMLEditor::DecreaseFontSizeAsAction() failed");
   1147  return rv;
   1148 }
   1149 
   1150 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
   1151    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1152    nsIEditingSession* aEditingSession) const {
   1153  return aParams.SetBool(STATE_ENABLED,
   1154                         IsCommandEnabled(aCommand, aEditorBase));
   1155 }
   1156 
   1157 /*****************************************************************************
   1158 * mozilla::InsertHTMLCommand
   1159 *****************************************************************************/
   1160 
   1161 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
   1162 
   1163 bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
   1164                                         EditorBase* aEditorBase) const {
   1165  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
   1166  if (!htmlEditor) {
   1167    return false;
   1168  }
   1169  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
   1170 }
   1171 
   1172 nsresult InsertHTMLCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
   1173                                      nsIPrincipal* aPrincipal) const {
   1174  // If InsertHTMLCommand is called with no parameters, it was probably called
   1175  // with an empty string parameter ''. In this case, it should act the same as
   1176  // the delete command
   1177  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1178  if (NS_WARN_IF(!htmlEditor)) {
   1179    return NS_ERROR_FAILURE;
   1180  }
   1181  nsresult rv =
   1182      MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(u""_ns, aPrincipal);
   1183  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1184                       "HTMLEditor::InsertHTMLAsAction() failed");
   1185  return rv;
   1186 }
   1187 
   1188 nsresult InsertHTMLCommand::DoCommandParam(Command aCommand,
   1189                                           const nsAString& aStringParam,
   1190                                           EditorBase& aEditorBase,
   1191                                           nsIPrincipal* aPrincipal) const {
   1192  if (NS_WARN_IF(aStringParam.IsVoid())) {
   1193    return NS_ERROR_INVALID_ARG;
   1194  }
   1195 
   1196  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1197  if (NS_WARN_IF(!htmlEditor)) {
   1198    return NS_ERROR_FAILURE;
   1199  }
   1200  nsresult rv =
   1201      MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(aStringParam, aPrincipal);
   1202  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1203                       "HTMLEditor::InsertHTMLAsAction() failed");
   1204  return rv;
   1205 }
   1206 
   1207 nsresult InsertHTMLCommand::GetCommandStateParams(
   1208    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1209    nsIEditingSession* aEditingSession) const {
   1210  return aParams.SetBool(STATE_ENABLED,
   1211                         IsCommandEnabled(aCommand, aEditorBase));
   1212 }
   1213 
   1214 /*****************************************************************************
   1215 * mozilla::InsertTagCommand
   1216 *****************************************************************************/
   1217 
   1218 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
   1219 
   1220 bool InsertTagCommand::IsCommandEnabled(Command aCommand,
   1221                                        EditorBase* aEditorBase) const {
   1222  HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
   1223  if (!htmlEditor) {
   1224    return false;
   1225  }
   1226  return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable() &&
   1227         htmlEditor->IsStyleEditable();
   1228 }
   1229 
   1230 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
   1231 nsresult InsertTagCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
   1232                                     nsIPrincipal* aPrincipal) const {
   1233  nsAtom* tagName = GetTagName(aCommand);
   1234  if (NS_WARN_IF(tagName != nsGkAtoms::hr)) {
   1235    return NS_ERROR_NOT_IMPLEMENTED;
   1236  }
   1237 
   1238  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1239  if (NS_WARN_IF(!htmlEditor)) {
   1240    return NS_ERROR_FAILURE;
   1241  }
   1242 
   1243  RefPtr<Element> newElement =
   1244      MOZ_KnownLive(htmlEditor)
   1245          ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
   1246  if (NS_WARN_IF(!newElement)) {
   1247    return NS_ERROR_FAILURE;
   1248  }
   1249  HTMLEditor::InsertElementOptions options{
   1250      HTMLEditor::InsertElementOption::DeleteSelection};
   1251  // We did insert <img> without splitting ancestor inline elements, but the
   1252  // other browsers split them.  Therefore, let's do it only when the document
   1253  // is content.
   1254  if (tagName == nsGkAtoms::img &&
   1255      htmlEditor->GetDocument()->IsContentDocument()) {
   1256    options += HTMLEditor::InsertElementOption::SplitAncestorInlineElements;
   1257  }
   1258  nsresult rv =
   1259      MOZ_KnownLive(htmlEditor)
   1260          ->InsertElementAtSelectionAsAction(newElement, options, aPrincipal);
   1261  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1262                       "HTMLEditor::InsertElementAtSelectionAsAction() failed");
   1263  return rv;
   1264 }
   1265 
   1266 nsresult InsertTagCommand::DoCommandParam(Command aCommand,
   1267                                          const nsAString& aStringParam,
   1268                                          EditorBase& aEditorBase,
   1269                                          nsIPrincipal* aPrincipal) const {
   1270  MOZ_ASSERT(aCommand != Command::InsertHorizontalRule);
   1271 
   1272  if (NS_WARN_IF(aStringParam.IsEmpty())) {
   1273    return NS_ERROR_INVALID_ARG;
   1274  }
   1275  nsAtom* tagName = GetTagName(aCommand);
   1276  if (NS_WARN_IF(!tagName)) {
   1277    return NS_ERROR_UNEXPECTED;
   1278  }
   1279 
   1280  HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
   1281  if (NS_WARN_IF(!htmlEditor)) {
   1282    return NS_ERROR_FAILURE;
   1283  }
   1284 
   1285  // filter out tags we don't know how to insert
   1286  nsAtom* attribute = nullptr;
   1287  if (tagName == nsGkAtoms::a) {
   1288    attribute = nsGkAtoms::href;
   1289  } else if (tagName == nsGkAtoms::img) {
   1290    attribute = nsGkAtoms::src;
   1291  } else {
   1292    return NS_ERROR_NOT_IMPLEMENTED;
   1293  }
   1294 
   1295  RefPtr<Element> newElement =
   1296      MOZ_KnownLive(htmlEditor)
   1297          ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
   1298  if (!newElement) {
   1299    NS_WARNING("HTMLEditor::CreateElementWithDefaults() failed");
   1300    return NS_ERROR_FAILURE;
   1301  }
   1302 
   1303  ErrorResult error;
   1304  newElement->SetAttr(attribute, aStringParam, error);
   1305  if (error.Failed()) {
   1306    NS_WARNING("Element::SetAttr() failed");
   1307    return error.StealNSResult();
   1308  }
   1309 
   1310  // do actual insertion
   1311  if (tagName == nsGkAtoms::a) {
   1312    nsresult rv =
   1313        MOZ_KnownLive(htmlEditor)
   1314            ->InsertLinkAroundSelectionAsAction(newElement, aPrincipal);
   1315    NS_WARNING_ASSERTION(
   1316        NS_SUCCEEDED(rv),
   1317        "HTMLEditor::InsertLinkAroundSelectionAsAction() failed");
   1318    return rv;
   1319  }
   1320 
   1321  HTMLEditor::InsertElementOptions options{
   1322      HTMLEditor::InsertElementOption::DeleteSelection};
   1323  // We did insert <img> without splitting ancestor inline elements, but the
   1324  // other browsers split them.  Therefore, let's do it only when the document
   1325  // is content.
   1326  if (htmlEditor->GetDocument()->IsContentDocument()) {
   1327    options += HTMLEditor::InsertElementOption::SplitAncestorInlineElements;
   1328  }
   1329  nsresult rv =
   1330      MOZ_KnownLive(htmlEditor)
   1331          ->InsertElementAtSelectionAsAction(newElement, options, aPrincipal);
   1332  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
   1333                       "HTMLEditor::InsertElementAtSelectionAsAction() failed");
   1334  return rv;
   1335 }
   1336 
   1337 nsresult InsertTagCommand::GetCommandStateParams(
   1338    Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
   1339    nsIEditingSession* aEditingSession) const {
   1340  return aParams.SetBool(STATE_ENABLED,
   1341                         IsCommandEnabled(aCommand, aEditorBase));
   1342 }
   1343 
   1344 /*****************************************************************************
   1345 * Helper methods
   1346 *****************************************************************************/
   1347 
   1348 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
   1349                             nsAString& aLocalName) {
   1350  MOZ_ASSERT(aHTMLEditor);
   1351  MOZ_ASSERT(aMixed);
   1352 
   1353  *aMixed = false;
   1354  aLocalName.Truncate();
   1355 
   1356  ErrorResult error;
   1357  ListElementSelectionState state(*aHTMLEditor, error);
   1358  if (error.Failed()) {
   1359    NS_WARNING("ListElementSelectionState failed");
   1360    return error.StealNSResult();
   1361  }
   1362  if (state.IsNotOneTypeListElementSelected()) {
   1363    *aMixed = true;
   1364    return NS_OK;
   1365  }
   1366 
   1367  if (state.IsOLElementSelected()) {
   1368    aLocalName.AssignLiteral("ol");
   1369  } else if (state.IsULElementSelected()) {
   1370    aLocalName.AssignLiteral("ul");
   1371  } else if (state.IsDLElementSelected()) {
   1372    aLocalName.AssignLiteral("dl");
   1373  }
   1374  return NS_OK;
   1375 }
   1376 
   1377 }  // namespace mozilla