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