1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "HTMLEditor.h"
9 #include "CSSEditUtils.h"
10 #include "EditAction.h"
11 #include "HTMLEditHelpers.h"
12 #include "HTMLEditorEventListener.h"
13 #include "HTMLEditUtils.h"
15 #include "mozilla/EventListenerManager.h"
16 #include "mozilla/mozalloc.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/PresShell.h"
19 #include "mozilla/StaticPrefs_editor.h"
20 #include "mozilla/dom/AncestorIterator.h"
21 #include "mozilla/dom/Selection.h"
22 #include "mozilla/dom/Element.h"
23 #include "mozilla/dom/EventTarget.h"
24 #include "nsAString.h"
25 #include "nsAlgorithm.h"
27 #include "nsComputedDOMStyle.h"
30 #include "nsGkAtoms.h"
31 #include "nsIContent.h"
32 #include "nsROCSSPrimitiveValue.h"
34 #include "nsIPrincipal.h"
35 #include "nsISupportsImpl.h"
36 #include "nsISupportsUtils.h"
37 #include "nsLiteralString.h"
38 #include "nsReadableUtils.h"
40 #include "nsStringFwd.h"
41 #include "nsStyledElement.h"
49 nsresult
HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction(
50 bool aEnabled
, nsIPrincipal
* aPrincipal
) {
51 AutoEditActionDataSetter
editActionData(
52 *this, EditAction::eSetPositionToAbsoluteOrStatic
, aPrincipal
);
53 nsresult rv
= editActionData
.CanHandleAndMaybeDispatchBeforeInputEvent();
55 NS_WARNING_ASSERTION(rv
== NS_ERROR_EDITOR_ACTION_CANCELED
,
56 "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
60 const RefPtr
<Element
> editingHost
= ComputeEditingHost();
62 return NS_SUCCESS_DOM_NO_OPERATION
;
66 Result
<EditActionResult
, nsresult
> result
=
67 SetSelectionToAbsoluteAsSubAction(*editingHost
);
68 if (MOZ_UNLIKELY(result
.isErr())) {
69 NS_WARNING("HTMLEditor::SetSelectionToAbsoluteAsSubAction() failed");
70 return result
.unwrapErr();
74 Result
<EditActionResult
, nsresult
> result
= SetSelectionToStaticAsSubAction();
75 if (MOZ_UNLIKELY(result
.isErr())) {
76 NS_WARNING("HTMLEditor::SetSelectionToStaticAsSubAction() failed");
77 return result
.unwrapErr();
82 already_AddRefed
<Element
>
83 HTMLEditor::GetAbsolutelyPositionedSelectionContainer() const {
84 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
85 if (NS_WARN_IF(!editActionData
.CanHandle())) {
89 Element
* selectionContainerElement
= GetSelectionContainerElement();
90 if (NS_WARN_IF(!selectionContainerElement
)) {
94 AutoTArray
<RefPtr
<Element
>, 24> arrayOfParentElements
;
95 for (Element
* element
:
96 selectionContainerElement
->InclusiveAncestorsOfType
<Element
>()) {
97 arrayOfParentElements
.AppendElement(element
);
100 nsAutoString positionValue
;
101 for (RefPtr
<Element
> element
= selectionContainerElement
; element
;
102 element
= element
->GetParentElement()) {
103 if (element
->IsHTMLElement(nsGkAtoms::html
)) {
105 "HTMLEditor::GetAbsolutelyPositionedSelectionContainer() reached "
109 nsCOMPtr
<nsINode
> parentNode
= element
->GetParentNode();
110 nsresult rv
= CSSEditUtils::GetComputedProperty(
111 MOZ_KnownLive(*element
), *nsGkAtoms::position
, positionValue
);
114 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
117 if (NS_WARN_IF(Destroyed()) ||
118 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
121 if (positionValue
.EqualsLiteral("absolute")) {
122 return element
.forget();
128 NS_IMETHODIMP
HTMLEditor::GetAbsolutePositioningEnabled(bool* aIsEnabled
) {
129 *aIsEnabled
= IsAbsolutePositionEditorEnabled();
133 NS_IMETHODIMP
HTMLEditor::SetAbsolutePositioningEnabled(bool aIsEnabled
) {
134 EnableAbsolutePositionEditor(aIsEnabled
);
138 Result
<int32_t, nsresult
> HTMLEditor::AddZIndexWithTransaction(
139 nsStyledElement
& aStyledElement
, int32_t aChange
) {
141 return 0; // XXX Why don't we return current z-index value in this case?
144 int32_t zIndex
= GetZIndex(aStyledElement
);
145 if (NS_WARN_IF(Destroyed())) {
146 return Err(NS_ERROR_EDITOR_DESTROYED
);
148 zIndex
= std::max(zIndex
+ aChange
, 0);
149 nsresult rv
= SetZIndexWithTransaction(aStyledElement
, zIndex
);
150 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
151 NS_WARNING("HTMLEditor::SetZIndexWithTransaction() destroyed the editor");
152 return Err(NS_ERROR_EDITOR_DESTROYED
);
154 NS_WARNING_ASSERTION(
156 "HTMLEditor::SetZIndexWithTransaction() failed, but ignored");
160 nsresult
HTMLEditor::SetZIndexWithTransaction(nsStyledElement
& aStyledElement
,
162 nsAutoString zIndexValue
;
163 zIndexValue
.AppendInt(aZIndex
);
165 nsresult rv
= CSSEditUtils::SetCSSPropertyWithTransaction(
166 *this, aStyledElement
, *nsGkAtoms::z_index
, zIndexValue
);
167 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
169 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::z_index) "
170 "destroyed the editor");
171 return NS_ERROR_EDITOR_DESTROYED
;
173 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
174 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::"
175 "z_index) failed, but ignored");
179 nsresult
HTMLEditor::AddZIndexAsAction(int32_t aChange
,
180 nsIPrincipal
* aPrincipal
) {
181 MOZ_ASSERT(IsEditActionDataAvailable());
183 AutoEditActionDataSetter
editActionData(
184 *this, EditAction::eIncreaseOrDecreaseZIndex
, aPrincipal
);
185 nsresult rv
= editActionData
.CanHandleAndMaybeDispatchBeforeInputEvent();
187 NS_WARNING_ASSERTION(rv
== NS_ERROR_EDITOR_ACTION_CANCELED
,
188 "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
189 return EditorBase::ToGenericNSResult(rv
);
192 Result
<EditActionResult
, nsresult
> result
= AddZIndexAsSubAction(aChange
);
193 if (MOZ_UNLIKELY(result
.isErr())) {
194 NS_WARNING("HTMLEditor::AddZIndexAsSubAction() failed");
195 return EditorBase::ToGenericNSResult(result
.unwrapErr());
200 int32_t HTMLEditor::GetZIndex(Element
& aElement
) {
201 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
202 if (NS_WARN_IF(!editActionData
.CanHandle())) {
206 nsAutoString zIndexValue
;
208 nsresult rv
= CSSEditUtils::GetSpecifiedProperty(
209 aElement
, *nsGkAtoms::z_index
, zIndexValue
);
211 NS_WARNING("CSSEditUtils::GetSpecifiedProperty(nsGkAtoms::z_index) failed");
214 if (zIndexValue
.EqualsLiteral("auto")) {
215 if (!aElement
.GetParentElement()) {
216 NS_WARNING("aElement was an orphan node or the root node");
219 // we have to look at the positioned ancestors
220 // cf. CSS 2 spec section 9.9.1
221 nsAutoString positionValue
;
222 for (RefPtr
<Element
> element
= aElement
.GetParentElement(); element
;
223 element
= element
->GetParentElement()) {
224 if (element
->IsHTMLElement(nsGkAtoms::body
)) {
227 nsCOMPtr
<nsINode
> parentNode
= element
->GetParentElement();
228 nsresult rv
= CSSEditUtils::GetComputedProperty(
229 *element
, *nsGkAtoms::position
, positionValue
);
232 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
235 if (NS_WARN_IF(Destroyed()) ||
236 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
239 if (!positionValue
.EqualsLiteral("absolute")) {
242 // ah, we found one, what's its z-index ? If its z-index is auto,
243 // we have to continue climbing the document's tree
244 rv
= CSSEditUtils::GetComputedProperty(*element
, *nsGkAtoms::z_index
,
248 "CSSEditUtils::GetComputedProperty(nsGkAtoms::z_index) failed");
251 if (NS_WARN_IF(Destroyed()) ||
252 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
255 if (!zIndexValue
.EqualsLiteral("auto")) {
261 if (zIndexValue
.EqualsLiteral("auto")) {
266 int32_t result
= zIndexValue
.ToInteger(&rvIgnored
);
267 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
268 "nsAString::ToInteger() failed, but ignored");
272 bool HTMLEditor::CreateGrabberInternal(nsIContent
& aParentContent
) {
273 if (NS_WARN_IF(mGrabber
)) {
277 mGrabber
= CreateAnonymousElement(nsGkAtoms::span
, aParentContent
,
278 u
"mozGrabber"_ns
, false);
280 // mGrabber may be destroyed during creation due to there may be
281 // mutation event listener.
284 "HTMLEditor::CreateAnonymousElement(nsGkAtoms::span, mozGrabber) "
289 EventListenerManager
* eventListenerManager
=
290 mGrabber
->GetOrCreateListenerManager();
291 eventListenerManager
->AddEventListenerByType(
292 mEventListener
, u
"mousedown"_ns
, TrustedEventsAtSystemGroupBubble());
293 MOZ_ASSERT(mGrabber
);
297 nsresult
HTMLEditor::RefreshGrabberInternal() {
298 MOZ_ASSERT(IsEditActionDataAvailable());
300 if (!mAbsolutelyPositionedObject
) {
304 OwningNonNull
<Element
> absolutelyPositionedObject
=
305 *mAbsolutelyPositionedObject
;
306 nsresult rv
= GetPositionAndDimensions(
307 absolutelyPositionedObject
, mPositionedObjectX
, mPositionedObjectY
,
308 mPositionedObjectWidth
, mPositionedObjectHeight
,
309 mPositionedObjectBorderLeft
, mPositionedObjectBorderTop
,
310 mPositionedObjectMarginLeft
, mPositionedObjectMarginTop
);
312 NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
315 if (NS_WARN_IF(absolutelyPositionedObject
!= mAbsolutelyPositionedObject
)) {
316 return NS_ERROR_FAILURE
;
319 RefPtr
<nsStyledElement
> grabberStyledElement
=
320 nsStyledElement::FromNodeOrNull(mGrabber
.get());
321 if (!grabberStyledElement
) {
324 rv
= SetAnonymousElementPositionWithoutTransaction(
325 *grabberStyledElement
, mPositionedObjectX
+ 12, mPositionedObjectY
- 14);
326 if (NS_WARN_IF(Destroyed())) {
327 return NS_ERROR_EDITOR_DESTROYED
;
331 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() failed");
334 if (NS_WARN_IF(grabberStyledElement
!= mGrabber
.get())) {
335 return NS_ERROR_FAILURE
;
340 void HTMLEditor::HideGrabberInternal() {
341 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
345 // Move all members to the local variables first since mutation event
346 // listener may try to show grabber while we're hiding them.
347 RefPtr
<Element
> absolutePositioningObject
=
348 std::move(mAbsolutelyPositionedObject
);
349 ManualNACPtr grabber
= std::move(mGrabber
);
350 ManualNACPtr positioningShadow
= std::move(mPositioningShadow
);
352 // If we're still in dragging mode, it means that the dragging is canceled
354 if (mGrabberClicked
|| mIsMoving
) {
355 mGrabberClicked
= false;
357 if (mEventListener
) {
358 DebugOnly
<nsresult
> rvIgnored
=
359 static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
360 ->ListenToMouseMoveEventForGrabber(false);
361 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
362 "HTMLEditorEventListener::"
363 "ListenToMouseMoveEventForGrabber(false) failed");
367 DebugOnly
<nsresult
> rv
= absolutePositioningObject
->UnsetAttr(
368 kNameSpaceID_None
, nsGkAtoms::_moz_abspos
, true);
369 NS_WARNING_ASSERTION(
371 "Element::UnsetAttr(nsGkAtoms::_moz_abspos) failed, but ignored");
373 // We allow the pres shell to be null; when it is, we presume there
374 // are no document observers to notify, but we still want to
376 RefPtr
<PresShell
> presShell
= GetPresShell();
378 DeleteRefToAnonymousNode(std::move(grabber
), presShell
);
380 if (positioningShadow
) {
381 DeleteRefToAnonymousNode(std::move(positioningShadow
), presShell
);
385 nsresult
HTMLEditor::ShowGrabberInternal(Element
& aElement
) {
386 MOZ_ASSERT(IsEditActionDataAvailable());
388 const RefPtr
<Element
> editingHost
= ComputeEditingHost();
389 if (NS_WARN_IF(!editingHost
) ||
390 NS_WARN_IF(!aElement
.IsInclusiveDescendantOf(editingHost
))) {
391 return NS_ERROR_UNEXPECTED
;
394 if (NS_WARN_IF(mGrabber
)) {
395 return NS_ERROR_UNEXPECTED
;
398 nsAutoString classValue
;
400 GetTemporaryStyleForFocusedPositionedElement(aElement
, classValue
);
403 "HTMLEditor::GetTemporaryStyleForFocusedPositionedElement() failed");
407 rv
= aElement
.SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_abspos
, classValue
,
410 NS_WARNING("Element::SetAttr(nsGkAtoms::_moz_abspos) failed");
414 mAbsolutelyPositionedObject
= &aElement
;
416 Element
* parentElement
= aElement
.GetParentElement();
417 if (NS_WARN_IF(!parentElement
)) {
418 return NS_ERROR_FAILURE
;
421 if (!CreateGrabberInternal(*parentElement
)) {
422 NS_WARNING("HTMLEditor::CreateGrabberInternal() failed");
423 return NS_ERROR_FAILURE
;
426 // If we succeeded to create the grabber, HideGrabberInternal() hasn't been
427 // called yet. So, mAbsolutelyPositionedObject should be non-nullptr.
428 MOZ_ASSERT(mAbsolutelyPositionedObject
);
430 // Finally, move the grabber to proper position.
431 rv
= RefreshGrabberInternal();
432 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
433 "HTMLEditor::RefereshGrabberInternal() failed");
437 nsresult
HTMLEditor::StartMoving() {
438 MOZ_ASSERT(mGrabber
);
440 RefPtr
<Element
> parentElement
= mGrabber
->GetParentElement();
441 if (NS_WARN_IF(!parentElement
) || NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
442 return NS_ERROR_FAILURE
;
445 // now, let's create the resizing shadow
447 CreateShadow(*parentElement
, *mAbsolutelyPositionedObject
);
448 if (!mPositioningShadow
) {
449 NS_WARNING("HTMLEditor::CreateShadow() failed");
450 return NS_ERROR_FAILURE
;
452 if (!mAbsolutelyPositionedObject
) {
453 NS_WARNING("The target has gone during HTMLEditor::CreateShadow()");
454 return NS_ERROR_FAILURE
;
456 RefPtr
<Element
> positioningShadow
= mPositioningShadow
.get();
457 RefPtr
<Element
> absolutelyPositionedObject
= mAbsolutelyPositionedObject
;
459 SetShadowPosition(*positioningShadow
, *absolutelyPositionedObject
,
460 mPositionedObjectX
, mPositionedObjectY
);
462 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
466 // make the shadow appear
467 DebugOnly
<nsresult
> rvIgnored
=
468 mPositioningShadow
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, true);
469 NS_WARNING_ASSERTION(
470 NS_SUCCEEDED(rvIgnored
),
471 "Element::UnsetAttr(nsGkAtoms::_class) failed, but ignored");
474 if (RefPtr
<nsStyledElement
> positioningShadowStyledElement
=
475 nsStyledElement::FromNode(mPositioningShadow
.get())) {
477 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
478 *positioningShadowStyledElement
, *nsGkAtoms::width
,
479 mPositionedObjectWidth
);
480 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
482 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
483 "nsGkAtoms::width) destroyed the editor");
484 return NS_ERROR_EDITOR_DESTROYED
;
486 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
487 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
488 "nsGkAtoms::width) failed, but ignored");
489 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
490 *positioningShadowStyledElement
, *nsGkAtoms::height
,
491 mPositionedObjectHeight
);
492 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
494 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
495 "nsGkAtoms::height) destroyed the editor");
496 return NS_ERROR_EDITOR_DESTROYED
;
498 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
499 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
500 "nsGkAtoms::height) failed, but ignored");
504 return NS_OK
; // XXX Looks like nobody refers this result
507 void HTMLEditor::SnapToGrid(int32_t& newX
, int32_t& newY
) const {
508 if (mSnapToGridEnabled
&& mGridSize
) {
509 newX
= (int32_t)floor(((float)newX
/ (float)mGridSize
) + 0.5f
) * mGridSize
;
510 newY
= (int32_t)floor(((float)newY
/ (float)mGridSize
) + 0.5f
) * mGridSize
;
514 nsresult
HTMLEditor::GrabberClicked() {
515 if (NS_WARN_IF(!mEventListener
)) {
516 return NS_ERROR_NOT_INITIALIZED
;
518 nsresult rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
519 ->ListenToMouseMoveEventForGrabber(true);
522 "HTMLEditorEventListener::ListenToMouseMoveEventForGrabber(true) "
523 "failed, but ignored");
526 mGrabberClicked
= true;
530 nsresult
HTMLEditor::EndMoving() {
531 if (mPositioningShadow
) {
532 RefPtr
<PresShell
> presShell
= GetPresShell();
533 if (NS_WARN_IF(!presShell
)) {
534 return NS_ERROR_NOT_INITIALIZED
;
537 DeleteRefToAnonymousNode(std::move(mPositioningShadow
), presShell
);
539 mPositioningShadow
= nullptr;
542 if (mEventListener
) {
543 DebugOnly
<nsresult
> rvIgnored
=
544 static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
545 ->ListenToMouseMoveEventForGrabber(false);
546 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
547 "HTMLEditorEventListener::"
548 "ListenToMouseMoveEventForGrabber(false) failed");
551 mGrabberClicked
= false;
553 nsresult rv
= RefreshEditingUI();
554 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
555 "HTMLEditor::RefreshEditingUI() failed");
559 nsresult
HTMLEditor::SetFinalPosition(int32_t aX
, int32_t aY
) {
560 MOZ_ASSERT(IsEditActionDataAvailable());
562 nsresult rv
= EndMoving();
564 NS_WARNING("HTMLEditor::EndMoving() failed");
568 // we have now to set the new width and height of the resized object
569 // we don't set the x and y position because we don't control that in
570 // a normal HTML layout
571 int32_t newX
= mPositionedObjectX
+ aX
- mOriginalX
-
572 (mPositionedObjectBorderLeft
+ mPositionedObjectMarginLeft
);
573 int32_t newY
= mPositionedObjectY
+ aY
- mOriginalY
-
574 (mPositionedObjectBorderTop
+ mPositionedObjectMarginTop
);
576 SnapToGrid(newX
, newY
);
582 // we want one transaction only from a user's point of view
583 AutoPlaceholderBatch
treatAsOneTransaction(
584 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
586 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
587 return NS_ERROR_FAILURE
;
589 if (RefPtr
<nsStyledElement
> styledAbsolutelyPositionedElement
=
590 nsStyledElement::FromNode(mAbsolutelyPositionedObject
)) {
592 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
593 *this, *styledAbsolutelyPositionedElement
, *nsGkAtoms::top
, newY
);
594 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
596 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
597 "destroyed the editor");
598 return NS_ERROR_EDITOR_DESTROYED
;
600 NS_WARNING_ASSERTION(
602 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
603 "failed, but ignored");
604 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
605 *this, *styledAbsolutelyPositionedElement
, *nsGkAtoms::left
, newX
);
606 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
608 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
609 "destroyed the editor");
610 return NS_ERROR_EDITOR_DESTROYED
;
612 NS_WARNING_ASSERTION(
614 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
615 "failed, but ignored");
617 // keep track of that size
618 mPositionedObjectX
= newX
;
619 mPositionedObjectY
= newY
;
621 rv
= RefreshResizersInternal();
622 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
623 "HTMLEditor::RefreshResizersInternal() failed");
627 nsresult
HTMLEditor::SetPositionToAbsoluteOrStatic(Element
& aElement
,
629 nsAutoString positionValue
;
630 DebugOnly
<nsresult
> rvIgnored
= CSSEditUtils::GetComputedProperty(
631 aElement
, *nsGkAtoms::position
, positionValue
);
632 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
633 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) "
634 "failed, but ignored");
635 // nothing to do if the element is already in the state we want
636 if (positionValue
.EqualsLiteral("absolute") == aEnabled
) {
641 nsresult rv
= SetPositionToAbsolute(aElement
);
642 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
643 "HTMLEditor::SetPositionToAbsolute() failed");
647 nsresult rv
= SetPositionToStatic(aElement
);
648 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
649 "HTMLEditor::SetPositionToStatic() failed");
653 nsresult
HTMLEditor::SetPositionToAbsolute(Element
& aElement
) {
654 MOZ_ASSERT(IsEditActionDataAvailable());
656 AutoPlaceholderBatch
treatAsOneTransaction(
657 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
660 DebugOnly
<nsresult
> rvIgnored
= GetElementOrigin(aElement
, x
, y
);
661 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
662 "HTMLEditor::GetElementOrigin() failed, but ignored");
664 nsStyledElement
* styledElement
= nsStyledElement::FromNode(&aElement
);
666 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
667 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
668 nsresult rv
= CSSEditUtils::SetCSSPropertyWithTransaction(
669 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::position
,
671 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
673 "CSSEditUtils::SetCSSProperyWithTransaction(nsGkAtoms::Position) "
674 "destroyed the editor");
675 return NS_ERROR_EDITOR_DESTROYED
;
677 NS_WARNING_ASSERTION(
678 NS_SUCCEEDED(rvIgnored
),
679 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::position, "
680 "absolute) failed, but ignored");
685 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
686 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
688 SetTopAndLeftWithTransaction(MOZ_KnownLive(*styledElement
), x
, y
);
690 NS_WARNING("HTMLEditor::SetTopAndLeftWithTransaction() failed");
695 // we may need to create a br if the positioned element is alone in its
697 nsINode
* parentNode
= aElement
.GetParentNode();
698 if (parentNode
->GetChildCount() != 1) {
701 Result
<CreateElementResult
, nsresult
> insertBRElementResult
=
702 InsertBRElement(WithTransaction::Yes
, EditorDOMPoint(parentNode
, 0u));
703 if (MOZ_UNLIKELY(insertBRElementResult
.isErr())) {
704 NS_WARNING("HTMLEditor::InsertBRElement(WithTransaction::Yes) failed");
705 return insertBRElementResult
.unwrapErr();
707 // XXX Is this intentional selection change?
708 nsresult rv
= insertBRElementResult
.inspect().SuggestCaretPointTo(
709 *this, {SuggestCaret::OnlyIfHasSuggestion
,
710 SuggestCaret::OnlyIfTransactionsAllowedToDoIt
});
711 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
712 "CreateElementResult::SuggestCaretPointTo() failed");
713 MOZ_ASSERT(insertBRElementResult
.inspect().GetNewNode());
717 nsresult
HTMLEditor::SetPositionToStatic(Element
& aElement
) {
718 nsStyledElement
* styledElement
= nsStyledElement::FromNode(&aElement
);
719 if (NS_WARN_IF(!styledElement
)) {
720 return NS_ERROR_INVALID_ARG
;
723 AutoPlaceholderBatch
treatAsOneTransaction(
724 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
727 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
728 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
729 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
730 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::position
, u
""_ns
);
731 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
733 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
734 "destroyed the editor");
735 return NS_ERROR_EDITOR_DESTROYED
;
737 NS_WARNING_ASSERTION(
739 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
740 "failed, but ignored");
741 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
742 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
743 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
744 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::top
, u
""_ns
);
745 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
747 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
748 "destroyed the editor");
749 return NS_ERROR_EDITOR_DESTROYED
;
751 NS_WARNING_ASSERTION(
753 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
754 "failed, but ignored");
755 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
756 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
757 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
758 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::left
, u
""_ns
);
759 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
761 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
762 "destroyed the editor");
763 return NS_ERROR_EDITOR_DESTROYED
;
765 NS_WARNING_ASSERTION(
767 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
768 "failed, but ignored");
769 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
770 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
771 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
772 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::z_index
, u
""_ns
);
773 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
775 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
776 "destroyed the editor");
777 return NS_ERROR_EDITOR_DESTROYED
;
779 NS_WARNING_ASSERTION(
781 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
782 "failed, but ignored");
784 if (!HTMLEditUtils::IsImage(styledElement
)) {
785 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
786 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
787 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
788 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::width
, u
""_ns
);
789 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
791 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
792 "destroyed the editor");
793 return NS_ERROR_EDITOR_DESTROYED
;
795 NS_WARNING_ASSERTION(
797 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
798 "failed, but ignored");
799 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
800 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
801 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
802 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::height
, u
""_ns
);
803 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
805 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
806 "destroyed the editor");
807 return NS_ERROR_EDITOR_DESTROYED
;
809 NS_WARNING_ASSERTION(
811 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
812 "failed, but ignored");
815 if (!styledElement
->IsHTMLElement(nsGkAtoms::div
) ||
816 HTMLEditor::HasStyleOrIdOrClassAttribute(*styledElement
)) {
820 EditorDOMPoint pointToPutCaret
;
821 // Make sure the first fild and last child of aElement starts/ends hard
822 // line(s) even after removing `aElement`.
824 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
825 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
826 Result
<CreateElementResult
, nsresult
>
827 maybeInsertBRElementBeforeFirstChildResult
=
828 EnsureHardLineBeginsWithFirstChildOf(MOZ_KnownLive(*styledElement
));
829 if (MOZ_UNLIKELY(maybeInsertBRElementBeforeFirstChildResult
.isErr())) {
830 NS_WARNING("HTMLEditor::EnsureHardLineBeginsWithFirstChildOf() failed");
831 return maybeInsertBRElementBeforeFirstChildResult
.unwrapErr();
833 CreateElementResult unwrappedResult
=
834 maybeInsertBRElementBeforeFirstChildResult
.unwrap();
835 if (unwrappedResult
.HasCaretPointSuggestion()) {
836 pointToPutCaret
= unwrappedResult
.UnwrapCaretPoint();
840 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
841 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
842 Result
<CreateElementResult
, nsresult
>
843 maybeInsertBRElementAfterLastChildResult
=
844 EnsureHardLineEndsWithLastChildOf(MOZ_KnownLive(*styledElement
));
845 if (MOZ_UNLIKELY(maybeInsertBRElementAfterLastChildResult
.isErr())) {
846 NS_WARNING("HTMLEditor::EnsureHardLineEndsWithLastChildOf() failed");
847 return maybeInsertBRElementAfterLastChildResult
.unwrapErr();
849 CreateElementResult unwrappedResult
=
850 maybeInsertBRElementAfterLastChildResult
.unwrap();
851 if (unwrappedResult
.HasCaretPointSuggestion()) {
852 pointToPutCaret
= unwrappedResult
.UnwrapCaretPoint();
856 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
857 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
858 Result
<EditorDOMPoint
, nsresult
> unwrapStyledElementResult
=
859 RemoveContainerWithTransaction(MOZ_KnownLive(*styledElement
));
860 if (MOZ_UNLIKELY(unwrapStyledElementResult
.isErr())) {
861 NS_WARNING("HTMLEditor::RemoveContainerWithTransaction() failed");
862 return unwrapStyledElementResult
.unwrapErr();
864 if (unwrapStyledElementResult
.inspect().IsSet()) {
865 pointToPutCaret
= unwrapStyledElementResult
.unwrap();
868 if (!AllowsTransactionsToChangeSelection() || !pointToPutCaret
.IsSet()) {
871 rv
= CollapseSelectionTo(pointToPutCaret
);
872 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
873 "EditorBase::CollapseSelectionTo() failed");
877 NS_IMETHODIMP
HTMLEditor::SetSnapToGridEnabled(bool aEnabled
) {
878 mSnapToGridEnabled
= aEnabled
;
882 NS_IMETHODIMP
HTMLEditor::GetSnapToGridEnabled(bool* aIsEnabled
) {
883 *aIsEnabled
= mSnapToGridEnabled
;
887 NS_IMETHODIMP
HTMLEditor::SetGridSize(uint32_t aSize
) {
892 NS_IMETHODIMP
HTMLEditor::GetGridSize(uint32_t* aSize
) {
897 nsresult
HTMLEditor::SetTopAndLeftWithTransaction(
898 nsStyledElement
& aStyledElement
, int32_t aX
, int32_t aY
) {
899 AutoPlaceholderBatch
treatAsOneTransaction(
900 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
902 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(*this, aStyledElement
,
903 *nsGkAtoms::left
, aX
);
904 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
906 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
907 "destroyed the editor");
908 return NS_ERROR_EDITOR_DESTROYED
;
910 NS_WARNING_ASSERTION(
912 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
913 "failed, but ignored");
914 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(*this, aStyledElement
,
915 *nsGkAtoms::top
, aY
);
916 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
918 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
919 "destroyed the editor");
920 return NS_ERROR_EDITOR_DESTROYED
;
922 NS_WARNING_ASSERTION(
924 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
925 "failed, but ignored");
929 nsresult
HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(
930 Element
& aElement
, nsAString
& aReturn
) {
931 // we are going to outline the positioned element and bring it to the
932 // front to overlap any other element intersecting with it. But
933 // first, let's see what's the background and foreground colors of the
934 // positioned element.
935 // if background-image computed value is 'none,
936 // If the background color is 'auto' and R G B values of the foreground are
937 // each above #d0, use a black background
938 // If the background color is 'auto' and at least one of R G B values of
939 // the foreground is below #d0, use a white background
940 // Otherwise don't change background/foreground
943 nsAutoString backgroundImageValue
;
944 nsresult rv
= CSSEditUtils::GetComputedProperty(
945 aElement
, *nsGkAtoms::background_image
, backgroundImageValue
);
948 "CSSEditUtils::GetComputedProperty(nsGkAtoms::background_image) "
952 if (!backgroundImageValue
.EqualsLiteral("none")) {
956 nsAutoString backgroundColorValue
;
957 rv
= CSSEditUtils::GetComputedProperty(aElement
, *nsGkAtoms::backgroundColor
,
958 backgroundColorValue
);
961 "CSSEditUtils::GetComputedProperty(nsGkAtoms::backgroundColor) "
965 if (!backgroundColorValue
.EqualsLiteral("rgba(0, 0, 0, 0)")) {
969 RefPtr
<const ComputedStyle
> style
=
970 nsComputedDOMStyle::GetComputedStyle(&aElement
);
971 if (NS_WARN_IF(Destroyed())) {
972 return NS_ERROR_EDITOR_DESTROYED
;
975 NS_WARNING("nsComputedDOMStyle::GetComputedStyle() failed");
976 return NS_ERROR_FAILURE
;
979 static const uint8_t kBlackBgTrigger
= 0xd0;
981 auto color
= style
->StyleText()->mColor
.ToColor();
982 if (NS_GET_R(color
) >= kBlackBgTrigger
&&
983 NS_GET_G(color
) >= kBlackBgTrigger
&&
984 NS_GET_B(color
) >= kBlackBgTrigger
) {
985 aReturn
.AssignLiteral("black");
987 aReturn
.AssignLiteral("white");
993 } // namespace mozilla