1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "HTMLEditor.h"
9 #include "CSSEditUtils.h"
10 #include "HTMLEditorEventListener.h"
11 #include "HTMLEditUtils.h"
13 #include "mozilla/DebugOnly.h"
14 #include "mozilla/LookAndFeel.h"
15 #include "mozilla/MathAlgorithms.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/Event.h"
21 #include "mozilla/dom/MouseEvent.h"
22 #include "mozilla/dom/EventTarget.h"
23 #include "nsAString.h"
24 #include "nsAlgorithm.h"
28 #include "nsGkAtoms.h"
30 #include "nsIContent.h"
32 #include "mozilla/dom/Document.h"
33 #include "nsISupportsUtils.h"
34 #include "nsPIDOMWindow.h"
35 #include "nsReadableUtils.h"
37 #include "nsStringFwd.h"
38 #include "nsStyledElement.h"
39 #include "nsTextNode.h"
43 #define kTopLeft u"nw"_ns
45 #define kTopRight u"ne"_ns
47 #define kRight u"e"_ns
48 #define kBottomLeft u"sw"_ns
49 #define kBottom u"s"_ns
50 #define kBottomRight u"se"_ns
56 /******************************************************************************
58 ******************************************************************************/
60 ManualNACPtr
HTMLEditor::CreateResizer(int16_t aLocation
,
61 nsIContent
& aParentContent
) {
62 ManualNACPtr resizer
= CreateAnonymousElement(nsGkAtoms::span
, aParentContent
,
63 u
"mozResizer"_ns
, false);
66 "HTMLEditor::CreateAnonymousElement(nsGkAtoms::span, mozResizer) "
71 // add the mouse listener so we can detect a click on a resizer
72 DebugOnly
<nsresult
> rvIgnored
=
73 resizer
->AddEventListener(u
"mousedown"_ns
, mEventListener
, true);
75 NS_SUCCEEDED(rvIgnored
),
76 "EventTarget::AddEventListener(mousedown) failed, but ignored");
78 nsAutoString locationStr
;
80 case nsIHTMLObjectResizer::eTopLeft
:
81 locationStr
= kTopLeft
;
83 case nsIHTMLObjectResizer::eTop
:
86 case nsIHTMLObjectResizer::eTopRight
:
87 locationStr
= kTopRight
;
90 case nsIHTMLObjectResizer::eLeft
:
93 case nsIHTMLObjectResizer::eRight
:
97 case nsIHTMLObjectResizer::eBottomLeft
:
98 locationStr
= kBottomLeft
;
100 case nsIHTMLObjectResizer::eBottom
:
101 locationStr
= kBottom
;
103 case nsIHTMLObjectResizer::eBottomRight
:
104 locationStr
= kBottomRight
;
108 if (NS_FAILED(resizer
->SetAttr(kNameSpaceID_None
, nsGkAtoms::anonlocation
,
109 locationStr
, true))) {
110 NS_WARNING("Element::SetAttr(nsGkAtoms::anonlocation) failed");
116 ManualNACPtr
HTMLEditor::CreateShadow(nsIContent
& aParentContent
,
117 Element
& aOriginalObject
) {
118 // let's create an image through the element factory
120 if (HTMLEditUtils::IsImage(&aOriginalObject
)) {
121 name
= nsGkAtoms::img
;
123 name
= nsGkAtoms::span
;
126 return CreateAnonymousElement(name
, aParentContent
, u
"mozResizingShadow"_ns
,
130 ManualNACPtr
HTMLEditor::CreateResizingInfo(nsIContent
& aParentContent
) {
131 // let's create an info box through the element factory
132 return CreateAnonymousElement(nsGkAtoms::span
, aParentContent
,
133 u
"mozResizingInfo"_ns
, true);
136 nsresult
HTMLEditor::SetAllResizersPosition() {
137 if (NS_WARN_IF(!mTopLeftHandle
)) {
138 return NS_ERROR_FAILURE
; // There are no resizers.
141 int32_t x
= mResizedObjectX
;
142 int32_t y
= mResizedObjectY
;
143 int32_t w
= mResizedObjectWidth
;
144 int32_t h
= mResizedObjectHeight
;
147 float resizerWidth
, resizerHeight
;
148 RefPtr
<nsAtom
> dummyUnit
;
149 DebugOnly
<nsresult
> rvIgnored
= NS_OK
;
150 OwningNonNull
<Element
> topLeftHandle
= *mTopLeftHandle
.get();
151 // XXX Do we really need to computed value rather than specified value?
152 // Because it's an anonymous node.
153 rvIgnored
= CSSEditUtils::GetComputedProperty(*topLeftHandle
,
154 *nsGkAtoms::width
, value
);
155 if (NS_WARN_IF(Destroyed())) {
156 return NS_ERROR_EDITOR_DESTROYED
;
158 if (NS_WARN_IF(topLeftHandle
!= mTopLeftHandle
)) {
159 return NS_ERROR_FAILURE
;
161 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
162 "CSSEditUtils::GetComputedProperty(nsGkAtoms::width) "
163 "failed, but ignored");
164 rvIgnored
= CSSEditUtils::GetComputedProperty(*topLeftHandle
,
165 *nsGkAtoms::height
, value
);
166 if (NS_WARN_IF(Destroyed())) {
167 return NS_ERROR_EDITOR_DESTROYED
;
169 if (NS_WARN_IF(topLeftHandle
!= mTopLeftHandle
)) {
170 return NS_ERROR_FAILURE
;
172 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
173 "CSSEditUtils::GetComputedProperty(nsGkAtoms::height) "
174 "failed, but ignored");
175 CSSEditUtils::ParseLength(value
, &resizerWidth
, getter_AddRefs(dummyUnit
));
176 CSSEditUtils::ParseLength(value
, &resizerHeight
, getter_AddRefs(dummyUnit
));
178 int32_t rw
= static_cast<int32_t>((resizerWidth
+ 1) / 2);
179 int32_t rh
= static_cast<int32_t>((resizerHeight
+ 1) / 2);
181 // While moving each resizer, mutation event listener may hide the resizers.
182 // And in worst case, new resizers may be recreated. So, we need to store
183 // all resizers here, and then, if we detect a resizer is removed or replaced,
184 // we should do nothing anymore.
185 // FYI: Note that only checking if mTopLeftHandle is replaced is enough.
186 // We're may be in hot path if user resizes an element a lot. So,
187 // we should just add-ref mTopLeftHandle.
188 auto setHandlePosition
=
189 [this](ManualNACPtr
& aHandleElement
, int32_t aNewX
, int32_t aNewY
)
190 MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
-> nsresult
{
191 RefPtr
<nsStyledElement
> handleStyledElement
=
192 nsStyledElement::FromNodeOrNull(aHandleElement
.get());
193 if (!handleStyledElement
) {
196 nsresult rv
= SetAnonymousElementPositionWithoutTransaction(
197 *handleStyledElement
, aNewX
, aNewY
);
200 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() "
204 return NS_WARN_IF(handleStyledElement
!= aHandleElement
.get())
209 rv
= setHandlePosition(mTopLeftHandle
, x
- rw
, y
- rh
);
211 NS_WARNING("Failed to set top-left handle position");
214 rv
= setHandlePosition(mTopHandle
, x
+ w
/ 2 - rw
, y
- rh
);
216 NS_WARNING("Failed to set top handle position");
219 rv
= setHandlePosition(mTopRightHandle
, x
+ w
- rw
- 1, y
- rh
);
221 NS_WARNING("Failed to set top-right handle position");
225 rv
= setHandlePosition(mLeftHandle
, x
- rw
, y
+ h
/ 2 - rh
);
227 NS_WARNING("Failed to set left handle position");
230 rv
= setHandlePosition(mRightHandle
, x
+ w
- rw
- 1, y
+ h
/ 2 - rh
);
232 NS_WARNING("Failed to set right handle position");
236 rv
= setHandlePosition(mBottomLeftHandle
, x
- rw
, y
+ h
- rh
- 1);
238 NS_WARNING("Failed to set bottom-left handle position");
241 rv
= setHandlePosition(mBottomHandle
, x
+ w
/ 2 - rw
, y
+ h
- rh
- 1);
243 NS_WARNING("Failed to set bottom handle position");
246 rv
= setHandlePosition(mBottomRightHandle
, x
+ w
- rw
- 1, y
+ h
- rh
- 1);
248 NS_WARNING("Failed to set bottom-right handle position");
255 nsresult
HTMLEditor::RefreshResizers() {
256 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
257 if (NS_WARN_IF(!editActionData
.CanHandle())) {
258 return NS_ERROR_NOT_INITIALIZED
;
261 nsresult rv
= RefreshResizersInternal();
262 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
263 "HTMLEditor::RefreshResizersInternal() failed");
264 return EditorBase::ToGenericNSResult(rv
);
267 nsresult
HTMLEditor::RefreshResizersInternal() {
268 MOZ_ASSERT(IsEditActionDataAvailable());
270 // Don't warn even if resizers are not visible since script cannot check
271 // if they are visible and this is non-virtual method. So, the cost of
272 // calling this can be ignored.
273 if (!mResizedObject
) {
277 OwningNonNull
<Element
> resizedObject
= *mResizedObject
;
278 nsresult rv
= GetPositionAndDimensions(
279 resizedObject
, mResizedObjectX
, mResizedObjectY
, mResizedObjectWidth
,
280 mResizedObjectHeight
, mResizedObjectBorderLeft
, mResizedObjectBorderTop
,
281 mResizedObjectMarginLeft
, mResizedObjectMarginTop
);
283 NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
286 if (NS_WARN_IF(resizedObject
!= mResizedObject
)) {
287 return NS_ERROR_FAILURE
;
290 rv
= SetAllResizersPosition();
292 NS_WARNING("HTMLEditor::SetAllResizersPosition() failed");
295 if (NS_WARN_IF(resizedObject
!= mResizedObject
)) {
296 return NS_ERROR_FAILURE
;
301 "SetAllResizersPosition() should return error if resizers are hidden");
302 RefPtr
<Element
> resizingShadow
= mResizingShadow
.get();
303 rv
= SetShadowPosition(*resizingShadow
, resizedObject
, mResizedObjectX
,
306 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
309 if (NS_WARN_IF(resizedObject
!= mResizedObject
)) {
310 return NS_ERROR_FAILURE
;
315 nsresult
HTMLEditor::ShowResizersInternal(Element
& aResizedElement
) {
316 // When we have visible resizers, we cannot show new resizers.
317 // So, the caller should call HideResizersInternal() first if this
319 if (NS_WARN_IF(mResizedObject
)) {
320 return NS_ERROR_UNEXPECTED
;
323 nsCOMPtr
<nsIContent
> parentContent
= aResizedElement
.GetParent();
324 if (NS_WARN_IF(!parentContent
)) {
325 return NS_ERROR_FAILURE
;
328 const RefPtr
<Element
> editingHost
= ComputeEditingHost();
329 if (NS_WARN_IF(!editingHost
) ||
330 NS_WARN_IF(!aResizedElement
.IsInclusiveDescendantOf(editingHost
))) {
331 return NS_ERROR_UNEXPECTED
;
334 // Let's create and setup resizers. If we failed something, we should
335 // cancel everything which we do in this method.
337 mResizedObject
= &aResizedElement
;
339 // The resizers and the shadow will be anonymous siblings of the element.
340 // Note that creating a resizer or shadow may causes calling
341 // HideRisizersInternal() via a mutation event listener. So, we should
342 // store new resizer to a local variable, then, check:
343 // - whether creating resizer is already set to the member or not
344 // - whether resizing element is changed to another element
345 // If showing resizers are canceled, we hit the latter check.
346 // If resizers for another element is shown during this, we hit the latter
348 // If resizers are just shown again for same element, we hit the former
350 ManualNACPtr newResizer
=
351 CreateResizer(nsIHTMLObjectResizer::eTopLeft
, *parentContent
);
353 NS_WARNING("HTMLEditor::CreateResizer(eTopLeft) failed");
356 if (NS_WARN_IF(mTopLeftHandle
) ||
357 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
358 // Don't hide current resizers in this case because they are not what
360 return NS_ERROR_FAILURE
;
362 mTopLeftHandle
= std::move(newResizer
);
363 newResizer
= CreateResizer(nsIHTMLObjectResizer::eTop
, *parentContent
);
365 NS_WARNING("HTMLEditor::CreateResizer(eTop) failed");
368 if (NS_WARN_IF(mTopHandle
) ||
369 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
370 return NS_ERROR_FAILURE
;
372 mTopHandle
= std::move(newResizer
);
373 newResizer
= CreateResizer(nsIHTMLObjectResizer::eTopRight
, *parentContent
);
375 NS_WARNING("HTMLEditor::CreateResizer(eTopRight) failed");
378 if (NS_WARN_IF(mTopRightHandle
) ||
379 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
380 return NS_ERROR_FAILURE
;
382 mTopRightHandle
= std::move(newResizer
);
384 newResizer
= CreateResizer(nsIHTMLObjectResizer::eLeft
, *parentContent
);
386 NS_WARNING("HTMLEditor::CreateResizer(eLeft) failed");
389 if (NS_WARN_IF(mLeftHandle
) ||
390 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
391 return NS_ERROR_FAILURE
;
393 mLeftHandle
= std::move(newResizer
);
394 newResizer
= CreateResizer(nsIHTMLObjectResizer::eRight
, *parentContent
);
396 NS_WARNING("HTMLEditor::CreateResizer(eRight) failed");
399 if (NS_WARN_IF(mRightHandle
) ||
400 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
401 return NS_ERROR_FAILURE
;
403 mRightHandle
= std::move(newResizer
);
406 CreateResizer(nsIHTMLObjectResizer::eBottomLeft
, *parentContent
);
408 NS_WARNING("HTMLEditor::CreateResizer(eBottomLeft) failed");
411 if (NS_WARN_IF(mBottomLeftHandle
) ||
412 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
413 return NS_ERROR_FAILURE
;
415 mBottomLeftHandle
= std::move(newResizer
);
416 newResizer
= CreateResizer(nsIHTMLObjectResizer::eBottom
, *parentContent
);
418 NS_WARNING("HTMLEditor::CreateResizer(eBottom) failed");
421 if (NS_WARN_IF(mBottomHandle
) ||
422 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
423 return NS_ERROR_FAILURE
;
425 mBottomHandle
= std::move(newResizer
);
427 CreateResizer(nsIHTMLObjectResizer::eBottomRight
, *parentContent
);
429 NS_WARNING("HTMLEditor::CreateResizer(eBottomRight) failed");
432 if (NS_WARN_IF(mBottomRightHandle
) ||
433 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
434 return NS_ERROR_FAILURE
;
436 mBottomRightHandle
= std::move(newResizer
);
438 // Store the last resizer which we created. This is useful when we
439 // need to check whether our resizers are hiddedn and recreated another
440 // set of resizers or not.
441 RefPtr
<Element
> createdBottomRightHandle
= mBottomRightHandle
.get();
443 nsresult rv
= GetPositionAndDimensions(
444 aResizedElement
, mResizedObjectX
, mResizedObjectY
, mResizedObjectWidth
,
445 mResizedObjectHeight
, mResizedObjectBorderLeft
, mResizedObjectBorderTop
,
446 mResizedObjectMarginLeft
, mResizedObjectMarginTop
);
448 NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
452 // and let's set their absolute positions in the document
453 rv
= SetAllResizersPosition();
455 NS_WARNING("HTMLEditor::SetAllResizersPosition() failed");
456 if (NS_WARN_IF(mBottomRightHandle
.get() != createdBottomRightHandle
)) {
457 return NS_ERROR_FAILURE
;
462 // now, let's create the resizing shadow
463 ManualNACPtr newShadow
= CreateShadow(*parentContent
, aResizedElement
);
465 NS_WARNING("HTMLEditor::CreateShadow() failed");
468 if (NS_WARN_IF(mResizingShadow
) ||
469 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
470 return NS_ERROR_FAILURE
;
472 mResizingShadow
= std::move(newShadow
);
474 // and set its position
475 RefPtr
<Element
> resizingShadow
= mResizingShadow
.get();
476 rv
= SetShadowPosition(*resizingShadow
, aResizedElement
, mResizedObjectX
,
479 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
480 if (NS_WARN_IF(mBottomRightHandle
.get() != createdBottomRightHandle
)) {
481 return NS_ERROR_FAILURE
;
486 // and then the resizing info tooltip
487 ManualNACPtr newResizingInfo
= CreateResizingInfo(*parentContent
);
488 if (!newResizingInfo
) {
489 NS_WARNING("HTMLEditor::CreateResizingInfo() failed");
492 if (NS_WARN_IF(mResizingInfo
) ||
493 NS_WARN_IF(mResizedObject
!= &aResizedElement
)) {
494 return NS_ERROR_FAILURE
;
496 mResizingInfo
= std::move(newResizingInfo
);
498 // and listen to the "resize" event on the window first, get the
499 // window from the document...
500 if (NS_WARN_IF(!mEventListener
)) {
504 rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
505 ->ListenToWindowResizeEvent(true);
508 "HTMLEditorEventListener::ListenToWindowResizeEvent(true) failed");
512 MOZ_ASSERT(mResizedObject
== &aResizedElement
);
514 // XXX Even when it failed to add event listener, should we need to set
515 // _moz_resizing attribute?
516 DebugOnly
<nsresult
> rvIgnored
= aResizedElement
.SetAttr(
517 kNameSpaceID_None
, nsGkAtoms::_moz_resizing
, u
"true"_ns
, true);
518 NS_WARNING_ASSERTION(
519 NS_SUCCEEDED(rvIgnored
),
520 "Element::SetAttr(nsGkAtoms::_moz_resizing, true) failed, but ignored");
524 DebugOnly
<nsresult
> rv
= HideResizersInternal();
525 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
526 "HTMLEditor::HideResizersInternal() failed to clean up");
527 return NS_ERROR_FAILURE
;
530 NS_IMETHODIMP
HTMLEditor::HideResizers() {
531 AutoEditActionDataSetter
editActionData(*this, EditAction::eNotEditing
);
532 if (NS_WARN_IF(!editActionData
.CanHandle())) {
533 return NS_ERROR_NOT_INITIALIZED
;
536 nsresult rv
= HideResizersInternal();
537 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
538 "HTMLEditor::HideResizersInternal() failed");
539 return EditorBase::ToGenericNSResult(rv
);
542 nsresult
HTMLEditor::HideResizersInternal() {
543 // Don't warn even if resizers are visible since script cannot check
544 // if they are visible and this is non-virtual method. So, the cost of
545 // calling this can be ignored.
546 if (!mResizedObject
) {
550 // get the presshell's document observer interface.
551 RefPtr
<PresShell
> presShell
= GetPresShell();
552 NS_WARNING_ASSERTION(presShell
, "There is no presShell");
553 // We allow the pres shell to be null; when it is, we presume there
554 // are no document observers to notify, but we still want to
557 constexpr auto mousedown
= u
"mousedown"_ns
;
559 // HTMLEditor should forget all members related to resizers first since
560 // removing a part of UI may cause showing the resizers again. In such
561 // case, the members may be overwritten by ShowResizers() and this will
562 // lose the chance to release the old resizers.
563 ManualNACPtr
topLeftHandle(std::move(mTopLeftHandle
));
564 ManualNACPtr
topHandle(std::move(mTopHandle
));
565 ManualNACPtr
topRightHandle(std::move(mTopRightHandle
));
566 ManualNACPtr
leftHandle(std::move(mLeftHandle
));
567 ManualNACPtr
rightHandle(std::move(mRightHandle
));
568 ManualNACPtr
bottomLeftHandle(std::move(mBottomLeftHandle
));
569 ManualNACPtr
bottomHandle(std::move(mBottomHandle
));
570 ManualNACPtr
bottomRightHandle(std::move(mBottomRightHandle
));
571 ManualNACPtr
resizingShadow(std::move(mResizingShadow
));
572 ManualNACPtr
resizingInfo(std::move(mResizingInfo
));
573 RefPtr
<Element
> activatedHandle(std::move(mActivatedHandle
));
574 RefPtr
<Element
> resizedObject(std::move(mResizedObject
));
576 // Remvoe all handles.
577 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
578 std::move(topLeftHandle
), presShell
);
580 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
581 std::move(topHandle
), presShell
);
583 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
584 std::move(topRightHandle
), presShell
);
586 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
587 std::move(leftHandle
), presShell
);
589 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
590 std::move(rightHandle
), presShell
);
592 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
593 std::move(bottomLeftHandle
), presShell
);
595 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
596 std::move(bottomHandle
), presShell
);
598 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
599 std::move(bottomRightHandle
), presShell
);
601 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
602 std::move(resizingShadow
), presShell
);
604 RemoveListenerAndDeleteRef(mousedown
, mEventListener
, true,
605 std::move(resizingInfo
), presShell
);
607 // Remove active state of a resizer.
608 if (activatedHandle
) {
609 DebugOnly
<nsresult
> rvIgnored
= activatedHandle
->UnsetAttr(
610 kNameSpaceID_None
, nsGkAtoms::_moz_activated
, true);
611 NS_WARNING_ASSERTION(
612 NS_SUCCEEDED(rvIgnored
),
613 "Element::UnsetAttr(nsGkAtoms::_moz_activated) failed, but ignored");
616 // Remove resizing state of the target element.
617 DebugOnly
<nsresult
> rvIgnored
= resizedObject
->UnsetAttr(
618 kNameSpaceID_None
, nsGkAtoms::_moz_resizing
, true);
619 NS_WARNING_ASSERTION(
620 NS_SUCCEEDED(rvIgnored
),
621 "Element::UnsetAttr(nsGkAtoms::_moz_resizing) failed, but ignored");
623 if (!mEventListener
) {
627 nsresult rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
628 ->ListenToMouseMoveEventForResizers(false);
631 "HTMLEditorEventListener::ListenToMouseMoveEventForResizers(false) "
636 // Remove resize event listener from the window.
637 if (!mEventListener
) {
641 rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
642 ->ListenToWindowResizeEvent(false);
643 NS_WARNING_ASSERTION(
645 "HTMLEditorEventListener::ListenToWindowResizeEvent(false) failed");
649 void HTMLEditor::HideShadowAndInfo() {
650 if (mResizingShadow
) {
651 DebugOnly
<nsresult
> rvIgnored
= mResizingShadow
->SetAttr(
652 kNameSpaceID_None
, nsGkAtoms::_class
, u
"hidden"_ns
, true);
653 NS_WARNING_ASSERTION(
654 NS_SUCCEEDED(rvIgnored
),
655 "Element::SetAttr(nsGkAtoms::_class, hidden) failed, but ignored");
658 DebugOnly
<nsresult
> rvIgnored
= mResizingInfo
->SetAttr(
659 kNameSpaceID_None
, nsGkAtoms::_class
, u
"hidden"_ns
, true);
660 NS_WARNING_ASSERTION(
661 NS_SUCCEEDED(rvIgnored
),
662 "Element::SetAttr(nsGkAtoms::_class, hidden) failed, but ignored");
666 nsresult
HTMLEditor::StartResizing(Element
& aHandleElement
) {
668 mActivatedHandle
= &aHandleElement
;
669 DebugOnly
<nsresult
> rvIgnored
= mActivatedHandle
->SetAttr(
670 kNameSpaceID_None
, nsGkAtoms::_moz_activated
, u
"true"_ns
, true);
671 if (NS_WARN_IF(Destroyed())) {
672 return NS_ERROR_EDITOR_DESTROYED
;
674 NS_WARNING_ASSERTION(
675 NS_SUCCEEDED(rvIgnored
),
676 "Element::SetAttr(nsGkAtoms::_moz_activated, true) failed");
678 // do we want to preserve ratio or not?
679 const bool preserveRatio
= HTMLEditUtils::IsImage(mResizedObject
);
681 // the way we change the position/size of the shadow depends on
683 nsAutoString locationStr
;
684 mActivatedHandle
->GetAttr(nsGkAtoms::anonlocation
, locationStr
);
685 if (locationStr
.Equals(kTopLeft
)) {
686 SetResizeIncrements(1, 1, -1, -1, preserveRatio
);
687 } else if (locationStr
.Equals(kTop
)) {
688 SetResizeIncrements(0, 1, 0, -1, false);
689 } else if (locationStr
.Equals(kTopRight
)) {
690 SetResizeIncrements(0, 1, 1, -1, preserveRatio
);
691 } else if (locationStr
.Equals(kLeft
)) {
692 SetResizeIncrements(1, 0, -1, 0, false);
693 } else if (locationStr
.Equals(kRight
)) {
694 SetResizeIncrements(0, 0, 1, 0, false);
695 } else if (locationStr
.Equals(kBottomLeft
)) {
696 SetResizeIncrements(1, 0, -1, 1, preserveRatio
);
697 } else if (locationStr
.Equals(kBottom
)) {
698 SetResizeIncrements(0, 0, 0, 1, false);
699 } else if (locationStr
.Equals(kBottomRight
)) {
700 SetResizeIncrements(0, 0, 1, 1, preserveRatio
);
703 // make the shadow appear
705 mResizingShadow
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, true);
706 if (NS_WARN_IF(Destroyed())) {
707 return NS_ERROR_EDITOR_DESTROYED
;
709 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
710 "Element::UnsetAttr(nsGkAtoms::_class) failed");
713 if (RefPtr
<nsStyledElement
> resizingShadowStyledElement
=
714 nsStyledElement::FromNodeOrNull(mResizingShadow
.get())) {
716 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
717 *resizingShadowStyledElement
, *nsGkAtoms::width
, mResizedObjectWidth
);
718 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
720 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
721 "nsGkAtoms::width) destroyed the editor");
722 return NS_ERROR_EDITOR_DESTROYED
;
724 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
725 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
726 "nsGkAtoms::width) failed");
727 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
728 *resizingShadowStyledElement
, *nsGkAtoms::height
, mResizedObjectHeight
);
729 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
731 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
732 "nsGkAtoms::height) destroyed the editor");
733 return NS_ERROR_EDITOR_DESTROYED
;
735 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
736 "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction("
737 "nsGkAtoms::height) failed");
740 // add a mouse move listener to the editor
741 if (NS_WARN_IF(!mEventListener
)) {
742 return NS_ERROR_NOT_INITIALIZED
;
744 nsresult rv
= static_cast<HTMLEditorEventListener
*>(mEventListener
.get())
745 ->ListenToMouseMoveEventForResizers(true);
746 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
747 "HTMLEditorEventListener::"
748 "ListenToMouseMoveEventForResizers(true) failed");
752 nsresult
HTMLEditor::StartToDragResizerOrHandleDragGestureOnGrabber(
753 MouseEvent
& aMouseDownEvent
, Element
& aEventTargetElement
) {
754 MOZ_ASSERT(aMouseDownEvent
.GetExplicitOriginalTarget() ==
755 &aEventTargetElement
);
756 MOZ_ASSERT(!aMouseDownEvent
.DefaultPrevented());
757 MOZ_ASSERT(aMouseDownEvent
.WidgetEventPtr()->mMessage
== eMouseDown
);
759 nsAutoString anonclass
;
760 aEventTargetElement
.GetAttr(nsGkAtoms::_moz_anonclass
, anonclass
);
762 if (anonclass
.EqualsLiteral("mozResizer")) {
763 AutoEditActionDataSetter
editActionData(*this,
764 EditAction::eResizingElement
);
765 if (NS_WARN_IF(!editActionData
.CanHandle())) {
766 return NS_ERROR_NOT_INITIALIZED
;
769 // If we have an anonymous element and that element is a resizer,
770 // let's start resizing!
771 aMouseDownEvent
.PreventDefault();
772 mOriginalX
= aMouseDownEvent
.ClientX();
773 mOriginalY
= aMouseDownEvent
.ClientY();
774 nsresult rv
= StartResizing(aEventTargetElement
);
775 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
776 "HTMLEditor::StartResizing() failed");
777 return EditorBase::ToGenericNSResult(rv
);
780 if (anonclass
.EqualsLiteral("mozGrabber")) {
781 AutoEditActionDataSetter
editActionData(*this, EditAction::eMovingElement
);
782 if (NS_WARN_IF(!editActionData
.CanHandle())) {
783 return NS_ERROR_NOT_INITIALIZED
;
786 // If we have an anonymous element and that element is a grabber,
787 // let's start moving the element!
788 mOriginalX
= aMouseDownEvent
.ClientX();
789 mOriginalY
= aMouseDownEvent
.ClientY();
790 nsresult rv
= GrabberClicked();
791 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
792 "HTMLEditor::GrabberClicked() failed");
793 return EditorBase::ToGenericNSResult(rv
);
799 nsresult
HTMLEditor::StopDraggingResizerOrGrabberAt(
800 const CSSIntPoint
& aClientPoint
) {
802 AutoEditActionDataSetter
editActionData(*this, EditAction::eResizeElement
);
803 if (NS_WARN_IF(!editActionData
.CanHandle())) {
804 return NS_ERROR_NOT_INITIALIZED
;
807 // we are resizing and release the mouse button, so let's
808 // end the resizing process
812 nsresult rv
= editActionData
.MaybeDispatchBeforeInputEvent();
814 NS_WARNING_ASSERTION(
815 rv
== NS_ERROR_EDITOR_ACTION_CANCELED
,
816 "EditorBase::MaybeDispatchBeforeInputEvent(), failed");
817 return EditorBase::ToGenericNSResult(rv
);
820 rv
= SetFinalSizeWithTransaction(aClientPoint
.x
, aClientPoint
.y
);
821 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
823 "HTMLEditor::SetFinalSizeWithTransaction() destroyed the editor");
824 return NS_ERROR_EDITOR_DESTROYED
;
826 NS_WARNING_ASSERTION(
828 "HTMLEditor::SetFinalSizeWithTransaction() failed, but ignored");
832 if (mIsMoving
|| mGrabberClicked
) {
833 AutoEditActionDataSetter
editActionData(*this, EditAction::eMoveElement
);
834 nsresult rv
= editActionData
.CanHandleAndMaybeDispatchBeforeInputEvent();
835 if (rv
!= NS_ERROR_EDITOR_ACTION_CANCELED
&& NS_WARN_IF(NS_FAILED(rv
))) {
836 NS_WARNING("CanHandleAndMaybeDispatchBeforeInputEvent() failed");
837 return EditorBase::ToGenericNSResult(rv
);
841 DebugOnly
<nsresult
> rvIgnored
= mPositioningShadow
->SetAttr(
842 kNameSpaceID_None
, nsGkAtoms::_class
, u
"hidden"_ns
, true);
843 NS_WARNING_ASSERTION(
844 NS_SUCCEEDED(rvIgnored
),
845 "Element::SetAttr(nsGkAtoms::_class, hidden) failed");
846 if (rv
!= NS_ERROR_EDITOR_ACTION_CANCELED
) {
847 SetFinalPosition(aClientPoint
.x
, aClientPoint
.y
);
850 if (mGrabberClicked
) {
851 DebugOnly
<nsresult
> rvIgnored
= EndMoving();
852 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
853 "HTMLEditor::EndMoving() failed");
855 return EditorBase::ToGenericNSResult(rv
);
861 void HTMLEditor::SetResizeIncrements(int32_t aX
, int32_t aY
, int32_t aW
,
862 int32_t aH
, bool aPreserveRatio
) {
863 mXIncrementFactor
= aX
;
864 mYIncrementFactor
= aY
;
865 mWidthIncrementFactor
= aW
;
866 mHeightIncrementFactor
= aH
;
867 mPreserveRatio
= aPreserveRatio
;
870 nsresult
HTMLEditor::SetResizingInfoPosition(int32_t aX
, int32_t aY
, int32_t aW
,
872 // Determine the position of the resizing info box based upon the new
873 // position and size of the element (aX, aY, aW, aH), and which
874 // resizer is the "activated handle". For example, place the resizing
875 // info box at the bottom-right corner of the new element, if the element
876 // is being resized by the bottom-right resizer.
877 int32_t infoXPosition
;
878 int32_t infoYPosition
;
880 if (mActivatedHandle
== mTopLeftHandle
|| mActivatedHandle
== mLeftHandle
||
881 mActivatedHandle
== mBottomLeftHandle
) {
883 } else if (mActivatedHandle
== mTopHandle
||
884 mActivatedHandle
== mBottomHandle
) {
885 infoXPosition
= aX
+ (aW
/ 2);
887 // should only occur when mActivatedHandle is one of the 3 right-side
888 // handles, but this is a reasonable default if it isn't any of them (?)
889 infoXPosition
= aX
+ aW
;
892 if (mActivatedHandle
== mTopLeftHandle
|| mActivatedHandle
== mTopHandle
||
893 mActivatedHandle
== mTopRightHandle
) {
895 } else if (mActivatedHandle
== mLeftHandle
||
896 mActivatedHandle
== mRightHandle
) {
897 infoYPosition
= aY
+ (aH
/ 2);
899 // should only occur when mActivatedHandle is one of the 3 bottom-side
900 // handles, but this is a reasonable default if it isn't any of them (?)
901 infoYPosition
= aY
+ aH
;
904 // Offset info box by 20 so it's not directly under the mouse cursor.
905 const int mouseCursorOffset
= 20;
906 if (RefPtr
<nsStyledElement
> resizingInfoStyledElement
=
907 nsStyledElement::FromNodeOrNull(mResizingInfo
.get())) {
909 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
910 *resizingInfoStyledElement
, *nsGkAtoms::left
,
911 infoXPosition
+ mouseCursorOffset
);
912 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
914 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
915 "destroyed the editor");
916 return NS_ERROR_EDITOR_DESTROYED
;
918 NS_WARNING_ASSERTION(
920 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
921 "failed, but ignored");
922 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
923 *resizingInfoStyledElement
, *nsGkAtoms::top
,
924 infoYPosition
+ mouseCursorOffset
);
925 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
927 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
928 "destroyed the editor");
929 return NS_ERROR_EDITOR_DESTROYED
;
931 NS_WARNING_ASSERTION(
933 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
934 "failed, but ignored");
937 nsCOMPtr
<nsIContent
> textInfo
= mResizingInfo
->GetFirstChild();
940 mResizingInfo
->RemoveChild(*textInfo
, error
);
941 if (error
.Failed()) {
942 NS_WARNING("nsINode::RemoveChild() failed");
943 return error
.StealNSResult();
948 nsAutoString widthStr
, heightStr
, diffWidthStr
, diffHeightStr
;
949 widthStr
.AppendInt(aW
);
950 heightStr
.AppendInt(aH
);
951 int32_t diffWidth
= aW
- mResizedObjectWidth
;
952 int32_t diffHeight
= aH
- mResizedObjectHeight
;
954 diffWidthStr
.Assign('+');
956 if (diffHeight
> 0) {
957 diffHeightStr
.Assign('+');
959 diffWidthStr
.AppendInt(diffWidth
);
960 diffHeightStr
.AppendInt(diffHeight
);
962 nsAutoString
info(widthStr
+ u
" x "_ns
+ heightStr
+ u
" ("_ns
+ diffWidthStr
+
963 u
", "_ns
+ diffHeightStr
+ u
")"_ns
);
965 RefPtr
<Document
> document
= GetDocument();
966 textInfo
= document
->CreateTextNode(info
);
968 NS_WARNING("Document::CreateTextNode() failed");
969 return NS_ERROR_FAILURE
;
971 mResizingInfo
->AppendChild(*textInfo
, error
);
972 if (error
.Failed()) {
973 NS_WARNING("nsINode::AppendChild() failed");
974 return error
.StealNSResult();
978 mResizingInfo
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_class
, true);
979 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
980 "Element::UnsetAttr(nsGkAtoms::_class) failed");
984 nsresult
HTMLEditor::SetShadowPosition(Element
& aShadowElement
,
985 Element
& aElement
, int32_t aElementX
,
987 MOZ_ASSERT(&aShadowElement
== mResizingShadow
||
988 &aShadowElement
== mPositioningShadow
);
989 RefPtr
<Element
> handlingShadowElement
= &aShadowElement
== mResizingShadow
990 ? mResizingShadow
.get()
991 : mPositioningShadow
.get();
993 if (nsStyledElement
* styledShadowElement
=
994 nsStyledElement::FromNode(&aShadowElement
)) {
995 // MOZ_KnownLive(*styledShadowElement): It's aShadowElement whose lifetime
996 // must be guaranteed by caller because of MOZ_CAN_RUN_SCRIPT method.
997 nsresult rv
= SetAnonymousElementPositionWithoutTransaction(
998 MOZ_KnownLive(*styledShadowElement
), aElementX
, aElementY
);
1001 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() "
1007 if (!HTMLEditUtils::IsImage(&aElement
)) {
1011 nsAutoString imageSource
;
1012 aElement
.GetAttr(nsGkAtoms::src
, imageSource
);
1013 nsresult rv
= aShadowElement
.SetAttr(kNameSpaceID_None
, nsGkAtoms::src
,
1015 if (NS_WARN_IF(Destroyed())) {
1016 return NS_ERROR_EDITOR_DESTROYED
;
1018 if (NS_FAILED(rv
)) {
1019 NS_WARNING("Element::SetAttr(nsGkAtoms::src) failed");
1020 return NS_ERROR_FAILURE
;
1022 return NS_WARN_IF(&aShadowElement
!= handlingShadowElement
) ? NS_ERROR_FAILURE
1026 int32_t HTMLEditor::GetNewResizingIncrement(int32_t aX
, int32_t aY
,
1027 ResizeAt aResizeAt
) const {
1029 if (!mPreserveRatio
) {
1030 switch (aResizeAt
) {
1032 case ResizeAt::eWidth
:
1033 result
= aX
- mOriginalX
;
1036 case ResizeAt::eHeight
:
1037 result
= aY
- mOriginalY
;
1040 MOZ_ASSERT_UNREACHABLE("Invalid resizing request");
1045 int32_t xi
= (aX
- mOriginalX
) * mWidthIncrementFactor
;
1046 int32_t yi
= (aY
- mOriginalY
) * mHeightIncrementFactor
;
1047 float objectSizeRatio
=
1048 ((float)mResizedObjectWidth
) / ((float)mResizedObjectHeight
);
1049 result
= (xi
> yi
) ? xi
: yi
;
1050 switch (aResizeAt
) {
1052 case ResizeAt::eWidth
:
1053 if (result
== yi
) result
= (int32_t)(((float)result
) * objectSizeRatio
);
1054 result
= (int32_t)(((float)result
) * mWidthIncrementFactor
);
1057 case ResizeAt::eHeight
:
1058 if (result
== xi
) result
= (int32_t)(((float)result
) / objectSizeRatio
);
1059 result
= (int32_t)(((float)result
) * mHeightIncrementFactor
);
1065 int32_t HTMLEditor::GetNewResizingX(int32_t aX
, int32_t aY
) {
1068 GetNewResizingIncrement(aX
, aY
, ResizeAt::eX
) * mXIncrementFactor
;
1069 int32_t max
= mResizedObjectX
+ mResizedObjectWidth
;
1070 return std::min(resized
, max
);
1073 int32_t HTMLEditor::GetNewResizingY(int32_t aX
, int32_t aY
) {
1076 GetNewResizingIncrement(aX
, aY
, ResizeAt::eY
) * mYIncrementFactor
;
1077 int32_t max
= mResizedObjectY
+ mResizedObjectHeight
;
1078 return std::min(resized
, max
);
1081 int32_t HTMLEditor::GetNewResizingWidth(int32_t aX
, int32_t aY
) {
1083 mResizedObjectWidth
+
1084 GetNewResizingIncrement(aX
, aY
, ResizeAt::eWidth
) * mWidthIncrementFactor
;
1085 return std::max(resized
, 1);
1088 int32_t HTMLEditor::GetNewResizingHeight(int32_t aX
, int32_t aY
) {
1089 int32_t resized
= mResizedObjectHeight
+
1090 GetNewResizingIncrement(aX
, aY
, ResizeAt::eHeight
) *
1091 mHeightIncrementFactor
;
1092 return std::max(resized
, 1);
1095 nsresult
HTMLEditor::UpdateResizerOrGrabberPositionTo(
1096 const CSSIntPoint
& aClientPoint
) {
1098 AutoEditActionDataSetter
editActionData(*this,
1099 EditAction::eResizingElement
);
1100 if (NS_WARN_IF(!editActionData
.CanHandle())) {
1101 return NS_ERROR_NOT_INITIALIZED
;
1104 // we are resizing and the mouse pointer's position has changed
1105 // we have to resdisplay the shadow
1106 const int32_t newX
= GetNewResizingX(aClientPoint
.x
, aClientPoint
.y
);
1107 const int32_t newY
= GetNewResizingY(aClientPoint
.x
, aClientPoint
.y
);
1108 const int32_t newWidth
=
1109 GetNewResizingWidth(aClientPoint
.x
, aClientPoint
.y
);
1110 const int32_t newHeight
=
1111 GetNewResizingHeight(aClientPoint
.x
, aClientPoint
.y
);
1113 if (RefPtr
<nsStyledElement
> resizingShadowStyledElement
=
1114 nsStyledElement::FromNodeOrNull(mResizingShadow
.get())) {
1116 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1117 *resizingShadowStyledElement
, *nsGkAtoms::left
, newX
);
1118 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1120 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left)"
1121 " destroyed the editor");
1122 return NS_ERROR_EDITOR_DESTROYED
;
1124 NS_WARNING_ASSERTION(
1126 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
1127 "failed, but ignored");
1128 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1129 *resizingShadowStyledElement
, *nsGkAtoms::top
, newY
);
1130 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1132 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top)"
1133 " destroyed the editor");
1134 return NS_ERROR_EDITOR_DESTROYED
;
1136 NS_WARNING_ASSERTION(
1138 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1139 "failed, but ignored");
1140 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1141 *resizingShadowStyledElement
, *nsGkAtoms::width
, newWidth
);
1142 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1144 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1145 "width) destroyed the editor");
1146 return NS_ERROR_EDITOR_DESTROYED
;
1148 NS_WARNING_ASSERTION(
1150 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::width) "
1151 "failed, but ignored");
1152 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1153 *resizingShadowStyledElement
, *nsGkAtoms::height
, newHeight
);
1154 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1156 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1157 "height) destroyed the editor");
1158 return NS_ERROR_EDITOR_DESTROYED
;
1160 NS_WARNING_ASSERTION(
1162 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::height)"
1163 " failed, but ignored");
1166 nsresult rv
= SetResizingInfoPosition(newX
, newY
, newWidth
, newHeight
);
1167 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
),
1168 "HTMLEditor::SetResizingInfoPosition() failed");
1172 AutoEditActionDataSetter
editActionData(*this, EditAction::eMovingElement
);
1173 if (NS_WARN_IF(!editActionData
.CanHandle())) {
1174 return NS_ERROR_NOT_INITIALIZED
;
1177 if (mGrabberClicked
) {
1178 int32_t xThreshold
=
1179 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX
, 1);
1180 int32_t yThreshold
=
1181 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY
, 1);
1183 if (DeprecatedAbs(aClientPoint
.x
- mOriginalX
) * 2 >= xThreshold
||
1184 DeprecatedAbs(aClientPoint
.y
- mOriginalY
) * 2 >= yThreshold
) {
1185 mGrabberClicked
= false;
1186 DebugOnly
<nsresult
> rvIgnored
= StartMoving();
1187 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored
),
1188 "HTMLEditor::StartMoving() failed, but ignored");
1192 int32_t newX
= mPositionedObjectX
+ aClientPoint
.x
- mOriginalX
;
1193 int32_t newY
= mPositionedObjectY
+ aClientPoint
.y
- mOriginalY
;
1195 // Maybe align newX and newY to the grid.
1196 SnapToGrid(newX
, newY
);
1198 if (RefPtr
<nsStyledElement
> positioningShadowStyledElement
=
1199 nsStyledElement::FromNodeOrNull(mPositioningShadow
.get())) {
1201 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1202 *positioningShadowStyledElement
, *nsGkAtoms::left
, newX
);
1203 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1205 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left)"
1206 " destroyed the editor");
1207 return NS_ERROR_EDITOR_DESTROYED
;
1209 NS_WARNING_ASSERTION(
1211 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
1212 "failed, but ignored");
1213 rv
= CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1214 *positioningShadowStyledElement
, *nsGkAtoms::top
, newY
);
1215 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1217 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1218 "destroyed the editor");
1219 return NS_ERROR_EDITOR_DESTROYED
;
1221 NS_WARNING_ASSERTION(
1223 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1224 "failed, but ignored");
1230 nsresult
HTMLEditor::SetFinalSizeWithTransaction(int32_t aX
, int32_t aY
) {
1231 if (!mResizedObject
) {
1236 if (mActivatedHandle
) {
1237 DebugOnly
<nsresult
> rvIgnored
= mActivatedHandle
->UnsetAttr(
1238 kNameSpaceID_None
, nsGkAtoms::_moz_activated
, true);
1239 NS_WARNING_ASSERTION(
1240 NS_SUCCEEDED(rvIgnored
),
1241 "Element::UnsetAttr(nsGkAtoms::_moz_activated) failed, but ignored");
1242 mActivatedHandle
= nullptr;
1245 // we have now to set the new width and height of the resized object
1246 // we don't set the x and y position because we don't control that in
1247 // a normal HTML layout
1248 int32_t left
= GetNewResizingX(aX
, aY
);
1249 int32_t top
= GetNewResizingY(aX
, aY
);
1250 int32_t width
= GetNewResizingWidth(aX
, aY
);
1251 int32_t height
= GetNewResizingHeight(aX
, aY
);
1253 !mResizedObjectIsAbsolutelyPositioned
|| (width
!= mResizedObjectWidth
);
1255 !mResizedObjectIsAbsolutelyPositioned
|| (height
!= mResizedObjectHeight
);
1258 x
= left
- ((mResizedObjectIsAbsolutelyPositioned
)
1259 ? mResizedObjectBorderLeft
+ mResizedObjectMarginLeft
1261 y
= top
- ((mResizedObjectIsAbsolutelyPositioned
)
1262 ? mResizedObjectBorderTop
+ mResizedObjectMarginTop
1265 // we want one transaction only from a user's point of view
1266 AutoPlaceholderBatch
treatAsOneTransaction(
1267 *this, ScrollSelectionIntoView::Yes
, __FUNCTION__
);
1268 RefPtr
<Element
> resizedElement(mResizedObject
);
1269 RefPtr
<nsStyledElement
> resizedStyleElement
=
1270 nsStyledElement::FromNodeOrNull(mResizedObject
);
1272 if (mResizedObjectIsAbsolutelyPositioned
&& resizedStyleElement
) {
1274 nsresult rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1275 *this, *resizedStyleElement
, *nsGkAtoms::top
, y
);
1276 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1278 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1279 "top) destoyed the editor");
1280 return NS_ERROR_EDITOR_DESTROYED
;
1282 NS_WARNING_ASSERTION(
1284 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1285 "failed, but ignored");
1288 nsresult rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1289 *this, *resizedStyleElement
, *nsGkAtoms::left
, x
);
1290 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1292 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1293 "left) destoyed the editor");
1294 return NS_ERROR_EDITOR_DESTROYED
;
1296 NS_WARNING_ASSERTION(
1298 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
1299 "failed, but ignored");
1302 if (IsCSSEnabled() || mResizedObjectIsAbsolutelyPositioned
) {
1303 if (setWidth
&& resizedElement
->HasAttr(nsGkAtoms::width
)) {
1305 RemoveAttributeWithTransaction(*resizedElement
, *nsGkAtoms::width
);
1306 if (MOZ_UNLIKELY(rv
== NS_ERROR_EDITOR_DESTROYED
)) {
1308 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::width) "
1310 return NS_ERROR_EDITOR_DESTROYED
;
1312 NS_WARNING_ASSERTION(
1314 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::width) "
1315 "failed, but ignored");
1318 if (setHeight
&& resizedElement
->HasAttr(nsGkAtoms::height
)) {
1320 RemoveAttributeWithTransaction(*resizedElement
, *nsGkAtoms::height
);
1321 if (MOZ_UNLIKELY(rv
== NS_ERROR_EDITOR_DESTROYED
)) {
1323 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::height) "
1325 return NS_ERROR_EDITOR_DESTROYED
;
1327 NS_WARNING_ASSERTION(
1329 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::height) "
1330 "failed, but ignored");
1333 if (resizedStyleElement
) {
1335 nsresult rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1336 *this, *resizedStyleElement
, *nsGkAtoms::width
, width
);
1337 if (NS_FAILED(rv
)) {
1339 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1340 "width) destoyed the editor");
1341 return NS_ERROR_EDITOR_DESTROYED
;
1343 NS_WARNING_ASSERTION(
1345 "CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::width) "
1346 "failed, but ignored");
1349 nsresult rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1350 *this, *resizedStyleElement
, *nsGkAtoms::height
, height
);
1351 if (NS_FAILED(rv
)) {
1353 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1354 "height) destoyed the editor");
1355 return NS_ERROR_EDITOR_DESTROYED
;
1357 NS_WARNING_ASSERTION(
1359 "CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::height) "
1360 "failed, but ignored");
1364 // we use HTML size and remove all equivalent CSS properties
1366 // we set the CSS width and height to remove it later,
1367 // triggering an immediate reflow; otherwise, we have problems
1368 // with asynchronous reflow
1369 if (resizedStyleElement
) {
1371 nsresult rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1372 *this, *resizedStyleElement
, *nsGkAtoms::width
, width
);
1373 if (NS_FAILED(rv
)) {
1375 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1376 "width) destoyed the editor");
1377 return NS_ERROR_EDITOR_DESTROYED
;
1379 NS_WARNING_ASSERTION(
1381 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1382 "width) failed, but ignored");
1385 nsresult rv
= CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1386 *this, *resizedStyleElement
, *nsGkAtoms::height
, height
);
1387 if (NS_FAILED(rv
)) {
1389 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1390 "height) destoyed the editor");
1391 return NS_ERROR_EDITOR_DESTROYED
;
1393 NS_WARNING_ASSERTION(
1395 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1396 "height) failed, but ignored");
1402 DebugOnly
<nsresult
> rvIgnored
=
1403 SetAttributeWithTransaction(*resizedElement
, *nsGkAtoms::width
, w
);
1404 if (NS_WARN_IF(Destroyed())) {
1405 return NS_ERROR_EDITOR_DESTROYED
;
1407 NS_WARNING_ASSERTION(
1408 NS_SUCCEEDED(rvIgnored
),
1409 "EditorBase::SetAttributeWithTransaction(nsGkAtoms::width) "
1410 "failed, but ignored");
1414 h
.AppendInt(height
);
1415 DebugOnly
<nsresult
> rvIgnored
=
1416 SetAttributeWithTransaction(*resizedElement
, *nsGkAtoms::height
, h
);
1417 if (NS_WARN_IF(Destroyed())) {
1418 return NS_ERROR_EDITOR_DESTROYED
;
1420 NS_WARNING_ASSERTION(
1421 NS_SUCCEEDED(rvIgnored
),
1422 "EditorBase::SetAttributeWithTransaction(nsGkAtoms::height) "
1423 "failed, but ignored");
1426 if (resizedStyleElement
) {
1428 nsresult rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
1429 *this, *resizedStyleElement
, *nsGkAtoms::width
, u
""_ns
);
1430 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1432 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width)"
1433 " destroyed the editor");
1434 return NS_ERROR_EDITOR_DESTROYED
;
1436 NS_WARNING_ASSERTION(
1438 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
1439 "failed, but ignored");
1442 nsresult rv
= CSSEditUtils::RemoveCSSPropertyWithTransaction(
1443 *this, *resizedStyleElement
, *nsGkAtoms::height
, u
""_ns
);
1444 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1446 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::"
1447 "height) destroyed the editor");
1448 return NS_ERROR_EDITOR_DESTROYED
;
1450 NS_WARNING_ASSERTION(
1452 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::height) "
1453 "failed, but ignored");
1458 // keep track of that size
1459 mResizedObjectWidth
= width
;
1460 mResizedObjectHeight
= height
;
1462 nsresult rv
= RefreshResizersInternal();
1463 if (rv
== NS_ERROR_EDITOR_DESTROYED
) {
1464 return NS_ERROR_EDITOR_DESTROYED
;
1466 NS_WARNING_ASSERTION(
1468 "HTMLEditor::RefreshResizersInternal() failed, but ignored");
1472 NS_IMETHODIMP
HTMLEditor::GetObjectResizingEnabled(
1473 bool* aIsObjectResizingEnabled
) {
1474 *aIsObjectResizingEnabled
= IsObjectResizerEnabled();
1478 NS_IMETHODIMP
HTMLEditor::SetObjectResizingEnabled(
1479 bool aObjectResizingEnabled
) {
1480 EnableObjectResizer(aObjectResizingEnabled
);
1493 } // namespace mozilla