Bug 1874684 - Part 17: Fix uninitialised variable warnings from clang-tidy. r=allstarschh
[gecko.git] / editor / libeditor / HTMLEditorObjectResizer.cpp
blob8a11c8487c1c865f354983663e8d3646385b98c6
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/. */
6 #include "ErrorList.h"
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"
25 #include "nsCOMPtr.h"
26 #include "nsDebug.h"
27 #include "nsError.h"
28 #include "nsGkAtoms.h"
29 #include "nsAtom.h"
30 #include "nsIContent.h"
31 #include "nsID.h"
32 #include "mozilla/dom/Document.h"
33 #include "nsISupportsUtils.h"
34 #include "nsPIDOMWindow.h"
35 #include "nsReadableUtils.h"
36 #include "nsString.h"
37 #include "nsStringFwd.h"
38 #include "nsStyledElement.h"
39 #include "nsTextNode.h"
40 #include "nscore.h"
41 #include <algorithm>
43 #define kTopLeft u"nw"_ns
44 #define kTop u"n"_ns
45 #define kTopRight u"ne"_ns
46 #define kLeft u"w"_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
52 namespace mozilla {
54 using namespace dom;
56 /******************************************************************************
57 * mozilla::HTMLEditor
58 ******************************************************************************/
60 ManualNACPtr HTMLEditor::CreateResizer(int16_t aLocation,
61 nsIContent& aParentContent) {
62 ManualNACPtr resizer = CreateAnonymousElement(nsGkAtoms::span, aParentContent,
63 u"mozResizer"_ns, false);
64 if (!resizer) {
65 NS_WARNING(
66 "HTMLEditor::CreateAnonymousElement(nsGkAtoms::span, mozResizer) "
67 "failed");
68 return nullptr;
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);
74 NS_WARNING_ASSERTION(
75 NS_SUCCEEDED(rvIgnored),
76 "EventTarget::AddEventListener(mousedown) failed, but ignored");
78 nsAutoString locationStr;
79 switch (aLocation) {
80 case nsIHTMLObjectResizer::eTopLeft:
81 locationStr = kTopLeft;
82 break;
83 case nsIHTMLObjectResizer::eTop:
84 locationStr = kTop;
85 break;
86 case nsIHTMLObjectResizer::eTopRight:
87 locationStr = kTopRight;
88 break;
90 case nsIHTMLObjectResizer::eLeft:
91 locationStr = kLeft;
92 break;
93 case nsIHTMLObjectResizer::eRight:
94 locationStr = kRight;
95 break;
97 case nsIHTMLObjectResizer::eBottomLeft:
98 locationStr = kBottomLeft;
99 break;
100 case nsIHTMLObjectResizer::eBottom:
101 locationStr = kBottom;
102 break;
103 case nsIHTMLObjectResizer::eBottomRight:
104 locationStr = kBottomRight;
105 break;
108 if (NS_FAILED(resizer->SetAttr(kNameSpaceID_None, nsGkAtoms::anonlocation,
109 locationStr, true))) {
110 NS_WARNING("Element::SetAttr(nsGkAtoms::anonlocation) failed");
111 return nullptr;
113 return resizer;
116 ManualNACPtr HTMLEditor::CreateShadow(nsIContent& aParentContent,
117 Element& aOriginalObject) {
118 // let's create an image through the element factory
119 RefPtr<nsAtom> name;
120 if (HTMLEditUtils::IsImage(&aOriginalObject)) {
121 name = nsGkAtoms::img;
122 } else {
123 name = nsGkAtoms::span;
126 return CreateAnonymousElement(name, aParentContent, u"mozResizingShadow"_ns,
127 true);
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;
146 nsAutoString value;
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) {
194 return NS_OK;
196 nsresult rv = SetAnonymousElementPositionWithoutTransaction(
197 *handleStyledElement, aNewX, aNewY);
198 if (NS_FAILED(rv)) {
199 NS_WARNING(
200 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() "
201 "failed");
202 return rv;
204 return NS_WARN_IF(handleStyledElement != aHandleElement.get())
205 ? NS_ERROR_FAILURE
206 : NS_OK;
208 nsresult rv;
209 rv = setHandlePosition(mTopLeftHandle, x - rw, y - rh);
210 if (NS_FAILED(rv)) {
211 NS_WARNING("Failed to set top-left handle position");
212 return rv;
214 rv = setHandlePosition(mTopHandle, x + w / 2 - rw, y - rh);
215 if (NS_FAILED(rv)) {
216 NS_WARNING("Failed to set top handle position");
217 return rv;
219 rv = setHandlePosition(mTopRightHandle, x + w - rw - 1, y - rh);
220 if (NS_FAILED(rv)) {
221 NS_WARNING("Failed to set top-right handle position");
222 return rv;
225 rv = setHandlePosition(mLeftHandle, x - rw, y + h / 2 - rh);
226 if (NS_FAILED(rv)) {
227 NS_WARNING("Failed to set left handle position");
228 return rv;
230 rv = setHandlePosition(mRightHandle, x + w - rw - 1, y + h / 2 - rh);
231 if (NS_FAILED(rv)) {
232 NS_WARNING("Failed to set right handle position");
233 return rv;
236 rv = setHandlePosition(mBottomLeftHandle, x - rw, y + h - rh - 1);
237 if (NS_FAILED(rv)) {
238 NS_WARNING("Failed to set bottom-left handle position");
239 return rv;
241 rv = setHandlePosition(mBottomHandle, x + w / 2 - rw, y + h - rh - 1);
242 if (NS_FAILED(rv)) {
243 NS_WARNING("Failed to set bottom handle position");
244 return rv;
246 rv = setHandlePosition(mBottomRightHandle, x + w - rw - 1, y + h - rh - 1);
247 if (NS_FAILED(rv)) {
248 NS_WARNING("Failed to set bottom-right handle position");
249 return rv;
252 return NS_OK;
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) {
274 return NS_OK;
277 OwningNonNull<Element> resizedObject = *mResizedObject;
278 nsresult rv = GetPositionAndDimensions(
279 resizedObject, mResizedObjectX, mResizedObjectY, mResizedObjectWidth,
280 mResizedObjectHeight, mResizedObjectBorderLeft, mResizedObjectBorderTop,
281 mResizedObjectMarginLeft, mResizedObjectMarginTop);
282 if (NS_FAILED(rv)) {
283 NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
284 return rv;
286 if (NS_WARN_IF(resizedObject != mResizedObject)) {
287 return NS_ERROR_FAILURE;
290 rv = SetAllResizersPosition();
291 if (NS_FAILED(rv)) {
292 NS_WARNING("HTMLEditor::SetAllResizersPosition() failed");
293 return rv;
295 if (NS_WARN_IF(resizedObject != mResizedObject)) {
296 return NS_ERROR_FAILURE;
299 MOZ_ASSERT(
300 mResizingShadow,
301 "SetAllResizersPosition() should return error if resizers are hidden");
302 RefPtr<Element> resizingShadow = mResizingShadow.get();
303 rv = SetShadowPosition(*resizingShadow, resizedObject, mResizedObjectX,
304 mResizedObjectY);
305 if (NS_FAILED(rv)) {
306 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
307 return rv;
309 if (NS_WARN_IF(resizedObject != mResizedObject)) {
310 return NS_ERROR_FAILURE;
312 return NS_OK;
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
318 // returns error.
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.
336 do {
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
347 // check too.
348 // If resizers are just shown again for same element, we hit the former
349 // check.
350 ManualNACPtr newResizer =
351 CreateResizer(nsIHTMLObjectResizer::eTopLeft, *parentContent);
352 if (!newResizer) {
353 NS_WARNING("HTMLEditor::CreateResizer(eTopLeft) failed");
354 break;
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
359 // we're creating.
360 return NS_ERROR_FAILURE;
362 mTopLeftHandle = std::move(newResizer);
363 newResizer = CreateResizer(nsIHTMLObjectResizer::eTop, *parentContent);
364 if (!newResizer) {
365 NS_WARNING("HTMLEditor::CreateResizer(eTop) failed");
366 break;
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);
374 if (!newResizer) {
375 NS_WARNING("HTMLEditor::CreateResizer(eTopRight) failed");
376 break;
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);
385 if (!newResizer) {
386 NS_WARNING("HTMLEditor::CreateResizer(eLeft) failed");
387 break;
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);
395 if (!newResizer) {
396 NS_WARNING("HTMLEditor::CreateResizer(eRight) failed");
397 break;
399 if (NS_WARN_IF(mRightHandle) ||
400 NS_WARN_IF(mResizedObject != &aResizedElement)) {
401 return NS_ERROR_FAILURE;
403 mRightHandle = std::move(newResizer);
405 newResizer =
406 CreateResizer(nsIHTMLObjectResizer::eBottomLeft, *parentContent);
407 if (!newResizer) {
408 NS_WARNING("HTMLEditor::CreateResizer(eBottomLeft) failed");
409 break;
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);
417 if (!newResizer) {
418 NS_WARNING("HTMLEditor::CreateResizer(eBottom) failed");
419 break;
421 if (NS_WARN_IF(mBottomHandle) ||
422 NS_WARN_IF(mResizedObject != &aResizedElement)) {
423 return NS_ERROR_FAILURE;
425 mBottomHandle = std::move(newResizer);
426 newResizer =
427 CreateResizer(nsIHTMLObjectResizer::eBottomRight, *parentContent);
428 if (!newResizer) {
429 NS_WARNING("HTMLEditor::CreateResizer(eBottomRight) failed");
430 break;
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);
447 if (NS_FAILED(rv)) {
448 NS_WARNING("HTMLEditor::GetPositionAndDimensions() failed");
449 break;
452 // and let's set their absolute positions in the document
453 rv = SetAllResizersPosition();
454 if (NS_FAILED(rv)) {
455 NS_WARNING("HTMLEditor::SetAllResizersPosition() failed");
456 if (NS_WARN_IF(mBottomRightHandle.get() != createdBottomRightHandle)) {
457 return NS_ERROR_FAILURE;
459 break;
462 // now, let's create the resizing shadow
463 ManualNACPtr newShadow = CreateShadow(*parentContent, aResizedElement);
464 if (!newShadow) {
465 NS_WARNING("HTMLEditor::CreateShadow() failed");
466 break;
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,
477 mResizedObjectY);
478 if (NS_FAILED(rv)) {
479 NS_WARNING("HTMLEditor::SetShadowPosition() failed");
480 if (NS_WARN_IF(mBottomRightHandle.get() != createdBottomRightHandle)) {
481 return NS_ERROR_FAILURE;
483 break;
486 // and then the resizing info tooltip
487 ManualNACPtr newResizingInfo = CreateResizingInfo(*parentContent);
488 if (!newResizingInfo) {
489 NS_WARNING("HTMLEditor::CreateResizingInfo() failed");
490 break;
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)) {
501 break;
504 rv = static_cast<HTMLEditorEventListener*>(mEventListener.get())
505 ->ListenToWindowResizeEvent(true);
506 if (NS_FAILED(rv)) {
507 NS_WARNING(
508 "HTMLEditorEventListener::ListenToWindowResizeEvent(true) failed");
509 break;
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");
521 return NS_OK;
522 } while (true);
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) {
547 return NS_OK;
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
555 // UnbindFromTree.
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) {
624 return NS_OK;
627 nsresult rv = static_cast<HTMLEditorEventListener*>(mEventListener.get())
628 ->ListenToMouseMoveEventForResizers(false);
629 if (NS_FAILED(rv)) {
630 NS_WARNING(
631 "HTMLEditorEventListener::ListenToMouseMoveEventForResizers(false) "
632 "failed");
633 return rv;
636 // Remove resize event listener from the window.
637 if (!mEventListener) {
638 return NS_OK;
641 rv = static_cast<HTMLEditorEventListener*>(mEventListener.get())
642 ->ListenToWindowResizeEvent(false);
643 NS_WARNING_ASSERTION(
644 NS_SUCCEEDED(rv),
645 "HTMLEditorEventListener::ListenToWindowResizeEvent(false) failed");
646 return rv;
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");
657 if (mResizingInfo) {
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) {
667 mIsResizing = true;
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
682 // the handle
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
704 rvIgnored =
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");
712 // position it
713 if (RefPtr<nsStyledElement> resizingShadowStyledElement =
714 nsStyledElement::FromNodeOrNull(mResizingShadow.get())) {
715 nsresult rv;
716 rv = CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
717 *resizingShadowStyledElement, *nsGkAtoms::width, mResizedObjectWidth);
718 if (rv == NS_ERROR_EDITOR_DESTROYED) {
719 NS_WARNING(
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) {
730 NS_WARNING(
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");
749 return rv;
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);
796 return NS_OK;
799 nsresult HTMLEditor::StopDraggingResizerOrGrabberAt(
800 const CSSIntPoint& aClientPoint) {
801 if (mIsResizing) {
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
809 mIsResizing = false;
810 HideShadowAndInfo();
812 nsresult rv = editActionData.MaybeDispatchBeforeInputEvent();
813 if (NS_FAILED(rv)) {
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) {
822 NS_WARNING(
823 "HTMLEditor::SetFinalSizeWithTransaction() destroyed the editor");
824 return NS_ERROR_EDITOR_DESTROYED;
826 NS_WARNING_ASSERTION(
827 NS_SUCCEEDED(rv),
828 "HTMLEditor::SetFinalSizeWithTransaction() failed, but ignored");
829 return NS_OK;
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);
840 if (mIsMoving) {
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);
858 return NS_OK;
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,
871 int32_t aH) {
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) {
882 infoXPosition = aX;
883 } else if (mActivatedHandle == mTopHandle ||
884 mActivatedHandle == mBottomHandle) {
885 infoXPosition = aX + (aW / 2);
886 } else {
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) {
894 infoYPosition = aY;
895 } else if (mActivatedHandle == mLeftHandle ||
896 mActivatedHandle == mRightHandle) {
897 infoYPosition = aY + (aH / 2);
898 } else {
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())) {
908 nsresult rv;
909 rv = CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
910 *resizingInfoStyledElement, *nsGkAtoms::left,
911 infoXPosition + mouseCursorOffset);
912 if (rv == NS_ERROR_EDITOR_DESTROYED) {
913 NS_WARNING(
914 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
915 "destroyed the editor");
916 return NS_ERROR_EDITOR_DESTROYED;
918 NS_WARNING_ASSERTION(
919 NS_SUCCEEDED(rv),
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) {
926 NS_WARNING(
927 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
928 "destroyed the editor");
929 return NS_ERROR_EDITOR_DESTROYED;
931 NS_WARNING_ASSERTION(
932 NS_SUCCEEDED(rv),
933 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
934 "failed, but ignored");
937 nsCOMPtr<nsIContent> textInfo = mResizingInfo->GetFirstChild();
938 ErrorResult error;
939 if (textInfo) {
940 mResizingInfo->RemoveChild(*textInfo, error);
941 if (error.Failed()) {
942 NS_WARNING("nsINode::RemoveChild() failed");
943 return error.StealNSResult();
945 textInfo = nullptr;
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;
953 if (diffWidth > 0) {
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);
967 if (!textInfo) {
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();
977 nsresult rv =
978 mResizingInfo->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class, true);
979 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
980 "Element::UnsetAttr(nsGkAtoms::_class) failed");
981 return rv;
984 nsresult HTMLEditor::SetShadowPosition(Element& aShadowElement,
985 Element& aElement, int32_t aElementX,
986 int32_t aElementY) {
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);
999 if (NS_FAILED(rv)) {
1000 NS_WARNING(
1001 "HTMLEditor::SetAnonymousElementPositionWithoutTransaction() "
1002 "failed");
1003 return rv;
1007 if (!HTMLEditUtils::IsImage(&aElement)) {
1008 return NS_OK;
1011 nsAutoString imageSource;
1012 aElement.GetAttr(nsGkAtoms::src, imageSource);
1013 nsresult rv = aShadowElement.SetAttr(kNameSpaceID_None, nsGkAtoms::src,
1014 imageSource, true);
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
1023 : NS_OK;
1026 int32_t HTMLEditor::GetNewResizingIncrement(int32_t aX, int32_t aY,
1027 ResizeAt aResizeAt) const {
1028 int32_t result = 0;
1029 if (!mPreserveRatio) {
1030 switch (aResizeAt) {
1031 case ResizeAt::eX:
1032 case ResizeAt::eWidth:
1033 result = aX - mOriginalX;
1034 break;
1035 case ResizeAt::eY:
1036 case ResizeAt::eHeight:
1037 result = aY - mOriginalY;
1038 break;
1039 default:
1040 MOZ_ASSERT_UNREACHABLE("Invalid resizing request");
1042 return result;
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) {
1051 case ResizeAt::eX:
1052 case ResizeAt::eWidth:
1053 if (result == yi) result = (int32_t)(((float)result) * objectSizeRatio);
1054 result = (int32_t)(((float)result) * mWidthIncrementFactor);
1055 break;
1056 case ResizeAt::eY:
1057 case ResizeAt::eHeight:
1058 if (result == xi) result = (int32_t)(((float)result) / objectSizeRatio);
1059 result = (int32_t)(((float)result) * mHeightIncrementFactor);
1060 break;
1062 return result;
1065 int32_t HTMLEditor::GetNewResizingX(int32_t aX, int32_t aY) {
1066 int32_t resized =
1067 mResizedObjectX +
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) {
1074 int32_t resized =
1075 mResizedObjectY +
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) {
1082 int32_t resized =
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) {
1097 if (mIsResizing) {
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())) {
1115 nsresult rv;
1116 rv = CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1117 *resizingShadowStyledElement, *nsGkAtoms::left, newX);
1118 if (rv == NS_ERROR_EDITOR_DESTROYED) {
1119 NS_WARNING(
1120 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left)"
1121 " destroyed the editor");
1122 return NS_ERROR_EDITOR_DESTROYED;
1124 NS_WARNING_ASSERTION(
1125 NS_SUCCEEDED(rv),
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) {
1131 NS_WARNING(
1132 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top)"
1133 " destroyed the editor");
1134 return NS_ERROR_EDITOR_DESTROYED;
1136 NS_WARNING_ASSERTION(
1137 NS_SUCCEEDED(rv),
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) {
1143 NS_WARNING(
1144 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1145 "width) destroyed the editor");
1146 return NS_ERROR_EDITOR_DESTROYED;
1148 NS_WARNING_ASSERTION(
1149 NS_SUCCEEDED(rv),
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) {
1155 NS_WARNING(
1156 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1157 "height) destroyed the editor");
1158 return NS_ERROR_EDITOR_DESTROYED;
1160 NS_WARNING_ASSERTION(
1161 NS_SUCCEEDED(rv),
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");
1169 return rv;
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");
1191 if (mIsMoving) {
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())) {
1200 nsresult rv;
1201 rv = CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(
1202 *positioningShadowStyledElement, *nsGkAtoms::left, newX);
1203 if (rv == NS_ERROR_EDITOR_DESTROYED) {
1204 NS_WARNING(
1205 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left)"
1206 " destroyed the editor");
1207 return NS_ERROR_EDITOR_DESTROYED;
1209 NS_WARNING_ASSERTION(
1210 NS_SUCCEEDED(rv),
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) {
1216 NS_WARNING(
1217 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1218 "destroyed the editor");
1219 return NS_ERROR_EDITOR_DESTROYED;
1221 NS_WARNING_ASSERTION(
1222 NS_SUCCEEDED(rv),
1223 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1224 "failed, but ignored");
1227 return NS_OK;
1230 nsresult HTMLEditor::SetFinalSizeWithTransaction(int32_t aX, int32_t aY) {
1231 if (!mResizedObject) {
1232 // paranoia
1233 return NS_OK;
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);
1252 bool setWidth =
1253 !mResizedObjectIsAbsolutelyPositioned || (width != mResizedObjectWidth);
1254 bool setHeight =
1255 !mResizedObjectIsAbsolutelyPositioned || (height != mResizedObjectHeight);
1257 int32_t x, y;
1258 x = left - ((mResizedObjectIsAbsolutelyPositioned)
1259 ? mResizedObjectBorderLeft + mResizedObjectMarginLeft
1260 : 0);
1261 y = top - ((mResizedObjectIsAbsolutelyPositioned)
1262 ? mResizedObjectBorderTop + mResizedObjectMarginTop
1263 : 0);
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) {
1273 if (setHeight) {
1274 nsresult rv = CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1275 *this, *resizedStyleElement, *nsGkAtoms::top, y);
1276 if (rv == NS_ERROR_EDITOR_DESTROYED) {
1277 NS_WARNING(
1278 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1279 "top) destoyed the editor");
1280 return NS_ERROR_EDITOR_DESTROYED;
1282 NS_WARNING_ASSERTION(
1283 NS_SUCCEEDED(rv),
1284 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::top) "
1285 "failed, but ignored");
1287 if (setWidth) {
1288 nsresult rv = CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1289 *this, *resizedStyleElement, *nsGkAtoms::left, x);
1290 if (rv == NS_ERROR_EDITOR_DESTROYED) {
1291 NS_WARNING(
1292 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1293 "left) destoyed the editor");
1294 return NS_ERROR_EDITOR_DESTROYED;
1296 NS_WARNING_ASSERTION(
1297 NS_SUCCEEDED(rv),
1298 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::left) "
1299 "failed, but ignored");
1302 if (IsCSSEnabled() || mResizedObjectIsAbsolutelyPositioned) {
1303 if (setWidth && resizedElement->HasAttr(nsGkAtoms::width)) {
1304 nsresult rv =
1305 RemoveAttributeWithTransaction(*resizedElement, *nsGkAtoms::width);
1306 if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
1307 NS_WARNING(
1308 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::width) "
1309 "failed");
1310 return NS_ERROR_EDITOR_DESTROYED;
1312 NS_WARNING_ASSERTION(
1313 NS_SUCCEEDED(rv),
1314 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::width) "
1315 "failed, but ignored");
1318 if (setHeight && resizedElement->HasAttr(nsGkAtoms::height)) {
1319 nsresult rv =
1320 RemoveAttributeWithTransaction(*resizedElement, *nsGkAtoms::height);
1321 if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
1322 NS_WARNING(
1323 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::height) "
1324 "failed");
1325 return NS_ERROR_EDITOR_DESTROYED;
1327 NS_WARNING_ASSERTION(
1328 NS_SUCCEEDED(rv),
1329 "EditorBase::RemoveAttributeWithTransaction(nsGkAtoms::height) "
1330 "failed, but ignored");
1333 if (resizedStyleElement) {
1334 if (setWidth) {
1335 nsresult rv = CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1336 *this, *resizedStyleElement, *nsGkAtoms::width, width);
1337 if (NS_FAILED(rv)) {
1338 NS_WARNING(
1339 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1340 "width) destoyed the editor");
1341 return NS_ERROR_EDITOR_DESTROYED;
1343 NS_WARNING_ASSERTION(
1344 NS_SUCCEEDED(rv),
1345 "CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::width) "
1346 "failed, but ignored");
1348 if (setHeight) {
1349 nsresult rv = CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1350 *this, *resizedStyleElement, *nsGkAtoms::height, height);
1351 if (NS_FAILED(rv)) {
1352 NS_WARNING(
1353 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1354 "height) destoyed the editor");
1355 return NS_ERROR_EDITOR_DESTROYED;
1357 NS_WARNING_ASSERTION(
1358 NS_SUCCEEDED(rv),
1359 "CSSEditUtils::SetCSSPropertyPixels(nsGkAtoms::height) "
1360 "failed, but ignored");
1363 } else {
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) {
1370 if (setWidth) {
1371 nsresult rv = CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1372 *this, *resizedStyleElement, *nsGkAtoms::width, width);
1373 if (NS_FAILED(rv)) {
1374 NS_WARNING(
1375 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1376 "width) destoyed the editor");
1377 return NS_ERROR_EDITOR_DESTROYED;
1379 NS_WARNING_ASSERTION(
1380 NS_SUCCEEDED(rv),
1381 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1382 "width) failed, but ignored");
1384 if (setHeight) {
1385 nsresult rv = CSSEditUtils::SetCSSPropertyPixelsWithTransaction(
1386 *this, *resizedStyleElement, *nsGkAtoms::height, height);
1387 if (NS_FAILED(rv)) {
1388 NS_WARNING(
1389 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1390 "height) destoyed the editor");
1391 return NS_ERROR_EDITOR_DESTROYED;
1393 NS_WARNING_ASSERTION(
1394 NS_SUCCEEDED(rv),
1395 "CSSEditUtils::SetCSSPropertyPixelsWithTransaction(nsGkAtoms::"
1396 "height) failed, but ignored");
1399 if (setWidth) {
1400 nsAutoString w;
1401 w.AppendInt(width);
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");
1412 if (setHeight) {
1413 nsAutoString h;
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) {
1427 if (setWidth) {
1428 nsresult rv = CSSEditUtils::RemoveCSSPropertyWithTransaction(
1429 *this, *resizedStyleElement, *nsGkAtoms::width, u""_ns);
1430 if (rv == NS_ERROR_EDITOR_DESTROYED) {
1431 NS_WARNING(
1432 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width)"
1433 " destroyed the editor");
1434 return NS_ERROR_EDITOR_DESTROYED;
1436 NS_WARNING_ASSERTION(
1437 NS_SUCCEEDED(rv),
1438 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::width) "
1439 "failed, but ignored");
1441 if (setHeight) {
1442 nsresult rv = CSSEditUtils::RemoveCSSPropertyWithTransaction(
1443 *this, *resizedStyleElement, *nsGkAtoms::height, u""_ns);
1444 if (rv == NS_ERROR_EDITOR_DESTROYED) {
1445 NS_WARNING(
1446 "CSSEditUtils::RemoveCSSPropertyWithTransaction(nsGkAtoms::"
1447 "height) destroyed the editor");
1448 return NS_ERROR_EDITOR_DESTROYED;
1450 NS_WARNING_ASSERTION(
1451 NS_SUCCEEDED(rv),
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(
1467 NS_SUCCEEDED(rv),
1468 "HTMLEditor::RefreshResizersInternal() failed, but ignored");
1469 return NS_OK;
1472 NS_IMETHODIMP HTMLEditor::GetObjectResizingEnabled(
1473 bool* aIsObjectResizingEnabled) {
1474 *aIsObjectResizingEnabled = IsObjectResizerEnabled();
1475 return NS_OK;
1478 NS_IMETHODIMP HTMLEditor::SetObjectResizingEnabled(
1479 bool aObjectResizingEnabled) {
1480 EnableObjectResizer(aObjectResizingEnabled);
1481 return NS_OK;
1484 #undef kTopLeft
1485 #undef kTop
1486 #undef kTopRight
1487 #undef kLeft
1488 #undef kRight
1489 #undef kBottomLeft
1490 #undef kBottom
1491 #undef kBottomRight
1493 } // namespace mozilla