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 "EditorLineBreak.h"
12 #include "HTMLEditHelpers.h"
13 #include "HTMLEditorEventListener.h"
14 #include "HTMLEditUtils.h"
16 #include "mozilla/EventListenerManager.h"
17 #include "mozilla/mozalloc.h"
18 #include "mozilla/Preferences.h"
19 #include "mozilla/PresShell.h"
20 #include "mozilla/StaticPrefs_editor.h"
21 #include "mozilla/dom/AncestorIterator.h"
22 #include "mozilla/dom/Selection.h"
23 #include "mozilla/dom/Element.h"
24 #include "mozilla/dom/EventTarget.h"
25 #include "nsAString.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 NS_IMETHODIMP
HTMLEditor::GetIsAbsolutePositioningActive(bool* aIsActive
) {
139 MOZ_ASSERT(aIsActive
);
140 *aIsActive
= !!mAbsolutelyPositionedObject
;
144 Result
<int32_t, nsresult
> HTMLEditor::AddZIndexWithTransaction(
145 nsStyledElement
& aStyledElement
, int32_t aChange
) {
147 return 0; // XXX Why don't we return current z-index value in this case?
150 int32_t zIndex
= GetZIndex(aStyledElement
);
151 if (NS_WARN_IF(Destroyed())) {
152 return Err(NS_ERROR_EDITOR_DESTROYED
);
154 zIndex
= std::max(zIndex
+ aChange
, 0);
155 nsresult rv
= SetZIndexWithTransaction(aStyledElement
, zIndex
);
156 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
157 NS_WARNING("HTMLEditor::SetZIndexWithTransaction() destroyed the editor");
158 return Err(NS_ERROR_EDITOR_DESTROYED
);
160 NS_WARNING_ASSERTION(
162 "HTMLEditor::SetZIndexWithTransaction() failed, but ignored");
166 nsresult
HTMLEditor::SetZIndexWithTransaction(nsStyledElement
& aStyledElement
,
168 nsAutoString zIndexValue
;
169 zIndexValue
.AppendInt(aZIndex
);
171 nsresult rv
= CSSEditUtils::SetCSSPropertyWithTransaction(
172 *this, aStyledElement
, *nsGkAtoms::z_index
, zIndexValue
);
173 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
175 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::z_index) "
176 "destroyed the editor");
177 return NS_ERROR_EDITOR_DESTROYED
;
179 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
180 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::"
181 "z_index) failed, but ignored");
185 nsresult
HTMLEditor::AddZIndexAsAction(int32_t aChange
,
186 nsIPrincipal
* aPrincipal
) {
187 MOZ_ASSERT(IsEditActionDataAvailable());
189 AutoEditActionDataSetter
editActionData(
190 *this, EditAction::eIncreaseOrDecreaseZIndex
, aPrincipal
);
191 nsresult rv
= editActionData
.CanHandleAndMaybeDispatchBeforeInputEvent();
193 NS_WARNING_ASSERTION(rv
== NS_ERROR_EDITOR_ACTION_CANCELED
,
194 "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
195 return EditorBase::ToGenericNSResult(rv
);
198 Result
<EditActionResult
, nsresult
> result
= AddZIndexAsSubAction(aChange
);
199 if (MOZ_UNLIKELY(result
.isErr())) {
200 NS_WARNING("HTMLEditor::AddZIndexAsSubAction() failed");
201 return EditorBase::ToGenericNSResult(result
.unwrapErr());
206 int32_t HTMLEditor::GetZIndex(Element
& aElement
) {
207 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
208 if (NS_WARN_IF(!editActionData
.CanHandle())) {
212 nsAutoString zIndexValue
;
214 nsresult rv
= CSSEditUtils::GetSpecifiedProperty(
215 aElement
, *nsGkAtoms::z_index
, zIndexValue
);
217 NS_WARNING("CSSEditUtils::GetSpecifiedProperty(nsGkAtoms::z_index) failed");
220 if (zIndexValue
.EqualsLiteral("auto")) {
221 if (!aElement
.GetParentElement()) {
222 NS_WARNING("aElement was an orphan node or the root node");
225 // we have to look at the positioned ancestors
226 // cf. CSS 2 spec section 9.9.1
227 nsAutoString positionValue
;
228 for (RefPtr
<Element
> element
= aElement
.GetParentElement(); element
;
229 element
= element
->GetParentElement()) {
230 if (element
->IsHTMLElement(nsGkAtoms::body
)) {
233 nsCOMPtr
<nsINode
> parentNode
= element
->GetParentElement();
234 nsresult rv
= CSSEditUtils::GetComputedProperty(
235 *element
, *nsGkAtoms::position
, positionValue
);
238 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
241 if (NS_WARN_IF(Destroyed()) ||
242 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
245 if (!positionValue
.EqualsLiteral("absolute")) {
248 // ah, we found one, what's its z-index ? If its z-index is auto,
249 // we have to continue climbing the document's tree
250 rv
= CSSEditUtils::GetComputedProperty(*element
, *nsGkAtoms::z_index
,
254 "CSSEditUtils::GetComputedProperty(nsGkAtoms::z_index) failed");
257 if (NS_WARN_IF(Destroyed()) ||
258 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
261 if (!zIndexValue
.EqualsLiteral("auto")) {
267 if (zIndexValue
.EqualsLiteral("auto")) {
272 int32_t result
= zIndexValue
.ToInteger(&rvIgnored
);
273 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
274 "nsAString::ToInteger() failed, but ignored");
278 bool HTMLEditor::CreateGrabberInternal(nsIContent
& aParentContent
) {
279 if (NS_WARN_IF(mGrabber
)) {
283 mGrabber
= CreateAnonymousElement(nsGkAtoms::span
, aParentContent
,
284 u
"mozGrabber"_ns
, false);
286 // mGrabber may be destroyed during creation due to there may be
287 // mutation event listener.
290 "HTMLEditor::CreateAnonymousElement(nsGkAtoms::span, mozGrabber) "
295 EventListenerManager
* eventListenerManager
=
296 mGrabber
->GetOrCreateListenerManager();
297 eventListenerManager
->AddEventListenerByType(
298 mEventListener
, u
"mousedown"_ns
, TrustedEventsAtSystemGroupBubble());
299 MOZ_ASSERT(mGrabber
);
303 nsresult
HTMLEditor::RefreshGrabberInternal() {
304 MOZ_ASSERT(IsEditActionDataAvailable());
306 if (!mAbsolutelyPositionedObject
) {
310 OwningNonNull
<Element
> absolutelyPositionedObject
=
311 *mAbsolutelyPositionedObject
;
312 nsresult rv
= GetPositionAndDimensions(
313 absolutelyPositionedObject
, mPositionedObjectX
, mPositionedObjectY
,
314 mPositionedObjectWidth
, mPositionedObjectHeight
,
315 mPositionedObjectBorderLeft
, mPositionedObjectBorderTop
,
316 mPositionedObjectMarginLeft
, mPositionedObjectMarginTop
);
318 NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
321 if (NS_WARN_IF(absolutelyPositionedObject
!= mAbsolutelyPositionedObject
)) {
322 return NS_ERROR_FAILURE
;
325 RefPtr
<nsStyledElement
> grabberStyledElement
=
326 nsStyledElement::FromNodeOrNull(mGrabber
.get());
327 if (!grabberStyledElement
) {
330 rv
= SetAnonymousElementPositionWithoutTransaction(
331 *grabberStyledElement
, mPositionedObjectX
+ 12, mPositionedObjectY
- 14);
332 if (NS_WARN_IF(Destroyed())) {
333 return NS_ERROR_EDITOR_DESTROYED
;
337 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() failed");
340 if (NS_WARN_IF(grabberStyledElement
!= mGrabber
.get())) {
341 return NS_ERROR_FAILURE
;
346 void HTMLEditor::HideGrabberInternal() {
347 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
351 // Move all members to the local variables first since mutation event
352 // listener may try to show grabber while we're hiding them.
353 RefPtr
<Element
> absolutePositioningObject
=
354 std::move(mAbsolutelyPositionedObject
);
355 ManualNACPtr grabber
= std::move(mGrabber
);
356 ManualNACPtr positioningShadow
= std::move(mPositioningShadow
);
358 // If we're still in dragging mode, it means that the dragging is canceled
360 if (mGrabberClicked
|| mIsMoving
) {
361 mGrabberClicked
= false;
363 if (mEventListener
) {
364 DebugOnly
<nsresult
> rvIgnored
=
365 static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
366 ->ListenToMouseMoveEventForGrabber(false);
367 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
368 "HTMLEditorEventListener::"
369 "ListenToMouseMoveEventForGrabber(false) failed");
373 DebugOnly
<nsresult
> rv
= absolutePositioningObject
->UnsetAttr(
374 kNameSpaceID_None
, nsGkAtoms::_moz_abspos
, true);
375 NS_WARNING_ASSERTION(
377 "Element::UnsetAttr(nsGkAtoms::_moz_abspos) failed, but ignored");
379 // We allow the pres shell to be null; when it is, we presume there
380 // are no document observers to notify, but we still want to
382 RefPtr
<PresShell
> presShell
= GetPresShell();
384 DeleteRefToAnonymousNode(std::move(grabber
), presShell
);
386 if (positioningShadow
) {
387 DeleteRefToAnonymousNode(std::move(positioningShadow
), presShell
);
391 nsresult
HTMLEditor::ShowGrabberInternal(Element
& aElement
) {
392 MOZ_ASSERT(IsEditActionDataAvailable());
394 const RefPtr
<Element
> editingHost
= ComputeEditingHost();
395 if (NS_WARN_IF(!editingHost
) ||
396 NS_WARN_IF(!aElement
.IsInclusiveDescendantOf(editingHost
))) {
397 return NS_ERROR_UNEXPECTED
;
400 if (NS_WARN_IF(mGrabber
)) {
401 return NS_ERROR_UNEXPECTED
;
404 nsAutoString classValue
;
406 GetTemporaryStyleForFocusedPositionedElement(aElement
, classValue
);
409 "HTMLEditor::GetTemporaryStyleForFocusedPositionedElement() failed");
413 rv
= aElement
.SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_abspos
, classValue
,
416 NS_WARNING("Element::SetAttr(nsGkAtoms::_moz_abspos) failed");
420 mAbsolutelyPositionedObject
= &aElement
;
422 Element
* parentElement
= aElement
.GetParentElement();
423 if (NS_WARN_IF(!parentElement
)) {
424 return NS_ERROR_FAILURE
;
427 if (!CreateGrabberInternal(*parentElement
)) {
428 NS_WARNING("HTMLEditor::CreateGrabberInternal() failed");
429 return NS_ERROR_FAILURE
;
432 // If we succeeded to create the grabber, HideGrabberInternal() hasn't been
433 // called yet. So, mAbsolutelyPositionedObject should be non-nullptr.
434 MOZ_ASSERT(mAbsolutelyPositionedObject
);
436 // Finally, move the grabber to proper position.
437 rv
= RefreshGrabberInternal();
438 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
439 "HTMLEditor::RefereshGrabberInternal() failed");
443 nsresult
HTMLEditor::StartMoving() {
444 MOZ_ASSERT(mGrabber
);
446 RefPtr
<Element
> parentElement
= mGrabber
->GetParentElement();
447 if (NS_WARN_IF(!parentElement
) || NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
448 return NS_ERROR_FAILURE
;
451 // now, let's create the resizing shadow
453 CreateShadow(*parentElement
, *mAbsolutelyPositionedObject
);
454 if (!mPositioningShadow
) {
455 NS_WARNING("HTMLEditor::CreateShadow() failed");
456 return NS_ERROR_FAILURE
;
458 if (!mAbsolutelyPositionedObject
) {
459 NS_WARNING("The target has gone during HTMLEditor::CreateShadow()");
460 return NS_ERROR_FAILURE
;
462 RefPtr
<Element
> positioningShadow
= mPositioningShadow
.get();
463 RefPtr
<Element
> absolutelyPositionedObject
= mAbsolutelyPositionedObject
;
465 SetShadowPosition(*positioningShadow
, *absolutelyPositionedObject
,
466 mPositionedObjectX
, mPositionedObjectY
);
468 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
472 // make the shadow appear
473 DebugOnly
<nsresult
> rvIgnored
=
474 mPositioningShadow
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, true);
475 NS_WARNING_ASSERTION(
476 NS_SUCCEEDED(rvIgnored
),
477 "Element::UnsetAttr(nsGkAtoms::_class) failed, but ignored");
480 if (RefPtr
<nsStyledElement
> positioningShadowStyledElement
=
481 nsStyledElement::FromNode(mPositioningShadow
.get())) {
483 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
484 *positioningShadowStyledElement
, *nsGkAtoms::width
,
485 mPositionedObjectWidth
);
486 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
488 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
489 "nsGkAtoms::width) destroyed the editor");
490 return NS_ERROR_EDITOR_DESTROYED
;
492 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
493 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
494 "nsGkAtoms::width) failed, but ignored");
495 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
496 *positioningShadowStyledElement
, *nsGkAtoms::height
,
497 mPositionedObjectHeight
);
498 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
500 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
501 "nsGkAtoms::height) destroyed the editor");
502 return NS_ERROR_EDITOR_DESTROYED
;
504 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
505 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
506 "nsGkAtoms::height) failed, but ignored");
510 return NS_OK
; // XXX Looks like nobody refers this result
513 void HTMLEditor::SnapToGrid(int32_t& newX
, int32_t& newY
) const {
514 if (mSnapToGridEnabled
&& mGridSize
) {
515 newX
= (int32_t)floor(((float)newX
/ (float)mGridSize
) + 0.5f
) * mGridSize
;
516 newY
= (int32_t)floor(((float)newY
/ (float)mGridSize
) + 0.5f
) * mGridSize
;
520 nsresult
HTMLEditor::GrabberClicked() {
521 if (NS_WARN_IF(!mEventListener
)) {
522 return NS_ERROR_NOT_INITIALIZED
;
524 nsresult rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
525 ->ListenToMouseMoveEventForGrabber(true);
528 "HTMLEditorEventListener::ListenToMouseMoveEventForGrabber(true) "
529 "failed, but ignored");
532 mGrabberClicked
= true;
536 nsresult
HTMLEditor::EndMoving() {
537 if (mPositioningShadow
) {
538 RefPtr
<PresShell
> presShell
= GetPresShell();
539 if (NS_WARN_IF(!presShell
)) {
540 return NS_ERROR_NOT_INITIALIZED
;
543 DeleteRefToAnonymousNode(std::move(mPositioningShadow
), presShell
);
545 mPositioningShadow
= nullptr;
548 if (mEventListener
) {
549 DebugOnly
<nsresult
> rvIgnored
=
550 static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
551 ->ListenToMouseMoveEventForGrabber(false);
552 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
553 "HTMLEditorEventListener::"
554 "ListenToMouseMoveEventForGrabber(false) failed");
557 mGrabberClicked
= false;
559 nsresult rv
= RefreshEditingUI();
560 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
561 "HTMLEditor::RefreshEditingUI() failed");
565 nsresult
HTMLEditor::SetFinalPosition(int32_t aX
, int32_t aY
) {
566 MOZ_ASSERT(IsEditActionDataAvailable());
568 nsresult rv
= EndMoving();
570 NS_WARNING("HTMLEditor::EndMoving() failed");
574 // we have now to set the new width and height of the resized object
575 // we don't set the x and y position because we don't control that in
576 // a normal HTML layout
577 int32_t newX
= mPositionedObjectX
+ aX
- mOriginalX
-
578 (mPositionedObjectBorderLeft
+ mPositionedObjectMarginLeft
);
579 int32_t newY
= mPositionedObjectY
+ aY
- mOriginalY
-
580 (mPositionedObjectBorderTop
+ mPositionedObjectMarginTop
);
582 SnapToGrid(newX
, newY
);
588 // we want one transaction only from a user's point of view
589 AutoPlaceholderBatch
treatAsOneTransaction(
590 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
592 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
593 return NS_ERROR_FAILURE
;
595 if (RefPtr
<nsStyledElement
> styledAbsolutelyPositionedElement
=
596 nsStyledElement::FromNode(mAbsolutelyPositionedObject
)) {
598 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
599 *this, *styledAbsolutelyPositionedElement
, *nsGkAtoms::top
, newY
);
600 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
602 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
603 "destroyed the editor");
604 return NS_ERROR_EDITOR_DESTROYED
;
606 NS_WARNING_ASSERTION(
608 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
609 "failed, but ignored");
610 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
611 *this, *styledAbsolutelyPositionedElement
, *nsGkAtoms::left
, newX
);
612 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
614 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
615 "destroyed the editor");
616 return NS_ERROR_EDITOR_DESTROYED
;
618 NS_WARNING_ASSERTION(
620 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
621 "failed, but ignored");
623 // keep track of that size
624 mPositionedObjectX
= newX
;
625 mPositionedObjectY
= newY
;
627 rv
= RefreshResizersInternal();
628 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
629 "HTMLEditor::RefreshResizersInternal() failed");
633 nsresult
HTMLEditor::SetPositionToAbsoluteOrStatic(Element
& aElement
,
635 nsAutoString positionValue
;
636 DebugOnly
<nsresult
> rvIgnored
= CSSEditUtils::GetComputedProperty(
637 aElement
, *nsGkAtoms::position
, positionValue
);
638 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
639 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) "
640 "failed, but ignored");
641 // nothing to do if the element is already in the state we want
642 if (positionValue
.EqualsLiteral("absolute") == aEnabled
) {
647 nsresult rv
= SetPositionToAbsolute(aElement
);
648 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
649 "HTMLEditor::SetPositionToAbsolute() failed");
653 nsresult rv
= SetPositionToStatic(aElement
);
654 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
655 "HTMLEditor::SetPositionToStatic() failed");
659 nsresult
HTMLEditor::SetPositionToAbsolute(Element
& aElement
) {
660 MOZ_ASSERT(IsEditActionDataAvailable());
662 AutoPlaceholderBatch
treatAsOneTransaction(
663 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
666 DebugOnly
<nsresult
> rvIgnored
= GetElementOrigin(aElement
, x
, y
);
667 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
668 "HTMLEditor::GetElementOrigin() failed, but ignored");
670 nsStyledElement
* styledElement
= nsStyledElement::FromNode(&aElement
);
672 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
673 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
674 nsresult rv
= CSSEditUtils::SetCSSPropertyWithTransaction(
675 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::position
,
677 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
679 "CSSEditUtils::SetCSSProperyWithTransaction(nsGkAtoms::Position) "
680 "destroyed the editor");
681 return NS_ERROR_EDITOR_DESTROYED
;
683 NS_WARNING_ASSERTION(
684 NS_SUCCEEDED(rvIgnored
),
685 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::position, "
686 "absolute) failed, but ignored");
691 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
692 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
694 SetTopAndLeftWithTransaction(MOZ_KnownLive(*styledElement
), x
, y
);
696 NS_WARNING("HTMLEditor::SetTopAndLeftWithTransaction() failed");
701 // we may need to create a br if the positioned element is alone in its
703 nsINode
* parentNode
= aElement
.GetParentNode();
704 if (parentNode
->GetChildCount() != 1) {
707 Result
<CreateLineBreakResult
, nsresult
> insertBRElementResultOrError
=
708 InsertLineBreak(WithTransaction::Yes
, LineBreakType::BRElement
,
709 EditorDOMPoint(parentNode
, 0u));
710 if (MOZ_UNLIKELY(insertBRElementResultOrError
.isErr())) {
712 "HTMLEditor::InsertLineBreak(WithTransaction::Yes, "
713 "LineBreakType::BRElement) failed");
714 return insertBRElementResultOrError
.unwrapErr();
716 CreateLineBreakResult insertBRElementResult
=
717 insertBRElementResultOrError
.unwrap();
718 MOZ_ASSERT(insertBRElementResult
.Handled());
719 // XXX Is this intentional selection change?
720 nsresult rv
= insertBRElementResult
.SuggestCaretPointTo(
721 *this, {SuggestCaret::OnlyIfHasSuggestion
,
722 SuggestCaret::OnlyIfTransactionsAllowedToDoIt
});
723 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
724 "CreateElementResult::SuggestCaretPointTo() failed");
728 nsresult
HTMLEditor::SetPositionToStatic(Element
& aElement
) {
729 nsStyledElement
* styledElement
= nsStyledElement::FromNode(&aElement
);
730 if (NS_WARN_IF(!styledElement
)) {
731 return NS_ERROR_INVALID_ARG
;
734 AutoPlaceholderBatch
treatAsOneTransaction(
735 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
738 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
739 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
740 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
741 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::position
, u
""_ns
);
742 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
744 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
745 "destroyed the editor");
746 return NS_ERROR_EDITOR_DESTROYED
;
748 NS_WARNING_ASSERTION(
750 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
751 "failed, but ignored");
752 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
753 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
754 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
755 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::top
, u
""_ns
);
756 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
758 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
759 "destroyed the editor");
760 return NS_ERROR_EDITOR_DESTROYED
;
762 NS_WARNING_ASSERTION(
764 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
765 "failed, but ignored");
766 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
767 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
768 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
769 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::left
, u
""_ns
);
770 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
772 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
773 "destroyed the editor");
774 return NS_ERROR_EDITOR_DESTROYED
;
776 NS_WARNING_ASSERTION(
778 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
779 "failed, but ignored");
780 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
781 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
782 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
783 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::z_index
, u
""_ns
);
784 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
786 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
787 "destroyed the editor");
788 return NS_ERROR_EDITOR_DESTROYED
;
790 NS_WARNING_ASSERTION(
792 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
793 "failed, but ignored");
795 if (!HTMLEditUtils::IsImage(styledElement
)) {
796 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
797 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
798 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
799 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::width
, u
""_ns
);
800 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
802 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
803 "destroyed the editor");
804 return NS_ERROR_EDITOR_DESTROYED
;
806 NS_WARNING_ASSERTION(
808 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
809 "failed, but ignored");
810 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
811 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
812 rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
813 *this, MOZ_KnownLive(*styledElement
), *nsGkAtoms::height
, u
""_ns
);
814 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
816 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
817 "destroyed the editor");
818 return NS_ERROR_EDITOR_DESTROYED
;
820 NS_WARNING_ASSERTION(
822 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
823 "failed, but ignored");
826 if (!styledElement
->IsHTMLElement(nsGkAtoms::div
) ||
827 HTMLEditor::HasStyleOrIdOrClassAttribute(*styledElement
)) {
831 EditorDOMPoint pointToPutCaret
;
832 // Make sure the first fild and last child of aElement starts/ends hard
833 // line(s) even after removing `aElement`.
835 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
836 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
837 Result
<CreateElementResult
, nsresult
>
838 maybeInsertBRElementBeforeFirstChildResult
=
839 EnsureHardLineBeginsWithFirstChildOf(MOZ_KnownLive(*styledElement
));
840 if (MOZ_UNLIKELY(maybeInsertBRElementBeforeFirstChildResult
.isErr())) {
841 NS_WARNING("HTMLEditor::EnsureHardLineBeginsWithFirstChildOf() failed");
842 return maybeInsertBRElementBeforeFirstChildResult
.unwrapErr();
844 CreateElementResult unwrappedResult
=
845 maybeInsertBRElementBeforeFirstChildResult
.unwrap();
846 if (unwrappedResult
.HasCaretPointSuggestion()) {
847 pointToPutCaret
= unwrappedResult
.UnwrapCaretPoint();
851 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
852 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
853 Result
<CreateElementResult
, nsresult
>
854 maybeInsertBRElementAfterLastChildResult
=
855 EnsureHardLineEndsWithLastChildOf(MOZ_KnownLive(*styledElement
));
856 if (MOZ_UNLIKELY(maybeInsertBRElementAfterLastChildResult
.isErr())) {
857 NS_WARNING("HTMLEditor::EnsureHardLineEndsWithLastChildOf() failed");
858 return maybeInsertBRElementAfterLastChildResult
.unwrapErr();
860 CreateElementResult unwrappedResult
=
861 maybeInsertBRElementAfterLastChildResult
.unwrap();
862 if (unwrappedResult
.HasCaretPointSuggestion()) {
863 pointToPutCaret
= unwrappedResult
.UnwrapCaretPoint();
867 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
868 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
869 Result
<EditorDOMPoint
, nsresult
> unwrapStyledElementResult
=
870 RemoveContainerWithTransaction(MOZ_KnownLive(*styledElement
));
871 if (MOZ_UNLIKELY(unwrapStyledElementResult
.isErr())) {
872 NS_WARNING("HTMLEditor::RemoveContainerWithTransaction() failed");
873 return unwrapStyledElementResult
.unwrapErr();
875 if (unwrapStyledElementResult
.inspect().IsSet()) {
876 pointToPutCaret
= unwrapStyledElementResult
.unwrap();
879 if (!AllowsTransactionsToChangeSelection() || !pointToPutCaret
.IsSet()) {
882 rv
= CollapseSelectionTo(pointToPutCaret
);
883 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
884 "EditorBase::CollapseSelectionTo() failed");
888 NS_IMETHODIMP
HTMLEditor::SetSnapToGridEnabled(bool aEnabled
) {
889 mSnapToGridEnabled
= aEnabled
;
893 NS_IMETHODIMP
HTMLEditor::GetSnapToGridEnabled(bool* aIsEnabled
) {
894 *aIsEnabled
= mSnapToGridEnabled
;
898 NS_IMETHODIMP
HTMLEditor::SetGridSize(uint32_t aSize
) {
903 NS_IMETHODIMP
HTMLEditor::GetGridSize(uint32_t* aSize
) {
908 nsresult
HTMLEditor::SetTopAndLeftWithTransaction(
909 nsStyledElement
& aStyledElement
, int32_t aX
, int32_t aY
) {
910 AutoPlaceholderBatch
treatAsOneTransaction(
911 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
913 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(*this, aStyledElement
,
914 *nsGkAtoms::left
, aX
);
915 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
917 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
918 "destroyed the editor");
919 return NS_ERROR_EDITOR_DESTROYED
;
921 NS_WARNING_ASSERTION(
923 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
924 "failed, but ignored");
925 rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(*this, aStyledElement
,
926 *nsGkAtoms::top
, aY
);
927 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
929 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
930 "destroyed the editor");
931 return NS_ERROR_EDITOR_DESTROYED
;
933 NS_WARNING_ASSERTION(
935 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
936 "failed, but ignored");
940 nsresult
HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(
941 Element
& aElement
, nsAString
& aReturn
) {
942 // we are going to outline the positioned element and bring it to the
943 // front to overlap any other element intersecting with it. But
944 // first, let's see what's the background and foreground colors of the
945 // positioned element.
946 // if background-image computed value is 'none,
947 // If the background color is 'auto' and R G B values of the foreground are
948 // each above #d0, use a black background
949 // If the background color is 'auto' and at least one of R G B values of
950 // the foreground is below #d0, use a white background
951 // Otherwise don't change background/foreground
954 nsAutoString backgroundImageValue
;
955 nsresult rv
= CSSEditUtils::GetComputedProperty(
956 aElement
, *nsGkAtoms::background_image
, backgroundImageValue
);
959 "CSSEditUtils::GetComputedProperty(nsGkAtoms::background_image) "
963 if (!backgroundImageValue
.EqualsLiteral("none")) {
967 nsAutoString backgroundColorValue
;
968 rv
= CSSEditUtils::GetComputedProperty(aElement
, *nsGkAtoms::backgroundColor
,
969 backgroundColorValue
);
972 "CSSEditUtils::GetComputedProperty(nsGkAtoms::backgroundColor) "
976 if (!backgroundColorValue
.EqualsLiteral("rgba(0, 0, 0, 0)")) {
980 RefPtr
<const ComputedStyle
> style
=
981 nsComputedDOMStyle::GetComputedStyle(&aElement
);
982 if (NS_WARN_IF(Destroyed())) {
983 return NS_ERROR_EDITOR_DESTROYED
;
986 NS_WARNING("nsComputedDOMStyle::GetComputedStyle() failed");
987 return NS_ERROR_FAILURE
;
990 static const uint8_t kBlackBgTrigger
= 0xd0;
992 auto color
= style
->StyleText()->mColor
.ToColor();
993 if (NS_GET_R(color
) >= kBlackBgTrigger
&&
994 NS_GET_G(color
) >= kBlackBgTrigger
&&
995 NS_GET_B(color
) >= kBlackBgTrigger
) {
996 aReturn
.AssignLiteral("black");
998 aReturn
.AssignLiteral("white");
1004 } // namespace mozilla