editor/libeditor/html/nsHTMLAbsPosition.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include <math.h>
michael@0 6
michael@0 7 #include "mozilla/Preferences.h"
michael@0 8 #include "mozilla/dom/Selection.h"
michael@0 9 #include "mozilla/dom/Element.h"
michael@0 10 #include "mozilla/mozalloc.h"
michael@0 11 #include "nsAString.h"
michael@0 12 #include "nsAlgorithm.h"
michael@0 13 #include "nsAutoPtr.h"
michael@0 14 #include "nsCOMPtr.h"
michael@0 15 #include "nsComputedDOMStyle.h"
michael@0 16 #include "nsDebug.h"
michael@0 17 #include "nsEditProperty.h"
michael@0 18 #include "nsEditRules.h"
michael@0 19 #include "nsEditor.h"
michael@0 20 #include "nsEditorUtils.h"
michael@0 21 #include "nsError.h"
michael@0 22 #include "nsGkAtoms.h"
michael@0 23 #include "nsHTMLCSSUtils.h"
michael@0 24 #include "nsHTMLEditRules.h"
michael@0 25 #include "nsHTMLEditUtils.h"
michael@0 26 #include "nsHTMLEditor.h"
michael@0 27 #include "nsHTMLObjectResizer.h"
michael@0 28 #include "nsIContent.h"
michael@0 29 #include "nsROCSSPrimitiveValue.h"
michael@0 30 #include "nsIDOMCSSStyleDeclaration.h"
michael@0 31 #include "nsIDOMElement.h"
michael@0 32 #include "nsIDOMEventListener.h"
michael@0 33 #include "nsIDOMEventTarget.h"
michael@0 34 #include "nsIDOMNode.h"
michael@0 35 #include "nsDOMCSSRGBColor.h"
michael@0 36 #include "nsIDOMWindow.h"
michael@0 37 #include "nsIEditor.h"
michael@0 38 #include "nsIHTMLEditor.h"
michael@0 39 #include "nsIHTMLObjectResizer.h"
michael@0 40 #include "nsINode.h"
michael@0 41 #include "nsIPresShell.h"
michael@0 42 #include "nsISelection.h"
michael@0 43 #include "nsISupportsImpl.h"
michael@0 44 #include "nsISupportsUtils.h"
michael@0 45 #include "nsLiteralString.h"
michael@0 46 #include "nsReadableUtils.h"
michael@0 47 #include "nsString.h"
michael@0 48 #include "nsStringFwd.h"
michael@0 49 #include "nsTextEditRules.h"
michael@0 50 #include "nsTextEditUtils.h"
michael@0 51 #include "nscore.h"
michael@0 52 #include <algorithm>
michael@0 53
michael@0 54 using namespace mozilla;
michael@0 55 using namespace mozilla::dom;
michael@0 56
michael@0 57 #define BLACK_BG_RGB_TRIGGER 0xd0
michael@0 58
michael@0 59 NS_IMETHODIMP
michael@0 60 nsHTMLEditor::AbsolutePositionSelection(bool aEnabled)
michael@0 61 {
michael@0 62 nsAutoEditBatch beginBatching(this);
michael@0 63 nsAutoRules beginRulesSniffing(this,
michael@0 64 aEnabled ? EditAction::setAbsolutePosition :
michael@0 65 EditAction::removeAbsolutePosition,
michael@0 66 nsIEditor::eNext);
michael@0 67
michael@0 68 // the line below does not match the code; should it be removed?
michael@0 69 // Find out if the selection is collapsed:
michael@0 70 nsRefPtr<Selection> selection = GetSelection();
michael@0 71 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
michael@0 72
michael@0 73 nsTextRulesInfo ruleInfo(aEnabled ? EditAction::setAbsolutePosition :
michael@0 74 EditAction::removeAbsolutePosition);
michael@0 75 bool cancel, handled;
michael@0 76 // Protect the edit rules object from dying
michael@0 77 nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
michael@0 78 nsresult res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
michael@0 79 if (NS_FAILED(res) || cancel)
michael@0 80 return res;
michael@0 81
michael@0 82 return mRules->DidDoAction(selection, &ruleInfo, res);
michael@0 83 }
michael@0 84
michael@0 85 NS_IMETHODIMP
michael@0 86 nsHTMLEditor::GetAbsolutelyPositionedSelectionContainer(nsIDOMElement **_retval)
michael@0 87 {
michael@0 88 nsCOMPtr<nsIDOMElement> element;
michael@0 89 nsresult res = GetSelectionContainer(getter_AddRefs(element));
michael@0 90 NS_ENSURE_SUCCESS(res, res);
michael@0 91
michael@0 92 nsAutoString positionStr;
michael@0 93 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(element);
michael@0 94 nsCOMPtr<nsIDOMNode> resultNode;
michael@0 95
michael@0 96 while (!resultNode && node && !nsEditor::NodeIsType(node, nsEditProperty::html)) {
michael@0 97 res = mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssPosition,
michael@0 98 positionStr);
michael@0 99 NS_ENSURE_SUCCESS(res, res);
michael@0 100 if (positionStr.EqualsLiteral("absolute"))
michael@0 101 resultNode = node;
michael@0 102 else {
michael@0 103 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 104 res = node->GetParentNode(getter_AddRefs(parentNode));
michael@0 105 NS_ENSURE_SUCCESS(res, res);
michael@0 106 node.swap(parentNode);
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 element = do_QueryInterface(resultNode );
michael@0 111 *_retval = element;
michael@0 112 NS_IF_ADDREF(*_retval);
michael@0 113 return NS_OK;
michael@0 114 }
michael@0 115
michael@0 116 NS_IMETHODIMP
michael@0 117 nsHTMLEditor::GetSelectionContainerAbsolutelyPositioned(bool *aIsSelectionContainerAbsolutelyPositioned)
michael@0 118 {
michael@0 119 *aIsSelectionContainerAbsolutelyPositioned = (mAbsolutelyPositionedObject != nullptr);
michael@0 120 return NS_OK;
michael@0 121 }
michael@0 122
michael@0 123 NS_IMETHODIMP
michael@0 124 nsHTMLEditor::GetAbsolutePositioningEnabled(bool * aIsEnabled)
michael@0 125 {
michael@0 126 *aIsEnabled = mIsAbsolutelyPositioningEnabled;
michael@0 127 return NS_OK;
michael@0 128 }
michael@0 129
michael@0 130 NS_IMETHODIMP
michael@0 131 nsHTMLEditor::SetAbsolutePositioningEnabled(bool aIsEnabled)
michael@0 132 {
michael@0 133 mIsAbsolutelyPositioningEnabled = aIsEnabled;
michael@0 134 return NS_OK;
michael@0 135 }
michael@0 136
michael@0 137 NS_IMETHODIMP
michael@0 138 nsHTMLEditor::RelativeChangeElementZIndex(nsIDOMElement * aElement,
michael@0 139 int32_t aChange,
michael@0 140 int32_t * aReturn)
michael@0 141 {
michael@0 142 NS_ENSURE_ARG_POINTER(aElement);
michael@0 143 NS_ENSURE_ARG_POINTER(aReturn);
michael@0 144 if (!aChange) // early way out, no change
michael@0 145 return NS_OK;
michael@0 146
michael@0 147 int32_t zIndex;
michael@0 148 nsresult res = GetElementZIndex(aElement, &zIndex);
michael@0 149 NS_ENSURE_SUCCESS(res, res);
michael@0 150
michael@0 151 zIndex = std::max(zIndex + aChange, 0);
michael@0 152 SetElementZIndex(aElement, zIndex);
michael@0 153 *aReturn = zIndex;
michael@0 154
michael@0 155 return NS_OK;
michael@0 156 }
michael@0 157
michael@0 158 NS_IMETHODIMP
michael@0 159 nsHTMLEditor::SetElementZIndex(nsIDOMElement * aElement,
michael@0 160 int32_t aZindex)
michael@0 161 {
michael@0 162 NS_ENSURE_ARG_POINTER(aElement);
michael@0 163
michael@0 164 nsAutoString zIndexStr;
michael@0 165 zIndexStr.AppendInt(aZindex);
michael@0 166
michael@0 167 mHTMLCSSUtils->SetCSSProperty(aElement,
michael@0 168 nsEditProperty::cssZIndex,
michael@0 169 zIndexStr,
michael@0 170 false);
michael@0 171 return NS_OK;
michael@0 172 }
michael@0 173
michael@0 174 NS_IMETHODIMP
michael@0 175 nsHTMLEditor::RelativeChangeZIndex(int32_t aChange)
michael@0 176 {
michael@0 177 nsAutoEditBatch beginBatching(this);
michael@0 178 nsAutoRules beginRulesSniffing(this,
michael@0 179 (aChange < 0) ? EditAction::decreaseZIndex :
michael@0 180 EditAction::increaseZIndex,
michael@0 181 nsIEditor::eNext);
michael@0 182
michael@0 183 // brade: can we get rid of this comment?
michael@0 184 // Find out if the selection is collapsed:
michael@0 185 nsRefPtr<Selection> selection = GetSelection();
michael@0 186 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
michael@0 187 nsTextRulesInfo ruleInfo(aChange < 0 ? EditAction::decreaseZIndex :
michael@0 188 EditAction::increaseZIndex);
michael@0 189 bool cancel, handled;
michael@0 190 // Protect the edit rules object from dying
michael@0 191 nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
michael@0 192 nsresult res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
michael@0 193 if (cancel || NS_FAILED(res))
michael@0 194 return res;
michael@0 195
michael@0 196 return mRules->DidDoAction(selection, &ruleInfo, res);
michael@0 197 }
michael@0 198
michael@0 199 NS_IMETHODIMP
michael@0 200 nsHTMLEditor::GetElementZIndex(nsIDOMElement * aElement,
michael@0 201 int32_t * aZindex)
michael@0 202 {
michael@0 203 nsAutoString zIndexStr;
michael@0 204 *aZindex = 0;
michael@0 205
michael@0 206 nsresult res = mHTMLCSSUtils->GetSpecifiedProperty(aElement,
michael@0 207 nsEditProperty::cssZIndex,
michael@0 208 zIndexStr);
michael@0 209 NS_ENSURE_SUCCESS(res, res);
michael@0 210 if (zIndexStr.EqualsLiteral("auto")) {
michael@0 211 // we have to look at the positioned ancestors
michael@0 212 // cf. CSS 2 spec section 9.9.1
michael@0 213 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 214 res = aElement->GetParentNode(getter_AddRefs(parentNode));
michael@0 215 NS_ENSURE_SUCCESS(res, res);
michael@0 216 nsCOMPtr<nsIDOMNode> node = parentNode;
michael@0 217 nsAutoString positionStr;
michael@0 218 while (node &&
michael@0 219 zIndexStr.EqualsLiteral("auto") &&
michael@0 220 !nsTextEditUtils::IsBody(node)) {
michael@0 221 res = mHTMLCSSUtils->GetComputedProperty(node,
michael@0 222 nsEditProperty::cssPosition,
michael@0 223 positionStr);
michael@0 224 NS_ENSURE_SUCCESS(res, res);
michael@0 225 if (positionStr.EqualsLiteral("absolute")) {
michael@0 226 // ah, we found one, what's its z-index ? If its z-index is auto,
michael@0 227 // we have to continue climbing the document's tree
michael@0 228 res = mHTMLCSSUtils->GetComputedProperty(node,
michael@0 229 nsEditProperty::cssZIndex,
michael@0 230 zIndexStr);
michael@0 231 NS_ENSURE_SUCCESS(res, res);
michael@0 232 }
michael@0 233 res = node->GetParentNode(getter_AddRefs(parentNode));
michael@0 234 NS_ENSURE_SUCCESS(res, res);
michael@0 235 node = parentNode;
michael@0 236 }
michael@0 237 }
michael@0 238
michael@0 239 if (!zIndexStr.EqualsLiteral("auto")) {
michael@0 240 nsresult errorCode;
michael@0 241 *aZindex = zIndexStr.ToInteger(&errorCode);
michael@0 242 }
michael@0 243
michael@0 244 return NS_OK;
michael@0 245 }
michael@0 246
michael@0 247 nsresult
michael@0 248 nsHTMLEditor::CreateGrabber(nsIDOMNode * aParentNode, nsIDOMElement ** aReturn)
michael@0 249 {
michael@0 250 // let's create a grabber through the element factory
michael@0 251 nsresult res = CreateAnonymousElement(NS_LITERAL_STRING("span"),
michael@0 252 aParentNode,
michael@0 253 NS_LITERAL_STRING("mozGrabber"),
michael@0 254 false,
michael@0 255 aReturn);
michael@0 256
michael@0 257 NS_ENSURE_TRUE(*aReturn, NS_ERROR_FAILURE);
michael@0 258
michael@0 259 // add the mouse listener so we can detect a click on a resizer
michael@0 260 nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(*aReturn));
michael@0 261 evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"),
michael@0 262 mEventListener, false);
michael@0 263
michael@0 264 return res;
michael@0 265 }
michael@0 266
michael@0 267 NS_IMETHODIMP
michael@0 268 nsHTMLEditor::RefreshGrabber()
michael@0 269 {
michael@0 270 NS_ENSURE_TRUE(mAbsolutelyPositionedObject, NS_ERROR_NULL_POINTER);
michael@0 271
michael@0 272 nsresult res = GetPositionAndDimensions(mAbsolutelyPositionedObject,
michael@0 273 mPositionedObjectX,
michael@0 274 mPositionedObjectY,
michael@0 275 mPositionedObjectWidth,
michael@0 276 mPositionedObjectHeight,
michael@0 277 mPositionedObjectBorderLeft,
michael@0 278 mPositionedObjectBorderTop,
michael@0 279 mPositionedObjectMarginLeft,
michael@0 280 mPositionedObjectMarginTop);
michael@0 281
michael@0 282 NS_ENSURE_SUCCESS(res, res);
michael@0 283
michael@0 284 SetAnonymousElementPosition(mPositionedObjectX+12,
michael@0 285 mPositionedObjectY-14,
michael@0 286 mGrabber);
michael@0 287 return NS_OK;
michael@0 288 }
michael@0 289
michael@0 290 NS_IMETHODIMP
michael@0 291 nsHTMLEditor::HideGrabber()
michael@0 292 {
michael@0 293 nsresult res =
michael@0 294 mAbsolutelyPositionedObject->RemoveAttribute(NS_LITERAL_STRING("_moz_abspos"));
michael@0 295 NS_ENSURE_SUCCESS(res, res);
michael@0 296
michael@0 297 mAbsolutelyPositionedObject = nullptr;
michael@0 298 NS_ENSURE_TRUE(mGrabber, NS_ERROR_NULL_POINTER);
michael@0 299
michael@0 300 // get the presshell's document observer interface.
michael@0 301 nsCOMPtr<nsIPresShell> ps = GetPresShell();
michael@0 302 // We allow the pres shell to be null; when it is, we presume there
michael@0 303 // are no document observers to notify, but we still want to
michael@0 304 // UnbindFromTree.
michael@0 305
michael@0 306 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 307 res = mGrabber->GetParentNode(getter_AddRefs(parentNode));
michael@0 308 NS_ENSURE_SUCCESS(res, res);
michael@0 309
michael@0 310 nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parentNode);
michael@0 311 NS_ENSURE_TRUE(parentContent, NS_ERROR_NULL_POINTER);
michael@0 312
michael@0 313 DeleteRefToAnonymousNode(mGrabber, parentContent, ps);
michael@0 314 mGrabber = nullptr;
michael@0 315 DeleteRefToAnonymousNode(mPositioningShadow, parentContent, ps);
michael@0 316 mPositioningShadow = nullptr;
michael@0 317
michael@0 318 return NS_OK;
michael@0 319 }
michael@0 320
michael@0 321 NS_IMETHODIMP
michael@0 322 nsHTMLEditor::ShowGrabberOnElement(nsIDOMElement * aElement)
michael@0 323 {
michael@0 324 NS_ENSURE_ARG_POINTER(aElement);
michael@0 325
michael@0 326 if (mGrabber) {
michael@0 327 NS_ERROR("call HideGrabber first");
michael@0 328 return NS_ERROR_UNEXPECTED;
michael@0 329 }
michael@0 330
michael@0 331 nsAutoString classValue;
michael@0 332 nsresult res = CheckPositionedElementBGandFG(aElement, classValue);
michael@0 333 NS_ENSURE_SUCCESS(res, res);
michael@0 334
michael@0 335 res = aElement->SetAttribute(NS_LITERAL_STRING("_moz_abspos"),
michael@0 336 classValue);
michael@0 337 NS_ENSURE_SUCCESS(res, res);
michael@0 338
michael@0 339 // first, let's keep track of that element...
michael@0 340 mAbsolutelyPositionedObject = aElement;
michael@0 341
michael@0 342 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 343 res = aElement->GetParentNode(getter_AddRefs(parentNode));
michael@0 344 NS_ENSURE_SUCCESS(res, res);
michael@0 345
michael@0 346 res = CreateGrabber(parentNode, getter_AddRefs(mGrabber));
michael@0 347 NS_ENSURE_SUCCESS(res, res);
michael@0 348
michael@0 349 // and set its position
michael@0 350 return RefreshGrabber();
michael@0 351 }
michael@0 352
michael@0 353 nsresult
michael@0 354 nsHTMLEditor::StartMoving(nsIDOMElement *aHandle)
michael@0 355 {
michael@0 356 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 357 nsresult res = mGrabber->GetParentNode(getter_AddRefs(parentNode));
michael@0 358 NS_ENSURE_SUCCESS(res, res);
michael@0 359
michael@0 360 // now, let's create the resizing shadow
michael@0 361 res = CreateShadow(getter_AddRefs(mPositioningShadow),
michael@0 362 parentNode, mAbsolutelyPositionedObject);
michael@0 363 NS_ENSURE_SUCCESS(res,res);
michael@0 364 res = SetShadowPosition(mPositioningShadow, mAbsolutelyPositionedObject,
michael@0 365 mPositionedObjectX, mPositionedObjectY);
michael@0 366 NS_ENSURE_SUCCESS(res,res);
michael@0 367
michael@0 368 // make the shadow appear
michael@0 369 mPositioningShadow->RemoveAttribute(NS_LITERAL_STRING("class"));
michael@0 370
michael@0 371 // position it
michael@0 372 mHTMLCSSUtils->SetCSSPropertyPixels(mPositioningShadow,
michael@0 373 NS_LITERAL_STRING("width"),
michael@0 374 mPositionedObjectWidth);
michael@0 375 mHTMLCSSUtils->SetCSSPropertyPixels(mPositioningShadow,
michael@0 376 NS_LITERAL_STRING("height"),
michael@0 377 mPositionedObjectHeight);
michael@0 378
michael@0 379 mIsMoving = true;
michael@0 380 return res;
michael@0 381 }
michael@0 382
michael@0 383 void
michael@0 384 nsHTMLEditor::SnapToGrid(int32_t & newX, int32_t & newY)
michael@0 385 {
michael@0 386 if (mSnapToGridEnabled && mGridSize) {
michael@0 387 newX = (int32_t) floor( ((float)newX / (float)mGridSize) + 0.5f ) * mGridSize;
michael@0 388 newY = (int32_t) floor( ((float)newY / (float)mGridSize) + 0.5f ) * mGridSize;
michael@0 389 }
michael@0 390 }
michael@0 391
michael@0 392 nsresult
michael@0 393 nsHTMLEditor::GrabberClicked()
michael@0 394 {
michael@0 395 // add a mouse move listener to the editor
michael@0 396 nsresult res = NS_OK;
michael@0 397 if (!mMouseMotionListenerP) {
michael@0 398 mMouseMotionListenerP = new ResizerMouseMotionListener(this);
michael@0 399 if (!mMouseMotionListenerP) {return NS_ERROR_NULL_POINTER;}
michael@0 400
michael@0 401 nsCOMPtr<nsIDOMEventTarget> piTarget = GetDOMEventTarget();
michael@0 402 NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE);
michael@0 403
michael@0 404 res = piTarget->AddEventListener(NS_LITERAL_STRING("mousemove"),
michael@0 405 mMouseMotionListenerP,
michael@0 406 false, false);
michael@0 407 NS_ASSERTION(NS_SUCCEEDED(res),
michael@0 408 "failed to register mouse motion listener");
michael@0 409 }
michael@0 410 mGrabberClicked = true;
michael@0 411 return res;
michael@0 412 }
michael@0 413
michael@0 414 nsresult
michael@0 415 nsHTMLEditor::EndMoving()
michael@0 416 {
michael@0 417 if (mPositioningShadow) {
michael@0 418 nsCOMPtr<nsIPresShell> ps = GetPresShell();
michael@0 419 NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
michael@0 420
michael@0 421 nsCOMPtr<nsIDOMNode> parentNode;
michael@0 422 nsresult res = mGrabber->GetParentNode(getter_AddRefs(parentNode));
michael@0 423 NS_ENSURE_SUCCESS(res, res);
michael@0 424
michael@0 425 nsCOMPtr<nsIContent> parentContent( do_QueryInterface(parentNode) );
michael@0 426 NS_ENSURE_TRUE(parentContent, NS_ERROR_FAILURE);
michael@0 427
michael@0 428 DeleteRefToAnonymousNode(mPositioningShadow, parentContent, ps);
michael@0 429
michael@0 430 mPositioningShadow = nullptr;
michael@0 431 }
michael@0 432 nsCOMPtr<nsIDOMEventTarget> piTarget = GetDOMEventTarget();
michael@0 433
michael@0 434 if (piTarget && mMouseMotionListenerP) {
michael@0 435 #ifdef DEBUG
michael@0 436 nsresult res =
michael@0 437 #endif
michael@0 438 piTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
michael@0 439 mMouseMotionListenerP,
michael@0 440 false);
michael@0 441 NS_ASSERTION(NS_SUCCEEDED(res), "failed to remove mouse motion listener");
michael@0 442 }
michael@0 443 mMouseMotionListenerP = nullptr;
michael@0 444
michael@0 445 mGrabberClicked = false;
michael@0 446 mIsMoving = false;
michael@0 447 nsCOMPtr<nsISelection> selection;
michael@0 448 GetSelection(getter_AddRefs(selection));
michael@0 449 if (!selection) {
michael@0 450 return NS_ERROR_NOT_INITIALIZED;
michael@0 451 }
michael@0 452 return CheckSelectionStateForAnonymousButtons(selection);
michael@0 453 }
michael@0 454 nsresult
michael@0 455 nsHTMLEditor::SetFinalPosition(int32_t aX, int32_t aY)
michael@0 456 {
michael@0 457 nsresult res = EndMoving();
michael@0 458 NS_ENSURE_SUCCESS(res, res);
michael@0 459
michael@0 460 // we have now to set the new width and height of the resized object
michael@0 461 // we don't set the x and y position because we don't control that in
michael@0 462 // a normal HTML layout
michael@0 463 int32_t newX = mPositionedObjectX + aX - mOriginalX - (mPositionedObjectBorderLeft+mPositionedObjectMarginLeft);
michael@0 464 int32_t newY = mPositionedObjectY + aY - mOriginalY - (mPositionedObjectBorderTop+mPositionedObjectMarginTop);
michael@0 465
michael@0 466 SnapToGrid(newX, newY);
michael@0 467
michael@0 468 nsAutoString x, y;
michael@0 469 x.AppendInt(newX);
michael@0 470 y.AppendInt(newY);
michael@0 471
michael@0 472 // we want one transaction only from a user's point of view
michael@0 473 nsAutoEditBatch batchIt(this);
michael@0 474
michael@0 475 mHTMLCSSUtils->SetCSSPropertyPixels(mAbsolutelyPositionedObject,
michael@0 476 nsEditProperty::cssTop,
michael@0 477 newY,
michael@0 478 false);
michael@0 479 mHTMLCSSUtils->SetCSSPropertyPixels(mAbsolutelyPositionedObject,
michael@0 480 nsEditProperty::cssLeft,
michael@0 481 newX,
michael@0 482 false);
michael@0 483 // keep track of that size
michael@0 484 mPositionedObjectX = newX;
michael@0 485 mPositionedObjectY = newY;
michael@0 486
michael@0 487 return RefreshResizers();
michael@0 488 }
michael@0 489
michael@0 490 void
michael@0 491 nsHTMLEditor::AddPositioningOffset(int32_t & aX, int32_t & aY)
michael@0 492 {
michael@0 493 // Get the positioning offset
michael@0 494 int32_t positioningOffset =
michael@0 495 Preferences::GetInt("editor.positioning.offset", 0);
michael@0 496
michael@0 497 aX += positioningOffset;
michael@0 498 aY += positioningOffset;
michael@0 499 }
michael@0 500
michael@0 501 NS_IMETHODIMP
michael@0 502 nsHTMLEditor::AbsolutelyPositionElement(nsIDOMElement * aElement,
michael@0 503 bool aEnabled)
michael@0 504 {
michael@0 505 NS_ENSURE_ARG_POINTER(aElement);
michael@0 506
michael@0 507 nsAutoString positionStr;
michael@0 508 mHTMLCSSUtils->GetComputedProperty(aElement, nsEditProperty::cssPosition,
michael@0 509 positionStr);
michael@0 510 bool isPositioned = (positionStr.EqualsLiteral("absolute"));
michael@0 511
michael@0 512 // nothing to do if the element is already in the state we want
michael@0 513 if (isPositioned == aEnabled)
michael@0 514 return NS_OK;
michael@0 515
michael@0 516 nsAutoEditBatch batchIt(this);
michael@0 517
michael@0 518 if (aEnabled) {
michael@0 519 int32_t x, y;
michael@0 520 GetElementOrigin(aElement, x, y);
michael@0 521
michael@0 522 mHTMLCSSUtils->SetCSSProperty(aElement,
michael@0 523 nsEditProperty::cssPosition,
michael@0 524 NS_LITERAL_STRING("absolute"),
michael@0 525 false);
michael@0 526
michael@0 527 AddPositioningOffset(x, y);
michael@0 528 SnapToGrid(x, y);
michael@0 529 SetElementPosition(aElement, x, y);
michael@0 530
michael@0 531 // we may need to create a br if the positioned element is alone in its
michael@0 532 // container
michael@0 533 nsCOMPtr<nsINode> element = do_QueryInterface(aElement);
michael@0 534 NS_ENSURE_STATE(element);
michael@0 535
michael@0 536 nsINode* parentNode = element->GetParentNode();
michael@0 537 if (parentNode->GetChildCount() == 1) {
michael@0 538 nsCOMPtr<nsIDOMNode> brNode;
michael@0 539 nsresult res = CreateBR(parentNode->AsDOMNode(), 0, address_of(brNode));
michael@0 540 NS_ENSURE_SUCCESS(res, res);
michael@0 541 }
michael@0 542 }
michael@0 543 else {
michael@0 544 mHTMLCSSUtils->RemoveCSSProperty(aElement,
michael@0 545 nsEditProperty::cssPosition,
michael@0 546 EmptyString(), false);
michael@0 547 mHTMLCSSUtils->RemoveCSSProperty(aElement,
michael@0 548 nsEditProperty::cssTop,
michael@0 549 EmptyString(), false);
michael@0 550 mHTMLCSSUtils->RemoveCSSProperty(aElement,
michael@0 551 nsEditProperty::cssLeft,
michael@0 552 EmptyString(), false);
michael@0 553 mHTMLCSSUtils->RemoveCSSProperty(aElement,
michael@0 554 nsEditProperty::cssZIndex,
michael@0 555 EmptyString(), false);
michael@0 556
michael@0 557 if (!nsHTMLEditUtils::IsImage(aElement)) {
michael@0 558 mHTMLCSSUtils->RemoveCSSProperty(aElement,
michael@0 559 nsEditProperty::cssWidth,
michael@0 560 EmptyString(), false);
michael@0 561 mHTMLCSSUtils->RemoveCSSProperty(aElement,
michael@0 562 nsEditProperty::cssHeight,
michael@0 563 EmptyString(), false);
michael@0 564 }
michael@0 565
michael@0 566 nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
michael@0 567 if (element && element->IsHTML(nsGkAtoms::div) && !HasStyleOrIdOrClass(element)) {
michael@0 568 nsRefPtr<nsHTMLEditRules> htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
michael@0 569 NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
michael@0 570 nsresult res = htmlRules->MakeSureElemStartsOrEndsOnCR(aElement);
michael@0 571 NS_ENSURE_SUCCESS(res, res);
michael@0 572 res = RemoveContainer(aElement);
michael@0 573 NS_ENSURE_SUCCESS(res, res);
michael@0 574 }
michael@0 575 }
michael@0 576 return NS_OK;
michael@0 577 }
michael@0 578
michael@0 579 NS_IMETHODIMP
michael@0 580 nsHTMLEditor::SetSnapToGridEnabled(bool aEnabled)
michael@0 581 {
michael@0 582 mSnapToGridEnabled = aEnabled;
michael@0 583 return NS_OK;
michael@0 584 }
michael@0 585
michael@0 586 NS_IMETHODIMP
michael@0 587 nsHTMLEditor::GetSnapToGridEnabled(bool * aIsEnabled)
michael@0 588 {
michael@0 589 *aIsEnabled = mSnapToGridEnabled;
michael@0 590 return NS_OK;
michael@0 591 }
michael@0 592
michael@0 593 NS_IMETHODIMP
michael@0 594 nsHTMLEditor::SetGridSize(uint32_t aSize)
michael@0 595 {
michael@0 596 mGridSize = aSize;
michael@0 597 return NS_OK;
michael@0 598 }
michael@0 599
michael@0 600 NS_IMETHODIMP
michael@0 601 nsHTMLEditor::GetGridSize(uint32_t * aSize)
michael@0 602 {
michael@0 603 *aSize = mGridSize;
michael@0 604 return NS_OK;
michael@0 605 }
michael@0 606
michael@0 607 // self-explanatory
michael@0 608 NS_IMETHODIMP
michael@0 609 nsHTMLEditor::SetElementPosition(nsIDOMElement *aElement, int32_t aX, int32_t aY)
michael@0 610 {
michael@0 611 nsAutoEditBatch batchIt(this);
michael@0 612
michael@0 613 mHTMLCSSUtils->SetCSSPropertyPixels(aElement,
michael@0 614 nsEditProperty::cssLeft,
michael@0 615 aX,
michael@0 616 false);
michael@0 617 mHTMLCSSUtils->SetCSSPropertyPixels(aElement,
michael@0 618 nsEditProperty::cssTop,
michael@0 619 aY,
michael@0 620 false);
michael@0 621 return NS_OK;
michael@0 622 }
michael@0 623
michael@0 624 // self-explanatory
michael@0 625 NS_IMETHODIMP
michael@0 626 nsHTMLEditor::GetPositionedElement(nsIDOMElement ** aReturn)
michael@0 627 {
michael@0 628 *aReturn = mAbsolutelyPositionedObject;
michael@0 629 NS_IF_ADDREF(*aReturn);
michael@0 630 return NS_OK;
michael@0 631 }
michael@0 632
michael@0 633 nsresult
michael@0 634 nsHTMLEditor::CheckPositionedElementBGandFG(nsIDOMElement * aElement,
michael@0 635 nsAString & aReturn)
michael@0 636 {
michael@0 637 // we are going to outline the positioned element and bring it to the
michael@0 638 // front to overlap any other element intersecting with it. But
michael@0 639 // first, let's see what's the background and foreground colors of the
michael@0 640 // positioned element.
michael@0 641 // if background-image computed value is 'none,
michael@0 642 // If the background color is 'auto' and R G B values of the foreground are
michael@0 643 // each above #d0, use a black background
michael@0 644 // If the background color is 'auto' and at least one of R G B values of
michael@0 645 // the foreground is below #d0, use a white background
michael@0 646 // Otherwise don't change background/foreground
michael@0 647
michael@0 648 aReturn.Truncate();
michael@0 649
michael@0 650 nsAutoString bgImageStr;
michael@0 651 nsresult res =
michael@0 652 mHTMLCSSUtils->GetComputedProperty(aElement,
michael@0 653 nsEditProperty::cssBackgroundImage,
michael@0 654 bgImageStr);
michael@0 655 NS_ENSURE_SUCCESS(res, res);
michael@0 656 if (bgImageStr.EqualsLiteral("none")) {
michael@0 657 nsAutoString bgColorStr;
michael@0 658 res =
michael@0 659 mHTMLCSSUtils->GetComputedProperty(aElement,
michael@0 660 nsEditProperty::cssBackgroundColor,
michael@0 661 bgColorStr);
michael@0 662 NS_ENSURE_SUCCESS(res, res);
michael@0 663 if (bgColorStr.EqualsLiteral("transparent")) {
michael@0 664 nsRefPtr<nsComputedDOMStyle> cssDecl =
michael@0 665 mHTMLCSSUtils->GetComputedStyle(aElement);
michael@0 666 NS_ENSURE_STATE(cssDecl);
michael@0 667
michael@0 668 // from these declarations, get the one we want and that one only
michael@0 669 ErrorResult error;
michael@0 670 nsRefPtr<dom::CSSValue> cssVal = cssDecl->GetPropertyCSSValue(NS_LITERAL_STRING("color"), error);
michael@0 671 NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode());
michael@0 672
michael@0 673 nsROCSSPrimitiveValue* val = cssVal->AsPrimitiveValue();
michael@0 674 NS_ENSURE_TRUE(val, NS_ERROR_FAILURE);
michael@0 675
michael@0 676 if (nsIDOMCSSPrimitiveValue::CSS_RGBCOLOR == val->PrimitiveType()) {
michael@0 677 nsDOMCSSRGBColor* rgbVal = val->GetRGBColorValue(error);
michael@0 678 NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode());
michael@0 679 float r = rgbVal->Red()->
michael@0 680 GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error);
michael@0 681 NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode());
michael@0 682 float g = rgbVal->Green()->
michael@0 683 GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error);
michael@0 684 NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode());
michael@0 685 float b = rgbVal->Blue()->
michael@0 686 GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error);
michael@0 687 NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode());
michael@0 688 if (r >= BLACK_BG_RGB_TRIGGER &&
michael@0 689 g >= BLACK_BG_RGB_TRIGGER &&
michael@0 690 b >= BLACK_BG_RGB_TRIGGER)
michael@0 691 aReturn.AssignLiteral("black");
michael@0 692 else
michael@0 693 aReturn.AssignLiteral("white");
michael@0 694 return NS_OK;
michael@0 695 }
michael@0 696 }
michael@0 697 }
michael@0 698
michael@0 699 return NS_OK;
michael@0 700 }

mercurial