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