Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | } |