Wed, 31 Dec 2014 06:55:50 +0100
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 |