1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "HTMLEditor.h"
6 
7 #include "HTMLEditUtils.h"
8 #include "mozilla/Attributes.h"
9 #include "mozilla/PresShell.h"
10 #include "mozilla/PresShellInlines.h"
11 #include "mozilla/dom/BindContext.h"
12 #include "mozilla/dom/Element.h"
13 #include "mozilla/dom/EventTarget.h"
14 #include "mozilla/mozalloc.h"
15 #include "nsAString.h"
16 #include "nsCOMPtr.h"
17 #include "nsComputedDOMStyle.h"
18 #include "nsDebug.h"
19 #include "nsError.h"
20 #include "nsGenericHTMLElement.h"
21 #include "nsGkAtoms.h"
22 #include "nsAtom.h"
23 #include "nsIContent.h"
24 #include "nsID.h"
25 #include "mozilla/dom/Document.h"
26 #include "nsIDocumentObserver.h"
27 #include "nsStubMutationObserver.h"
28 #include "nsINode.h"
29 #include "nsISupportsImpl.h"
30 #include "nsISupportsUtils.h"
31 #include "nsLiteralString.h"
32 #include "nsPresContext.h"
33 #include "nsReadableUtils.h"
34 #include "nsString.h"
35 #include "nsStringFwd.h"
36 #include "nsStyledElement.h"
37 #include "nsUnicharUtils.h"
38 #include "nscore.h"
39 #include "nsContentUtils.h"  // for nsAutoScriptBlocker
40 #include "nsROCSSPrimitiveValue.h"
41 
42 class nsIDOMEventListener;
43 
44 namespace mozilla {
45 
46 using namespace dom;
47 
48 // Retrieve the rounded number of CSS pixels from a computed CSS property.
49 //
50 // Note that this should only be called for properties whose resolved value
51 // is CSS pixels (like width, height, left, top, right, bottom, margin, padding,
52 // border-*-width, ...).
53 //
54 // See: https://drafts.csswg.org/cssom/#resolved-values
GetCSSFloatValue(nsComputedDOMStyle * aComputedStyle,const nsACString & aProperty)55 static int32_t GetCSSFloatValue(nsComputedDOMStyle* aComputedStyle,
56                                 const nsACString& aProperty) {
57   MOZ_ASSERT(aComputedStyle);
58 
59   // get the computed CSSValue of the property
60   nsAutoCString value;
61   nsresult rv = aComputedStyle->GetPropertyValue(aProperty, value);
62   if (NS_FAILED(rv)) {
63     NS_WARNING("nsComputedDOMStyle::GetPropertyValue() failed");
64     return 0;
65   }
66 
67   // We only care about resolved values, not a big deal if the element is
68   // undisplayed, for example, and the value is "auto" or what not.
69   int32_t val = value.ToInteger(&rv);
70   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "nsAString::ToInteger() failed");
71   return NS_SUCCEEDED(rv) ? val : 0;
72 }
73 
74 class ElementDeletionObserver final : public nsStubMutationObserver {
75  public:
ElementDeletionObserver(nsIContent * aNativeAnonNode,Element * aObservedElement)76   ElementDeletionObserver(nsIContent* aNativeAnonNode,
77                           Element* aObservedElement)
78       : mNativeAnonNode(aNativeAnonNode), mObservedElement(aObservedElement) {}
79 
80   NS_DECL_ISUPPORTS
81   NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
82   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
83 
84  protected:
85   ~ElementDeletionObserver() = default;
86   nsIContent* mNativeAnonNode;
87   Element* mObservedElement;
88 };
89 
NS_IMPL_ISUPPORTS(ElementDeletionObserver,nsIMutationObserver)90 NS_IMPL_ISUPPORTS(ElementDeletionObserver, nsIMutationObserver)
91 
92 void ElementDeletionObserver::ParentChainChanged(nsIContent* aContent) {
93   // If the native anonymous content has been unbound already in
94   // DeleteRefToAnonymousNode, mNativeAnonNode's parentNode is null.
95   if (aContent != mObservedElement || !mNativeAnonNode ||
96       mNativeAnonNode->GetParent() != aContent) {
97     return;
98   }
99 
100   ManualNACPtr::RemoveContentFromNACArray(mNativeAnonNode);
101 
102   mObservedElement->RemoveMutationObserver(this);
103   mObservedElement = nullptr;
104   mNativeAnonNode->RemoveMutationObserver(this);
105   mNativeAnonNode = nullptr;
106   NS_RELEASE_THIS();
107 }
108 
NodeWillBeDestroyed(const nsINode * aNode)109 void ElementDeletionObserver::NodeWillBeDestroyed(const nsINode* aNode) {
110   NS_ASSERTION(aNode == mNativeAnonNode || aNode == mObservedElement,
111                "Wrong aNode!");
112   if (aNode == mNativeAnonNode) {
113     mObservedElement->RemoveMutationObserver(this);
114     mObservedElement = nullptr;
115   } else {
116     mNativeAnonNode->RemoveMutationObserver(this);
117     mNativeAnonNode->UnbindFromTree();
118     mNativeAnonNode = nullptr;
119   }
120 
121   NS_RELEASE_THIS();
122 }
123 
CreateAnonymousElement(nsAtom * aTag,nsIContent & aParentContent,const nsAString & aAnonClass,bool aIsCreatedHidden)124 ManualNACPtr HTMLEditor::CreateAnonymousElement(nsAtom* aTag,
125                                                 nsIContent& aParentContent,
126                                                 const nsAString& aAnonClass,
127                                                 bool aIsCreatedHidden) {
128   // Don't put anonymous editor element into non-HTML element.
129   // It is mainly for avoiding other anonymous element being inserted
130   // into <svg:use>, but in general we probably don't want to insert
131   // some random HTML anonymous element into a non-HTML element.
132   if (!aParentContent.IsHTMLElement()) {
133     return nullptr;
134   }
135 
136   if (NS_WARN_IF(!GetDocument())) {
137     return nullptr;
138   }
139 
140   RefPtr<PresShell> presShell = GetPresShell();
141   if (NS_WARN_IF(!presShell)) {
142     return nullptr;
143   }
144 
145   // Create a new node through the element factory
146   RefPtr<Element> newElement = CreateHTMLContent(aTag);
147   if (!newElement) {
148     NS_WARNING("EditorBase::CreateHTMLContent() failed");
149     return nullptr;
150   }
151 
152   // add the "hidden" class if needed
153   if (aIsCreatedHidden) {
154     nsresult rv = newElement->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
155                                       u"hidden"_ns, true);
156     if (NS_FAILED(rv)) {
157       NS_WARNING("Element::SetAttr(nsGkAtoms::_class, hidden) failed");
158       return nullptr;
159     }
160   }
161 
162   // add an _moz_anonclass attribute if needed
163   if (!aAnonClass.IsEmpty()) {
164     nsresult rv = newElement->SetAttr(
165         kNameSpaceID_None, nsGkAtoms::_moz_anonclass, aAnonClass, true);
166     if (NS_FAILED(rv)) {
167       NS_WARNING("Element::SetAttr(nsGkAtoms::_moz_anonclass) failed");
168       return nullptr;
169     }
170   }
171 
172   {
173     nsAutoScriptBlocker scriptBlocker;
174 
175     // establish parenthood of the element
176     newElement->SetIsNativeAnonymousRoot();
177     BindContext context(*aParentContent.AsElement(),
178                         BindContext::ForNativeAnonymous);
179     nsresult rv = newElement->BindToTree(context, aParentContent);
180     if (NS_FAILED(rv)) {
181       NS_WARNING("Element::BindToTree(BindContext::ForNativeAnonymous) failed");
182       newElement->UnbindFromTree();
183       return nullptr;
184     }
185   }
186 
187   ManualNACPtr newNativeAnonymousContent(newElement.forget());
188 
189   // Must style the new element, otherwise the PostRecreateFramesFor call
190   // below will do nothing.
191   ServoStyleSet* styleSet = presShell->StyleSet();
192   // Sometimes editor likes to append anonymous content to elements
193   // in display:none subtrees, so avoid styling in those cases.
194   if (ServoStyleSet::MayTraverseFrom(newNativeAnonymousContent)) {
195     styleSet->StyleNewSubtree(newNativeAnonymousContent);
196   }
197 
198   auto* observer = new ElementDeletionObserver(newNativeAnonymousContent,
199                                                aParentContent.AsElement());
200   NS_ADDREF(observer);  // NodeWillBeDestroyed releases.
201   aParentContent.AddMutationObserver(observer);
202   newNativeAnonymousContent->AddMutationObserver(observer);
203 
204 #ifdef DEBUG
205   // Editor anonymous content gets passed to PostRecreateFramesFor... which
206   // can't _really_ deal with anonymous content (because it can't get the frame
207   // tree ordering right).  But for us the ordering doesn't matter so this is
208   // sort of ok.
209   newNativeAnonymousContent->SetProperty(nsGkAtoms::restylableAnonymousNode,
210                                          reinterpret_cast<void*>(true));
211 #endif  // DEBUG
212 
213   // display the element
214   presShell->PostRecreateFramesFor(newNativeAnonymousContent);
215 
216   return newNativeAnonymousContent;
217 }
218 
219 // Removes event listener and calls DeleteRefToAnonymousNode.
RemoveListenerAndDeleteRef(const nsAString & aEvent,nsIDOMEventListener * aListener,bool aUseCapture,ManualNACPtr aElement,PresShell * aPresShell)220 void HTMLEditor::RemoveListenerAndDeleteRef(const nsAString& aEvent,
221                                             nsIDOMEventListener* aListener,
222                                             bool aUseCapture,
223                                             ManualNACPtr aElement,
224                                             PresShell* aPresShell) {
225   if (aElement) {
226     aElement->RemoveEventListener(aEvent, aListener, aUseCapture);
227   }
228   DeleteRefToAnonymousNode(std::move(aElement), aPresShell);
229 }
230 
231 // Deletes all references to an anonymous element
DeleteRefToAnonymousNode(ManualNACPtr aContent,PresShell * aPresShell)232 void HTMLEditor::DeleteRefToAnonymousNode(ManualNACPtr aContent,
233                                           PresShell* aPresShell) {
234   // call ContentRemoved() for the anonymous content
235   // node so its references get removed from the frame manager's
236   // undisplay map, and its layout frames get destroyed!
237 
238   if (NS_WARN_IF(!aContent)) {
239     return;
240   }
241 
242   if (NS_WARN_IF(!aContent->GetParent())) {
243     // aContent was already removed?
244     return;
245   }
246 
247   nsAutoScriptBlocker scriptBlocker;
248   // Need to check whether aPresShell has been destroyed (but not yet deleted).
249   // See bug 338129.
250   if (aContent->IsInComposedDoc() && aPresShell &&
251       !aPresShell->IsDestroying()) {
252     MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree());
253     MOZ_ASSERT(!aContent->GetPreviousSibling(), "NAC has no siblings");
254 
255     // FIXME(emilio): This is the only caller to PresShell::ContentRemoved that
256     // passes NAC into it. This is not great!
257     aPresShell->ContentRemoved(aContent, nullptr);
258   }
259 
260   // The ManualNACPtr destructor will invoke UnbindFromTree.
261 }
262 
HideAnonymousEditingUIs()263 void HTMLEditor::HideAnonymousEditingUIs() {
264   if (mAbsolutelyPositionedObject) {
265     HideGrabberInternal();
266     NS_ASSERTION(!mAbsolutelyPositionedObject,
267                  "HTMLEditor::HideGrabberInternal() failed, but ignored");
268   }
269   if (mInlineEditedCell) {
270     HideInlineTableEditingUIInternal();
271     NS_ASSERTION(
272         !mInlineEditedCell,
273         "HTMLEditor::HideInlineTableEditingUIInternal() failed, but ignored");
274   }
275   if (mResizedObject) {
276     DebugOnly<nsresult> rvIgnored = HideResizersInternal();
277     NS_WARNING_ASSERTION(
278         NS_SUCCEEDED(rvIgnored),
279         "HTMLEditor::HideResizersInternal() failed, but ignored");
280     NS_ASSERTION(!mResizedObject,
281                  "HTMLEditor::HideResizersInternal() failed, but ignored");
282   }
283 }
284 
HideAnonymousEditingUIsIfUnnecessary()285 void HTMLEditor::HideAnonymousEditingUIsIfUnnecessary() {
286   // XXX Perhaps, this is wrong approach to hide multiple UIs because
287   //     hiding one UI may causes overwriting existing UI with newly
288   //     created one.  In such case, we will leak ovewritten UI.
289   if (!IsAbsolutePositionEditorEnabled() && mAbsolutelyPositionedObject) {
290     // XXX If we're moving something, we need to cancel or commit the
291     //     operation now.
292     HideGrabberInternal();
293     NS_ASSERTION(!mAbsolutelyPositionedObject,
294                  "HTMLEditor::HideGrabberInternal() failed, but ignored");
295   }
296   if (!IsInlineTableEditorEnabled() && mInlineEditedCell) {
297     // XXX If we're resizing a table element, we need to cancel or commit the
298     //     operation now.
299     HideInlineTableEditingUIInternal();
300     NS_ASSERTION(
301         !mInlineEditedCell,
302         "HTMLEditor::HideInlineTableEditingUIInternal() failed, but ignored");
303   }
304   if (!IsObjectResizerEnabled() && mResizedObject) {
305     // XXX If we're resizing something, we need to cancel or commit the
306     //     operation now.
307     DebugOnly<nsresult> rvIgnored = HideResizersInternal();
308     NS_WARNING_ASSERTION(
309         NS_SUCCEEDED(rvIgnored),
310         "HTMLEditor::HideResizersInternal() failed, but ignored");
311     NS_ASSERTION(!mResizedObject,
312                  "HTMLEditor::HideResizersInternal() failed, but ignored");
313   }
314 }
315 
CheckSelectionStateForAnonymousButtons()316 NS_IMETHODIMP HTMLEditor::CheckSelectionStateForAnonymousButtons() {
317   AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
318   if (NS_WARN_IF(!editActionData.CanHandle())) {
319     return NS_ERROR_NOT_INITIALIZED;
320   }
321 
322   nsresult rv = RefreshEditingUI();
323   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
324                        "HTMLEditor::RefereshEditingUI() failed");
325   return EditorBase::ToGenericNSResult(rv);
326 }
327 
RefreshEditingUI()328 nsresult HTMLEditor::RefreshEditingUI() {
329   MOZ_ASSERT(IsEditActionDataAvailable());
330 
331   // First, we need to remove unnecessary editing UI now since some of them
332   // may be disabled while them are visible.
333   HideAnonymousEditingUIsIfUnnecessary();
334 
335   // early way out if all contextual UI extensions are disabled
336   if (!IsObjectResizerEnabled() && !IsAbsolutePositionEditorEnabled() &&
337       !IsInlineTableEditorEnabled()) {
338     return NS_OK;
339   }
340 
341   // Don't change selection state if we're moving.
342   if (mIsMoving) {
343     return NS_OK;
344   }
345 
346   // let's get the containing element of the selection
347   RefPtr<Element> selectionContainerElement = GetSelectionContainerElement();
348   if (NS_WARN_IF(!selectionContainerElement)) {
349     return NS_OK;
350   }
351 
352   // If we're not in a document, don't try to add resizers
353   if (!selectionContainerElement->IsInUncomposedDoc()) {
354     return NS_OK;
355   }
356 
357   // what's its tag?
358   RefPtr<Element> focusElement = std::move(selectionContainerElement);
359   nsAtom* focusTagAtom = focusElement->NodeInfo()->NameAtom();
360 
361   RefPtr<Element> absPosElement;
362   if (IsAbsolutePositionEditorEnabled()) {
363     // Absolute Positioning support is enabled, is the selection contained
364     // in an absolutely positioned element ?
365     absPosElement = GetAbsolutelyPositionedSelectionContainer();
366     if (NS_WARN_IF(Destroyed())) {
367       return NS_ERROR_EDITOR_DESTROYED;
368     }
369   }
370 
371   RefPtr<Element> cellElement;
372   if (IsObjectResizerEnabled() || IsInlineTableEditorEnabled()) {
373     // Resizing or Inline Table Editing is enabled, we need to check if the
374     // selection is contained in a table cell
375     cellElement = GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
376   }
377 
378   if (IsObjectResizerEnabled() && cellElement) {
379     // we are here because Resizing is enabled AND selection is contained in
380     // a cell
381 
382     // get the enclosing table
383     if (nsGkAtoms::img != focusTagAtom) {
384       // the element container of the selection is not an image, so we'll show
385       // the resizers around the table
386       // XXX There may be a bug.  cellElement may be not in <table> in invalid
387       //     tree.  So, perhaps, GetClosestAncestorTableElement() returns
388       //     nullptr, we should not set focusTagAtom to nsGkAtoms::table.
389       focusElement =
390           HTMLEditUtils::GetClosestAncestorTableElement(*cellElement);
391       focusTagAtom = nsGkAtoms::table;
392     }
393   }
394 
395   // we allow resizers only around images, tables, and absolutely positioned
396   // elements. If we don't have image/table, let's look at the latter case.
397   if (nsGkAtoms::img != focusTagAtom && nsGkAtoms::table != focusTagAtom) {
398     focusElement = absPosElement;
399   }
400 
401   // at this point, focusElement  contains the element for Resizing,
402   //                cellElement   contains the element for InlineTableEditing
403   //                absPosElement contains the element for Positioning
404 
405   // Note: All the Hide/Show methods below may change attributes on real
406   // content which means a DOMAttrModified handler may cause arbitrary
407   // side effects while this code runs (bug 420439).
408 
409   if (IsAbsolutePositionEditorEnabled() && mAbsolutelyPositionedObject &&
410       absPosElement != mAbsolutelyPositionedObject) {
411     HideGrabberInternal();
412     NS_ASSERTION(!mAbsolutelyPositionedObject,
413                  "HTMLEditor::HideGrabberInternal() failed, but ignored");
414   }
415 
416   if (IsObjectResizerEnabled() && mResizedObject &&
417       mResizedObject != focusElement) {
418     // Perhaps, even if HideResizersInternal() failed, we should try to hide
419     // inline table editing UI.  However, it returns error only when we cannot
420     // do anything.  So, it's okay for now.
421     nsresult rv = HideResizersInternal();
422     if (NS_FAILED(rv)) {
423       NS_WARNING("HTMLEditor::HideResizersInternal() failed");
424       return rv;
425     }
426     NS_ASSERTION(!mResizedObject,
427                  "HTMLEditor::HideResizersInternal() failed, but ignored");
428   }
429 
430   if (IsInlineTableEditorEnabled() && mInlineEditedCell &&
431       mInlineEditedCell != cellElement) {
432     HideInlineTableEditingUIInternal();
433     NS_ASSERTION(
434         !mInlineEditedCell,
435         "HTMLEditor::HideInlineTableEditingUIInternal failed, but ignored");
436   }
437 
438   // now, let's display all contextual UI for good
439   nsIContent* hostContent = GetActiveEditingHost();
440 
441   if (IsObjectResizerEnabled() && focusElement &&
442       HTMLEditUtils::IsSimplyEditableNode(*focusElement) &&
443       focusElement != hostContent) {
444     if (nsGkAtoms::img == focusTagAtom) {
445       mResizedObjectIsAnImage = true;
446     }
447     if (mResizedObject) {
448       nsresult rv = RefreshResizersInternal();
449       if (NS_FAILED(rv)) {
450         NS_WARNING("HTMLEditor::RefreshResizersInternal() failed");
451         return rv;
452       }
453     } else {
454       nsresult rv = ShowResizersInternal(*focusElement);
455       if (NS_FAILED(rv)) {
456         NS_WARNING("HTMLEditor::ShowResizersInternal() failed");
457         return rv;
458       }
459     }
460   }
461 
462   if (IsAbsolutePositionEditorEnabled() && absPosElement &&
463       HTMLEditUtils::IsSimplyEditableNode(*absPosElement) &&
464       absPosElement != hostContent) {
465     if (mAbsolutelyPositionedObject) {
466       nsresult rv = RefreshGrabberInternal();
467       if (NS_FAILED(rv)) {
468         NS_WARNING("HTMLEditor::RefreshGrabberInternal() failed");
469         return rv;
470       }
471     } else {
472       nsresult rv = ShowGrabberInternal(*absPosElement);
473       if (NS_FAILED(rv)) {
474         NS_WARNING("HTMLEditor::ShowGrabberInternal() failed");
475         return rv;
476       }
477     }
478   }
479 
480   // XXX Shouldn't we check whether the `<table>` element is editable or not?
481   if (IsInlineTableEditorEnabled() && cellElement &&
482       HTMLEditUtils::IsSimplyEditableNode(*cellElement) &&
483       cellElement != hostContent) {
484     if (mInlineEditedCell) {
485       nsresult rv = RefreshInlineTableEditingUIInternal();
486       if (NS_FAILED(rv)) {
487         NS_WARNING("HTMLEditor::RefreshInlineTableEditingUIInternal() failed");
488         return rv;
489       }
490     } else {
491       nsresult rv = ShowInlineTableEditingUIInternal(*cellElement);
492       if (NS_FAILED(rv)) {
493         NS_WARNING("HTMLEditor::ShowInlineTableEditingUIInternal() failed");
494         return rv;
495       }
496     }
497   }
498 
499   return NS_OK;
500 }
501 
502 // Resizing and Absolute Positioning need to know everything about the
503 // containing box of the element: position, size, margins, borders
GetPositionAndDimensions(Element & aElement,int32_t & aX,int32_t & aY,int32_t & aW,int32_t & aH,int32_t & aBorderLeft,int32_t & aBorderTop,int32_t & aMarginLeft,int32_t & aMarginTop)504 nsresult HTMLEditor::GetPositionAndDimensions(Element& aElement, int32_t& aX,
505                                               int32_t& aY, int32_t& aW,
506                                               int32_t& aH, int32_t& aBorderLeft,
507                                               int32_t& aBorderTop,
508                                               int32_t& aMarginLeft,
509                                               int32_t& aMarginTop) {
510   // Is the element positioned ? let's check the cheap way first...
511   bool isPositioned =
512       aElement.HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_abspos);
513   if (!isPositioned) {
514     // hmmm... the expensive way now...
515     nsAutoString positionValue;
516     DebugOnly<nsresult> rvIgnored = CSSEditUtils::GetComputedProperty(
517         aElement, *nsGkAtoms::position, positionValue);
518     if (NS_WARN_IF(Destroyed())) {
519       return NS_ERROR_EDITOR_DESTROYED;
520     }
521     NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
522                          "CSSEditUtils::GetComputedProperty(nsGkAtoms::"
523                          "position) failed, but ignored");
524     isPositioned = positionValue.EqualsLiteral("absolute");
525   }
526 
527   if (isPositioned) {
528     // Yes, it is absolutely positioned
529     mResizedObjectIsAbsolutelyPositioned = true;
530 
531     // Get the all the computed css styles attached to the element node
532     RefPtr<nsComputedDOMStyle> computedDOMStyle =
533         CSSEditUtils::GetComputedStyle(&aElement);
534     if (NS_WARN_IF(!computedDOMStyle)) {
535       return NS_ERROR_FAILURE;
536     }
537 
538     aBorderLeft = GetCSSFloatValue(computedDOMStyle, "border-left-width"_ns);
539     aBorderTop = GetCSSFloatValue(computedDOMStyle, "border-top-width"_ns);
540     aMarginLeft = GetCSSFloatValue(computedDOMStyle, "margin-left"_ns);
541     aMarginTop = GetCSSFloatValue(computedDOMStyle, "margin-top"_ns);
542 
543     aX = GetCSSFloatValue(computedDOMStyle, "left"_ns) + aMarginLeft +
544          aBorderLeft;
545     aY = GetCSSFloatValue(computedDOMStyle, "top"_ns) + aMarginTop + aBorderTop;
546     aW = GetCSSFloatValue(computedDOMStyle, "width"_ns);
547     aH = GetCSSFloatValue(computedDOMStyle, "height"_ns);
548   } else {
549     mResizedObjectIsAbsolutelyPositioned = false;
550     RefPtr<nsGenericHTMLElement> htmlElement =
551         nsGenericHTMLElement::FromNode(aElement);
552     if (!htmlElement) {
553       return NS_ERROR_NULL_POINTER;
554     }
555     DebugOnly<nsresult> rvIgnored = GetElementOrigin(aElement, aX, aY);
556     NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
557                          "HTMLEditor::GetElementOrigin() failed, but ignored");
558 
559     aW = htmlElement->OffsetWidth();
560     aH = htmlElement->OffsetHeight();
561 
562     aBorderLeft = 0;
563     aBorderTop = 0;
564     aMarginLeft = 0;
565     aMarginTop = 0;
566   }
567   return NS_OK;
568 }
569 
SetAnonymousElementPositionWithoutTransaction(nsStyledElement & aStyledElement,int32_t aX,int32_t aY)570 nsresult HTMLEditor::SetAnonymousElementPositionWithoutTransaction(
571     nsStyledElement& aStyledElement, int32_t aX, int32_t aY) {
572   nsresult rv;
573   rv = mCSSEditUtils->SetCSSPropertyPixelsWithoutTransaction(
574       aStyledElement, *nsGkAtoms::left, aX);
575   if (rv == NS_ERROR_EDITOR_DESTROYED) {
576     NS_WARNING(
577         "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(nsGkAtoms::left) "
578         "destroyed the editor");
579     return NS_ERROR_EDITOR_DESTROYED;
580   }
581   NS_WARNING_ASSERTION(
582       NS_SUCCEEDED(rv),
583       "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(nsGkAtoms::left) "
584       "failed, but ignored");
585   rv = mCSSEditUtils->SetCSSPropertyPixelsWithoutTransaction(
586       aStyledElement, *nsGkAtoms::top, aY);
587   if (rv == NS_ERROR_EDITOR_DESTROYED) {
588     NS_WARNING(
589         "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(nsGkAtoms::top) "
590         "destroyed the editor");
591     return NS_ERROR_EDITOR_DESTROYED;
592   }
593   NS_WARNING_ASSERTION(
594       NS_SUCCEEDED(rv),
595       "CSSEditUtils::SetCSSPropertyPixelsWithoutTransaction(nsGkAtoms::top) "
596       "failed, but ignored");
597   return NS_OK;
598 }
599 
600 }  // namespace mozilla
601