HTMLAnonymousNodeEditor.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  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. #include "mozilla/HTMLEditor.h"
  5. #include "mozilla/Attributes.h"
  6. #include "mozilla/dom/Element.h"
  7. #include "mozilla/mozalloc.h"
  8. #include "nsAString.h"
  9. #include "nsCOMPtr.h"
  10. #include "nsComputedDOMStyle.h"
  11. #include "nsDebug.h"
  12. #ifdef DEBUG
  13. #include "nsDocument.h"
  14. #endif
  15. #include "nsError.h"
  16. #include "nsGkAtoms.h"
  17. #include "nsIAtom.h"
  18. #include "nsIContent.h"
  19. #include "nsID.h"
  20. #include "nsIDOMCSSPrimitiveValue.h"
  21. #include "nsIDOMCSSStyleDeclaration.h"
  22. #include "nsIDOMCSSValue.h"
  23. #include "nsIDOMElement.h"
  24. #include "nsIDOMEventTarget.h"
  25. #include "nsIDOMHTMLElement.h"
  26. #include "nsIDOMNode.h"
  27. #include "nsIDOMWindow.h"
  28. #include "nsIDocument.h"
  29. #include "nsIDocumentObserver.h"
  30. #include "nsIHTMLAbsPosEditor.h"
  31. #include "nsIHTMLInlineTableEditor.h"
  32. #include "nsIHTMLObjectResizer.h"
  33. #include "nsStubMutationObserver.h"
  34. #include "nsINode.h"
  35. #include "nsIPresShell.h"
  36. #include "nsISupportsImpl.h"
  37. #include "nsISupportsUtils.h"
  38. #include "nsLiteralString.h"
  39. #include "nsPresContext.h"
  40. #include "nsReadableUtils.h"
  41. #include "nsString.h"
  42. #include "nsStringFwd.h"
  43. #include "nsUnicharUtils.h"
  44. #include "nscore.h"
  45. #include "nsContentUtils.h" // for nsAutoScriptBlocker
  46. class nsIDOMEventListener;
  47. class nsISelection;
  48. namespace mozilla {
  49. using namespace dom;
  50. // retrieve an integer stored into a CSS computed float value
  51. static int32_t GetCSSFloatValue(nsIDOMCSSStyleDeclaration * aDecl,
  52. const nsAString & aProperty)
  53. {
  54. MOZ_ASSERT(aDecl);
  55. nsCOMPtr<nsIDOMCSSValue> value;
  56. // get the computed CSSValue of the property
  57. nsresult rv = aDecl->GetPropertyCSSValue(aProperty, getter_AddRefs(value));
  58. if (NS_FAILED(rv) || !value) {
  59. return 0;
  60. }
  61. // check the type of the returned CSSValue; we handle here only
  62. // pixel and enum types
  63. nsCOMPtr<nsIDOMCSSPrimitiveValue> val = do_QueryInterface(value);
  64. uint16_t type;
  65. val->GetPrimitiveType(&type);
  66. float f = 0;
  67. switch (type) {
  68. case nsIDOMCSSPrimitiveValue::CSS_PX:
  69. // the value is in pixels, just get it
  70. rv = val->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_PX, &f);
  71. NS_ENSURE_SUCCESS(rv, 0);
  72. break;
  73. case nsIDOMCSSPrimitiveValue::CSS_IDENT: {
  74. // the value is keyword, we have to map these keywords into
  75. // numeric values
  76. nsAutoString str;
  77. val->GetStringValue(str);
  78. if (str.EqualsLiteral("thin")) {
  79. f = 1;
  80. } else if (str.EqualsLiteral("medium")) {
  81. f = 3;
  82. } else if (str.EqualsLiteral("thick")) {
  83. f = 5;
  84. }
  85. break;
  86. }
  87. }
  88. return (int32_t) f;
  89. }
  90. class ElementDeletionObserver final : public nsStubMutationObserver
  91. {
  92. public:
  93. ElementDeletionObserver(nsIContent* aNativeAnonNode,
  94. nsIContent* aObservedNode)
  95. : mNativeAnonNode(aNativeAnonNode)
  96. , mObservedNode(aObservedNode)
  97. {}
  98. NS_DECL_ISUPPORTS
  99. NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
  100. NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
  101. protected:
  102. ~ElementDeletionObserver() {}
  103. nsIContent* mNativeAnonNode;
  104. nsIContent* mObservedNode;
  105. };
  106. NS_IMPL_ISUPPORTS(ElementDeletionObserver, nsIMutationObserver)
  107. void
  108. ElementDeletionObserver::ParentChainChanged(nsIContent* aContent)
  109. {
  110. // If the native anonymous content has been unbound already in
  111. // DeleteRefToAnonymousNode, mNativeAnonNode's parentNode is null.
  112. if (aContent == mObservedNode && mNativeAnonNode &&
  113. mNativeAnonNode->GetParentNode() == aContent) {
  114. // If the observed node has been moved to another document, there isn't much
  115. // we can do easily. But at least be safe and unbind the native anonymous
  116. // content and stop observing changes.
  117. if (mNativeAnonNode->OwnerDoc() != mObservedNode->OwnerDoc()) {
  118. mObservedNode->RemoveMutationObserver(this);
  119. mObservedNode = nullptr;
  120. mNativeAnonNode->RemoveMutationObserver(this);
  121. mNativeAnonNode->UnbindFromTree();
  122. mNativeAnonNode = nullptr;
  123. NS_RELEASE_THIS();
  124. return;
  125. }
  126. // We're staying in the same document, just rebind the native anonymous
  127. // node so that the subtree root points to the right object etc.
  128. mNativeAnonNode->UnbindFromTree();
  129. mNativeAnonNode->BindToTree(mObservedNode->GetUncomposedDoc(), mObservedNode,
  130. mObservedNode, true);
  131. }
  132. }
  133. void
  134. ElementDeletionObserver::NodeWillBeDestroyed(const nsINode* aNode)
  135. {
  136. NS_ASSERTION(aNode == mNativeAnonNode || aNode == mObservedNode,
  137. "Wrong aNode!");
  138. if (aNode == mNativeAnonNode) {
  139. mObservedNode->RemoveMutationObserver(this);
  140. mObservedNode = nullptr;
  141. } else {
  142. mNativeAnonNode->RemoveMutationObserver(this);
  143. mNativeAnonNode->UnbindFromTree();
  144. mNativeAnonNode = nullptr;
  145. }
  146. NS_RELEASE_THIS();
  147. }
  148. // Returns in *aReturn an anonymous nsDOMElement of type aTag,
  149. // child of aParentNode. If aIsCreatedHidden is true, the class
  150. // "hidden" is added to the created element. If aAnonClass is not
  151. // the empty string, it becomes the value of the attribute "_moz_anonclass"
  152. nsresult
  153. HTMLEditor::CreateAnonymousElement(const nsAString& aTag,
  154. nsIDOMNode* aParentNode,
  155. const nsAString& aAnonClass,
  156. bool aIsCreatedHidden,
  157. nsIDOMElement** aReturn)
  158. {
  159. NS_ENSURE_ARG_POINTER(aParentNode);
  160. NS_ENSURE_ARG_POINTER(aReturn);
  161. *aReturn = nullptr;
  162. nsCOMPtr<nsIContent> parentContent( do_QueryInterface(aParentNode) );
  163. NS_ENSURE_TRUE(parentContent, NS_OK);
  164. nsCOMPtr<nsIDocument> doc = GetDocument();
  165. NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
  166. // Get the pres shell
  167. nsCOMPtr<nsIPresShell> ps = GetPresShell();
  168. NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
  169. // Create a new node through the element factory
  170. nsCOMPtr<nsIAtom> tagAtom = NS_Atomize(aTag);
  171. nsCOMPtr<Element> newContent = CreateHTMLContent(tagAtom);
  172. NS_ENSURE_STATE(newContent);
  173. nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent);
  174. NS_ENSURE_TRUE(newElement, NS_ERROR_FAILURE);
  175. // add the "hidden" class if needed
  176. if (aIsCreatedHidden) {
  177. nsresult rv = newElement->SetAttribute(NS_LITERAL_STRING("class"),
  178. NS_LITERAL_STRING("hidden"));
  179. NS_ENSURE_SUCCESS(rv, rv);
  180. }
  181. // add an _moz_anonclass attribute if needed
  182. if (!aAnonClass.IsEmpty()) {
  183. nsresult rv = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"),
  184. aAnonClass);
  185. NS_ENSURE_SUCCESS(rv, rv);
  186. }
  187. {
  188. nsAutoScriptBlocker scriptBlocker;
  189. // establish parenthood of the element
  190. newContent->SetIsNativeAnonymousRoot();
  191. nsresult rv =
  192. newContent->BindToTree(doc, parentContent, parentContent, true);
  193. if (NS_FAILED(rv)) {
  194. newContent->UnbindFromTree();
  195. return rv;
  196. }
  197. }
  198. ElementDeletionObserver* observer =
  199. new ElementDeletionObserver(newContent, parentContent);
  200. NS_ADDREF(observer); // NodeWillBeDestroyed releases.
  201. parentContent->AddMutationObserver(observer);
  202. newContent->AddMutationObserver(observer);
  203. #ifdef DEBUG
  204. // Editor anonymous content gets passed to RecreateFramesFor... which can't
  205. // _really_ deal with anonymous content (because it can't get the frame tree
  206. // ordering right). But for us the ordering doesn't matter so this is sort of
  207. // ok.
  208. newContent->SetProperty(nsGkAtoms::restylableAnonymousNode,
  209. reinterpret_cast<void*>(true));
  210. #endif // DEBUG
  211. // display the element
  212. ps->RecreateFramesFor(newContent);
  213. newElement.forget(aReturn);
  214. return NS_OK;
  215. }
  216. // Removes event listener and calls DeleteRefToAnonymousNode.
  217. void
  218. HTMLEditor::RemoveListenerAndDeleteRef(const nsAString& aEvent,
  219. nsIDOMEventListener* aListener,
  220. bool aUseCapture,
  221. Element* aElement,
  222. nsIContent* aParentContent,
  223. nsIPresShell* aShell)
  224. {
  225. nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
  226. if (evtTarget) {
  227. evtTarget->RemoveEventListener(aEvent, aListener, aUseCapture);
  228. }
  229. DeleteRefToAnonymousNode(static_cast<nsIDOMElement*>(GetAsDOMNode(aElement)), aParentContent, aShell);
  230. }
  231. // Deletes all references to an anonymous element
  232. void
  233. HTMLEditor::DeleteRefToAnonymousNode(nsIDOMElement* aElement,
  234. nsIContent* aParentContent,
  235. nsIPresShell* aShell)
  236. {
  237. // call ContentRemoved() for the anonymous content
  238. // node so its references get removed from the frame manager's
  239. // undisplay map, and its layout frames get destroyed!
  240. if (aElement) {
  241. nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
  242. if (content) {
  243. nsAutoScriptBlocker scriptBlocker;
  244. // Need to check whether aShell has been destroyed (but not yet deleted).
  245. // In that case presContext->GetPresShell() returns nullptr.
  246. // See bug 338129.
  247. if (content->IsInComposedDoc() && aShell && aShell->GetPresContext() &&
  248. aShell->GetPresContext()->GetPresShell() == aShell) {
  249. nsCOMPtr<nsIDocumentObserver> docObserver = do_QueryInterface(aShell);
  250. if (docObserver) {
  251. // Call BeginUpdate() so that the nsCSSFrameConstructor/PresShell
  252. // knows we're messing with the frame tree.
  253. nsCOMPtr<nsIDocument> document = GetDocument();
  254. if (document) {
  255. docObserver->BeginUpdate(document, UPDATE_CONTENT_MODEL);
  256. }
  257. // XXX This is wrong (bug 439258). Once it's fixed, the NS_WARNING
  258. // in RestyleManager::RestyleForRemove should be changed back
  259. // to an assertion.
  260. docObserver->ContentRemoved(content->GetComposedDoc(),
  261. aParentContent, content, -1,
  262. content->GetPreviousSibling());
  263. if (document) {
  264. docObserver->EndUpdate(document, UPDATE_CONTENT_MODEL);
  265. }
  266. }
  267. }
  268. content->UnbindFromTree();
  269. }
  270. }
  271. }
  272. // The following method is mostly called by a selection listener. When a
  273. // selection change is notified, the method is called to check if resizing
  274. // handles, a grabber and/or inline table editing UI need to be displayed
  275. // or refreshed
  276. NS_IMETHODIMP
  277. HTMLEditor::CheckSelectionStateForAnonymousButtons(nsISelection* aSelection)
  278. {
  279. NS_ENSURE_ARG_POINTER(aSelection);
  280. // early way out if all contextual UI extensions are disabled
  281. NS_ENSURE_TRUE(mIsObjectResizingEnabled ||
  282. mIsAbsolutelyPositioningEnabled ||
  283. mIsInlineTableEditingEnabled, NS_OK);
  284. // Don't change selection state if we're moving.
  285. if (mIsMoving) {
  286. return NS_OK;
  287. }
  288. nsCOMPtr<nsIDOMElement> focusElement;
  289. // let's get the containing element of the selection
  290. nsresult rv = GetSelectionContainer(getter_AddRefs(focusElement));
  291. NS_ENSURE_TRUE(focusElement, NS_OK);
  292. NS_ENSURE_SUCCESS(rv, rv);
  293. // If we're not in a document, don't try to add resizers
  294. nsCOMPtr<dom::Element> focusElementNode = do_QueryInterface(focusElement);
  295. NS_ENSURE_STATE(focusElementNode);
  296. if (!focusElementNode->IsInUncomposedDoc()) {
  297. return NS_OK;
  298. }
  299. // what's its tag?
  300. nsAutoString focusTagName;
  301. rv = focusElement->GetTagName(focusTagName);
  302. NS_ENSURE_SUCCESS(rv, rv);
  303. ToLowerCase(focusTagName);
  304. nsCOMPtr<nsIAtom> focusTagAtom = NS_Atomize(focusTagName);
  305. nsCOMPtr<nsIDOMElement> absPosElement;
  306. if (mIsAbsolutelyPositioningEnabled) {
  307. // Absolute Positioning support is enabled, is the selection contained
  308. // in an absolutely positioned element ?
  309. rv =
  310. GetAbsolutelyPositionedSelectionContainer(getter_AddRefs(absPosElement));
  311. NS_ENSURE_SUCCESS(rv, rv);
  312. }
  313. nsCOMPtr<nsIDOMElement> cellElement;
  314. if (mIsObjectResizingEnabled || mIsInlineTableEditingEnabled) {
  315. // Resizing or Inline Table Editing is enabled, we need to check if the
  316. // selection is contained in a table cell
  317. rv = GetElementOrParentByTagName(NS_LITERAL_STRING("td"),
  318. nullptr,
  319. getter_AddRefs(cellElement));
  320. NS_ENSURE_SUCCESS(rv, rv);
  321. }
  322. if (mIsObjectResizingEnabled && cellElement) {
  323. // we are here because Resizing is enabled AND selection is contained in
  324. // a cell
  325. // get the enclosing table
  326. if (nsGkAtoms::img != focusTagAtom) {
  327. // the element container of the selection is not an image, so we'll show
  328. // the resizers around the table
  329. nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(cellElement);
  330. focusElement = do_QueryInterface(tableNode);
  331. focusTagAtom = nsGkAtoms::table;
  332. }
  333. }
  334. // we allow resizers only around images, tables, and absolutely positioned
  335. // elements. If we don't have image/table, let's look at the latter case.
  336. if (nsGkAtoms::img != focusTagAtom && nsGkAtoms::table != focusTagAtom) {
  337. focusElement = absPosElement;
  338. }
  339. // at this point, focusElement contains the element for Resizing,
  340. // cellElement contains the element for InlineTableEditing
  341. // absPosElement contains the element for Positioning
  342. // Note: All the Hide/Show methods below may change attributes on real
  343. // content which means a DOMAttrModified handler may cause arbitrary
  344. // side effects while this code runs (bug 420439).
  345. if (mIsAbsolutelyPositioningEnabled && mAbsolutelyPositionedObject &&
  346. absPosElement != GetAsDOMNode(mAbsolutelyPositionedObject)) {
  347. rv = HideGrabber();
  348. NS_ENSURE_SUCCESS(rv, rv);
  349. NS_ASSERTION(!mAbsolutelyPositionedObject, "HideGrabber failed");
  350. }
  351. if (mIsObjectResizingEnabled && mResizedObject &&
  352. GetAsDOMNode(mResizedObject) != focusElement) {
  353. rv = HideResizers();
  354. NS_ENSURE_SUCCESS(rv, rv);
  355. NS_ASSERTION(!mResizedObject, "HideResizers failed");
  356. }
  357. if (mIsInlineTableEditingEnabled && mInlineEditedCell &&
  358. mInlineEditedCell != cellElement) {
  359. rv = HideInlineTableEditingUI();
  360. NS_ENSURE_SUCCESS(rv, rv);
  361. NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed");
  362. }
  363. // now, let's display all contextual UI for good
  364. nsIContent* hostContent = GetActiveEditingHost();
  365. nsCOMPtr<nsIDOMNode> hostNode = do_QueryInterface(hostContent);
  366. if (mIsObjectResizingEnabled && focusElement &&
  367. IsModifiableNode(focusElement) && focusElement != hostNode) {
  368. if (nsGkAtoms::img == focusTagAtom) {
  369. mResizedObjectIsAnImage = true;
  370. }
  371. if (mResizedObject) {
  372. nsresult rv = RefreshResizers();
  373. if (NS_WARN_IF(NS_FAILED(rv))) {
  374. return rv;
  375. }
  376. } else {
  377. nsresult rv = ShowResizers(focusElement);
  378. if (NS_WARN_IF(NS_FAILED(rv))) {
  379. return rv;
  380. }
  381. }
  382. }
  383. if (mIsAbsolutelyPositioningEnabled && absPosElement &&
  384. IsModifiableNode(absPosElement) && absPosElement != hostNode) {
  385. if (mAbsolutelyPositionedObject) {
  386. nsresult rv = RefreshGrabber();
  387. if (NS_WARN_IF(NS_FAILED(rv))) {
  388. return rv;
  389. }
  390. } else {
  391. nsresult rv = ShowGrabberOnElement(absPosElement);
  392. if (NS_WARN_IF(NS_FAILED(rv))) {
  393. return rv;
  394. }
  395. }
  396. }
  397. if (mIsInlineTableEditingEnabled && cellElement &&
  398. IsModifiableNode(cellElement) && cellElement != hostNode) {
  399. if (mInlineEditedCell) {
  400. nsresult rv = RefreshInlineTableEditingUI();
  401. if (NS_WARN_IF(NS_FAILED(rv))) {
  402. return rv;
  403. }
  404. } else {
  405. nsresult rv = ShowInlineTableEditingUI(cellElement);
  406. if (NS_WARN_IF(NS_FAILED(rv))) {
  407. return rv;
  408. }
  409. }
  410. }
  411. return NS_OK;
  412. }
  413. // Resizing and Absolute Positioning need to know everything about the
  414. // containing box of the element: position, size, margins, borders
  415. nsresult
  416. HTMLEditor::GetPositionAndDimensions(nsIDOMElement* aElement,
  417. int32_t& aX,
  418. int32_t& aY,
  419. int32_t& aW,
  420. int32_t& aH,
  421. int32_t& aBorderLeft,
  422. int32_t& aBorderTop,
  423. int32_t& aMarginLeft,
  424. int32_t& aMarginTop)
  425. {
  426. nsCOMPtr<Element> element = do_QueryInterface(aElement);
  427. NS_ENSURE_ARG_POINTER(element);
  428. // Is the element positioned ? let's check the cheap way first...
  429. bool isPositioned = false;
  430. nsresult rv =
  431. aElement->HasAttribute(NS_LITERAL_STRING("_moz_abspos"), &isPositioned);
  432. NS_ENSURE_SUCCESS(rv, rv);
  433. if (!isPositioned) {
  434. // hmmm... the expensive way now...
  435. nsAutoString positionStr;
  436. mCSSEditUtils->GetComputedProperty(*element, *nsGkAtoms::position,
  437. positionStr);
  438. isPositioned = positionStr.EqualsLiteral("absolute");
  439. }
  440. if (isPositioned) {
  441. // Yes, it is absolutely positioned
  442. mResizedObjectIsAbsolutelyPositioned = true;
  443. // Get the all the computed css styles attached to the element node
  444. RefPtr<nsComputedDOMStyle> cssDecl =
  445. mCSSEditUtils->GetComputedStyle(element);
  446. NS_ENSURE_STATE(cssDecl);
  447. aBorderLeft = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("border-left-width"));
  448. aBorderTop = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("border-top-width"));
  449. aMarginLeft = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("margin-left"));
  450. aMarginTop = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("margin-top"));
  451. aX = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("left")) +
  452. aMarginLeft + aBorderLeft;
  453. aY = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("top")) +
  454. aMarginTop + aBorderTop;
  455. aW = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("width"));
  456. aH = GetCSSFloatValue(cssDecl, NS_LITERAL_STRING("height"));
  457. } else {
  458. mResizedObjectIsAbsolutelyPositioned = false;
  459. nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aElement);
  460. if (!htmlElement) {
  461. return NS_ERROR_NULL_POINTER;
  462. }
  463. GetElementOrigin(aElement, aX, aY);
  464. if (NS_WARN_IF(NS_FAILED(htmlElement->GetOffsetWidth(&aW))) ||
  465. NS_WARN_IF(NS_FAILED(htmlElement->GetOffsetHeight(&aH)))) {
  466. return rv;
  467. }
  468. aBorderLeft = 0;
  469. aBorderTop = 0;
  470. aMarginLeft = 0;
  471. aMarginTop = 0;
  472. }
  473. return NS_OK;
  474. }
  475. // self-explanatory
  476. void
  477. HTMLEditor::SetAnonymousElementPosition(int32_t aX,
  478. int32_t aY,
  479. nsIDOMElement* aElement)
  480. {
  481. mCSSEditUtils->SetCSSPropertyPixels(aElement, NS_LITERAL_STRING("left"), aX);
  482. mCSSEditUtils->SetCSSPropertyPixels(aElement, NS_LITERAL_STRING("top"), aY);
  483. }
  484. } // namespace mozilla