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