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