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