editor/libeditor/html/nsHTMLObjectResizer.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/LookAndFeel.h"
michael@0 7 #include "mozilla/MathAlgorithms.h"
michael@0 8 #include "mozilla/Preferences.h"
michael@0 9 #include "mozilla/mozalloc.h"
michael@0 10 #include "nsAString.h"
michael@0 11 #include "nsAlgorithm.h"
michael@0 12 #include "nsAutoPtr.h"
michael@0 13 #include "nsCOMArray.h"
michael@0 14 #include "nsCOMPtr.h"
michael@0 15 #include "nsDebug.h"
michael@0 16 #include "nsEditProperty.h"
michael@0 17 #include "nsEditorUtils.h"
michael@0 18 #include "nsError.h"
michael@0 19 #include "nsHTMLCSSUtils.h"
michael@0 20 #include "nsHTMLEditUtils.h"
michael@0 21 #include "nsHTMLEditor.h"
michael@0 22 #include "nsHTMLObjectResizer.h"
michael@0 23 #include "nsIAtom.h"
michael@0 24 #include "nsIContent.h"
michael@0 25 #include "nsID.h"
michael@0 26 #include "nsIDOMDocument.h"
michael@0 27 #include "nsIDOMElement.h"
michael@0 28 #include "nsIDOMEvent.h"
michael@0 29 #include "nsIDOMEventTarget.h"
michael@0 30 #include "nsIDOMMouseEvent.h"
michael@0 31 #include "nsIDOMNode.h"
michael@0 32 #include "nsIDOMText.h"
michael@0 33 #include "nsIDocument.h"
michael@0 34 #include "nsIEditor.h"
michael@0 35 #include "nsIHTMLEditor.h"
michael@0 36 #include "nsIHTMLObjectResizeListener.h"
michael@0 37 #include "nsIHTMLObjectResizer.h"
michael@0 38 #include "nsIPresShell.h"
michael@0 39 #include "nsISupportsUtils.h"
michael@0 40 #include "nsPIDOMWindow.h"
michael@0 41 #include "nsReadableUtils.h"
michael@0 42 #include "nsString.h"
michael@0 43 #include "nsStringFwd.h"
michael@0 44 #include "nsSubstringTuple.h"
michael@0 45 #include "nscore.h"
michael@0 46 #include <algorithm>
michael@0 47
michael@0 48 class nsISelection;
michael@0 49
michael@0 50 using namespace mozilla;
michael@0 51
michael@0 52 class nsHTMLEditUtils;
michael@0 53
michael@0 54 // ==================================================================
michael@0 55 // DocumentResizeEventListener
michael@0 56 // ==================================================================
michael@0 57 NS_IMPL_ISUPPORTS(DocumentResizeEventListener, nsIDOMEventListener)
michael@0 58
michael@0 59 DocumentResizeEventListener::DocumentResizeEventListener(nsIHTMLEditor * aEditor)
michael@0 60 {
michael@0 61 mEditor = do_GetWeakReference(aEditor);
michael@0 62 }
michael@0 63
michael@0 64 DocumentResizeEventListener::~DocumentResizeEventListener()
michael@0 65 {
michael@0 66 }
michael@0 67
michael@0 68 NS_IMETHODIMP
michael@0 69 DocumentResizeEventListener::HandleEvent(nsIDOMEvent* aMouseEvent)
michael@0 70 {
michael@0 71 nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryReferent(mEditor);
michael@0 72 if (objectResizer)
michael@0 73 return objectResizer->RefreshResizers();
michael@0 74 return NS_OK;
michael@0 75 }
michael@0 76
michael@0 77 // ==================================================================
michael@0 78 // ResizerSelectionListener
michael@0 79 // ==================================================================
michael@0 80
michael@0 81 NS_IMPL_ISUPPORTS(ResizerSelectionListener, nsISelectionListener)
michael@0 82
michael@0 83 ResizerSelectionListener::ResizerSelectionListener(nsIHTMLEditor * aEditor)
michael@0 84 {
michael@0 85 mEditor = do_GetWeakReference(aEditor);
michael@0 86 }
michael@0 87
michael@0 88 ResizerSelectionListener::~ResizerSelectionListener()
michael@0 89 {
michael@0 90 }
michael@0 91
michael@0 92 NS_IMETHODIMP
michael@0 93 ResizerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *aSelection, int16_t aReason)
michael@0 94 {
michael@0 95 if ((aReason & (nsISelectionListener::MOUSEDOWN_REASON |
michael@0 96 nsISelectionListener::KEYPRESS_REASON |
michael@0 97 nsISelectionListener::SELECTALL_REASON)) && aSelection)
michael@0 98 {
michael@0 99 // the selection changed and we need to check if we have to
michael@0 100 // hide and/or redisplay resizing handles
michael@0 101 nsCOMPtr<nsIHTMLEditor> editor = do_QueryReferent(mEditor);
michael@0 102 if (editor)
michael@0 103 editor->CheckSelectionStateForAnonymousButtons(aSelection);
michael@0 104 }
michael@0 105
michael@0 106 return NS_OK;
michael@0 107 }
michael@0 108
michael@0 109 // ==================================================================
michael@0 110 // ResizerMouseMotionListener
michael@0 111 // ==================================================================
michael@0 112
michael@0 113 NS_IMPL_ISUPPORTS(ResizerMouseMotionListener, nsIDOMEventListener)
michael@0 114
michael@0 115 ResizerMouseMotionListener::ResizerMouseMotionListener(nsIHTMLEditor * aEditor)
michael@0 116 {
michael@0 117 mEditor = do_GetWeakReference(aEditor);
michael@0 118 }
michael@0 119
michael@0 120 ResizerMouseMotionListener::~ResizerMouseMotionListener()
michael@0 121 {
michael@0 122 }
michael@0 123
michael@0 124 NS_IMETHODIMP
michael@0 125 ResizerMouseMotionListener::HandleEvent(nsIDOMEvent* aMouseEvent)
michael@0 126 {
michael@0 127 nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
michael@0 128 if (!mouseEvent) {
michael@0 129 //non-ui event passed in. bad things.
michael@0 130 return NS_OK;
michael@0 131 }
michael@0 132
michael@0 133 // Don't do anything special if not an HTML object resizer editor
michael@0 134 nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryReferent(mEditor);
michael@0 135 if (objectResizer)
michael@0 136 {
michael@0 137 // check if we have to redisplay a resizing shadow
michael@0 138 objectResizer->MouseMove(aMouseEvent);
michael@0 139 }
michael@0 140
michael@0 141 return NS_OK;
michael@0 142 }
michael@0 143
michael@0 144 // ==================================================================
michael@0 145 // nsHTMLEditor
michael@0 146 // ==================================================================
michael@0 147
michael@0 148 nsresult
michael@0 149 nsHTMLEditor::CreateResizer(nsIDOMElement ** aReturn, int16_t aLocation, nsIDOMNode * aParentNode)
michael@0 150 {
michael@0 151 nsresult res = CreateAnonymousElement(NS_LITERAL_STRING("span"),
michael@0 152 aParentNode,
michael@0 153 NS_LITERAL_STRING("mozResizer"),
michael@0 154 false,
michael@0 155 aReturn);
michael@0 156
michael@0 157 NS_ENSURE_SUCCESS(res, res);
michael@0 158 NS_ENSURE_TRUE(*aReturn, NS_ERROR_FAILURE);
michael@0 159
michael@0 160 // add the mouse listener so we can detect a click on a resizer
michael@0 161 nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(*aReturn));
michael@0 162 evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mEventListener,
michael@0 163 true);
michael@0 164
michael@0 165 nsAutoString locationStr;
michael@0 166 switch (aLocation) {
michael@0 167 case nsIHTMLObjectResizer::eTopLeft:
michael@0 168 locationStr = kTopLeft;
michael@0 169 break;
michael@0 170 case nsIHTMLObjectResizer::eTop:
michael@0 171 locationStr = kTop;
michael@0 172 break;
michael@0 173 case nsIHTMLObjectResizer::eTopRight:
michael@0 174 locationStr = kTopRight;
michael@0 175 break;
michael@0 176
michael@0 177 case nsIHTMLObjectResizer::eLeft:
michael@0 178 locationStr = kLeft;
michael@0 179 break;
michael@0 180 case nsIHTMLObjectResizer::eRight:
michael@0 181 locationStr = kRight;
michael@0 182 break;
michael@0 183
michael@0 184 case nsIHTMLObjectResizer::eBottomLeft:
michael@0 185 locationStr = kBottomLeft;
michael@0 186 break;
michael@0 187 case nsIHTMLObjectResizer::eBottom:
michael@0 188 locationStr = kBottom;
michael@0 189 break;
michael@0 190 case nsIHTMLObjectResizer::eBottomRight:
michael@0 191 locationStr = kBottomRight;
michael@0 192 break;
michael@0 193 }
michael@0 194
michael@0 195 res = (*aReturn)->SetAttribute(NS_LITERAL_STRING("anonlocation"),
michael@0 196 locationStr);
michael@0 197 return res;
michael@0 198 }
michael@0 199
michael@0 200 nsresult
michael@0 201 nsHTMLEditor::CreateShadow(nsIDOMElement ** aReturn, nsIDOMNode * aParentNode,
michael@0 202 nsIDOMElement * aOriginalObject)
michael@0 203 {
michael@0 204 // let's create an image through the element factory
michael@0 205 nsAutoString name;
michael@0 206 if (nsHTMLEditUtils::IsImage(aOriginalObject))
michael@0 207 name.AssignLiteral("img");
michael@0 208 else
michael@0 209 name.AssignLiteral("span");
michael@0 210 nsresult res = CreateAnonymousElement(name,
michael@0 211 aParentNode,
michael@0 212 NS_LITERAL_STRING("mozResizingShadow"),
michael@0 213 true,
michael@0 214 aReturn);
michael@0 215
michael@0 216 NS_ENSURE_TRUE(*aReturn, NS_ERROR_FAILURE);
michael@0 217
michael@0 218 return res;
michael@0 219 }
michael@0 220
michael@0 221 nsresult
michael@0 222 nsHTMLEditor::CreateResizingInfo(nsIDOMElement ** aReturn, nsIDOMNode * aParentNode)
michael@0 223 {
michael@0 224 // let's create an info box through the element factory
michael@0 225 nsresult res = CreateAnonymousElement(NS_LITERAL_STRING("span"),
michael@0 226 aParentNode,
michael@0 227 NS_LITERAL_STRING("mozResizingInfo"),
michael@0 228 true,
michael@0 229 aReturn);
michael@0 230
michael@0 231 NS_ENSURE_TRUE(*aReturn, NS_ERROR_FAILURE);
michael@0 232
michael@0 233 return res;
michael@0 234 }
michael@0 235
michael@0 236 nsresult
michael@0 237 nsHTMLEditor::SetAllResizersPosition()
michael@0 238 {
michael@0 239 NS_ENSURE_TRUE(mTopLeftHandle, NS_ERROR_FAILURE);
michael@0 240
michael@0 241 int32_t x = mResizedObjectX;
michael@0 242 int32_t y = mResizedObjectY;
michael@0 243 int32_t w = mResizedObjectWidth;
michael@0 244 int32_t h = mResizedObjectHeight;
michael@0 245
michael@0 246 // now let's place all the resizers around the image
michael@0 247
michael@0 248 // get the size of resizers
michael@0 249 nsAutoString value;
michael@0 250 float resizerWidth, resizerHeight;
michael@0 251 nsCOMPtr<nsIAtom> dummyUnit;
michael@0 252 mHTMLCSSUtils->GetComputedProperty(mTopLeftHandle, nsEditProperty::cssWidth, value);
michael@0 253 mHTMLCSSUtils->ParseLength(value, &resizerWidth, getter_AddRefs(dummyUnit));
michael@0 254 mHTMLCSSUtils->GetComputedProperty(mTopLeftHandle, nsEditProperty::cssHeight, value);
michael@0 255 mHTMLCSSUtils->ParseLength(value, &resizerHeight, getter_AddRefs(dummyUnit));
michael@0 256
michael@0 257 int32_t rw = (int32_t)((resizerWidth + 1) / 2);
michael@0 258 int32_t rh = (int32_t)((resizerHeight+ 1) / 2);
michael@0 259
michael@0 260 SetAnonymousElementPosition(x-rw, y-rh, mTopLeftHandle);
michael@0 261 SetAnonymousElementPosition(x+w/2-rw, y-rh, mTopHandle);
michael@0 262 SetAnonymousElementPosition(x+w-rw-1, y-rh, mTopRightHandle);
michael@0 263
michael@0 264 SetAnonymousElementPosition(x-rw, y+h/2-rh, mLeftHandle);
michael@0 265 SetAnonymousElementPosition(x+w-rw-1, y+h/2-rh, mRightHandle);
michael@0 266
michael@0 267 SetAnonymousElementPosition(x-rw, y+h-rh-1, mBottomLeftHandle);
michael@0 268 SetAnonymousElementPosition(x+w/2-rw, y+h-rh-1, mBottomHandle);
michael@0 269 SetAnonymousElementPosition(x+w-rw-1, y+h-rh-1, mBottomRightHandle);
michael@0 270
michael@0 271 return NS_OK;
michael@0 272 }
michael@0 273
michael@0 274 NS_IMETHODIMP
michael@0 275 nsHTMLEditor::RefreshResizers()
michael@0 276 {
michael@0 277 // nothing to do if resizers are not displayed...
michael@0 278 NS_ENSURE_TRUE(mResizedObject, NS_OK);
michael@0 279
michael@0 280 nsresult res = GetPositionAndDimensions(mResizedObject,
michael@0 281 mResizedObjectX,
michael@0 282 mResizedObjectY,
michael@0 283 mResizedObjectWidth,
michael@0 284 mResizedObjectHeight,
michael@0 285 mResizedObjectBorderLeft,
michael@0 286 mResizedObjectBorderTop,
michael@0 287 mResizedObjectMarginLeft,
michael@0 288 mResizedObjectMarginTop);
michael@0 289
michael@0 290 NS_ENSURE_SUCCESS(res, res);
michael@0 291 res = SetAllResizersPosition();
michael@0 292 NS_ENSURE_SUCCESS(res, res);
michael@0 293 return SetShadowPosition(mResizingShadow, mResizedObject,
michael@0 294 mResizedObjectX, mResizedObjectY);
michael@0 295 }
michael@0 296
michael@0 297 NS_IMETHODIMP
michael@0 298 nsHTMLEditor::ShowResizers(nsIDOMElement *aResizedElement)
michael@0 299 {
michael@0 300 nsresult res = ShowResizersInner(aResizedElement);
michael@0 301 if (NS_FAILED(res))
michael@0 302 HideResizers();
michael@0 303 return res;
michael@0 304 }
michael@0 305
michael@0 306 nsresult
michael@0 307 nsHTMLEditor::ShowResizersInner(nsIDOMElement *aResizedElement)
michael@0 308 {
michael@0 309 NS_ENSURE_ARG_POINTER(aResizedElement);
michael@0 310 nsresult res;
michael@0 311
michael@0 312 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 313 res = aResizedElement->GetParentNode(getter_AddRefs(parentNode));
michael@0 314 NS_ENSURE_SUCCESS(res, res);
michael@0 315
michael@0 316 if (mResizedObject) {
michael@0 317 NS_ERROR("call HideResizers first");
michael@0 318 return NS_ERROR_UNEXPECTED;
michael@0 319 }
michael@0 320 mResizedObject = aResizedElement;
michael@0 321
michael@0 322 // The resizers and the shadow will be anonymous siblings of the element.
michael@0 323 res = CreateResizer(getter_AddRefs(mTopLeftHandle),
michael@0 324 nsIHTMLObjectResizer::eTopLeft, parentNode);
michael@0 325 NS_ENSURE_SUCCESS(res, res);
michael@0 326 res = CreateResizer(getter_AddRefs(mTopHandle),
michael@0 327 nsIHTMLObjectResizer::eTop, parentNode);
michael@0 328 NS_ENSURE_SUCCESS(res, res);
michael@0 329 res = CreateResizer(getter_AddRefs(mTopRightHandle),
michael@0 330 nsIHTMLObjectResizer::eTopRight, parentNode);
michael@0 331 NS_ENSURE_SUCCESS(res, res);
michael@0 332
michael@0 333 res = CreateResizer(getter_AddRefs(mLeftHandle),
michael@0 334 nsIHTMLObjectResizer::eLeft, parentNode);
michael@0 335 NS_ENSURE_SUCCESS(res, res);
michael@0 336 res = CreateResizer(getter_AddRefs(mRightHandle),
michael@0 337 nsIHTMLObjectResizer::eRight, parentNode);
michael@0 338 NS_ENSURE_SUCCESS(res, res);
michael@0 339
michael@0 340 res = CreateResizer(getter_AddRefs(mBottomLeftHandle),
michael@0 341 nsIHTMLObjectResizer::eBottomLeft, parentNode);
michael@0 342 NS_ENSURE_SUCCESS(res, res);
michael@0 343 res = CreateResizer(getter_AddRefs(mBottomHandle),
michael@0 344 nsIHTMLObjectResizer::eBottom, parentNode);
michael@0 345 NS_ENSURE_SUCCESS(res, res);
michael@0 346 res = CreateResizer(getter_AddRefs(mBottomRightHandle),
michael@0 347 nsIHTMLObjectResizer::eBottomRight, parentNode);
michael@0 348 NS_ENSURE_SUCCESS(res, res);
michael@0 349
michael@0 350 res = GetPositionAndDimensions(aResizedElement,
michael@0 351 mResizedObjectX,
michael@0 352 mResizedObjectY,
michael@0 353 mResizedObjectWidth,
michael@0 354 mResizedObjectHeight,
michael@0 355 mResizedObjectBorderLeft,
michael@0 356 mResizedObjectBorderTop,
michael@0 357 mResizedObjectMarginLeft,
michael@0 358 mResizedObjectMarginTop);
michael@0 359 NS_ENSURE_SUCCESS(res, res);
michael@0 360
michael@0 361 // and let's set their absolute positions in the document
michael@0 362 res = SetAllResizersPosition();
michael@0 363 NS_ENSURE_SUCCESS(res, res);
michael@0 364
michael@0 365 // now, let's create the resizing shadow
michael@0 366 res = CreateShadow(getter_AddRefs(mResizingShadow), parentNode,
michael@0 367 aResizedElement);
michael@0 368 NS_ENSURE_SUCCESS(res, res);
michael@0 369 // and set its position
michael@0 370 res = SetShadowPosition(mResizingShadow, mResizedObject,
michael@0 371 mResizedObjectX, mResizedObjectY);
michael@0 372 NS_ENSURE_SUCCESS(res, res);
michael@0 373
michael@0 374 // and then the resizing info tooltip
michael@0 375 res = CreateResizingInfo(getter_AddRefs(mResizingInfo), parentNode);
michael@0 376 NS_ENSURE_SUCCESS(res, res);
michael@0 377
michael@0 378 // and listen to the "resize" event on the window first, get the
michael@0 379 // window from the document...
michael@0 380 nsCOMPtr<nsIDocument> doc = GetDocument();
michael@0 381 NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
michael@0 382
michael@0 383 nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(doc->GetWindow());
michael@0 384 if (!target) { return NS_ERROR_NULL_POINTER; }
michael@0 385
michael@0 386 mResizeEventListenerP = new DocumentResizeEventListener(this);
michael@0 387 if (!mResizeEventListenerP) { return NS_ERROR_OUT_OF_MEMORY; }
michael@0 388 res = target->AddEventListener(NS_LITERAL_STRING("resize"), mResizeEventListenerP, false);
michael@0 389
michael@0 390 aResizedElement->SetAttribute(NS_LITERAL_STRING("_moz_resizing"), NS_LITERAL_STRING("true"));
michael@0 391 return res;
michael@0 392 }
michael@0 393
michael@0 394 NS_IMETHODIMP
michael@0 395 nsHTMLEditor::HideResizers(void)
michael@0 396 {
michael@0 397 NS_ENSURE_TRUE(mResizedObject, NS_OK);
michael@0 398
michael@0 399 // get the presshell's document observer interface.
michael@0 400 nsCOMPtr<nsIPresShell> ps = GetPresShell();
michael@0 401 // We allow the pres shell to be null; when it is, we presume there
michael@0 402 // are no document observers to notify, but we still want to
michael@0 403 // UnbindFromTree.
michael@0 404
michael@0 405 nsresult res;
michael@0 406 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 407 nsCOMPtr<nsIContent> parentContent;
michael@0 408
michael@0 409 if (mTopLeftHandle) {
michael@0 410 res = mTopLeftHandle->GetParentNode(getter_AddRefs(parentNode));
michael@0 411 NS_ENSURE_SUCCESS(res, res);
michael@0 412 parentContent = do_QueryInterface(parentNode);
michael@0 413 }
michael@0 414
michael@0 415 NS_NAMED_LITERAL_STRING(mousedown, "mousedown");
michael@0 416
michael@0 417 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 418 mTopLeftHandle, parentContent, ps);
michael@0 419 mTopLeftHandle = nullptr;
michael@0 420
michael@0 421 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 422 mTopHandle, parentContent, ps);
michael@0 423 mTopHandle = nullptr;
michael@0 424
michael@0 425 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 426 mTopRightHandle, parentContent, ps);
michael@0 427 mTopRightHandle = nullptr;
michael@0 428
michael@0 429 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 430 mLeftHandle, parentContent, ps);
michael@0 431 mLeftHandle = nullptr;
michael@0 432
michael@0 433 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 434 mRightHandle, parentContent, ps);
michael@0 435 mRightHandle = nullptr;
michael@0 436
michael@0 437 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 438 mBottomLeftHandle, parentContent, ps);
michael@0 439 mBottomLeftHandle = nullptr;
michael@0 440
michael@0 441 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 442 mBottomHandle, parentContent, ps);
michael@0 443 mBottomHandle = nullptr;
michael@0 444
michael@0 445 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 446 mBottomRightHandle, parentContent, ps);
michael@0 447 mBottomRightHandle = nullptr;
michael@0 448
michael@0 449 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 450 mResizingShadow, parentContent, ps);
michael@0 451 mResizingShadow = nullptr;
michael@0 452
michael@0 453 RemoveListenerAndDeleteRef(mousedown, mEventListener, true,
michael@0 454 mResizingInfo, parentContent, ps);
michael@0 455 mResizingInfo = nullptr;
michael@0 456
michael@0 457 if (mActivatedHandle) {
michael@0 458 mActivatedHandle->RemoveAttribute(NS_LITERAL_STRING("_moz_activated"));
michael@0 459 mActivatedHandle = nullptr;
michael@0 460 }
michael@0 461
michael@0 462 // don't forget to remove the listeners !
michael@0 463
michael@0 464 nsCOMPtr<nsIDOMEventTarget> target = GetDOMEventTarget();
michael@0 465
michael@0 466 if (target && mMouseMotionListenerP)
michael@0 467 {
michael@0 468 res = target->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
michael@0 469 mMouseMotionListenerP, true);
michael@0 470 NS_ASSERTION(NS_SUCCEEDED(res), "failed to remove mouse motion listener");
michael@0 471 }
michael@0 472 mMouseMotionListenerP = nullptr;
michael@0 473
michael@0 474 nsCOMPtr<nsIDocument> doc = GetDocument();
michael@0 475 if (!doc) { return NS_ERROR_NULL_POINTER; }
michael@0 476 target = do_QueryInterface(doc->GetWindow());
michael@0 477 if (!target) { return NS_ERROR_NULL_POINTER; }
michael@0 478
michael@0 479 if (mResizeEventListenerP) {
michael@0 480 res = target->RemoveEventListener(NS_LITERAL_STRING("resize"), mResizeEventListenerP, false);
michael@0 481 NS_ASSERTION(NS_SUCCEEDED(res), "failed to remove resize event listener");
michael@0 482 }
michael@0 483 mResizeEventListenerP = nullptr;
michael@0 484
michael@0 485 mResizedObject->RemoveAttribute(NS_LITERAL_STRING("_moz_resizing"));
michael@0 486 mResizedObject = nullptr;
michael@0 487
michael@0 488 return NS_OK;
michael@0 489 }
michael@0 490
michael@0 491 void
michael@0 492 nsHTMLEditor::HideShadowAndInfo()
michael@0 493 {
michael@0 494 if (mResizingShadow)
michael@0 495 mResizingShadow->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden"));
michael@0 496 if (mResizingInfo)
michael@0 497 mResizingInfo->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden"));
michael@0 498 }
michael@0 499
michael@0 500 nsresult
michael@0 501 nsHTMLEditor::StartResizing(nsIDOMElement *aHandle)
michael@0 502 {
michael@0 503 // First notify the listeners if any
michael@0 504 int32_t listenersCount = objectResizeEventListeners.Count();
michael@0 505 if (listenersCount) {
michael@0 506 nsCOMPtr<nsIHTMLObjectResizeListener> listener;
michael@0 507 int32_t index;
michael@0 508 for (index = 0; index < listenersCount; index++) {
michael@0 509 listener = objectResizeEventListeners[index];
michael@0 510 listener->OnStartResizing(mResizedObject);
michael@0 511 }
michael@0 512 }
michael@0 513
michael@0 514 mIsResizing = true;
michael@0 515 mActivatedHandle = aHandle;
michael@0 516 mActivatedHandle->SetAttribute(NS_LITERAL_STRING("_moz_activated"), NS_LITERAL_STRING("true"));
michael@0 517
michael@0 518 // do we want to preserve ratio or not?
michael@0 519 bool preserveRatio = nsHTMLEditUtils::IsImage(mResizedObject) &&
michael@0 520 Preferences::GetBool("editor.resizing.preserve_ratio", true);
michael@0 521
michael@0 522 // the way we change the position/size of the shadow depends on
michael@0 523 // the handle
michael@0 524 nsAutoString locationStr;
michael@0 525 aHandle->GetAttribute(NS_LITERAL_STRING("anonlocation"), locationStr);
michael@0 526 if (locationStr.Equals(kTopLeft)) {
michael@0 527 SetResizeIncrements(1, 1, -1, -1, preserveRatio);
michael@0 528 }
michael@0 529 else if (locationStr.Equals(kTop)) {
michael@0 530 SetResizeIncrements(0, 1, 0, -1, false);
michael@0 531 }
michael@0 532 else if (locationStr.Equals(kTopRight)) {
michael@0 533 SetResizeIncrements(0, 1, 1, -1, preserveRatio);
michael@0 534 }
michael@0 535 else if (locationStr.Equals(kLeft)) {
michael@0 536 SetResizeIncrements(1, 0, -1, 0, false);
michael@0 537 }
michael@0 538 else if (locationStr.Equals(kRight)) {
michael@0 539 SetResizeIncrements(0, 0, 1, 0, false);
michael@0 540 }
michael@0 541 else if (locationStr.Equals(kBottomLeft)) {
michael@0 542 SetResizeIncrements(1, 0, -1, 1, preserveRatio);
michael@0 543 }
michael@0 544 else if (locationStr.Equals(kBottom)) {
michael@0 545 SetResizeIncrements(0, 0, 0, 1, false);
michael@0 546 }
michael@0 547 else if (locationStr.Equals(kBottomRight)) {
michael@0 548 SetResizeIncrements(0, 0, 1, 1, preserveRatio);
michael@0 549 }
michael@0 550
michael@0 551 // make the shadow appear
michael@0 552 mResizingShadow->RemoveAttribute(NS_LITERAL_STRING("class"));
michael@0 553
michael@0 554 // position it
michael@0 555 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingShadow,
michael@0 556 NS_LITERAL_STRING("width"),
michael@0 557 mResizedObjectWidth);
michael@0 558 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingShadow,
michael@0 559 NS_LITERAL_STRING("height"),
michael@0 560 mResizedObjectHeight);
michael@0 561
michael@0 562 // add a mouse move listener to the editor
michael@0 563 nsresult result = NS_OK;
michael@0 564 if (!mMouseMotionListenerP) {
michael@0 565 mMouseMotionListenerP = new ResizerMouseMotionListener(this);
michael@0 566 if (!mMouseMotionListenerP) {
michael@0 567 return NS_ERROR_OUT_OF_MEMORY;
michael@0 568 }
michael@0 569
michael@0 570 nsCOMPtr<nsIDOMEventTarget> target = GetDOMEventTarget();
michael@0 571 NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
michael@0 572
michael@0 573 result = target->AddEventListener(NS_LITERAL_STRING("mousemove"),
michael@0 574 mMouseMotionListenerP, true);
michael@0 575 NS_ASSERTION(NS_SUCCEEDED(result),
michael@0 576 "failed to register mouse motion listener");
michael@0 577 }
michael@0 578 return result;
michael@0 579 }
michael@0 580
michael@0 581
michael@0 582 NS_IMETHODIMP
michael@0 583 nsHTMLEditor::MouseDown(int32_t aClientX, int32_t aClientY,
michael@0 584 nsIDOMElement *aTarget, nsIDOMEvent* aEvent)
michael@0 585 {
michael@0 586 bool anonElement = false;
michael@0 587 if (aTarget && NS_SUCCEEDED(aTarget->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement)))
michael@0 588 // we caught a click on an anonymous element
michael@0 589 if (anonElement) {
michael@0 590 nsAutoString anonclass;
michael@0 591 nsresult res = aTarget->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass);
michael@0 592 NS_ENSURE_SUCCESS(res, res);
michael@0 593 if (anonclass.EqualsLiteral("mozResizer")) {
michael@0 594 // and that element is a resizer, let's start resizing!
michael@0 595 aEvent->PreventDefault();
michael@0 596
michael@0 597 mOriginalX = aClientX;
michael@0 598 mOriginalY = aClientY;
michael@0 599 return StartResizing(aTarget);
michael@0 600 }
michael@0 601 if (anonclass.EqualsLiteral("mozGrabber")) {
michael@0 602 // and that element is a grabber, let's start moving the element!
michael@0 603 mOriginalX = aClientX;
michael@0 604 mOriginalY = aClientY;
michael@0 605 return GrabberClicked();
michael@0 606 }
michael@0 607 }
michael@0 608 return NS_OK;
michael@0 609 }
michael@0 610
michael@0 611 NS_IMETHODIMP
michael@0 612 nsHTMLEditor::MouseUp(int32_t aClientX, int32_t aClientY,
michael@0 613 nsIDOMElement *aTarget)
michael@0 614 {
michael@0 615 if (mIsResizing) {
michael@0 616 // we are resizing and release the mouse button, so let's
michael@0 617 // end the resizing process
michael@0 618 mIsResizing = false;
michael@0 619 HideShadowAndInfo();
michael@0 620 SetFinalSize(aClientX, aClientY);
michael@0 621 }
michael@0 622 else if (mIsMoving || mGrabberClicked) {
michael@0 623 if (mIsMoving) {
michael@0 624 mPositioningShadow->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden"));
michael@0 625 SetFinalPosition(aClientX, aClientY);
michael@0 626 }
michael@0 627 if (mGrabberClicked) {
michael@0 628 EndMoving();
michael@0 629 }
michael@0 630 }
michael@0 631 return NS_OK;
michael@0 632 }
michael@0 633
michael@0 634
michael@0 635 void
michael@0 636 nsHTMLEditor::SetResizeIncrements(int32_t aX, int32_t aY,
michael@0 637 int32_t aW, int32_t aH,
michael@0 638 bool aPreserveRatio)
michael@0 639 {
michael@0 640 mXIncrementFactor = aX;
michael@0 641 mYIncrementFactor = aY;
michael@0 642 mWidthIncrementFactor = aW;
michael@0 643 mHeightIncrementFactor = aH;
michael@0 644 mPreserveRatio = aPreserveRatio;
michael@0 645 }
michael@0 646
michael@0 647 nsresult
michael@0 648 nsHTMLEditor::SetResizingInfoPosition(int32_t aX, int32_t aY, int32_t aW, int32_t aH)
michael@0 649 {
michael@0 650 nsCOMPtr<nsIDOMDocument> domdoc = GetDOMDocument();
michael@0 651
michael@0 652 NS_NAMED_LITERAL_STRING(leftStr, "left");
michael@0 653 NS_NAMED_LITERAL_STRING(topStr, "top");
michael@0 654
michael@0 655 // Determine the position of the resizing info box based upon the new
michael@0 656 // position and size of the element (aX, aY, aW, aH), and which
michael@0 657 // resizer is the "activated handle". For example, place the resizing
michael@0 658 // info box at the bottom-right corner of the new element, if the element
michael@0 659 // is being resized by the bottom-right resizer.
michael@0 660 int32_t infoXPosition;
michael@0 661 int32_t infoYPosition;
michael@0 662
michael@0 663 if (mActivatedHandle == mTopLeftHandle ||
michael@0 664 mActivatedHandle == mLeftHandle ||
michael@0 665 mActivatedHandle == mBottomLeftHandle)
michael@0 666 infoXPosition = aX;
michael@0 667 else if (mActivatedHandle == mTopHandle ||
michael@0 668 mActivatedHandle == mBottomHandle)
michael@0 669 infoXPosition = aX + (aW / 2);
michael@0 670 else
michael@0 671 // should only occur when mActivatedHandle is one of the 3 right-side
michael@0 672 // handles, but this is a reasonable default if it isn't any of them (?)
michael@0 673 infoXPosition = aX + aW;
michael@0 674
michael@0 675 if (mActivatedHandle == mTopLeftHandle ||
michael@0 676 mActivatedHandle == mTopHandle ||
michael@0 677 mActivatedHandle == mTopRightHandle)
michael@0 678 infoYPosition = aY;
michael@0 679 else if (mActivatedHandle == mLeftHandle ||
michael@0 680 mActivatedHandle == mRightHandle)
michael@0 681 infoYPosition = aY + (aH / 2);
michael@0 682 else
michael@0 683 // should only occur when mActivatedHandle is one of the 3 bottom-side
michael@0 684 // handles, but this is a reasonable default if it isn't any of them (?)
michael@0 685 infoYPosition = aY + aH;
michael@0 686
michael@0 687 // Offset info box by 20 so it's not directly under the mouse cursor.
michael@0 688 const int mouseCursorOffset = 20;
michael@0 689 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingInfo, leftStr,
michael@0 690 infoXPosition + mouseCursorOffset);
michael@0 691 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingInfo, topStr,
michael@0 692 infoYPosition + mouseCursorOffset);
michael@0 693
michael@0 694 nsCOMPtr<nsIDOMNode> textInfo;
michael@0 695 nsresult res = mResizingInfo->GetFirstChild(getter_AddRefs(textInfo));
michael@0 696 NS_ENSURE_SUCCESS(res, res);
michael@0 697 nsCOMPtr<nsIDOMNode> junk;
michael@0 698 if (textInfo) {
michael@0 699 res = mResizingInfo->RemoveChild(textInfo, getter_AddRefs(junk));
michael@0 700 NS_ENSURE_SUCCESS(res, res);
michael@0 701 textInfo = nullptr;
michael@0 702 junk = nullptr;
michael@0 703 }
michael@0 704
michael@0 705 nsAutoString widthStr, heightStr, diffWidthStr, diffHeightStr;
michael@0 706 widthStr.AppendInt(aW);
michael@0 707 heightStr.AppendInt(aH);
michael@0 708 int32_t diffWidth = aW - mResizedObjectWidth;
michael@0 709 int32_t diffHeight = aH - mResizedObjectHeight;
michael@0 710 if (diffWidth > 0)
michael@0 711 diffWidthStr.AssignLiteral("+");
michael@0 712 if (diffHeight > 0)
michael@0 713 diffHeightStr.AssignLiteral("+");
michael@0 714 diffWidthStr.AppendInt(diffWidth);
michael@0 715 diffHeightStr.AppendInt(diffHeight);
michael@0 716
michael@0 717 nsAutoString info(widthStr + NS_LITERAL_STRING(" x ") + heightStr +
michael@0 718 NS_LITERAL_STRING(" (") + diffWidthStr +
michael@0 719 NS_LITERAL_STRING(", ") + diffHeightStr +
michael@0 720 NS_LITERAL_STRING(")"));
michael@0 721
michael@0 722 nsCOMPtr<nsIDOMText> nodeAsText;
michael@0 723 res = domdoc->CreateTextNode(info, getter_AddRefs(nodeAsText));
michael@0 724 NS_ENSURE_SUCCESS(res, res);
michael@0 725 textInfo = do_QueryInterface(nodeAsText);
michael@0 726 res = mResizingInfo->AppendChild(textInfo, getter_AddRefs(junk));
michael@0 727 NS_ENSURE_SUCCESS(res, res);
michael@0 728
michael@0 729 bool hasClass = false;
michael@0 730 if (NS_SUCCEEDED(mResizingInfo->HasAttribute(NS_LITERAL_STRING("class"), &hasClass )) && hasClass)
michael@0 731 res = mResizingInfo->RemoveAttribute(NS_LITERAL_STRING("class"));
michael@0 732
michael@0 733 return res;
michael@0 734 }
michael@0 735
michael@0 736 nsresult
michael@0 737 nsHTMLEditor::SetShadowPosition(nsIDOMElement * aShadow,
michael@0 738 nsIDOMElement * aOriginalObject,
michael@0 739 int32_t aOriginalObjectX,
michael@0 740 int32_t aOriginalObjectY)
michael@0 741 {
michael@0 742 SetAnonymousElementPosition(aOriginalObjectX, aOriginalObjectY, aShadow);
michael@0 743
michael@0 744 if (nsHTMLEditUtils::IsImage(aOriginalObject)) {
michael@0 745 nsAutoString imageSource;
michael@0 746 nsresult res = aOriginalObject->GetAttribute(NS_LITERAL_STRING("src"),
michael@0 747 imageSource);
michael@0 748 NS_ENSURE_SUCCESS(res, res);
michael@0 749 res = aShadow->SetAttribute(NS_LITERAL_STRING("src"), imageSource);
michael@0 750 NS_ENSURE_SUCCESS(res, res);
michael@0 751 }
michael@0 752 return NS_OK;
michael@0 753 }
michael@0 754
michael@0 755 int32_t
michael@0 756 nsHTMLEditor::GetNewResizingIncrement(int32_t aX, int32_t aY, int32_t aID)
michael@0 757 {
michael@0 758 int32_t result = 0;
michael@0 759 if (!mPreserveRatio) {
michael@0 760 switch (aID) {
michael@0 761 case kX:
michael@0 762 case kWidth:
michael@0 763 result = aX - mOriginalX;
michael@0 764 break;
michael@0 765 case kY:
michael@0 766 case kHeight:
michael@0 767 result = aY - mOriginalY;
michael@0 768 break;
michael@0 769 }
michael@0 770 return result;
michael@0 771 }
michael@0 772
michael@0 773 int32_t xi = (aX - mOriginalX) * mWidthIncrementFactor;
michael@0 774 int32_t yi = (aY - mOriginalY) * mHeightIncrementFactor;
michael@0 775 float objectSizeRatio =
michael@0 776 ((float)mResizedObjectWidth) / ((float)mResizedObjectHeight);
michael@0 777 result = (xi > yi) ? xi : yi;
michael@0 778 switch (aID) {
michael@0 779 case kX:
michael@0 780 case kWidth:
michael@0 781 if (result == yi)
michael@0 782 result = (int32_t) (((float) result) * objectSizeRatio);
michael@0 783 result = (int32_t) (((float) result) * mWidthIncrementFactor);
michael@0 784 break;
michael@0 785 case kY:
michael@0 786 case kHeight:
michael@0 787 if (result == xi)
michael@0 788 result = (int32_t) (((float) result) / objectSizeRatio);
michael@0 789 result = (int32_t) (((float) result) * mHeightIncrementFactor);
michael@0 790 break;
michael@0 791 }
michael@0 792 return result;
michael@0 793 }
michael@0 794
michael@0 795 int32_t
michael@0 796 nsHTMLEditor::GetNewResizingX(int32_t aX, int32_t aY)
michael@0 797 {
michael@0 798 int32_t resized = mResizedObjectX +
michael@0 799 GetNewResizingIncrement(aX, aY, kX) * mXIncrementFactor;
michael@0 800 int32_t max = mResizedObjectX + mResizedObjectWidth;
michael@0 801 return std::min(resized, max);
michael@0 802 }
michael@0 803
michael@0 804 int32_t
michael@0 805 nsHTMLEditor::GetNewResizingY(int32_t aX, int32_t aY)
michael@0 806 {
michael@0 807 int32_t resized = mResizedObjectY +
michael@0 808 GetNewResizingIncrement(aX, aY, kY) * mYIncrementFactor;
michael@0 809 int32_t max = mResizedObjectY + mResizedObjectHeight;
michael@0 810 return std::min(resized, max);
michael@0 811 }
michael@0 812
michael@0 813 int32_t
michael@0 814 nsHTMLEditor::GetNewResizingWidth(int32_t aX, int32_t aY)
michael@0 815 {
michael@0 816 int32_t resized = mResizedObjectWidth +
michael@0 817 GetNewResizingIncrement(aX, aY, kWidth) *
michael@0 818 mWidthIncrementFactor;
michael@0 819 return std::max(resized, 1);
michael@0 820 }
michael@0 821
michael@0 822 int32_t
michael@0 823 nsHTMLEditor::GetNewResizingHeight(int32_t aX, int32_t aY)
michael@0 824 {
michael@0 825 int32_t resized = mResizedObjectHeight +
michael@0 826 GetNewResizingIncrement(aX, aY, kHeight) *
michael@0 827 mHeightIncrementFactor;
michael@0 828 return std::max(resized, 1);
michael@0 829 }
michael@0 830
michael@0 831
michael@0 832 NS_IMETHODIMP
michael@0 833 nsHTMLEditor::MouseMove(nsIDOMEvent* aMouseEvent)
michael@0 834 {
michael@0 835 NS_NAMED_LITERAL_STRING(leftStr, "left");
michael@0 836 NS_NAMED_LITERAL_STRING(topStr, "top");
michael@0 837
michael@0 838 if (mIsResizing) {
michael@0 839 // we are resizing and the mouse pointer's position has changed
michael@0 840 // we have to resdisplay the shadow
michael@0 841 nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
michael@0 842 int32_t clientX, clientY;
michael@0 843 mouseEvent->GetClientX(&clientX);
michael@0 844 mouseEvent->GetClientY(&clientY);
michael@0 845
michael@0 846 int32_t newX = GetNewResizingX(clientX, clientY);
michael@0 847 int32_t newY = GetNewResizingY(clientX, clientY);
michael@0 848 int32_t newWidth = GetNewResizingWidth(clientX, clientY);
michael@0 849 int32_t newHeight = GetNewResizingHeight(clientX, clientY);
michael@0 850
michael@0 851 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingShadow,
michael@0 852 leftStr,
michael@0 853 newX);
michael@0 854 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingShadow,
michael@0 855 topStr,
michael@0 856 newY);
michael@0 857 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingShadow,
michael@0 858 NS_LITERAL_STRING("width"),
michael@0 859 newWidth);
michael@0 860 mHTMLCSSUtils->SetCSSPropertyPixels(mResizingShadow,
michael@0 861 NS_LITERAL_STRING("height"),
michael@0 862 newHeight);
michael@0 863
michael@0 864 return SetResizingInfoPosition(newX, newY, newWidth, newHeight);
michael@0 865 }
michael@0 866
michael@0 867 if (mGrabberClicked) {
michael@0 868 nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
michael@0 869 int32_t clientX, clientY;
michael@0 870 mouseEvent->GetClientX(&clientX);
michael@0 871 mouseEvent->GetClientY(&clientY);
michael@0 872
michael@0 873 int32_t xThreshold =
michael@0 874 LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 1);
michael@0 875 int32_t yThreshold =
michael@0 876 LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 1);
michael@0 877
michael@0 878 if (DeprecatedAbs(clientX - mOriginalX) * 2 >= xThreshold ||
michael@0 879 DeprecatedAbs(clientY - mOriginalY) * 2 >= yThreshold) {
michael@0 880 mGrabberClicked = false;
michael@0 881 StartMoving(nullptr);
michael@0 882 }
michael@0 883 }
michael@0 884 if (mIsMoving) {
michael@0 885 nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
michael@0 886 int32_t clientX, clientY;
michael@0 887 mouseEvent->GetClientX(&clientX);
michael@0 888 mouseEvent->GetClientY(&clientY);
michael@0 889
michael@0 890 int32_t newX = mPositionedObjectX + clientX - mOriginalX;
michael@0 891 int32_t newY = mPositionedObjectY + clientY - mOriginalY;
michael@0 892
michael@0 893 SnapToGrid(newX, newY);
michael@0 894
michael@0 895 mHTMLCSSUtils->SetCSSPropertyPixels(mPositioningShadow, leftStr, newX);
michael@0 896 mHTMLCSSUtils->SetCSSPropertyPixels(mPositioningShadow, topStr, newY);
michael@0 897 }
michael@0 898 return NS_OK;
michael@0 899 }
michael@0 900
michael@0 901 void
michael@0 902 nsHTMLEditor::SetFinalSize(int32_t aX, int32_t aY)
michael@0 903 {
michael@0 904 if (!mResizedObject) {
michael@0 905 // paranoia
michael@0 906 return;
michael@0 907 }
michael@0 908
michael@0 909 if (mActivatedHandle) {
michael@0 910 mActivatedHandle->RemoveAttribute(NS_LITERAL_STRING("_moz_activated"));
michael@0 911 mActivatedHandle = nullptr;
michael@0 912 }
michael@0 913
michael@0 914 // we have now to set the new width and height of the resized object
michael@0 915 // we don't set the x and y position because we don't control that in
michael@0 916 // a normal HTML layout
michael@0 917 int32_t left = GetNewResizingX(aX, aY);
michael@0 918 int32_t top = GetNewResizingY(aX, aY);
michael@0 919 int32_t width = GetNewResizingWidth(aX, aY);
michael@0 920 int32_t height = GetNewResizingHeight(aX, aY);
michael@0 921 bool setWidth = !mResizedObjectIsAbsolutelyPositioned || (width != mResizedObjectWidth);
michael@0 922 bool setHeight = !mResizedObjectIsAbsolutelyPositioned || (height != mResizedObjectHeight);
michael@0 923
michael@0 924 int32_t x, y;
michael@0 925 x = left - ((mResizedObjectIsAbsolutelyPositioned) ? mResizedObjectBorderLeft+mResizedObjectMarginLeft : 0);
michael@0 926 y = top - ((mResizedObjectIsAbsolutelyPositioned) ? mResizedObjectBorderTop+mResizedObjectMarginTop : 0);
michael@0 927
michael@0 928 // we want one transaction only from a user's point of view
michael@0 929 nsAutoEditBatch batchIt(this);
michael@0 930
michael@0 931 NS_NAMED_LITERAL_STRING(widthStr, "width");
michael@0 932 NS_NAMED_LITERAL_STRING(heightStr, "height");
michael@0 933
michael@0 934 bool hasAttr = false;
michael@0 935 if (mResizedObjectIsAbsolutelyPositioned) {
michael@0 936 if (setHeight)
michael@0 937 mHTMLCSSUtils->SetCSSPropertyPixels(mResizedObject,
michael@0 938 nsEditProperty::cssTop,
michael@0 939 y,
michael@0 940 false);
michael@0 941 if (setWidth)
michael@0 942 mHTMLCSSUtils->SetCSSPropertyPixels(mResizedObject,
michael@0 943 nsEditProperty::cssLeft,
michael@0 944 x,
michael@0 945 false);
michael@0 946 }
michael@0 947 if (IsCSSEnabled() || mResizedObjectIsAbsolutelyPositioned) {
michael@0 948 if (setWidth && NS_SUCCEEDED(mResizedObject->HasAttribute(widthStr, &hasAttr)) && hasAttr)
michael@0 949 RemoveAttribute(mResizedObject, widthStr);
michael@0 950
michael@0 951 hasAttr = false;
michael@0 952 if (setHeight && NS_SUCCEEDED(mResizedObject->HasAttribute(heightStr, &hasAttr)) && hasAttr)
michael@0 953 RemoveAttribute(mResizedObject, heightStr);
michael@0 954
michael@0 955 if (setWidth)
michael@0 956 mHTMLCSSUtils->SetCSSPropertyPixels(mResizedObject,
michael@0 957 nsEditProperty::cssWidth,
michael@0 958 width,
michael@0 959 false);
michael@0 960 if (setHeight)
michael@0 961 mHTMLCSSUtils->SetCSSPropertyPixels(mResizedObject,
michael@0 962 nsEditProperty::cssHeight,
michael@0 963 height,
michael@0 964 false);
michael@0 965 }
michael@0 966 else {
michael@0 967 // we use HTML size and remove all equivalent CSS properties
michael@0 968
michael@0 969 // we set the CSS width and height to remove it later,
michael@0 970 // triggering an immediate reflow; otherwise, we have problems
michael@0 971 // with asynchronous reflow
michael@0 972 if (setWidth)
michael@0 973 mHTMLCSSUtils->SetCSSPropertyPixels(mResizedObject,
michael@0 974 nsEditProperty::cssWidth,
michael@0 975 width,
michael@0 976 false);
michael@0 977 if (setHeight)
michael@0 978 mHTMLCSSUtils->SetCSSPropertyPixels(mResizedObject,
michael@0 979 nsEditProperty::cssHeight,
michael@0 980 height,
michael@0 981 false);
michael@0 982
michael@0 983 if (setWidth) {
michael@0 984 nsAutoString w;
michael@0 985 w.AppendInt(width);
michael@0 986 SetAttribute(mResizedObject, widthStr, w);
michael@0 987 }
michael@0 988 if (setHeight) {
michael@0 989 nsAutoString h;
michael@0 990 h.AppendInt(height);
michael@0 991 SetAttribute(mResizedObject, heightStr, h);
michael@0 992 }
michael@0 993
michael@0 994 if (setWidth)
michael@0 995 mHTMLCSSUtils->RemoveCSSProperty(mResizedObject,
michael@0 996 nsEditProperty::cssWidth,
michael@0 997 EmptyString(),
michael@0 998 false);
michael@0 999 if (setHeight)
michael@0 1000 mHTMLCSSUtils->RemoveCSSProperty(mResizedObject,
michael@0 1001 nsEditProperty::cssHeight,
michael@0 1002 EmptyString(),
michael@0 1003 false);
michael@0 1004 }
michael@0 1005 // finally notify the listeners if any
michael@0 1006 int32_t listenersCount = objectResizeEventListeners.Count();
michael@0 1007 if (listenersCount) {
michael@0 1008 nsCOMPtr<nsIHTMLObjectResizeListener> listener;
michael@0 1009 int32_t index;
michael@0 1010 for (index = 0; index < listenersCount; index++) {
michael@0 1011 listener = objectResizeEventListeners[index];
michael@0 1012 listener->OnEndResizing(mResizedObject,
michael@0 1013 mResizedObjectWidth, mResizedObjectHeight,
michael@0 1014 width, height);
michael@0 1015 }
michael@0 1016 }
michael@0 1017
michael@0 1018 // keep track of that size
michael@0 1019 mResizedObjectWidth = width;
michael@0 1020 mResizedObjectHeight = height;
michael@0 1021
michael@0 1022 RefreshResizers();
michael@0 1023 }
michael@0 1024
michael@0 1025 NS_IMETHODIMP
michael@0 1026 nsHTMLEditor::GetResizedObject(nsIDOMElement * *aResizedObject)
michael@0 1027 {
michael@0 1028 *aResizedObject = mResizedObject;
michael@0 1029 NS_IF_ADDREF(*aResizedObject);
michael@0 1030 return NS_OK;
michael@0 1031 }
michael@0 1032
michael@0 1033 NS_IMETHODIMP
michael@0 1034 nsHTMLEditor::GetObjectResizingEnabled(bool *aIsObjectResizingEnabled)
michael@0 1035 {
michael@0 1036 *aIsObjectResizingEnabled = mIsObjectResizingEnabled;
michael@0 1037 return NS_OK;
michael@0 1038 }
michael@0 1039
michael@0 1040 NS_IMETHODIMP
michael@0 1041 nsHTMLEditor::SetObjectResizingEnabled(bool aObjectResizingEnabled)
michael@0 1042 {
michael@0 1043 mIsObjectResizingEnabled = aObjectResizingEnabled;
michael@0 1044 return NS_OK;
michael@0 1045 }
michael@0 1046
michael@0 1047 NS_IMETHODIMP
michael@0 1048 nsHTMLEditor::AddObjectResizeEventListener(nsIHTMLObjectResizeListener * aListener)
michael@0 1049 {
michael@0 1050 NS_ENSURE_ARG_POINTER(aListener);
michael@0 1051 if (objectResizeEventListeners.Count() &&
michael@0 1052 objectResizeEventListeners.IndexOf(aListener) != -1) {
michael@0 1053 /* listener already registered */
michael@0 1054 NS_ASSERTION(false,
michael@0 1055 "trying to register an already registered object resize event listener");
michael@0 1056 return NS_OK;
michael@0 1057 }
michael@0 1058 objectResizeEventListeners.AppendObject(aListener);
michael@0 1059 return NS_OK;
michael@0 1060 }
michael@0 1061
michael@0 1062 NS_IMETHODIMP
michael@0 1063 nsHTMLEditor::RemoveObjectResizeEventListener(nsIHTMLObjectResizeListener * aListener)
michael@0 1064 {
michael@0 1065 NS_ENSURE_ARG_POINTER(aListener);
michael@0 1066 if (!objectResizeEventListeners.Count() ||
michael@0 1067 objectResizeEventListeners.IndexOf(aListener) == -1) {
michael@0 1068 /* listener was not registered */
michael@0 1069 NS_ASSERTION(false,
michael@0 1070 "trying to remove an object resize event listener that was not already registered");
michael@0 1071 return NS_OK;
michael@0 1072 }
michael@0 1073 objectResizeEventListeners.RemoveObject(aListener);
michael@0 1074 return NS_OK;
michael@0 1075 }
michael@0 1076

mercurial