2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2020-04-09 13:10:34 +03:00
|
|
|
#include "HTMLEditor.h"
|
2016-07-09 05:42:33 +03:00
|
|
|
|
2003-06-25 12:50:48 +04:00
|
|
|
#include <math.h>
|
|
|
|
|
2018-11-06 09:09:18 +03:00
|
|
|
#include "HTMLEditorEventListener.h"
|
2016-07-07 08:01:12 +03:00
|
|
|
#include "HTMLEditUtils.h"
|
2018-01-12 13:01:04 +03:00
|
|
|
#include "mozilla/EditAction.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2019-03-15 08:01:10 +03:00
|
|
|
#include "mozilla/PresShell.h"
|
2020-03-18 09:06:22 +03:00
|
|
|
#include "mozilla/dom/AncestorIterator.h"
|
2014-04-10 20:09:40 +04:00
|
|
|
#include "mozilla/dom/Selection.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2018-04-05 20:42:40 +03:00
|
|
|
#include "mozilla/dom/EventTarget.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "mozilla/mozalloc.h"
|
|
|
|
#include "nsAString.h"
|
|
|
|
#include "nsAlgorithm.h"
|
|
|
|
#include "nsCOMPtr.h"
|
2012-07-08 13:50:31 +04:00
|
|
|
#include "nsComputedDOMStyle.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsDebug.h"
|
|
|
|
#include "nsError.h"
|
|
|
|
#include "nsGkAtoms.h"
|
2003-06-25 12:50:48 +04:00
|
|
|
#include "nsIContent.h"
|
2012-12-14 13:14:21 +04:00
|
|
|
#include "nsROCSSPrimitiveValue.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsINode.h"
|
2019-06-10 13:27:07 +03:00
|
|
|
#include "nsIPrincipal.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsISupportsImpl.h"
|
|
|
|
#include "nsISupportsUtils.h"
|
|
|
|
#include "nsLiteralString.h"
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsStringFwd.h"
|
2020-08-26 07:48:16 +03:00
|
|
|
#include "nsStyledElement.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nscore.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2011-06-17 04:59:29 +04:00
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace dom;
|
2011-06-17 04:59:29 +04:00
|
|
|
|
2019-06-10 13:27:07 +03:00
|
|
|
nsresult HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction(
|
|
|
|
bool aEnabled, nsIPrincipal* aPrincipal) {
|
2018-10-30 13:02:58 +03:00
|
|
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
|
|
|
|
2018-10-30 13:00:17 +03:00
|
|
|
AutoEditActionDataSetter editActionData(
|
2019-06-10 13:27:07 +03:00
|
|
|
*this, EditAction::eSetPositionToAbsoluteOrStatic, aPrincipal);
|
Bug 970802 - part 5: Make `AutoEditActionDataSetter` created method dispatch "beforeinput" event r=smaug,m_kato
`AutoEditActionDataSetter` is created in the stack when editor's public method
is called and that guarantees lifetime of global objects in editor such as
editor itself, selection controller, etc.
The dispatcher of `beforeinput` event returns `NS_ERROR_EDITOR_ACTION_CANCELED`
if an event is actually dispatched but canceled. The reason why it's an error
is, editor code must stop handling anything when any methods return error.
So, returning an error code is reasonable in editor module. But when it's
filtered by `EditorBase::ToGenericNSResult()` at return statement of public
methods, it's converted to `NS_SUCCESS_DOM_NO_OPERATION`. This avoids throwing
new exception, but editor class users in C++ can distinguish whether each edit
action is canceled or handled. The reason why we should not throw new
exception from XPCOM API is, without taking care of each caller may break some
our UI (especially for avoiding to break comm-central). Therefore, this patch
does not make XPCOM methods return error code when `beforeinput` event is
canceled.
In most cases, immediately after creating `AutoEditActionDataSetter` is good
timing to dispatch `beforeinput` event since editor has not touched the DOM
yet. If `beforeinput` requires `data` or `dataTransfer`, methods need to
dispatch `beforeinput` event after that. Alhtough this is not a good thing
from point of view of consistency of the code. However, I have no better
idea.
Note 1: Our implementation does NOT conform to the spec about event order
between `keypress` and `beforeinput` (dispatching `beforeinput` event after
`keypress` event). However, we follow all other browsers' behavior so that it
must be safe and the spec should be updated for backward compatibility.
Spec issue: https://github.com/w3c/uievents/issues/220
Note 2: Our implementation does NOT conform to the spec about event order
between `compositionupdate` and `beforeinput`. Our behavior is same as
Safari, but different from Chrome. This might cause web-compat issues.
However, our behavior does make sense from point of view of consistency of
event spec. Additionally, at both `compositionupdate` and `beforeinput`,
composition string in editor has not been modified yet. Therefore, this
may not cause web-compat issues (and I hope so).
Spec issue: https://github.com/w3c/input-events/issues/49
Note that this patch makes editor detect bugs that `beforeinput` event hasn't
been handled yet when it dispatches `input` event or modifying `data` and
`dataTransfer` value are modified after dispatching `beforeinput` event with
`MOZ_ASSERT`s.
Differential Revision: https://phabricator.services.mozilla.com/D58127
--HG--
extra : moz-landing-system : lando
2020-01-14 10:18:51 +03:00
|
|
|
nsresult rv = editActionData.CanHandleAndMaybeDispatchBeforeInputEvent();
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING_ASSERTION(rv == NS_ERROR_EDITOR_ACTION_CANCELED,
|
|
|
|
"CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
|
Bug 970802 - part 5: Make `AutoEditActionDataSetter` created method dispatch "beforeinput" event r=smaug,m_kato
`AutoEditActionDataSetter` is created in the stack when editor's public method
is called and that guarantees lifetime of global objects in editor such as
editor itself, selection controller, etc.
The dispatcher of `beforeinput` event returns `NS_ERROR_EDITOR_ACTION_CANCELED`
if an event is actually dispatched but canceled. The reason why it's an error
is, editor code must stop handling anything when any methods return error.
So, returning an error code is reasonable in editor module. But when it's
filtered by `EditorBase::ToGenericNSResult()` at return statement of public
methods, it's converted to `NS_SUCCESS_DOM_NO_OPERATION`. This avoids throwing
new exception, but editor class users in C++ can distinguish whether each edit
action is canceled or handled. The reason why we should not throw new
exception from XPCOM API is, without taking care of each caller may break some
our UI (especially for avoiding to break comm-central). Therefore, this patch
does not make XPCOM methods return error code when `beforeinput` event is
canceled.
In most cases, immediately after creating `AutoEditActionDataSetter` is good
timing to dispatch `beforeinput` event since editor has not touched the DOM
yet. If `beforeinput` requires `data` or `dataTransfer`, methods need to
dispatch `beforeinput` event after that. Alhtough this is not a good thing
from point of view of consistency of the code. However, I have no better
idea.
Note 1: Our implementation does NOT conform to the spec about event order
between `keypress` and `beforeinput` (dispatching `beforeinput` event after
`keypress` event). However, we follow all other browsers' behavior so that it
must be safe and the spec should be updated for backward compatibility.
Spec issue: https://github.com/w3c/uievents/issues/220
Note 2: Our implementation does NOT conform to the spec about event order
between `compositionupdate` and `beforeinput`. Our behavior is same as
Safari, but different from Chrome. This might cause web-compat issues.
However, our behavior does make sense from point of view of consistency of
event spec. Additionally, at both `compositionupdate` and `beforeinput`,
composition string in editor has not been modified yet. Therefore, this
may not cause web-compat issues (and I hope so).
Spec issue: https://github.com/w3c/input-events/issues/49
Note that this patch makes editor detect bugs that `beforeinput` event hasn't
been handled yet when it dispatches `input` event or modifying `data` and
`dataTransfer` value are modified after dispatching `beforeinput` event with
`MOZ_ASSERT`s.
Differential Revision: https://phabricator.services.mozilla.com/D58127
--HG--
extra : moz-landing-system : lando
2020-01-14 10:18:51 +03:00
|
|
|
return rv;
|
2018-10-30 13:00:17 +03:00
|
|
|
}
|
|
|
|
|
2019-09-12 08:45:13 +03:00
|
|
|
if (aEnabled) {
|
|
|
|
EditActionResult result = SetSelectionToAbsoluteAsSubAction();
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
result.Succeeded(),
|
|
|
|
"HTMLEditor::SetSelectionToAbsoluteAsSubAction() failed");
|
2019-09-12 08:45:13 +03:00
|
|
|
return result.Rv();
|
|
|
|
}
|
|
|
|
EditActionResult result = SetSelectionToStaticAsSubAction();
|
|
|
|
NS_WARNING_ASSERTION(result.Succeeded(),
|
2020-03-18 09:06:22 +03:00
|
|
|
"HTMLEditor::SetSelectionToStaticAsSubAction() failed");
|
2019-09-12 08:45:13 +03:00
|
|
|
return result.Rv();
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2018-01-30 07:42:52 +03:00
|
|
|
already_AddRefed<Element>
|
2019-08-13 10:34:11 +03:00
|
|
|
HTMLEditor::GetAbsolutelyPositionedSelectionContainer() const {
|
2018-10-30 13:00:17 +03:00
|
|
|
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
|
|
|
|
if (NS_WARN_IF(!editActionData.CanHandle())) {
|
2018-08-16 18:12:51 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
Element* selectionContainerElement = GetSelectionContainerElement();
|
|
|
|
if (NS_WARN_IF(!selectionContainerElement)) {
|
2018-08-16 18:12:51 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-04-09 13:10:34 +03:00
|
|
|
AutoTArray<RefPtr<Element>, 24> arrayOfParentElements;
|
2020-03-18 09:06:22 +03:00
|
|
|
for (Element* element :
|
2020-05-20 17:55:15 +03:00
|
|
|
selectionContainerElement->InclusiveAncestorsOfType<Element>()) {
|
2020-04-09 13:10:34 +03:00
|
|
|
arrayOfParentElements.AppendElement(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString positionValue;
|
|
|
|
for (RefPtr<Element> element = selectionContainerElement; element;
|
|
|
|
element = element->GetParentElement()) {
|
2020-03-18 09:06:22 +03:00
|
|
|
if (element->IsHTMLElement(nsGkAtoms::html)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"HTMLEditor::GetAbsolutelyPositionedSelectionContainer() reached "
|
|
|
|
"<html> element");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
nsCOMPtr<nsINode> parentNode = element->GetParentNode();
|
2018-02-02 12:42:25 +03:00
|
|
|
nsresult rv = CSSEditUtils::GetComputedProperty(
|
2020-04-09 13:10:34 +03:00
|
|
|
MOZ_KnownLive(*element), *nsGkAtoms::position, positionValue);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
|
2018-01-30 07:42:52 +03:00
|
|
|
return nullptr;
|
2017-08-04 12:30:13 +03:00
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(Destroyed()) ||
|
|
|
|
NS_WARN_IF(parentNode != element->GetParentNode())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
if (positionValue.EqualsLiteral("absolute")) {
|
2020-04-09 13:10:34 +03:00
|
|
|
return element.forget();
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
2008-01-22 10:39:06 +03:00
|
|
|
}
|
2018-01-30 07:42:52 +03:00
|
|
|
return nullptr;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::GetAbsolutePositioningEnabled(bool* aIsEnabled) {
|
2018-04-04 16:27:49 +03:00
|
|
|
*aIsEnabled = IsAbsolutePositionEditorEnabled();
|
2003-06-25 12:50:48 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::SetAbsolutePositioningEnabled(bool aIsEnabled) {
|
2018-04-04 16:27:49 +03:00
|
|
|
EnableAbsolutePositionEditor(aIsEnabled);
|
2003-06-25 12:50:48 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-02-01 04:55:25 +03:00
|
|
|
nsresult HTMLEditor::RelativeChangeElementZIndex(Element& aElement,
|
|
|
|
int32_t aChange,
|
|
|
|
int32_t* aReturn) {
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_WARN_IF(!aReturn)) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aChange) {
|
2003-06-25 12:50:48 +04:00
|
|
|
return NS_OK;
|
2020-03-18 09:06:22 +03:00
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-02-01 04:55:25 +03:00
|
|
|
int32_t zIndex = GetZIndex(aElement);
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(Destroyed())) {
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
2013-01-15 16:22:03 +04:00
|
|
|
zIndex = std::max(zIndex + aChange, 0);
|
2018-02-01 04:55:25 +03:00
|
|
|
SetZIndex(aElement, zIndex);
|
2003-06-25 12:50:48 +04:00
|
|
|
*aReturn = zIndex;
|
|
|
|
|
2020-04-09 13:10:34 +03:00
|
|
|
return NS_WARN_IF(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : NS_OK;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
void HTMLEditor::SetZIndex(Element& aElement, int32_t aZIndex) {
|
|
|
|
nsAutoString zIndexValue;
|
|
|
|
zIndexValue.AppendInt(aZIndex);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
DebugOnly<nsresult> rvIgnored =
|
|
|
|
mCSSEditUtils->SetCSSProperty(aElement, *nsGkAtoms::z_index, zIndexValue);
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSProperty(nsGkAtoms::z_index) failed, but ignored");
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2019-06-10 13:27:07 +03:00
|
|
|
nsresult HTMLEditor::AddZIndexAsAction(int32_t aChange,
|
|
|
|
nsIPrincipal* aPrincipal) {
|
2018-10-30 13:02:58 +03:00
|
|
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
|
|
|
|
2018-10-30 13:00:17 +03:00
|
|
|
AutoEditActionDataSetter editActionData(
|
2019-06-10 13:27:07 +03:00
|
|
|
*this, EditAction::eIncreaseOrDecreaseZIndex, aPrincipal);
|
Bug 970802 - part 5: Make `AutoEditActionDataSetter` created method dispatch "beforeinput" event r=smaug,m_kato
`AutoEditActionDataSetter` is created in the stack when editor's public method
is called and that guarantees lifetime of global objects in editor such as
editor itself, selection controller, etc.
The dispatcher of `beforeinput` event returns `NS_ERROR_EDITOR_ACTION_CANCELED`
if an event is actually dispatched but canceled. The reason why it's an error
is, editor code must stop handling anything when any methods return error.
So, returning an error code is reasonable in editor module. But when it's
filtered by `EditorBase::ToGenericNSResult()` at return statement of public
methods, it's converted to `NS_SUCCESS_DOM_NO_OPERATION`. This avoids throwing
new exception, but editor class users in C++ can distinguish whether each edit
action is canceled or handled. The reason why we should not throw new
exception from XPCOM API is, without taking care of each caller may break some
our UI (especially for avoiding to break comm-central). Therefore, this patch
does not make XPCOM methods return error code when `beforeinput` event is
canceled.
In most cases, immediately after creating `AutoEditActionDataSetter` is good
timing to dispatch `beforeinput` event since editor has not touched the DOM
yet. If `beforeinput` requires `data` or `dataTransfer`, methods need to
dispatch `beforeinput` event after that. Alhtough this is not a good thing
from point of view of consistency of the code. However, I have no better
idea.
Note 1: Our implementation does NOT conform to the spec about event order
between `keypress` and `beforeinput` (dispatching `beforeinput` event after
`keypress` event). However, we follow all other browsers' behavior so that it
must be safe and the spec should be updated for backward compatibility.
Spec issue: https://github.com/w3c/uievents/issues/220
Note 2: Our implementation does NOT conform to the spec about event order
between `compositionupdate` and `beforeinput`. Our behavior is same as
Safari, but different from Chrome. This might cause web-compat issues.
However, our behavior does make sense from point of view of consistency of
event spec. Additionally, at both `compositionupdate` and `beforeinput`,
composition string in editor has not been modified yet. Therefore, this
may not cause web-compat issues (and I hope so).
Spec issue: https://github.com/w3c/input-events/issues/49
Note that this patch makes editor detect bugs that `beforeinput` event hasn't
been handled yet when it dispatches `input` event or modifying `data` and
`dataTransfer` value are modified after dispatching `beforeinput` event with
`MOZ_ASSERT`s.
Differential Revision: https://phabricator.services.mozilla.com/D58127
--HG--
extra : moz-landing-system : lando
2020-01-14 10:18:51 +03:00
|
|
|
nsresult rv = editActionData.CanHandleAndMaybeDispatchBeforeInputEvent();
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING_ASSERTION(rv == NS_ERROR_EDITOR_ACTION_CANCELED,
|
|
|
|
"CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
|
Bug 970802 - part 5: Make `AutoEditActionDataSetter` created method dispatch "beforeinput" event r=smaug,m_kato
`AutoEditActionDataSetter` is created in the stack when editor's public method
is called and that guarantees lifetime of global objects in editor such as
editor itself, selection controller, etc.
The dispatcher of `beforeinput` event returns `NS_ERROR_EDITOR_ACTION_CANCELED`
if an event is actually dispatched but canceled. The reason why it's an error
is, editor code must stop handling anything when any methods return error.
So, returning an error code is reasonable in editor module. But when it's
filtered by `EditorBase::ToGenericNSResult()` at return statement of public
methods, it's converted to `NS_SUCCESS_DOM_NO_OPERATION`. This avoids throwing
new exception, but editor class users in C++ can distinguish whether each edit
action is canceled or handled. The reason why we should not throw new
exception from XPCOM API is, without taking care of each caller may break some
our UI (especially for avoiding to break comm-central). Therefore, this patch
does not make XPCOM methods return error code when `beforeinput` event is
canceled.
In most cases, immediately after creating `AutoEditActionDataSetter` is good
timing to dispatch `beforeinput` event since editor has not touched the DOM
yet. If `beforeinput` requires `data` or `dataTransfer`, methods need to
dispatch `beforeinput` event after that. Alhtough this is not a good thing
from point of view of consistency of the code. However, I have no better
idea.
Note 1: Our implementation does NOT conform to the spec about event order
between `keypress` and `beforeinput` (dispatching `beforeinput` event after
`keypress` event). However, we follow all other browsers' behavior so that it
must be safe and the spec should be updated for backward compatibility.
Spec issue: https://github.com/w3c/uievents/issues/220
Note 2: Our implementation does NOT conform to the spec about event order
between `compositionupdate` and `beforeinput`. Our behavior is same as
Safari, but different from Chrome. This might cause web-compat issues.
However, our behavior does make sense from point of view of consistency of
event spec. Additionally, at both `compositionupdate` and `beforeinput`,
composition string in editor has not been modified yet. Therefore, this
may not cause web-compat issues (and I hope so).
Spec issue: https://github.com/w3c/input-events/issues/49
Note that this patch makes editor detect bugs that `beforeinput` event hasn't
been handled yet when it dispatches `input` event or modifying `data` and
`dataTransfer` value are modified after dispatching `beforeinput` event with
`MOZ_ASSERT`s.
Differential Revision: https://phabricator.services.mozilla.com/D58127
--HG--
extra : moz-landing-system : lando
2020-01-14 10:18:51 +03:00
|
|
|
return EditorBase::ToGenericNSResult(rv);
|
2018-10-30 13:00:17 +03:00
|
|
|
}
|
|
|
|
|
2019-09-12 09:20:49 +03:00
|
|
|
EditActionResult result = AddZIndexAsSubAction(aChange);
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(result.Succeeded(),
|
|
|
|
"HTMLEditor::AddZIndexAsSubAction() failed");
|
2019-09-12 09:20:49 +03:00
|
|
|
return EditorBase::ToGenericNSResult(result.Rv());
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2018-02-01 04:55:25 +03:00
|
|
|
int32_t HTMLEditor::GetZIndex(Element& aElement) {
|
2018-10-30 13:00:17 +03:00
|
|
|
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
|
|
|
|
if (NS_WARN_IF(!editActionData.CanHandle())) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
nsAutoString zIndexValue;
|
2003-09-03 17:58:00 +04:00
|
|
|
|
2018-02-02 12:42:25 +03:00
|
|
|
nsresult rv = CSSEditUtils::GetSpecifiedProperty(
|
2020-03-18 09:06:22 +03:00
|
|
|
aElement, *nsGkAtoms::z_index, zIndexValue);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("CSSEditUtils::GetSpecifiedProperty(nsGkAtoms::z_index) failed");
|
2018-02-01 04:55:25 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
if (zIndexValue.EqualsLiteral("auto")) {
|
|
|
|
if (!aElement.GetParentElement()) {
|
|
|
|
NS_WARNING("aElement was an orphan node or the root node");
|
|
|
|
return 0;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
// we have to look at the positioned ancestors
|
|
|
|
// cf. CSS 2 spec section 9.9.1
|
2020-03-18 09:06:22 +03:00
|
|
|
nsAutoString positionValue;
|
2020-04-09 13:10:34 +03:00
|
|
|
for (RefPtr<Element> element = aElement.GetParentElement(); element;
|
|
|
|
element = element->GetParentElement()) {
|
2020-03-18 09:06:22 +03:00
|
|
|
if (element->IsHTMLElement(nsGkAtoms::body)) {
|
2018-02-01 04:55:25 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
nsCOMPtr<nsINode> parentNode = element->GetParentElement();
|
2020-03-18 09:06:22 +03:00
|
|
|
nsresult rv = CSSEditUtils::GetComputedProperty(
|
|
|
|
*element, *nsGkAtoms::position, positionValue);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(Destroyed()) ||
|
|
|
|
NS_WARN_IF(parentNode != element->GetParentNode())) {
|
|
|
|
return 0;
|
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
if (!positionValue.EqualsLiteral("absolute")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// ah, we found one, what's its z-index ? If its z-index is auto,
|
|
|
|
// we have to continue climbing the document's tree
|
|
|
|
rv = CSSEditUtils::GetComputedProperty(*element, *nsGkAtoms::z_index,
|
|
|
|
zIndexValue);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::GetComputedProperty(nsGkAtoms::z_index) failed");
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(Destroyed()) ||
|
|
|
|
NS_WARN_IF(parentNode != element->GetParentNode())) {
|
|
|
|
return 0;
|
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
if (!zIndexValue.EqualsLiteral("auto")) {
|
|
|
|
break;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
if (zIndexValue.EqualsLiteral("auto")) {
|
2018-02-01 04:55:25 +03:00
|
|
|
return 0;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
nsresult rvIgnored;
|
|
|
|
int32_t result = zIndexValue.ToInteger(&rvIgnored);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"nsAString::ToInteger() failed, but ignored");
|
|
|
|
return result;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
bool HTMLEditor::CreateGrabberInternal(nsIContent& aParentContent) {
|
|
|
|
if (NS_WARN_IF(mGrabber)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mGrabber = CreateAnonymousElement(nsGkAtoms::span, aParentContent,
|
2020-07-01 11:29:29 +03:00
|
|
|
u"mozGrabber"_ns, false);
|
2018-09-11 08:30:33 +03:00
|
|
|
|
|
|
|
// mGrabber may be destroyed during creation due to there may be
|
|
|
|
// mutation event listener.
|
2020-03-18 09:06:22 +03:00
|
|
|
if (!mGrabber) {
|
|
|
|
NS_WARNING(
|
|
|
|
"HTMLEditor::CreateAnonymousElement(nsGkAtoms::span, mozGrabber) "
|
|
|
|
"failed");
|
2018-09-11 08:30:33 +03:00
|
|
|
return false;
|
2016-11-24 12:07:47 +03:00
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-04-04 18:32:32 +03:00
|
|
|
EventListenerManager* eventListenerManager =
|
2018-09-11 08:30:33 +03:00
|
|
|
mGrabber->GetOrCreateListenerManager();
|
2018-04-04 18:32:32 +03:00
|
|
|
eventListenerManager->AddEventListenerByType(
|
2020-07-01 11:29:29 +03:00
|
|
|
mEventListener, u"mousedown"_ns, TrustedEventsAtSystemGroupBubble());
|
2018-09-11 08:30:33 +03:00
|
|
|
MOZ_ASSERT(mGrabber);
|
|
|
|
return true;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::RefreshGrabber() {
|
2018-09-11 08:30:33 +03:00
|
|
|
if (NS_WARN_IF(!mAbsolutelyPositionedObject)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-10-30 13:00:17 +03:00
|
|
|
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
|
|
|
|
if (NS_WARN_IF(!editActionData.CanHandle())) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
nsresult rv = RefreshGrabberInternal();
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"HTMLEditor::RefreshGrabberInternal() failed");
|
|
|
|
return EditorBase::ToGenericNSResult(rv);
|
2018-09-11 08:30:33 +03:00
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
nsresult HTMLEditor::RefreshGrabberInternal() {
|
|
|
|
if (!mAbsolutelyPositionedObject) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
OwningNonNull<Element> absolutelyPositionedObject =
|
|
|
|
*mAbsolutelyPositionedObject;
|
2018-09-11 08:30:33 +03:00
|
|
|
nsresult rv = GetPositionAndDimensions(
|
2020-04-09 13:10:34 +03:00
|
|
|
absolutelyPositionedObject, mPositionedObjectX, mPositionedObjectY,
|
2018-09-11 08:30:33 +03:00
|
|
|
mPositionedObjectWidth, mPositionedObjectHeight,
|
|
|
|
mPositionedObjectBorderLeft, mPositionedObjectBorderTop,
|
|
|
|
mPositionedObjectMarginLeft, mPositionedObjectMarginTop);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
|
2018-09-11 08:30:33 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(absolutelyPositionedObject != mAbsolutelyPositionedObject)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2018-09-11 08:30:33 +03:00
|
|
|
|
2019-05-09 10:37:51 +03:00
|
|
|
RefPtr<Element> grabber = mGrabber.get();
|
2020-03-18 09:06:22 +03:00
|
|
|
MOZ_ASSERT(grabber);
|
2018-09-11 08:30:33 +03:00
|
|
|
SetAnonymousElementPosition(mPositionedObjectX + 12, mPositionedObjectY - 14,
|
2019-05-09 10:37:51 +03:00
|
|
|
grabber);
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(Destroyed())) {
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
if (NS_WARN_IF(grabber != mGrabber.get())) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
void HTMLEditor::HideGrabberInternal() {
|
|
|
|
if (NS_WARN_IF(!mAbsolutelyPositionedObject)) {
|
2018-02-01 04:55:25 +03:00
|
|
|
return;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
// Move all members to the local variables first since mutation event
|
|
|
|
// listener may try to show grabber while we're hiding them.
|
|
|
|
RefPtr<Element> absolutePositioningObject =
|
|
|
|
std::move(mAbsolutelyPositionedObject);
|
|
|
|
ManualNACPtr grabber = std::move(mGrabber);
|
|
|
|
ManualNACPtr positioningShadow = std::move(mPositioningShadow);
|
|
|
|
|
|
|
|
DebugOnly<nsresult> rv = absolutePositioningObject->UnsetAttr(
|
|
|
|
kNameSpaceID_None, nsGkAtoms::_moz_abspos, true);
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"Element::UnsetAttr(nsGkAtoms::_moz_abspos) failed, but ignored");
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2010-05-06 05:20:43 +04:00
|
|
|
// We allow the pres shell to be null; when it is, we presume there
|
|
|
|
// are no document observers to notify, but we still want to
|
|
|
|
// UnbindFromTree.
|
2019-03-15 08:01:10 +03:00
|
|
|
RefPtr<PresShell> presShell = GetPresShell();
|
2018-09-11 08:30:33 +03:00
|
|
|
if (grabber) {
|
|
|
|
DeleteRefToAnonymousNode(std::move(grabber), presShell);
|
|
|
|
}
|
|
|
|
if (positioningShadow) {
|
|
|
|
DeleteRefToAnonymousNode(std::move(positioningShadow), presShell);
|
|
|
|
}
|
2018-01-30 07:42:52 +03:00
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
nsresult HTMLEditor::ShowGrabberInternal(Element& aElement) {
|
2018-01-30 07:42:52 +03:00
|
|
|
if (NS_WARN_IF(!IsDescendantOfEditorRoot(&aElement))) {
|
2017-09-09 17:49:02 +03:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
if (NS_WARN_IF(mGrabber)) {
|
2008-04-14 00:22:31 +04:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2003-06-25 12:50:48 +04:00
|
|
|
nsAutoString classValue;
|
2018-01-30 07:42:52 +03:00
|
|
|
nsresult rv =
|
|
|
|
GetTemporaryStyleForFocusedPositionedElement(aElement, classValue);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"HTMLEditor::GetTemporaryStyleForFocusedPositionedElement() failed");
|
|
|
|
return rv;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-01-30 07:42:52 +03:00
|
|
|
rv = aElement.SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_abspos, classValue,
|
2016-10-19 12:09:33 +03:00
|
|
|
true);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Element::SetAttr(nsGkAtoms::_moz_abspos) failed");
|
|
|
|
return rv;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-01-30 07:42:52 +03:00
|
|
|
mAbsolutelyPositionedObject = &aElement;
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
Element* parentElement = aElement.GetParentElement();
|
|
|
|
if (NS_WARN_IF(!parentElement)) {
|
2017-08-07 08:09:51 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
if (!CreateGrabberInternal(*parentElement)) {
|
|
|
|
NS_WARNING("HTMLEditor::CreateGrabberInternal() failed");
|
2018-09-11 08:30:33 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we succeeded to create the grabber, HideGrabberInternal() hasn't been
|
|
|
|
// called yet. So, mAbsolutelyPositionedObject should be non-nullptr.
|
|
|
|
MOZ_ASSERT(mAbsolutelyPositionedObject);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
// Finally, move the grabber to proper position.
|
|
|
|
rv = RefreshGrabberInternal();
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"HTMLEditor::RefereshGrabberInternal() failed");
|
|
|
|
return rv;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2018-03-19 08:14:45 +03:00
|
|
|
nsresult HTMLEditor::StartMoving() {
|
2020-03-18 09:06:22 +03:00
|
|
|
RefPtr<Element> parentElement = mGrabber->GetParentElement();
|
|
|
|
if (NS_WARN_IF(!parentElement) || NS_WARN_IF(!mAbsolutelyPositionedObject)) {
|
2017-08-07 08:09:51 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
|
|
|
// now, let's create the resizing shadow
|
2017-08-07 08:09:51 +03:00
|
|
|
mPositioningShadow =
|
2020-03-18 09:06:22 +03:00
|
|
|
CreateShadow(*parentElement, *mAbsolutelyPositionedObject);
|
|
|
|
if (!mPositioningShadow) {
|
|
|
|
NS_WARNING("HTMLEditor::CreateShadow() failed");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
if (!mAbsolutelyPositionedObject) {
|
|
|
|
NS_WARNING("The target has gone during HTMLEditor::CreateShadow()");
|
2018-09-11 11:15:52 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2019-05-09 10:37:51 +03:00
|
|
|
RefPtr<Element> positioningShadow = mPositioningShadow.get();
|
|
|
|
RefPtr<Element> absolutelyPositionedObject = mAbsolutelyPositionedObject;
|
2018-09-11 11:15:52 +03:00
|
|
|
nsresult rv =
|
2019-05-09 10:37:51 +03:00
|
|
|
SetShadowPosition(*positioningShadow, *absolutelyPositionedObject,
|
2016-10-19 12:09:33 +03:00
|
|
|
mPositionedObjectX, mPositionedObjectY);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("HTMLEditor::SetShadowPosition() failed");
|
2019-05-09 10:37:51 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
|
|
|
// make the shadow appear
|
2020-03-18 09:06:22 +03:00
|
|
|
DebugOnly<nsresult> rvIgnored =
|
|
|
|
mPositioningShadow->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class, true);
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rvIgnored),
|
|
|
|
"Element::UnsetAttr(nsGkAtoms::_class) failed, but ignored");
|
2003-06-25 12:50:48 +04:00
|
|
|
|
|
|
|
// position it
|
2019-05-09 10:37:51 +03:00
|
|
|
positioningShadow = mPositioningShadow.get();
|
2020-03-18 09:06:22 +03:00
|
|
|
rvIgnored = mCSSEditUtils->SetCSSPropertyPixels(
|
|
|
|
*positioningShadow, *nsGkAtoms::width, mPositionedObjectWidth);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::width) "
|
|
|
|
"failed, but ignored");
|
|
|
|
rvIgnored = mCSSEditUtils->SetCSSPropertyPixels(
|
|
|
|
*positioningShadow, *nsGkAtoms::height, mPositionedObjectHeight);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::height) "
|
|
|
|
"failed, but ignored");
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mIsMoving = true;
|
2016-10-19 12:09:33 +03:00
|
|
|
return NS_OK; // XXX Looks like nobody refers this result
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
void HTMLEditor::SnapToGrid(int32_t& newX, int32_t& newY) {
|
2003-06-25 12:50:48 +04:00
|
|
|
if (mSnapToGridEnabled && mGridSize) {
|
2012-08-22 19:56:38 +04:00
|
|
|
newX = (int32_t)floor(((float)newX / (float)mGridSize) + 0.5f) * mGridSize;
|
|
|
|
newY = (int32_t)floor(((float)newY / (float)mGridSize) + 0.5f) * mGridSize;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
nsresult HTMLEditor::GrabberClicked() {
|
2018-11-06 09:09:18 +03:00
|
|
|
if (NS_WARN_IF(!mEventListener)) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = static_cast<HTMLEditorEventListener*>(mEventListener.get())
|
|
|
|
->ListenToMouseMoveEventForGrabber(true);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"HTMLEditorEventListener::ListenToMouseMoveEventForGrabber(true) "
|
|
|
|
"failed, but ignored");
|
2018-11-06 09:09:18 +03:00
|
|
|
return NS_OK;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
mGrabberClicked = true;
|
2020-03-18 09:06:22 +03:00
|
|
|
return NS_OK;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
nsresult HTMLEditor::EndMoving() {
|
2003-06-25 12:50:48 +04:00
|
|
|
if (mPositioningShadow) {
|
2019-03-15 08:01:10 +03:00
|
|
|
RefPtr<PresShell> presShell = GetPresShell();
|
|
|
|
if (NS_WARN_IF(!presShell)) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2019-03-15 08:01:10 +03:00
|
|
|
DeleteRefToAnonymousNode(std::move(mPositioningShadow), presShell);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mPositioningShadow = nullptr;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2018-11-06 09:09:18 +03:00
|
|
|
if (mEventListener) {
|
|
|
|
DebugOnly<nsresult> rvIgnored =
|
|
|
|
static_cast<HTMLEditorEventListener*>(mEventListener.get())
|
|
|
|
->ListenToMouseMoveEventForGrabber(false);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
2020-03-18 09:06:22 +03:00
|
|
|
"HTMLEditorEventListener::"
|
|
|
|
"ListenToMouseMoveEventForGrabber(false) failed");
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mGrabberClicked = false;
|
|
|
|
mIsMoving = false;
|
2019-05-09 10:37:51 +03:00
|
|
|
nsresult rv = RefreshEditingUI();
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"HTMLEditor::RefreshEditingUI() failed");
|
|
|
|
return rv;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
nsresult HTMLEditor::SetFinalPosition(int32_t aX, int32_t aY) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = EndMoving();
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("HTMLEditor::EndMoving() failed");
|
|
|
|
return rv;
|
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
|
|
|
// we have now to set the new width and height of the resized object
|
|
|
|
// we don't set the x and y position because we don't control that in
|
|
|
|
// a normal HTML layout
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t newX = mPositionedObjectX + aX - mOriginalX -
|
|
|
|
(mPositionedObjectBorderLeft + mPositionedObjectMarginLeft);
|
|
|
|
int32_t newY = mPositionedObjectY + aY - mOriginalY -
|
|
|
|
(mPositionedObjectBorderTop + mPositionedObjectMarginTop);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
|
|
|
SnapToGrid(newX, newY);
|
|
|
|
|
|
|
|
nsAutoString x, y;
|
|
|
|
x.AppendInt(newX);
|
|
|
|
y.AppendInt(newY);
|
|
|
|
|
|
|
|
// we want one transaction only from a user's point of view
|
2020-08-24 09:39:50 +03:00
|
|
|
AutoPlaceholderBatch treatAsOneTransaction(*this,
|
|
|
|
ScrollSelectionIntoView::Yes);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-09-11 08:30:33 +03:00
|
|
|
if (NS_WARN_IF(!mAbsolutelyPositionedObject)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
OwningNonNull<Element> absolutelyPositionedObject =
|
|
|
|
*mAbsolutelyPositionedObject;
|
2020-03-18 09:06:22 +03:00
|
|
|
DebugOnly<nsresult> rvIgnored = NS_OK;
|
|
|
|
rvIgnored = mCSSEditUtils->SetCSSPropertyPixels(*absolutelyPositionedObject,
|
|
|
|
*nsGkAtoms::top, newY);
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::top) failed, but ignored");
|
|
|
|
rvIgnored = mCSSEditUtils->SetCSSPropertyPixels(*absolutelyPositionedObject,
|
|
|
|
*nsGkAtoms::left, newX);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::left) "
|
|
|
|
"failed, but ignored");
|
2003-06-25 12:50:48 +04:00
|
|
|
// keep track of that size
|
|
|
|
mPositionedObjectX = newX;
|
|
|
|
mPositionedObjectY = newY;
|
|
|
|
|
2018-09-11 11:15:52 +03:00
|
|
|
rv = RefreshResizers();
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"HTMLEditor::RefreshResizers() failed");
|
|
|
|
return rv;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
void HTMLEditor::AddPositioningOffset(int32_t& aX, int32_t& aY) {
|
2003-06-25 12:50:48 +04:00
|
|
|
// Get the positioning offset
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t positioningOffset =
|
2011-06-17 04:59:29 +04:00
|
|
|
Preferences::GetInt("editor.positioning.offset", 0);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
|
|
|
aX += positioningOffset;
|
|
|
|
aY += positioningOffset;
|
|
|
|
}
|
|
|
|
|
2018-02-01 04:55:25 +03:00
|
|
|
nsresult HTMLEditor::SetPositionToAbsoluteOrStatic(Element& aElement,
|
|
|
|
bool aEnabled) {
|
2020-03-18 09:06:22 +03:00
|
|
|
nsAutoString positionValue;
|
|
|
|
DebugOnly<nsresult> rvIgnored = CSSEditUtils::GetComputedProperty(
|
|
|
|
aElement, *nsGkAtoms::position, positionValue);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::GetComputedProperty(nsGkAtoms::position) "
|
|
|
|
"failed, but ignored");
|
2003-06-25 12:50:48 +04:00
|
|
|
// nothing to do if the element is already in the state we want
|
2020-03-18 09:06:22 +03:00
|
|
|
if (positionValue.EqualsLiteral("absolute") == aEnabled) {
|
2003-06-25 12:50:48 +04:00
|
|
|
return NS_OK;
|
2018-02-01 04:55:25 +03:00
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-02-01 04:55:25 +03:00
|
|
|
if (aEnabled) {
|
2020-03-18 09:06:22 +03:00
|
|
|
nsresult rv = SetPositionToAbsolute(aElement);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"HTMLEditor::SetPositionToAbsolute() failed");
|
|
|
|
return rv;
|
2018-02-01 04:55:25 +03:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
nsresult rv = SetPositionToStatic(aElement);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"HTMLEditor::SetPositionToStatic() failed");
|
|
|
|
return rv;
|
2018-02-01 04:55:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult HTMLEditor::SetPositionToAbsolute(Element& aElement) {
|
2018-10-30 13:04:08 +03:00
|
|
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
|
|
|
|
2020-08-24 09:39:50 +03:00
|
|
|
AutoPlaceholderBatch treatAsOneTransaction(*this,
|
|
|
|
ScrollSelectionIntoView::Yes);
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2018-02-01 04:55:25 +03:00
|
|
|
int32_t x, y;
|
2020-03-18 09:06:22 +03:00
|
|
|
DebugOnly<nsresult> rvIgnored = GetElementOrigin(aElement, x, y);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"HTMLEditor::GetElementOrigin() failed, but ignored");
|
2018-02-01 04:55:25 +03:00
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
rvIgnored = mCSSEditUtils->SetCSSProperty(aElement, *nsGkAtoms::position,
|
2020-07-01 11:29:29 +03:00
|
|
|
u"absolute"_ns);
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSProperty(nsGkAtoms::position, "
|
|
|
|
"absolute) failed, but ignored");
|
2018-02-01 04:55:25 +03:00
|
|
|
|
|
|
|
AddPositioningOffset(x, y);
|
|
|
|
SnapToGrid(x, y);
|
|
|
|
SetTopAndLeft(aElement, x, y);
|
|
|
|
|
|
|
|
// we may need to create a br if the positioned element is alone in its
|
|
|
|
// container
|
|
|
|
nsINode* parentNode = aElement.GetParentNode();
|
2020-03-18 09:06:22 +03:00
|
|
|
if (parentNode->GetChildCount() != 1) {
|
|
|
|
return NS_OK;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
RefPtr<Element> newBRElement =
|
|
|
|
InsertBRElementWithTransaction(EditorDOMPoint(parentNode, 0));
|
|
|
|
NS_WARNING_ASSERTION(newBRElement,
|
|
|
|
"HTMLEditor::InsertBRElementWithTransaction() failed");
|
|
|
|
return newBRElement ? NS_OK : NS_ERROR_FAILURE;
|
2018-02-01 04:55:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult HTMLEditor::SetPositionToStatic(Element& aElement) {
|
2020-08-26 07:48:16 +03:00
|
|
|
nsCOMPtr<nsStyledElement> styledElement = do_QueryInterface(&aElement);
|
|
|
|
if (NS_WARN_IF(!styledElement)) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2020-08-24 09:39:50 +03:00
|
|
|
AutoPlaceholderBatch treatAsOneTransaction(*this,
|
|
|
|
ScrollSelectionIntoView::Yes);
|
2018-02-01 04:55:25 +03:00
|
|
|
|
2020-08-26 07:48:16 +03:00
|
|
|
nsresult rv;
|
|
|
|
rv = mCSSEditUtils->RemoveCSSPropertyWithTransaction(
|
|
|
|
*styledElement, *nsGkAtoms::position, EmptyString());
|
|
|
|
if (rv == NS_ERROR_EDITOR_DESTROYED) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
|
|
|
|
"destroyed the editor");
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
|
|
|
|
"failed, but ignored");
|
|
|
|
rv = mCSSEditUtils->RemoveCSSPropertyWithTransaction(
|
|
|
|
*styledElement, *nsGkAtoms::top, EmptyString());
|
|
|
|
if (rv == NS_ERROR_EDITOR_DESTROYED) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
|
|
|
|
"destroyed the editor");
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
|
|
|
|
"failed, but ignored");
|
|
|
|
rv = mCSSEditUtils->RemoveCSSPropertyWithTransaction(
|
|
|
|
*styledElement, *nsGkAtoms::left, EmptyString());
|
|
|
|
if (rv == NS_ERROR_EDITOR_DESTROYED) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
|
|
|
|
"destroyed the editor");
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
|
|
|
|
"failed, but ignored");
|
|
|
|
rv = mCSSEditUtils->RemoveCSSPropertyWithTransaction(
|
|
|
|
*styledElement, *nsGkAtoms::z_index, EmptyString());
|
|
|
|
if (rv == NS_ERROR_EDITOR_DESTROYED) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
|
|
|
|
"destroyed the editor");
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
|
|
|
|
"failed, but ignored");
|
2018-02-01 04:55:25 +03:00
|
|
|
|
2020-08-26 07:48:16 +03:00
|
|
|
if (!HTMLEditUtils::IsImage(styledElement)) {
|
|
|
|
rv = mCSSEditUtils->RemoveCSSPropertyWithTransaction(
|
|
|
|
*styledElement, *nsGkAtoms::width, EmptyString());
|
|
|
|
if (rv == NS_ERROR_EDITOR_DESTROYED) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
|
|
|
|
"destroyed the editor");
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
|
|
|
|
"failed, but ignored");
|
|
|
|
rv = mCSSEditUtils->RemoveCSSPropertyWithTransaction(
|
|
|
|
*styledElement, *nsGkAtoms::height, EmptyString());
|
|
|
|
if (rv == NS_ERROR_EDITOR_DESTROYED) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
|
|
|
|
"destroyed the editor");
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
"CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
|
|
|
|
"failed, but ignored");
|
2018-02-01 04:55:25 +03:00
|
|
|
}
|
2003-06-25 12:50:48 +04:00
|
|
|
|
2020-08-26 07:48:16 +03:00
|
|
|
if (!styledElement->IsHTMLElement(nsGkAtoms::div) ||
|
|
|
|
HTMLEditor::HasStyleOrIdOrClassAttribute(*styledElement)) {
|
2019-09-09 13:47:08 +03:00
|
|
|
return NS_OK;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
2019-09-09 13:47:08 +03:00
|
|
|
|
|
|
|
// Make sure the first fild and last child of aElement starts/ends hard
|
|
|
|
// line(s) even after removing `aElement`.
|
2020-08-26 07:48:16 +03:00
|
|
|
rv = EnsureHardLineBeginsWithFirstChildOf(*styledElement);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("HTMLEditor::EnsureHardLineBeginsWithFirstChildOf() failed");
|
2019-09-09 13:47:08 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2020-08-26 07:48:16 +03:00
|
|
|
rv = EnsureHardLineEndsWithLastChildOf(*styledElement);
|
2020-03-18 09:06:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("HTMLEditor::EnsureHardLineEndsWithLastChildOf() failed");
|
2019-09-09 13:47:08 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2020-08-26 07:48:16 +03:00
|
|
|
rv = RemoveContainerWithTransaction(*styledElement);
|
|
|
|
if (NS_WARN_IF(Destroyed())) {
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
2019-09-09 13:47:08 +03:00
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
2020-04-30 09:36:41 +03:00
|
|
|
"HTMLEditor::RemoveContainerWithTransaction() failed");
|
2019-09-09 13:47:08 +03:00
|
|
|
return rv;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::SetSnapToGridEnabled(bool aEnabled) {
|
2003-06-25 12:50:48 +04:00
|
|
|
mSnapToGridEnabled = aEnabled;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::GetSnapToGridEnabled(bool* aIsEnabled) {
|
2003-06-25 12:50:48 +04:00
|
|
|
*aIsEnabled = mSnapToGridEnabled;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::SetGridSize(uint32_t aSize) {
|
2003-06-25 12:50:48 +04:00
|
|
|
mGridSize = aSize;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
NS_IMETHODIMP HTMLEditor::GetGridSize(uint32_t* aSize) {
|
2003-06-25 12:50:48 +04:00
|
|
|
*aSize = mGridSize;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// self-explanatory
|
2018-02-01 04:55:25 +03:00
|
|
|
void HTMLEditor::SetTopAndLeft(Element& aElement, int32_t aX, int32_t aY) {
|
2020-08-24 09:39:50 +03:00
|
|
|
AutoPlaceholderBatch treatAsOneTransaction(*this,
|
|
|
|
ScrollSelectionIntoView::Yes);
|
2020-03-18 09:06:22 +03:00
|
|
|
DebugOnly<nsresult> rvIgnored = NS_OK;
|
|
|
|
rvIgnored =
|
|
|
|
mCSSEditUtils->SetCSSPropertyPixels(aElement, *nsGkAtoms::left, aX);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::left) "
|
|
|
|
"failed, but ignored");
|
|
|
|
rvIgnored =
|
|
|
|
mCSSEditUtils->SetCSSPropertyPixels(aElement, *nsGkAtoms::top, aY);
|
|
|
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
|
|
|
"CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::top) "
|
|
|
|
"failed, but ignored");
|
2015-05-13 18:58:25 +03:00
|
|
|
}
|
|
|
|
|
2018-01-30 07:42:52 +03:00
|
|
|
nsresult HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(
|
|
|
|
Element& aElement, nsAString& aReturn) {
|
2003-06-25 12:50:48 +04:00
|
|
|
// we are going to outline the positioned element and bring it to the
|
|
|
|
// front to overlap any other element intersecting with it. But
|
|
|
|
// first, let's see what's the background and foreground colors of the
|
|
|
|
// positioned element.
|
|
|
|
// if background-image computed value is 'none,
|
|
|
|
// If the background color is 'auto' and R G B values of the foreground are
|
|
|
|
// each above #d0, use a black background
|
|
|
|
// If the background color is 'auto' and at least one of R G B values of
|
|
|
|
// the foreground is below #d0, use a white background
|
|
|
|
// Otherwise don't change background/foreground
|
|
|
|
aReturn.Truncate();
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
nsAutoString backgroundImageValue;
|
2018-02-02 12:42:25 +03:00
|
|
|
nsresult rv = CSSEditUtils::GetComputedProperty(
|
2020-03-18 09:06:22 +03:00
|
|
|
aElement, *nsGkAtoms::background_image, backgroundImageValue);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::GetComputedProperty(nsGkAtoms::background_image) "
|
|
|
|
"failed");
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (!backgroundImageValue.EqualsLiteral("none")) {
|
2018-01-30 07:42:52 +03:00
|
|
|
return NS_OK;
|
2003-06-25 12:50:48 +04:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
nsAutoString backgroundColorValue;
|
2018-02-02 12:42:25 +03:00
|
|
|
rv = CSSEditUtils::GetComputedProperty(aElement, *nsGkAtoms::backgroundColor,
|
2020-03-18 09:06:22 +03:00
|
|
|
backgroundColorValue);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"CSSEditUtils::GetComputedProperty(nsGkAtoms::backgroundColor) "
|
|
|
|
"failed");
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (!backgroundColorValue.EqualsLiteral("rgba(0, 0, 0, 0)")) {
|
2018-01-30 07:42:52 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-03-22 21:20:41 +03:00
|
|
|
RefPtr<ComputedStyle> style =
|
|
|
|
nsComputedDOMStyle::GetComputedStyle(&aElement, nullptr);
|
2020-04-09 13:10:34 +03:00
|
|
|
if (NS_WARN_IF(Destroyed())) {
|
|
|
|
return NS_ERROR_EDITOR_DESTROYED;
|
|
|
|
}
|
2020-03-18 09:06:22 +03:00
|
|
|
if (!style) {
|
|
|
|
NS_WARNING("nsComputedDOMStyle::GetComputedStyle() failed");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2018-01-30 07:42:52 +03:00
|
|
|
|
2020-03-18 09:06:22 +03:00
|
|
|
static const uint8_t kBlackBgTrigger = 0xd0;
|
2018-01-30 07:42:52 +03:00
|
|
|
|
2019-05-31 17:48:22 +03:00
|
|
|
const auto& color = style->StyleText()->mColor;
|
2019-04-06 20:47:58 +03:00
|
|
|
if (color.red >= kBlackBgTrigger && color.green >= kBlackBgTrigger &&
|
|
|
|
color.blue >= kBlackBgTrigger) {
|
2018-01-30 07:42:52 +03:00
|
|
|
aReturn.AssignLiteral("black");
|
|
|
|
} else {
|
|
|
|
aReturn.AssignLiteral("white");
|
|
|
|
}
|
2018-03-15 14:57:38 +03:00
|
|
|
|
2003-06-25 12:50:48 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-07-09 05:42:33 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|