nsHTMLEditor::SetFinalSize]
- A one line fix in HideResizers() which prevents the
reported crash by setting mIsResizing to false. I assume
we can't be resizing if the resize handles are being hidden.
The assertion and null check in SetFinalSize() are just because
I'm paranoid, but they should never be triggered if HideResizers()
is called first.
- The changes in StartResizing() makes it so that we don't create
a new mouse motion listener if we already have one. We were
creating a new listener each time we clicked on the handles, and
never unregistering the old one ... this meant that the old
listeners could be triggered if the editor were ever destroyed
and the document left in tact ... allowing us to crash because the
listeners keep an un-addref'd pointer to the HTMLEditor. Note that
this crash is not likely to be hit in Mozilla since we always
destroy the document and editor in Composer and MailCompose, but
it can happen in an embedding context.
r=glazman@netscape.com sr=sfraser@netscape.com
git-svn-id: svn://10.0.0.236/trunk@140921 18797224-902f-48f8-a5cc-f745e15eee43
1135 lines
37 KiB
C++
1135 lines
37 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla.org.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corp.
|
|
* Portions created by the Initial Developer are Copyright (C) 2003
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Daniel Glazman (glazman@netscape.com) (Original author)
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "nsHTMLObjectResizer.h"
|
|
|
|
#include "nsIDOMEventTarget.h"
|
|
#include "nsIDOMNSHTMLElement.h"
|
|
#include "nsIDOMEventReceiver.h"
|
|
#include "nsIDOMText.h"
|
|
|
|
#include "nsIContent.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDocumentObserver.h"
|
|
#include "nsIEditor.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsHTMLEditor.h"
|
|
#include "nsEditor.h"
|
|
#include "nsEditorUtils.h"
|
|
#include "nsHTMLEditUtils.h"
|
|
|
|
#include "nsPoint.h"
|
|
|
|
class nsHTMLEditUtils;
|
|
|
|
// ==================================================================
|
|
// ResizeEventListener
|
|
// ==================================================================
|
|
NS_IMPL_ADDREF(ResizeEventListener)
|
|
NS_IMPL_RELEASE(ResizeEventListener)
|
|
|
|
NS_INTERFACE_MAP_BEGIN(ResizeEventListener)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
ResizeEventListener::ResizeEventListener(nsIHTMLEditor * aEditor) :
|
|
mEditor(aEditor)
|
|
{
|
|
}
|
|
|
|
ResizeEventListener::~ResizeEventListener()
|
|
{
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ResizeEventListener::HandleEvent(nsIDOMEvent* aMouseEvent)
|
|
{
|
|
nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(mEditor);
|
|
objectResizer->RefreshResizers();
|
|
return NS_OK;
|
|
}
|
|
|
|
// ==================================================================
|
|
// ResizerSelectionListener
|
|
// ==================================================================
|
|
|
|
NS_IMPL_ADDREF(ResizerSelectionListener)
|
|
NS_IMPL_RELEASE(ResizerSelectionListener)
|
|
|
|
NS_INTERFACE_MAP_BEGIN(ResizerSelectionListener)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
ResizerSelectionListener::ResizerSelectionListener(nsIHTMLEditor * aEditor) :
|
|
mEditor(aEditor)
|
|
{
|
|
}
|
|
|
|
ResizerSelectionListener::~ResizerSelectionListener()
|
|
{
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ResizerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *aSelection,short aReason)
|
|
{
|
|
if ((aReason & (nsISelectionListener::MOUSEDOWN_REASON |
|
|
nsISelectionListener::KEYPRESS_REASON |
|
|
nsISelectionListener::SELECTALL_REASON)) && aSelection) {
|
|
// the selection changed and we need to check if we have to
|
|
// hide and/or redisplay resizing handles
|
|
nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(mEditor);
|
|
objectResizer->CheckResizingState(aSelection);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// ==================================================================
|
|
// ResizerMouseMotionListener
|
|
// ==================================================================
|
|
|
|
NS_IMPL_ADDREF(ResizerMouseMotionListener)
|
|
|
|
NS_IMPL_RELEASE(ResizerMouseMotionListener)
|
|
|
|
ResizerMouseMotionListener::ResizerMouseMotionListener(nsIHTMLEditor * aEditor):
|
|
mEditor(aEditor)
|
|
{
|
|
}
|
|
|
|
ResizerMouseMotionListener::~ResizerMouseMotionListener()
|
|
{
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
ResizerMouseMotionListener::MouseMove(nsIDOMEvent* aMouseEvent)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aMouseEvent);
|
|
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
|
|
if (!mouseEvent) {
|
|
//non-ui event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
// Don't do anything special if not an HTML editor
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
{
|
|
// check if we have to redisplay a resizing shadow
|
|
nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(htmlEditor);
|
|
objectResizer->MouseMove(aMouseEvent);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ResizerMouseMotionListener::HandleEvent(nsIDOMEvent* aMouseEvent)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ResizerMouseMotionListener::DragMove(nsIDOMEvent* aMouseEvent)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_INTERFACE_MAP_BEGIN(ResizerMouseMotionListener)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
// ==================================================================
|
|
// nsHTMLEditor
|
|
// ==================================================================
|
|
|
|
nsresult
|
|
nsHTMLEditor::CreateResizer(nsIDOMElement ** aReturn, PRInt16 aLocation, nsISupportsArray * aArray)
|
|
{
|
|
// let's create a span through the element factory
|
|
nsCOMPtr<nsIContent> newContent;
|
|
nsresult res = CreateHTMLContent(NS_LITERAL_STRING("span"), getter_AddRefs(newContent));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent);
|
|
if (!newElement)
|
|
return NS_ERROR_FAILURE;
|
|
*aReturn = newElement;
|
|
NS_ADDREF(*aReturn);
|
|
|
|
// add the mouse listener so we can detect a click on a resizer
|
|
nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(*aReturn));
|
|
evtTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMouseListenerP, PR_TRUE);
|
|
|
|
nsAutoString locationStr;
|
|
switch (aLocation) {
|
|
case nsIHTMLObjectResizer::eTopLeft:
|
|
locationStr = kTopLeft;
|
|
break;
|
|
case nsIHTMLObjectResizer::eTop:
|
|
locationStr = kTop;
|
|
break;
|
|
case nsIHTMLObjectResizer::eTopRight:
|
|
locationStr = kTopRight;
|
|
break;
|
|
|
|
case nsIHTMLObjectResizer::eLeft:
|
|
locationStr = kLeft;
|
|
break;
|
|
case nsIHTMLObjectResizer::eRight:
|
|
locationStr = kRight;
|
|
break;
|
|
|
|
case nsIHTMLObjectResizer::eBottomLeft:
|
|
locationStr = kBottomLeft;
|
|
break;
|
|
case nsIHTMLObjectResizer::eBottom:
|
|
locationStr = kBottom;
|
|
break;
|
|
case nsIHTMLObjectResizer::eBottomRight:
|
|
locationStr = kBottomRight;
|
|
break;
|
|
}
|
|
|
|
|
|
res = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"),
|
|
NS_LITERAL_STRING("mozResizer"));
|
|
if (NS_FAILED(res)) return res;
|
|
res = newElement->SetAttribute(NS_LITERAL_STRING("anonlocation"),
|
|
locationStr);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
return aArray->AppendElement(newContent);
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLEditor::CreateShadow(nsIDOMElement ** aReturn, nsISupportsArray * aArray)
|
|
{
|
|
// let's create an image through the element factory
|
|
nsCOMPtr<nsIContent> newContent;
|
|
nsAutoString name;
|
|
if (NodeIsType(mResizedObject, NS_LITERAL_STRING("img")))
|
|
name = NS_LITERAL_STRING("img");
|
|
else
|
|
name = NS_LITERAL_STRING("span");
|
|
nsresult res = CreateHTMLContent(name, getter_AddRefs(newContent));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent);
|
|
if (!newElement)
|
|
return NS_ERROR_FAILURE;
|
|
*aReturn = newElement;
|
|
NS_ADDREF(*aReturn);
|
|
|
|
return aArray->AppendElement(newContent);
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLEditor::CreateResizingInfo(nsIDOMElement ** aReturn, nsISupportsArray * aArray)
|
|
{
|
|
// let's create an image through the element factory
|
|
nsCOMPtr<nsIContent> newContent;
|
|
nsresult res = CreateHTMLContent(NS_LITERAL_STRING("span"), getter_AddRefs(newContent));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent);
|
|
if (NS_FAILED(res) || !newElement)
|
|
return NS_ERROR_FAILURE;
|
|
*aReturn = newElement;
|
|
NS_ADDREF(*aReturn);
|
|
|
|
res = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"),
|
|
NS_LITERAL_STRING("mozResizingInfo"));
|
|
if (NS_FAILED(res)) return res;
|
|
res = newElement->SetAttribute(NS_LITERAL_STRING("class"),
|
|
NS_LITERAL_STRING("hidden"));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
return aArray->AppendElement(newContent);
|
|
}
|
|
|
|
void
|
|
nsHTMLEditor::SetResizerPosition(PRInt32 aX, PRInt32 aY, nsIDOMElement *aResizer)
|
|
{
|
|
nsAutoString x, y;
|
|
x.AppendInt(aX);
|
|
y.AppendInt(aY);
|
|
|
|
mHTMLCSSUtils->SetCSSProperty(aResizer,
|
|
nsIEditProperty::cssLeft,
|
|
x + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(aResizer,
|
|
nsIEditProperty::cssTop,
|
|
y + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLEditor::SetAllResizersPosition(nsIDOMElement * aResizedElement, PRInt32 & aX, PRInt32 & aY)
|
|
{
|
|
nsCOMPtr<nsIDOMNSHTMLElement> nsElement = do_QueryInterface(aResizedElement);
|
|
if (!nsElement) {return NS_ERROR_NULL_POINTER; }
|
|
|
|
GetElementOrigin(aResizedElement, aX, aY);
|
|
|
|
mResizedObjectX = aX;
|
|
mResizedObjectY = aY;
|
|
|
|
nsresult res = nsElement->GetOffsetWidth(&mResizedObjectWidth );
|
|
if (NS_FAILED(res)) return res;
|
|
res = nsElement->GetOffsetHeight(&mResizedObjectHeight);
|
|
if (NS_FAILED(res)) return res;
|
|
PRInt32 w = mResizedObjectWidth;
|
|
PRInt32 h = mResizedObjectHeight;
|
|
|
|
// now let's place all the resizers around the image
|
|
SetResizerPosition(aX-4, aY-4, mTopLeftHandle);
|
|
SetResizerPosition(aX+w/2-3, aY-4, mTopHandle);
|
|
SetResizerPosition(aX+w-2, aY-4, mTopRightHandle);
|
|
|
|
SetResizerPosition(aX-4, aY+h/2-3, mLeftHandle);
|
|
SetResizerPosition(aX+w-2, aY+h/2-3, mRightHandle);
|
|
|
|
SetResizerPosition(aX-4, aY+h-2, mBottomLeftHandle);
|
|
SetResizerPosition(aX+w/2-3, aY+h-2, mBottomHandle);
|
|
SetResizerPosition(aX+w-2, aY+h-2, mBottomRightHandle);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::RefreshResizers()
|
|
{
|
|
PRInt32 x, y;
|
|
nsresult res = SetAllResizersPosition(mResizedObject, x, y);
|
|
if (NS_FAILED(res)) return res;
|
|
return SetShadowPosition(mResizedObject, x, y);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::ShowResizers(nsIDOMElement *aResizedElement)
|
|
{
|
|
// we are going to need the PresShell
|
|
if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsISupportsArray> anonymousItems;
|
|
NS_NewISupportsArray(getter_AddRefs(anonymousItems));
|
|
if (!anonymousItems) return NS_ERROR_NULL_POINTER;
|
|
|
|
mResizedObject = aResizedElement;
|
|
|
|
// the resizers and the shadow will be anonymous children of the body
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIContent> bodyContent( do_QueryInterface(bodyElement) );
|
|
|
|
// let's create the resizers
|
|
res = CreateResizer(getter_AddRefs(mTopLeftHandle),
|
|
nsIHTMLObjectResizer::eTopLeft, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
res = CreateResizer(getter_AddRefs(mTopHandle),
|
|
nsIHTMLObjectResizer::eTop, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
res = CreateResizer(getter_AddRefs(mTopRightHandle),
|
|
nsIHTMLObjectResizer::eTopRight, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = CreateResizer(getter_AddRefs(mLeftHandle),
|
|
nsIHTMLObjectResizer::eLeft, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
res = CreateResizer(getter_AddRefs(mRightHandle),
|
|
nsIHTMLObjectResizer::eRight, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = CreateResizer(getter_AddRefs(mBottomLeftHandle),
|
|
nsIHTMLObjectResizer::eBottomLeft, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
res = CreateResizer(getter_AddRefs(mBottomHandle),
|
|
nsIHTMLObjectResizer::eBottom, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
res = CreateResizer(getter_AddRefs(mBottomRightHandle),
|
|
nsIHTMLObjectResizer::eBottomRight, anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// and let's set their absolute positions in the document
|
|
PRInt32 x, y;
|
|
res = SetAllResizersPosition(aResizedElement, x, y);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// now, let's create the resizing shadow
|
|
res = CreateShadow(getter_AddRefs(mResizingShadow), anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
// and set its position
|
|
res = SetShadowPosition(aResizedElement, x, y);
|
|
if (NS_FAILED(res)) return res;
|
|
mResizingShadow->SetAttribute(NS_LITERAL_STRING("class"),
|
|
NS_LITERAL_STRING("hidden"));
|
|
|
|
|
|
// and then the resizing info tooltip
|
|
res = CreateResizingInfo(getter_AddRefs(mResizingInfo), anonymousItems);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
PRUint32 count = 0;
|
|
anonymousItems->Count(&count);
|
|
|
|
// we are going to need the document too
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
GetDocument(getter_AddRefs(domDoc));
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
|
if (!doc) return NS_ERROR_NULL_POINTER;
|
|
|
|
for (PRUint32 i=0; i < count; i++) {
|
|
// for each anonymous node we created, set what's needed to make it work
|
|
// and create its frames
|
|
nsCOMPtr<nsIContent> content;
|
|
if (NS_FAILED(anonymousItems->QueryElementAt(i, NS_GET_IID(nsIContent), getter_AddRefs(content))))
|
|
continue;
|
|
|
|
content->SetNativeAnonymous(PR_TRUE);
|
|
content->SetParent(bodyContent);
|
|
content->SetDocument(doc, PR_TRUE, PR_TRUE);
|
|
content->SetBindingParent(content);
|
|
ps->RecreateFramesFor(content);
|
|
}
|
|
|
|
// and listen to the "resize" event on the window
|
|
// first, get the script global object from the document...
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
|
res = doc->GetScriptGlobalObject(getter_AddRefs(global));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!global) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
mResizeEventListenerP = new ResizeEventListener(this);
|
|
if (!mResizeEventListenerP) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(global);
|
|
res = target->AddEventListener(NS_LITERAL_STRING("resize"), mResizeEventListenerP, PR_FALSE);
|
|
|
|
return res;
|
|
}
|
|
|
|
void
|
|
nsHTMLEditor::DeleteRefToAnonymousNode(nsIDOMElement* aElement,
|
|
nsIContent * aParentContent,
|
|
nsIDocumentObserver * aDocObserver)
|
|
{
|
|
// call ContentRemoved() for the anonymous content
|
|
// node so its references get removed from the frame manager's
|
|
// undisplay map, and its layout frames get destroyed!
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
|
if (content) {
|
|
aDocObserver->ContentRemoved(nsnull, aParentContent, content, -1);
|
|
content->SetDocument(nsnull, PR_TRUE, PR_TRUE);
|
|
content->SetParent(nsnull);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::HideResizers(void)
|
|
{
|
|
if (!mIsShowingResizeHandles || !mResizedObject)
|
|
return NS_OK;
|
|
|
|
// get the presshell's document observer interface.
|
|
|
|
if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIDocumentObserver> docObserver(do_QueryInterface(ps));
|
|
if (!docObserver) return NS_ERROR_FAILURE;
|
|
|
|
// get the root content node.
|
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
|
nsresult res = nsEditor::GetRootElement(getter_AddRefs(bodyElement));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIContent> bodyContent( do_QueryInterface(bodyElement) );
|
|
if (!bodyContent) return NS_ERROR_FAILURE;
|
|
|
|
DeleteRefToAnonymousNode(mTopLeftHandle, bodyContent, docObserver);
|
|
mTopLeftHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mTopHandle, bodyContent, docObserver);
|
|
mTopHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mTopRightHandle, bodyContent, docObserver);
|
|
mTopRightHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mLeftHandle, bodyContent, docObserver);
|
|
mLeftHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mRightHandle, bodyContent, docObserver);
|
|
mRightHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mBottomLeftHandle, bodyContent, docObserver);
|
|
mBottomLeftHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mBottomHandle, bodyContent, docObserver);
|
|
mBottomHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mBottomRightHandle, bodyContent, docObserver);
|
|
mBottomRightHandle = nsnull;
|
|
DeleteRefToAnonymousNode(mResizingShadow, bodyContent, docObserver);
|
|
mResizingShadow = nsnull;
|
|
DeleteRefToAnonymousNode(mResizingInfo, bodyContent, docObserver);
|
|
mResizingInfo = nsnull;
|
|
|
|
// don't forget to remove the listeners !
|
|
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
|
res = GetDOMEventReceiver(getter_AddRefs(erP));
|
|
|
|
if (NS_SUCCEEDED(res) && erP && mMouseMotionListenerP)
|
|
{
|
|
res = erP->RemoveEventListener(NS_LITERAL_STRING("mousemove"), mMouseMotionListenerP, PR_TRUE);
|
|
NS_ASSERTION(NS_SUCCEEDED(res), "failed to remove mouse motion listener");
|
|
}
|
|
mMouseMotionListenerP = nsnull;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
GetDocument(getter_AddRefs(domDoc));
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
|
if (!doc) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
|
res = doc->GetScriptGlobalObject(getter_AddRefs(global));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!global) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(global);
|
|
if (target && mResizeEventListenerP) {
|
|
res = target->RemoveEventListener(NS_LITERAL_STRING("resize"), mResizeEventListenerP, PR_FALSE);
|
|
NS_ASSERTION(NS_SUCCEEDED(res), "failed to remove resize event listener");
|
|
}
|
|
mResizeEventListenerP = nsnull;
|
|
|
|
mIsShowingResizeHandles = PR_FALSE;
|
|
mResizedObject = nsnull;
|
|
mIsResizing = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsHTMLEditor::HideShadowAndInfo()
|
|
{
|
|
if (mResizingShadow)
|
|
mResizingShadow->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden"));
|
|
if (mResizingInfo)
|
|
mResizingInfo->SetAttribute(NS_LITERAL_STRING("class"), NS_LITERAL_STRING("hidden"));
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLEditor::StartResizing(nsIDOMElement *aHandle)
|
|
{
|
|
mIsResizing = PR_TRUE;
|
|
|
|
// the way we change the position/size of the shadow depends on
|
|
// the handle
|
|
nsAutoString locationStr;
|
|
aHandle->GetAttribute(NS_LITERAL_STRING("anonlocation"), locationStr);
|
|
if (locationStr.Equals(kTopLeft))
|
|
SetResizeIncrements(1, 1, -1, -1, PR_TRUE);
|
|
else if (locationStr.Equals(kTop))
|
|
SetResizeIncrements(0, 1, 0, -1, PR_FALSE);
|
|
else if (locationStr.Equals(kTopRight))
|
|
SetResizeIncrements(0, 1, 1, -1, PR_TRUE);
|
|
else if (locationStr.Equals(kLeft))
|
|
SetResizeIncrements(1, 0, -1, 0, PR_FALSE);
|
|
else if (locationStr.Equals(kRight))
|
|
SetResizeIncrements(0, 0, 1, 0, PR_FALSE);
|
|
else if (locationStr.Equals(kBottomLeft))
|
|
SetResizeIncrements(1, 0, -1, 1, PR_TRUE);
|
|
else if (locationStr.Equals(kBottom))
|
|
SetResizeIncrements(0, 0, 0, 1, PR_FALSE);
|
|
else if (locationStr.Equals(kBottomRight))
|
|
SetResizeIncrements(0, 0, 1, 1, PR_TRUE);
|
|
|
|
// make the shadow appear
|
|
mResizingShadow->RemoveAttribute(NS_LITERAL_STRING("class"));
|
|
|
|
// position it
|
|
nsAutoString w, h;
|
|
w.AppendInt(mResizedObjectWidth);
|
|
h.AppendInt(mResizedObjectHeight);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssWidth,
|
|
w + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssHeight,
|
|
h + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (!mMouseMotionListenerP)
|
|
{
|
|
// add a mouse move listener to the editor
|
|
mMouseMotionListenerP = new ResizerMouseMotionListener(this);
|
|
if (!mMouseMotionListenerP) {return NS_ERROR_NULL_POINTER;}
|
|
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
|
result = GetDOMEventReceiver(getter_AddRefs(erP));
|
|
if (NS_SUCCEEDED(result) && erP)
|
|
{
|
|
result = erP->AddEventListener(NS_LITERAL_STRING("mousemove"), mMouseMotionListenerP, PR_TRUE);
|
|
NS_ASSERTION(NS_SUCCEEDED(result), "failed to register mouse motion listener");
|
|
}
|
|
else
|
|
HandleEventListenerError();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::MouseDown(PRInt32 aClientX, PRInt32 aClientY,
|
|
nsIDOMElement *aTarget)
|
|
{
|
|
PRBool anonElement = PR_FALSE;
|
|
if (aTarget && NS_SUCCEEDED(aTarget->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement)))
|
|
// we caught a click on an anonymous element
|
|
if (anonElement) {
|
|
nsAutoString anonclass;
|
|
nsresult res = aTarget->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass);
|
|
if (NS_FAILED(res)) return res;
|
|
if (anonclass.Equals(NS_LITERAL_STRING("mozResizer"))) {
|
|
// and that element is a resizer, let's start resizing!
|
|
mOriginalX = aClientX;
|
|
mOriginalY = aClientY;
|
|
res = StartResizing(aTarget);
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::MouseUp(PRInt32 aClientX, PRInt32 aClientY,
|
|
nsIDOMElement *aResizedObject)
|
|
{
|
|
if (mIsResizing) {
|
|
// we are resizing and release the mouse button, so let's
|
|
// end the resizing process
|
|
mIsResizing = PR_FALSE;
|
|
HideShadowAndInfo();
|
|
SetFinalSize(aClientX, aClientY);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
void
|
|
nsHTMLEditor::SetResizeIncrements(PRInt32 aX, PRInt32 aY,
|
|
PRInt32 aW, PRInt32 aH,
|
|
PRBool aPreserveRatio)
|
|
{
|
|
mXIncrementFactor = aX;
|
|
mYIncrementFactor = aY;
|
|
mWidthIncrementFactor = aW;
|
|
mHeightIncrementFactor = aH;
|
|
mPreserveRatio = aPreserveRatio;
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLEditor::SetResizingInfoPosition(PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt32 aH)
|
|
{
|
|
nsAutoString x, y;
|
|
x.AppendInt(aX + 20);
|
|
y.AppendInt(aY + 20);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingInfo,
|
|
nsIEditProperty::cssLeft,
|
|
x + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingInfo,
|
|
nsIEditProperty::cssTop,
|
|
y + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
|
|
nsCOMPtr<nsIDOMNode> textInfo;
|
|
nsresult res = mResizingInfo->GetFirstChild(getter_AddRefs(textInfo));
|
|
if (NS_FAILED(res)) return res;
|
|
nsCOMPtr<nsIDOMNode> junk;
|
|
if (textInfo) {
|
|
res = mResizingInfo->RemoveChild(textInfo, getter_AddRefs(junk));
|
|
if (NS_FAILED(res)) return res;
|
|
textInfo = nsnull;
|
|
junk = nsnull;
|
|
}
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
GetDocument(getter_AddRefs(domDoc));
|
|
|
|
nsAutoString widthStr, heightStr, diffWidthStr, diffHeightStr;
|
|
widthStr.AppendInt(aW);
|
|
heightStr.AppendInt(aH);
|
|
PRInt32 diffWidth = aW - mResizedObjectWidth;
|
|
PRInt32 diffHeight = aH - mResizedObjectHeight;
|
|
if (diffWidth > 0)
|
|
diffWidthStr = NS_LITERAL_STRING("+");
|
|
if (diffHeight > 0)
|
|
diffHeightStr = NS_LITERAL_STRING("+");
|
|
diffWidthStr.AppendInt(diffWidth);
|
|
diffHeightStr.AppendInt(diffHeight);
|
|
|
|
nsAutoString info(widthStr + NS_LITERAL_STRING(" x ") + heightStr +
|
|
NS_LITERAL_STRING(" (") + diffWidthStr +
|
|
NS_LITERAL_STRING(", ") + diffHeightStr +
|
|
NS_LITERAL_STRING(")"));
|
|
|
|
nsCOMPtr<nsIDOMText> nodeAsText;
|
|
res = domDoc->CreateTextNode(info, getter_AddRefs(nodeAsText));
|
|
if (NS_FAILED(res)) return res;
|
|
textInfo = do_QueryInterface(nodeAsText);
|
|
res = mResizingInfo->AppendChild(textInfo, getter_AddRefs(junk));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
PRBool hasClass = PR_FALSE;
|
|
if (NS_SUCCEEDED(mResizingInfo->HasAttribute(NS_LITERAL_STRING("class"), &hasClass )) && hasClass)
|
|
res = mResizingInfo->RemoveAttribute(NS_LITERAL_STRING("class"));
|
|
|
|
return res;
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLEditor::SetShadowPosition(nsIDOMElement *aResizedObject,
|
|
PRInt32 aX, PRInt32 aY)
|
|
{
|
|
nsAutoString x, y;
|
|
x.AppendInt(aX);
|
|
y.AppendInt(aY);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssLeft,
|
|
x + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssTop,
|
|
y + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
|
|
if(NodeIsType(mResizedObject, NS_LITERAL_STRING("img"))) {
|
|
nsAutoString imageSource;
|
|
nsresult res = aResizedObject->GetAttribute(NS_LITERAL_STRING("src"),
|
|
imageSource);
|
|
if (NS_FAILED(res)) return res;
|
|
res = mResizingShadow->SetAttribute(NS_LITERAL_STRING("src"), imageSource);
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
return mResizingShadow->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"),
|
|
NS_LITERAL_STRING("mozResizingShadow"));
|
|
}
|
|
|
|
PRInt32
|
|
nsHTMLEditor::GetNewResizingIncrement(PRInt32 aX, PRInt32 aY, PRInt32 aID)
|
|
{
|
|
PRInt32 result = 0;
|
|
if (!mPreserveRatio) {
|
|
switch (aID) {
|
|
case kX:
|
|
case kWidth:
|
|
result = aX - mOriginalX;
|
|
break;
|
|
case kY:
|
|
case kHeight:
|
|
result = aY - mOriginalY;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PRInt32 xi = (aX - mOriginalX) * mWidthIncrementFactor;
|
|
PRInt32 yi = (aY - mOriginalY) * mHeightIncrementFactor;
|
|
float objectSizeRatio =
|
|
((float)mResizedObjectWidth) / ((float)mResizedObjectHeight);
|
|
result = (xi > yi) ? xi : yi;
|
|
switch (aID) {
|
|
case kX:
|
|
case kWidth:
|
|
if (result == yi)
|
|
result *= objectSizeRatio;
|
|
result *= mWidthIncrementFactor;
|
|
break;
|
|
case kY:
|
|
case kHeight:
|
|
if (result == xi)
|
|
result /= objectSizeRatio;
|
|
result *= mHeightIncrementFactor;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PRInt32
|
|
nsHTMLEditor::GetNewResizingX(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
PRInt32 resized = mResizedObjectX +
|
|
GetNewResizingIncrement(aX, aY, kX) * mXIncrementFactor;
|
|
PRInt32 max = mResizedObjectX + mResizedObjectWidth;
|
|
return PR_MIN(resized, max);
|
|
}
|
|
|
|
PRInt32
|
|
nsHTMLEditor::GetNewResizingY(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
PRInt32 resized = mResizedObjectY +
|
|
GetNewResizingIncrement(aX, aY, kY) * mYIncrementFactor;
|
|
PRInt32 max = mResizedObjectY + mResizedObjectHeight;
|
|
return PR_MIN(resized, max);
|
|
}
|
|
|
|
PRInt32
|
|
nsHTMLEditor::GetNewResizingWidth(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
PRInt32 resized = mResizedObjectWidth +
|
|
GetNewResizingIncrement(aX, aY, kWidth) *
|
|
mWidthIncrementFactor;
|
|
return PR_MAX(resized, 1);
|
|
}
|
|
|
|
PRInt32
|
|
nsHTMLEditor::GetNewResizingHeight(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
PRInt32 resized = mResizedObjectHeight +
|
|
GetNewResizingIncrement(aX, aY, kHeight) *
|
|
mHeightIncrementFactor;
|
|
return PR_MAX(resized, 1);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::MouseMove(nsIDOMEvent* aMouseEvent)
|
|
{
|
|
if (mIsResizing) {
|
|
// we are resizing and the mouse pointer's position has changed
|
|
// we have to resdisplay the shadow
|
|
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
|
|
PRInt32 clientX, clientY;
|
|
mouseEvent->GetClientX(&clientX);
|
|
mouseEvent->GetClientY(&clientY);
|
|
|
|
nsAutoString x, y, w, h;
|
|
PRInt32 newWidth = GetNewResizingWidth(clientX, clientY);
|
|
PRInt32 newHeight = GetNewResizingHeight(clientX, clientY);
|
|
x.AppendInt(GetNewResizingX(clientX, clientY));
|
|
y.AppendInt(GetNewResizingY(clientX, clientY));
|
|
w.AppendInt(newWidth);
|
|
h.AppendInt(newHeight);
|
|
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssLeft,
|
|
x + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssTop,
|
|
y + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssWidth,
|
|
w + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizingShadow,
|
|
nsIEditProperty::cssHeight,
|
|
h + NS_LITERAL_STRING("px"),
|
|
PR_TRUE);
|
|
|
|
SetResizingInfoPosition(clientX, clientY, newWidth, newHeight);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsHTMLEditor::SetFinalSize(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
NS_ASSERTION(mResizedObject, "SetFinalSize() called with null mResizedObject ptr!");
|
|
if (!mResizedObject) return;
|
|
|
|
// we have now to set the new width and height of the resized object
|
|
// we don't set the x and y position because we don't control that in
|
|
// a normal HTML layout
|
|
PRInt32 width = GetNewResizingWidth(aX, aY);
|
|
PRInt32 height = GetNewResizingHeight(aX, aY);
|
|
nsAutoString w, h;
|
|
w.AppendInt(width);
|
|
h.AppendInt(height);
|
|
// keep track of that size
|
|
mResizedObjectWidth = width;
|
|
mResizedObjectHeight = height;
|
|
|
|
// we need to know if we're in a CSS-enabled editor or not
|
|
PRBool useCSS;
|
|
GetIsCSSEnabled(&useCSS);
|
|
|
|
// we want one transaction only from a user's point of view
|
|
nsAutoEditBatch batchIt(this);
|
|
|
|
NS_NAMED_LITERAL_STRING(widthStr, "width");
|
|
NS_NAMED_LITERAL_STRING(heightStr, "height");
|
|
|
|
PRBool hasAttr = PR_FALSE;
|
|
if (useCSS) {
|
|
if (NS_SUCCEEDED(mResizedObject->HasAttribute(widthStr, &hasAttr)) && hasAttr)
|
|
RemoveAttribute(mResizedObject, widthStr);
|
|
|
|
hasAttr = PR_FALSE;
|
|
if (NS_SUCCEEDED(mResizedObject->HasAttribute(heightStr, &hasAttr)) && hasAttr)
|
|
RemoveAttribute(mResizedObject, heightStr);
|
|
|
|
mHTMLCSSUtils->SetCSSProperty(mResizedObject,
|
|
nsIEditProperty::cssWidth,
|
|
w + NS_LITERAL_STRING("px"),
|
|
PR_FALSE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizedObject,
|
|
nsIEditProperty::cssHeight,
|
|
h + NS_LITERAL_STRING("px"),
|
|
PR_FALSE);
|
|
}
|
|
else {
|
|
// we use HTML size and remove all equivalent CSS properties
|
|
|
|
// we set the CSS width and height to remove it later,
|
|
// triggering an immediate reflow; otherwise, we have problems
|
|
// with asynchronous reflow
|
|
mHTMLCSSUtils->SetCSSProperty(mResizedObject,
|
|
nsIEditProperty::cssWidth,
|
|
w + NS_LITERAL_STRING("px"),
|
|
PR_FALSE);
|
|
mHTMLCSSUtils->SetCSSProperty(mResizedObject,
|
|
nsIEditProperty::cssHeight,
|
|
h + NS_LITERAL_STRING("px"),
|
|
PR_FALSE);
|
|
|
|
SetAttribute(mResizedObject, widthStr, w);
|
|
SetAttribute(mResizedObject, heightStr, h);
|
|
|
|
mHTMLCSSUtils->RemoveCSSProperty(mResizedObject,
|
|
nsIEditProperty::cssWidth,
|
|
NS_LITERAL_STRING(""),
|
|
PR_FALSE);
|
|
mHTMLCSSUtils->RemoveCSSProperty(mResizedObject,
|
|
nsIEditProperty::cssHeight,
|
|
NS_LITERAL_STRING(""),
|
|
PR_FALSE);
|
|
}
|
|
RefreshResizers();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::CheckResizingState(nsISelection *aSelection)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aSelection);
|
|
|
|
if (!mIsImageResizingEnabled)
|
|
return NS_OK;
|
|
|
|
PRBool bCollapsed;
|
|
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMNode> focusNode;
|
|
|
|
if (bCollapsed) {
|
|
res = aSelection->GetFocusNode(getter_AddRefs(focusNode));
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
else {
|
|
|
|
PRInt32 rangeCount;
|
|
res = aSelection->GetRangeCount(&rangeCount);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (rangeCount == 1) {
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
res = aSelection->GetRangeAt(0, getter_AddRefs(range));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!range) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode> startContainer, endContainer;
|
|
res = range->GetStartContainer(getter_AddRefs(startContainer));
|
|
if (NS_FAILED(res)) return res;
|
|
res = range->GetEndContainer(getter_AddRefs(endContainer));
|
|
if (NS_FAILED(res)) return res;
|
|
PRInt32 startOffset, endOffset;
|
|
res = range->GetStartOffset(&startOffset);
|
|
if (NS_FAILED(res)) return res;
|
|
res = range->GetEndOffset(&endOffset);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsCOMPtr<nsIDOMElement> focusElement;
|
|
if (startContainer == endContainer && startOffset + 1 == endOffset) {
|
|
res = GetSelectedElement(NS_LITERAL_STRING(""), getter_AddRefs(focusElement));
|
|
if (NS_FAILED(res)) return res;
|
|
if (focusElement)
|
|
focusNode = do_QueryInterface(focusElement);
|
|
}
|
|
if (!focusNode) {
|
|
res = range->GetCommonAncestorContainer(getter_AddRefs(focusNode));
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
}
|
|
else {
|
|
PRInt32 i;
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
for (i = 0; i < rangeCount; i++)
|
|
{
|
|
res = aSelection->GetRangeAt(i, getter_AddRefs(range));
|
|
if (NS_FAILED(res)) return res;
|
|
nsCOMPtr<nsIDOMNode> startContainer;
|
|
range->GetStartContainer(getter_AddRefs(startContainer));
|
|
if (!focusNode)
|
|
focusNode = startContainer;
|
|
else if (focusNode != startContainer) {
|
|
res = startContainer->GetParentNode(getter_AddRefs(focusNode));
|
|
if (NS_FAILED(res)) return res;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PRUint16 nodeType;
|
|
focusNode->GetNodeType(&nodeType);
|
|
if (nsIDOMNode::TEXT_NODE == nodeType) {
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
res = focusNode->GetParentNode(getter_AddRefs(parent));
|
|
if (NS_FAILED(res)) return res;
|
|
focusNode = parent;
|
|
}
|
|
|
|
if (focusNode) {
|
|
|
|
nsCOMPtr<nsIDOMElement>element;
|
|
element = do_QueryInterface(focusNode);
|
|
nsAutoString tagName;
|
|
res = element->GetTagName(tagName);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
ToLowerCase(tagName);
|
|
nsCOMPtr<nsIAtom> tagAtom = getter_AddRefs(NS_NewAtom(tagName));
|
|
if (!tagAtom) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDOMNode> tableContainer = GetEnclosingTable(focusNode);
|
|
|
|
if (nsIEditProperty::img == tagAtom ||
|
|
tableContainer) {
|
|
mResizedObjectIsAnImage = PR_FALSE;
|
|
|
|
if (nsIEditProperty::img == tagAtom)
|
|
mResizedObjectIsAnImage = PR_TRUE;
|
|
else {
|
|
focusNode = tableContainer;
|
|
}
|
|
|
|
// that node is an image, we have to show resizers
|
|
element = do_QueryInterface(focusNode);
|
|
if (mIsShowingResizeHandles) {
|
|
// we were already displaying resizers and we only have to
|
|
// refresh the position
|
|
nsCOMPtr<nsIDOMNode> resizedNode = do_QueryInterface(mResizedObject);
|
|
if (!NodesSameType(focusNode, resizedNode)) {
|
|
res = HideResizers();
|
|
if (NS_FAILED(res)) return res;
|
|
mResizedObject = element;
|
|
res = ShowResizers(element);
|
|
}
|
|
else {
|
|
mResizedObject = element;
|
|
res = RefreshResizers();
|
|
}
|
|
}
|
|
else {
|
|
// run through the whole thing
|
|
res = ShowResizers(element);
|
|
}
|
|
if (NS_FAILED(res)) return res;
|
|
mIsShowingResizeHandles = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
}
|
|
if (mIsShowingResizeHandles) {
|
|
// we were showing resizers but the selection is not an image any longer
|
|
res = HideResizers();
|
|
// just in case we were resizing... (bug 195412)
|
|
mIsResizing = PR_FALSE;
|
|
if (NS_FAILED(res)) return res;
|
|
// paranoia...
|
|
// mIsResizing = PR_FALSE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::GetResizedObject(nsIDOMElement * *aResizedObject)
|
|
{
|
|
NS_IF_ADDREF(*aResizedObject = mResizedObject);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::GetResizedObjectSize(PRInt32 *aWidth, PRInt32 *aHeight)
|
|
{
|
|
*aWidth = mResizedObjectWidth;
|
|
*aHeight = mResizedObjectHeight;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::GetIsImageResizingEnabled(PRBool *aIsImageResizingEnabled)
|
|
{
|
|
*aIsImageResizingEnabled = mIsImageResizingEnabled;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLEditor::SetIsImageResizingEnabled(PRBool aIsImageResizingEnabled)
|
|
{
|
|
mIsImageResizingEnabled = aIsImageResizingEnabled;
|
|
return NS_OK;
|
|
}
|