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 "HTMLEditorEventListener.h"
10 #include "HTMLEditUtils.h"
11 #include "mozilla/EditAction.h"
12 #include "mozilla/EventListenerManager.h"
13 #include "mozilla/Preferences.h"
14 #include "mozilla/PresShell.h"
15 #include "mozilla/dom/AncestorIterator.h"
16 #include "mozilla/dom/Selection.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/EventTarget.h"
19 #include "mozilla/mozalloc.h"
20 #include "nsAString.h"
21 #include "nsAlgorithm.h"
23 #include "nsComputedDOMStyle.h"
26 #include "nsGkAtoms.h"
27 #include "nsIContent.h"
28 #include "nsROCSSPrimitiveValue.h"
30 #include "nsIPrincipal.h"
31 #include "nsISupportsImpl.h"
32 #include "nsISupportsUtils.h"
33 #include "nsLiteralString.h"
34 #include "nsReadableUtils.h"
36 #include "nsStringFwd.h"
37 #include "nsStyledElement.h"
45 nsresult
HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction(
46 bool aEnabled
, nsIPrincipal
* aPrincipal
) {
47 MOZ_ASSERT(IsEditActionDataAvailable());
49 AutoEditActionDataSetter
editActionData(
50 *this, EditAction::eSetPositionToAbsoluteOrStatic
, aPrincipal
);
51 nsresult rv
= editActionData
.CanHandleAndMaybeDispatchBeforeInputEvent();
53 NS_WARNING_ASSERTION(rv
== NS_ERROR_EDITOR_ACTION_CANCELED
,
54 "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
59 EditActionResult result
= SetSelectionToAbsoluteAsSubAction();
62 "HTMLEditor::SetSelectionToAbsoluteAsSubAction() failed");
65 EditActionResult result
= SetSelectionToStaticAsSubAction();
66 NS_WARNING_ASSERTION(result
.Succeeded(),
67 "HTMLEditor::SetSelectionToStaticAsSubAction() failed");
71 already_AddRefed
<Element
>
72 HTMLEditor::GetAbsolutelyPositionedSelectionContainer() const {
73 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
74 if (NS_WARN_IF(!editActionData
.CanHandle())) {
78 Element
* selectionContainerElement
= GetSelectionContainerElement();
79 if (NS_WARN_IF(!selectionContainerElement
)) {
83 AutoTArray
<RefPtr
<Element
>, 24> arrayOfParentElements
;
84 for (Element
* element
:
85 selectionContainerElement
->InclusiveAncestorsOfType
<Element
>()) {
86 arrayOfParentElements
.AppendElement(element
);
89 nsAutoString positionValue
;
90 for (RefPtr
<Element
> element
= selectionContainerElement
; element
;
91 element
= element
->GetParentElement()) {
92 if (element
->IsHTMLElement(nsGkAtoms::html
)) {
94 "HTMLEditor::GetAbsolutelyPositionedSelectionContainer() reached "
98 nsCOMPtr
<nsINode
> parentNode
= element
->GetParentNode();
99 nsresult rv
= CSSEditUtils::GetComputedProperty(
100 MOZ_KnownLive(*element
), *nsGkAtoms::position
, positionValue
);
103 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
106 if (NS_WARN_IF(Destroyed()) ||
107 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
110 if (positionValue
.EqualsLiteral("absolute")) {
111 return element
.forget();
117 NS_IMETHODIMP
HTMLEditor::GetAbsolutePositioningEnabled(bool* aIsEnabled
) {
118 *aIsEnabled
= IsAbsolutePositionEditorEnabled();
122 NS_IMETHODIMP
HTMLEditor::SetAbsolutePositioningEnabled(bool aIsEnabled
) {
123 EnableAbsolutePositionEditor(aIsEnabled
);
127 Result
<int32_t, nsresult
> HTMLEditor::AddZIndexWithTransaction(
128 nsStyledElement
& aStyledElement
, int32_t aChange
) {
130 return 0; // XXX Why don't we return current z-index value in this case?
133 int32_t zIndex
= GetZIndex(aStyledElement
);
134 if (NS_WARN_IF(Destroyed())) {
135 return Err(NS_ERROR_EDITOR_DESTROYED
);
137 zIndex
= std::max(zIndex
+ aChange
, 0);
138 nsresult rv
= SetZIndexWithTransaction(aStyledElement
, zIndex
);
139 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
140 NS_WARNING("HTMLEditor::SetZIndexWithTransaction() destroyed the editor");
141 return Err(NS_ERROR_EDITOR_DESTROYED
);
143 NS_WARNING_ASSERTION(
145 "HTMLEditor::SetZIndexWithTransaction() failed, but ignored");
149 nsresult
HTMLEditor::SetZIndexWithTransaction(nsStyledElement
& aStyledElement
,
151 nsAutoString zIndexValue
;
152 zIndexValue
.AppendInt(aZIndex
);
154 nsresult rv
= mCSSEditUtils
->SetCSSPropertyWithTransaction(
155 aStyledElement
, *nsGkAtoms::z_index
, zIndexValue
);
156 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
158 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::z_index) "
159 "destroyed the editor");
160 return NS_ERROR_EDITOR_DESTROYED
;
162 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
163 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::"
164 "z_index) failed, but ignored");
168 nsresult
HTMLEditor::AddZIndexAsAction(int32_t aChange
,
169 nsIPrincipal
* aPrincipal
) {
170 MOZ_ASSERT(IsEditActionDataAvailable());
172 AutoEditActionDataSetter
editActionData(
173 *this, EditAction::eIncreaseOrDecreaseZIndex
, aPrincipal
);
174 nsresult rv
= editActionData
.CanHandleAndMaybeDispatchBeforeInputEvent();
176 NS_WARNING_ASSERTION(rv
== NS_ERROR_EDITOR_ACTION_CANCELED
,
177 "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
178 return EditorBase::ToGenericNSResult(rv
);
181 EditActionResult result
= AddZIndexAsSubAction(aChange
);
182 NS_WARNING_ASSERTION(result
.Succeeded(),
183 "HTMLEditor::AddZIndexAsSubAction() failed");
184 return EditorBase::ToGenericNSResult(result
.Rv());
187 int32_t HTMLEditor::GetZIndex(Element
& aElement
) {
188 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
189 if (NS_WARN_IF(!editActionData
.CanHandle())) {
193 nsAutoString zIndexValue
;
195 nsresult rv
= CSSEditUtils::GetSpecifiedProperty(
196 aElement
, *nsGkAtoms::z_index
, zIndexValue
);
198 NS_WARNING("CSSEditUtils::GetSpecifiedProperty(nsGkAtoms::z_index) failed");
201 if (zIndexValue
.EqualsLiteral("auto")) {
202 if (!aElement
.GetParentElement()) {
203 NS_WARNING("aElement was an orphan node or the root node");
206 // we have to look at the positioned ancestors
207 // cf. CSS 2 spec section 9.9.1
208 nsAutoString positionValue
;
209 for (RefPtr
<Element
> element
= aElement
.GetParentElement(); element
;
210 element
= element
->GetParentElement()) {
211 if (element
->IsHTMLElement(nsGkAtoms::body
)) {
214 nsCOMPtr
<nsINode
> parentNode
= element
->GetParentElement();
215 nsresult rv
= CSSEditUtils::GetComputedProperty(
216 *element
, *nsGkAtoms::position
, positionValue
);
219 "CSSEditUtils::GetComputedProperty(nsGkAtoms::position) failed");
222 if (NS_WARN_IF(Destroyed()) ||
223 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
226 if (!positionValue
.EqualsLiteral("absolute")) {
229 // ah, we found one, what's its z-index ? If its z-index is auto,
230 // we have to continue climbing the document's tree
231 rv
= CSSEditUtils::GetComputedProperty(*element
, *nsGkAtoms::z_index
,
235 "CSSEditUtils::GetComputedProperty(nsGkAtoms::z_index) failed");
238 if (NS_WARN_IF(Destroyed()) ||
239 NS_WARN_IF(parentNode
!= element
->GetParentNode())) {
242 if (!zIndexValue
.EqualsLiteral("auto")) {
248 if (zIndexValue
.EqualsLiteral("auto")) {
253 int32_t result
= zIndexValue
.ToInteger(&rvIgnored
);
254 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
255 "nsAString::ToInteger() failed, but ignored");
259 bool HTMLEditor::CreateGrabberInternal(nsIContent
& aParentContent
) {
260 if (NS_WARN_IF(mGrabber
)) {
264 mGrabber
= CreateAnonymousElement(nsGkAtoms::span
, aParentContent
,
265 u
"mozGrabber"_ns
, false);
267 // mGrabber may be destroyed during creation due to there may be
268 // mutation event listener.
271 "HTMLEditor::CreateAnonymousElement(nsGkAtoms::span, mozGrabber) "
276 EventListenerManager
* eventListenerManager
=
277 mGrabber
->GetOrCreateListenerManager();
278 eventListenerManager
->AddEventListenerByType(
279 mEventListener
, u
"mousedown"_ns
, TrustedEventsAtSystemGroupBubble());
280 MOZ_ASSERT(mGrabber
);
284 NS_IMETHODIMP
HTMLEditor::RefreshGrabber() {
285 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
286 return NS_ERROR_FAILURE
;
289 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
290 if (NS_WARN_IF(!editActionData
.CanHandle())) {
291 return NS_ERROR_NOT_INITIALIZED
;
294 nsresult rv
= RefreshGrabberInternal();
295 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
296 "HTMLEditor::RefreshGrabberInternal() failed");
297 return EditorBase::ToGenericNSResult(rv
);
300 nsresult
HTMLEditor::RefreshGrabberInternal() {
301 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);
328 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() failed");
331 if (NS_WARN_IF(grabberStyledElement
!= mGrabber
.get())) {
332 return NS_ERROR_FAILURE
;
337 void HTMLEditor::HideGrabberInternal() {
338 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
342 // Move all members to the local variables first since mutation event
343 // listener may try to show grabber while we're hiding them.
344 RefPtr
<Element
> absolutePositioningObject
=
345 std::move(mAbsolutelyPositionedObject
);
346 ManualNACPtr grabber
= std::move(mGrabber
);
347 ManualNACPtr positioningShadow
= std::move(mPositioningShadow
);
349 // If we're still in dragging mode, it means that the dragging is canceled
351 if (mGrabberClicked
|| mIsMoving
) {
352 mGrabberClicked
= false;
354 if (mEventListener
) {
355 DebugOnly
<nsresult
> rvIgnored
=
356 static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
357 ->ListenToMouseMoveEventForGrabber(false);
358 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
359 "HTMLEditorEventListener::"
360 "ListenToMouseMoveEventForGrabber(false) failed");
364 DebugOnly
<nsresult
> rv
= absolutePositioningObject
->UnsetAttr(
365 kNameSpaceID_None
, nsGkAtoms::_moz_abspos
, true);
366 NS_WARNING_ASSERTION(
368 "Element::UnsetAttr(nsGkAtoms::_moz_abspos) failed, but ignored");
370 // We allow the pres shell to be null; when it is, we presume there
371 // are no document observers to notify, but we still want to
373 RefPtr
<PresShell
> presShell
= GetPresShell();
375 DeleteRefToAnonymousNode(std::move(grabber
), presShell
);
377 if (positioningShadow
) {
378 DeleteRefToAnonymousNode(std::move(positioningShadow
), presShell
);
382 nsresult
HTMLEditor::ShowGrabberInternal(Element
& aElement
) {
383 if (NS_WARN_IF(!IsDescendantOfEditorRoot(&aElement
))) {
384 return NS_ERROR_UNEXPECTED
;
387 if (NS_WARN_IF(mGrabber
)) {
388 return NS_ERROR_UNEXPECTED
;
391 nsAutoString classValue
;
393 GetTemporaryStyleForFocusedPositionedElement(aElement
, classValue
);
396 "HTMLEditor::GetTemporaryStyleForFocusedPositionedElement() failed");
400 rv
= aElement
.SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_abspos
, classValue
,
403 NS_WARNING("Element::SetAttr(nsGkAtoms::_moz_abspos) failed");
407 mAbsolutelyPositionedObject
= &aElement
;
409 Element
* parentElement
= aElement
.GetParentElement();
410 if (NS_WARN_IF(!parentElement
)) {
411 return NS_ERROR_FAILURE
;
414 if (!CreateGrabberInternal(*parentElement
)) {
415 NS_WARNING("HTMLEditor::CreateGrabberInternal() failed");
416 return NS_ERROR_FAILURE
;
419 // If we succeeded to create the grabber, HideGrabberInternal() hasn't been
420 // called yet. So, mAbsolutelyPositionedObject should be non-nullptr.
421 MOZ_ASSERT(mAbsolutelyPositionedObject
);
423 // Finally, move the grabber to proper position.
424 rv
= RefreshGrabberInternal();
425 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
426 "HTMLEditor::RefereshGrabberInternal() failed");
430 nsresult
HTMLEditor::StartMoving() {
431 MOZ_ASSERT(mGrabber
);
433 RefPtr
<Element
> parentElement
= mGrabber
->GetParentElement();
434 if (NS_WARN_IF(!parentElement
) || NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
435 return NS_ERROR_FAILURE
;
438 // now, let's create the resizing shadow
440 CreateShadow(*parentElement
, *mAbsolutelyPositionedObject
);
441 if (!mPositioningShadow
) {
442 NS_WARNING("HTMLEditor::CreateShadow() failed");
443 return NS_ERROR_FAILURE
;
445 if (!mAbsolutelyPositionedObject
) {
446 NS_WARNING("The target has gone during HTMLEditor::CreateShadow()");
447 return NS_ERROR_FAILURE
;
449 RefPtr
<Element
> positioningShadow
= mPositioningShadow
.get();
450 RefPtr
<Element
> absolutelyPositionedObject
= mAbsolutelyPositionedObject
;
452 SetShadowPosition(*positioningShadow
, *absolutelyPositionedObject
,
453 mPositionedObjectX
, mPositionedObjectY
);
455 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
459 // make the shadow appear
460 DebugOnly
<nsresult
> rvIgnored
=
461 mPositioningShadow
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, true);
462 NS_WARNING_ASSERTION(
463 NS_SUCCEEDED(rvIgnored
),
464 "Element::UnsetAttr(nsGkAtoms::_class) failed, but ignored");
467 if (RefPtr
<nsStyledElement
> positioningShadowStyledElement
=
468 nsStyledElement::FromNode(mPositioningShadow
.get())) {
470 rv
= mCSSEditUtils
->SetCSSPropertyPixelsWithoutTransaction(
471 *positioningShadowStyledElement
, *nsGkAtoms::width
,
472 mPositionedObjectWidth
);
473 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
475 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
476 "nsGkAtoms::width) destroyed the editor");
477 return NS_ERROR_EDITOR_DESTROYED
;
479 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
480 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
481 "nsGkAtoms::width) failed, but ignored");
482 rv
= mCSSEditUtils
->SetCSSPropertyPixelsWithoutTransaction(
483 *positioningShadowStyledElement
, *nsGkAtoms::height
,
484 mPositionedObjectHeight
);
485 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
487 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
488 "nsGkAtoms::height) destroyed the editor");
489 return NS_ERROR_EDITOR_DESTROYED
;
491 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
492 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
493 "nsGkAtoms::height) failed, but ignored");
497 return NS_OK
; // XXX Looks like nobody refers this result
500 void HTMLEditor::SnapToGrid(int32_t& newX
, int32_t& newY
) {
501 if (mSnapToGridEnabled
&& mGridSize
) {
502 newX
= (int32_t)floor(((float)newX
/ (float)mGridSize
) + 0.5f
) * mGridSize
;
503 newY
= (int32_t)floor(((float)newY
/ (float)mGridSize
) + 0.5f
) * mGridSize
;
507 nsresult
HTMLEditor::GrabberClicked() {
508 if (NS_WARN_IF(!mEventListener
)) {
509 return NS_ERROR_NOT_INITIALIZED
;
511 nsresult rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
512 ->ListenToMouseMoveEventForGrabber(true);
515 "HTMLEditorEventListener::ListenToMouseMoveEventForGrabber(true) "
516 "failed, but ignored");
519 mGrabberClicked
= true;
523 nsresult
HTMLEditor::EndMoving() {
524 if (mPositioningShadow
) {
525 RefPtr
<PresShell
> presShell
= GetPresShell();
526 if (NS_WARN_IF(!presShell
)) {
527 return NS_ERROR_NOT_INITIALIZED
;
530 DeleteRefToAnonymousNode(std::move(mPositioningShadow
), presShell
);
532 mPositioningShadow
= nullptr;
535 if (mEventListener
) {
536 DebugOnly
<nsresult
> rvIgnored
=
537 static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
538 ->ListenToMouseMoveEventForGrabber(false);
539 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
540 "HTMLEditorEventListener::"
541 "ListenToMouseMoveEventForGrabber(false) failed");
544 mGrabberClicked
= false;
546 nsresult rv
= RefreshEditingUI();
547 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
548 "HTMLEditor::RefreshEditingUI() failed");
552 nsresult
HTMLEditor::SetFinalPosition(int32_t aX
, int32_t aY
) {
553 nsresult rv
= EndMoving();
555 NS_WARNING("HTMLEditor::EndMoving() failed");
559 // we have now to set the new width and height of the resized object
560 // we don't set the x and y position because we don't control that in
561 // a normal HTML layout
562 int32_t newX
= mPositionedObjectX
+ aX
- mOriginalX
-
563 (mPositionedObjectBorderLeft
+ mPositionedObjectMarginLeft
);
564 int32_t newY
= mPositionedObjectY
+ aY
- mOriginalY
-
565 (mPositionedObjectBorderTop
+ mPositionedObjectMarginTop
);
567 SnapToGrid(newX
, newY
);
573 // we want one transaction only from a user's point of view
574 AutoPlaceholderBatch
treatAsOneTransaction(*this,
575 ScrollSelectionIntoView::Yes
);
577 if (NS_WARN_IF(!mAbsolutelyPositionedObject
)) {
578 return NS_ERROR_FAILURE
;
580 if (RefPtr
<nsStyledElement
> styledAbsolutelyPositionedElement
=
581 nsStyledElement::FromNode(mAbsolutelyPositionedObject
)) {
583 rv
= mCSSEditUtils
->SetCSSPropertyPixelsWithTransaction(
584 *styledAbsolutelyPositionedElement
, *nsGkAtoms::top
, newY
);
585 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
587 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
588 "destroyed the editor");
589 return NS_ERROR_EDITOR_DESTROYED
;
591 NS_WARNING_ASSERTION(
593 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
594 "failed, but ignored");
595 rv
= mCSSEditUtils
->SetCSSPropertyPixelsWithTransaction(
596 *styledAbsolutelyPositionedElement
, *nsGkAtoms::left
, newX
);
597 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
599 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
600 "destroyed the editor");
601 return NS_ERROR_EDITOR_DESTROYED
;
603 NS_WARNING_ASSERTION(
605 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
606 "failed, but ignored");
608 // keep track of that size
609 mPositionedObjectX
= newX
;
610 mPositionedObjectY
= newY
;
612 rv
= RefreshResizers();
613 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
614 "HTMLEditor::RefreshResizers() failed");
618 void HTMLEditor::AddPositioningOffset(int32_t& aX
, int32_t& aY
) {
619 // Get the positioning offset
620 int32_t positioningOffset
=
621 Preferences::GetInt("editor.positioning.offset", 0);
623 aX
+= positioningOffset
;
624 aY
+= positioningOffset
;
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(*this,
657 ScrollSelectionIntoView::Yes
);
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
= mCSSEditUtils
->SetCSSPropertyWithTransaction(
669 MOZ_KnownLive(*styledElement
), *nsGkAtoms::position
, u
"absolute"_ns
);
670 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
672 "CSSEditUtils::SetCSSProperyWithTransaction(nsGkAtoms::Position) "
673 "destroyed the editor");
674 return NS_ERROR_EDITOR_DESTROYED
;
676 NS_WARNING_ASSERTION(
677 NS_SUCCEEDED(rvIgnored
),
678 "CSSEditUtils::SetCSSPropertyWithTransaction(nsGkAtoms::position, "
679 "absolute) failed, but ignored");
682 AddPositioningOffset(x
, y
);
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
<RefPtr
<Element
>, nsresult
> resultOfInsertingBRElement
=
702 InsertBRElementWithTransaction(EditorDOMPoint(parentNode
, 0));
703 if (resultOfInsertingBRElement
.isErr()) {
704 NS_WARNING("HTMLEditor::InsertBRElementWithTransaction() failed");
705 return resultOfInsertingBRElement
.unwrapErr();
707 MOZ_ASSERT(resultOfInsertingBRElement
.inspect());
711 nsresult
HTMLEditor::SetPositionToStatic(Element
& aElement
) {
712 nsStyledElement
* styledElement
= nsStyledElement::FromNode(&aElement
);
713 if (NS_WARN_IF(!styledElement
)) {
714 return NS_ERROR_INVALID_ARG
;
717 AutoPlaceholderBatch
treatAsOneTransaction(*this,
718 ScrollSelectionIntoView::Yes
);
721 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
722 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
723 rv
= mCSSEditUtils
->RemoveCSSPropertyWithTransaction(
724 MOZ_KnownLive(*styledElement
), *nsGkAtoms::position
, u
""_ns
);
725 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
727 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
728 "destroyed the editor");
729 return NS_ERROR_EDITOR_DESTROYED
;
731 NS_WARNING_ASSERTION(
733 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::position) "
734 "failed, but ignored");
735 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
736 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
737 rv
= mCSSEditUtils
->RemoveCSSPropertyWithTransaction(
738 MOZ_KnownLive(*styledElement
), *nsGkAtoms::top
, u
""_ns
);
739 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
741 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
742 "destroyed the editor");
743 return NS_ERROR_EDITOR_DESTROYED
;
745 NS_WARNING_ASSERTION(
747 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::top) "
748 "failed, but ignored");
749 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
750 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
751 rv
= mCSSEditUtils
->RemoveCSSPropertyWithTransaction(
752 MOZ_KnownLive(*styledElement
), *nsGkAtoms::left
, u
""_ns
);
753 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
755 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
756 "destroyed the editor");
757 return NS_ERROR_EDITOR_DESTROYED
;
759 NS_WARNING_ASSERTION(
761 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::left) "
762 "failed, but ignored");
763 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
764 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
765 rv
= mCSSEditUtils
->RemoveCSSPropertyWithTransaction(
766 MOZ_KnownLive(*styledElement
), *nsGkAtoms::z_index
, u
""_ns
);
767 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
769 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
770 "destroyed the editor");
771 return NS_ERROR_EDITOR_DESTROYED
;
773 NS_WARNING_ASSERTION(
775 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::z_index) "
776 "failed, but ignored");
778 if (!HTMLEditUtils::IsImage(styledElement
)) {
779 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
780 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
781 rv
= mCSSEditUtils
->RemoveCSSPropertyWithTransaction(
782 MOZ_KnownLive(*styledElement
), *nsGkAtoms::width
, u
""_ns
);
783 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
785 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
786 "destroyed the editor");
787 return NS_ERROR_EDITOR_DESTROYED
;
789 NS_WARNING_ASSERTION(
791 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
792 "failed, but ignored");
793 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
794 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
795 rv
= mCSSEditUtils
->RemoveCSSPropertyWithTransaction(
796 MOZ_KnownLive(*styledElement
), *nsGkAtoms::height
, u
""_ns
);
797 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
799 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
800 "destroyed the editor");
801 return NS_ERROR_EDITOR_DESTROYED
;
803 NS_WARNING_ASSERTION(
805 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
806 "failed, but ignored");
809 if (!styledElement
->IsHTMLElement(nsGkAtoms::div
) ||
810 HTMLEditor::HasStyleOrIdOrClassAttribute(*styledElement
)) {
814 // Make sure the first fild and last child of aElement starts/ends hard
815 // line(s) even after removing `aElement`.
816 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
817 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
818 rv
= EnsureHardLineBeginsWithFirstChildOf(MOZ_KnownLive(*styledElement
));
820 NS_WARNING("HTMLEditor::EnsureHardLineBeginsWithFirstChildOf() failed");
823 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
824 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
825 rv
= EnsureHardLineEndsWithLastChildOf(MOZ_KnownLive(*styledElement
));
827 NS_WARNING("HTMLEditor::EnsureHardLineEndsWithLastChildOf() failed");
830 // MOZ_KnownLive(*styledElement): aElement's lifetime must be guarantted
831 // by the caller because of MOZ_CAN_RUN_SCRIPT method.
832 rv
= RemoveContainerWithTransaction(MOZ_KnownLive(*styledElement
));
833 if (NS_WARN_IF(Destroyed())) {
834 return NS_ERROR_EDITOR_DESTROYED
;
836 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
837 "HTMLEditor::RemoveContainerWithTransaction() failed");
841 NS_IMETHODIMP
HTMLEditor::SetSnapToGridEnabled(bool aEnabled
) {
842 mSnapToGridEnabled
= aEnabled
;
846 NS_IMETHODIMP
HTMLEditor::GetSnapToGridEnabled(bool* aIsEnabled
) {
847 *aIsEnabled
= mSnapToGridEnabled
;
851 NS_IMETHODIMP
HTMLEditor::SetGridSize(uint32_t aSize
) {
856 NS_IMETHODIMP
HTMLEditor::GetGridSize(uint32_t* aSize
) {
861 nsresult
HTMLEditor::SetTopAndLeftWithTransaction(
862 nsStyledElement
& aStyledElement
, int32_t aX
, int32_t aY
) {
863 AutoPlaceholderBatch
treatAsOneTransaction(*this,
864 ScrollSelectionIntoView::Yes
);
866 rv
= mCSSEditUtils
->SetCSSPropertyPixelsWithTransaction(aStyledElement
,
867 *nsGkAtoms::left
, aX
);
868 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
870 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
871 "destroyed the editor");
872 return NS_ERROR_EDITOR_DESTROYED
;
874 NS_WARNING_ASSERTION(
876 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
877 "failed, but ignored");
878 rv
= mCSSEditUtils
->SetCSSPropertyPixelsWithTransaction(aStyledElement
,
879 *nsGkAtoms::top
, aY
);
880 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
882 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
883 "destroyed the editor");
884 return NS_ERROR_EDITOR_DESTROYED
;
886 NS_WARNING_ASSERTION(
888 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
889 "failed, but ignored");
893 nsresult
HTMLEditor::GetTemporaryStyleForFocusedPositionedElement(
894 Element
& aElement
, nsAString
& aReturn
) {
895 // we are going to outline the positioned element and bring it to the
896 // front to overlap any other element intersecting with it. But
897 // first, let's see what's the background and foreground colors of the
898 // positioned element.
899 // if background-image computed value is 'none,
900 // If the background color is 'auto' and R G B values of the foreground are
901 // each above #d0, use a black background
902 // If the background color is 'auto' and at least one of R G B values of
903 // the foreground is below #d0, use a white background
904 // Otherwise don't change background/foreground
907 nsAutoString backgroundImageValue
;
908 nsresult rv
= CSSEditUtils::GetComputedProperty(
909 aElement
, *nsGkAtoms::background_image
, backgroundImageValue
);
912 "CSSEditUtils::GetComputedProperty(nsGkAtoms::background_image) "
916 if (!backgroundImageValue
.EqualsLiteral("none")) {
920 nsAutoString backgroundColorValue
;
921 rv
= CSSEditUtils::GetComputedProperty(aElement
, *nsGkAtoms::backgroundColor
,
922 backgroundColorValue
);
925 "CSSEditUtils::GetComputedProperty(nsGkAtoms::backgroundColor) "
929 if (!backgroundColorValue
.EqualsLiteral("rgba(0, 0, 0, 0)")) {
933 RefPtr
<ComputedStyle
> style
=
934 nsComputedDOMStyle::GetComputedStyle(&aElement
, nullptr);
935 if (NS_WARN_IF(Destroyed())) {
936 return NS_ERROR_EDITOR_DESTROYED
;
939 NS_WARNING("nsComputedDOMStyle::GetComputedStyle() failed");
940 return NS_ERROR_FAILURE
;
943 static const uint8_t kBlackBgTrigger
= 0xd0;
945 const auto& color
= style
->StyleText()->mColor
;
946 if (color
.red
>= kBlackBgTrigger
&& color
.green
>= kBlackBgTrigger
&&
947 color
.blue
>= kBlackBgTrigger
) {
948 aReturn
.AssignLiteral("black");
950 aReturn
.AssignLiteral("white");
956 } // namespace mozilla