a=i'm leaving now for vacation, and i can't find anyone around, but i'm assuming that you actually want them before January 3rd, so I'm checking them in.
4097 lines
133 KiB
C++
4097 lines
133 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
|
*
|
|
* 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 code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
#include "nsCOMPtr.h"
|
|
#include "nsGfxTextControlFrame.h"
|
|
#include "nsIContent.h"
|
|
#include "prtypes.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsISupports.h"
|
|
#include "nsIAtom.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIHTMLContent.h"
|
|
#include "nsHTMLIIDs.h"
|
|
#include "nsITextWidget.h"
|
|
#include "nsITextAreaWidget.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsSize.h"
|
|
#include "nsString.h"
|
|
#include "nsHTMLAtoms.h"
|
|
#include "nsIStyleContext.h"
|
|
#include "nsFont.h"
|
|
#include "nsDOMEvent.h"
|
|
#include "nsIFormControl.h"
|
|
#include "nsFormFrame.h"
|
|
#include "nsIFrameManager.h"
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
#include "nsIDOMHTMLTextAreaElement.h"
|
|
// begin includes for controllers
|
|
#include "nsIDOMNSHTMLInputElement.h"
|
|
#include "nsIDOMNSHTMLTextAreaElement.h"
|
|
#include "nsIDOMXULCommandDispatcher.h"
|
|
#include "nsIControllers.h"
|
|
// end includes for controllers
|
|
#include "nsIScrollbar.h"
|
|
|
|
#include "nsCSSRendering.h"
|
|
#include "nsIDeviceContext.h"
|
|
#include "nsIFontMetrics.h"
|
|
#include "nsILookAndFeel.h"
|
|
#include "nsIComponentManager.h"
|
|
|
|
#include "nsIWebShell.h"
|
|
#include "nsIBaseWindow.h"
|
|
#include "nsIMarkupDocumentViewer.h"
|
|
#include "nsIDocumentLoader.h"
|
|
#include "nsINameSpaceManager.h"
|
|
#include "nsIPref.h"
|
|
#include "nsIView.h"
|
|
#include "nsIScrollableView.h"
|
|
#include "nsIDocumentViewer.h"
|
|
#include "nsViewsCID.h"
|
|
#include "nsWidgetsCID.h"
|
|
|
|
#include "nsIHTMLEditor.h"
|
|
#include "nsIDocumentEncoder.h"
|
|
#include "nsIEditorMailSupport.h"
|
|
#include "nsEditorCID.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsIDOMElement.h"
|
|
#include "nsIDOMNodeList.h"
|
|
#include "nsIDOMSelection.h"
|
|
#include "nsIDOMCharacterData.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDOMEventReceiver.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIEventStateManager.h"
|
|
#include "nsStyleUtil.h"
|
|
|
|
// for anonymous content and frames
|
|
#include "nsHTMLParts.h"
|
|
#include "nsITextContent.h"
|
|
|
|
//for editor controllers
|
|
#include "nsIEditorController.h"
|
|
#include "nsIController.h"
|
|
#include "nsIControllers.h"
|
|
#include "nsIDOMNSHTMLTextAreaElement.h"
|
|
#include "nsIDOMNSHTMLInputElement.h"
|
|
#include "nsLayoutAtoms.h"
|
|
|
|
|
|
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
|
|
static NS_DEFINE_IID(kTextCID, NS_TEXTFIELD_CID);
|
|
static NS_DEFINE_IID(kTextAreaCID, NS_TEXTAREA_CID);
|
|
static NS_DEFINE_IID(kITextWidgetIID, NS_ITEXTWIDGET_IID);
|
|
static NS_DEFINE_IID(kITextAreaWidgetIID, NS_ITEXTAREAWIDGET_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID, NS_IDOMHTMLTEXTAREAELEMENT_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID);
|
|
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
static NS_DEFINE_IID(kIWebShellContainerIID, NS_IWEB_SHELL_CONTAINER_IID);
|
|
static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID);
|
|
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
|
|
static NS_DEFINE_IID(kCViewCID, NS_VIEW_CID);
|
|
static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
|
|
static NS_DEFINE_IID(kIDocumentLoaderObserverIID, NS_IDOCUMENT_LOADER_OBSERVER_IID);
|
|
static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENT_OBSERVER_IID);
|
|
|
|
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
|
|
static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID);
|
|
|
|
#define EMPTY_DOCUMENT "about:blank"
|
|
#define PASSWORD_REPLACEMENT_CHAR '*'
|
|
|
|
#define NEW_WEBSHELL_INTERFACES
|
|
|
|
//#define NOISY
|
|
const nscoord kSuggestedNotSet = -1;
|
|
|
|
/*================== global functions =========================*/
|
|
nsIWidget * GetDeepestWidget(nsIView * aView)
|
|
{
|
|
|
|
PRInt32 count;
|
|
aView->GetChildCount(count);
|
|
if (0 != count) {
|
|
for (PRInt32 i=0;i<count;i++) {
|
|
nsIView * child;
|
|
aView->GetChild(i, child);
|
|
nsIWidget * widget = GetDeepestWidget(child);
|
|
if (widget) {
|
|
return widget;
|
|
} else {
|
|
aView->GetWidget(widget);
|
|
if (widget) {
|
|
nsCOMPtr<nsIScrollbar> scrollbar(do_QueryInterface(widget));
|
|
if (scrollbar) {
|
|
NS_RELEASE(widget);
|
|
} else {
|
|
return widget;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
void GetWidgetForView(nsIView *aView, nsIWidget *&aWidget)
|
|
{
|
|
aWidget = nsnull;
|
|
nsIView *view = aView;
|
|
while (!aWidget && view)
|
|
{
|
|
view->GetWidget(aWidget);
|
|
if (!aWidget)
|
|
view->GetParent(view);
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
NS_NewGfxTextControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
|
|
{
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
if (nsnull == aNewFrame) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
*aNewFrame = new (aPresShell) nsGfxTextControlFrame;
|
|
if (nsnull == aNewFrame) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
// Frames are not refcounted, no need to AddRef
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|
{
|
|
NS_PRECONDITION(0 != aInstancePtr, "null ptr");
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
} else if (aIID.Equals(NS_GET_IID(nsIGfxTextControlFrame))) {
|
|
*aInstancePtr = (void*)(nsIGfxTextControlFrame*) this;
|
|
return NS_OK;
|
|
}
|
|
|
|
return nsTextControlFrame::QueryInterface(aIID, aInstancePtr);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::Init(nsIPresContext* aPresContext,
|
|
nsIContent* aContent,
|
|
nsIFrame* aParent,
|
|
nsIStyleContext* aContext,
|
|
nsIFrame* aPrevInFlow)
|
|
{
|
|
mFramePresContext = aPresContext;
|
|
return (nsTextControlFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow));
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetEditor(nsIEditor **aEditor)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aEditor);
|
|
|
|
*aEditor = mEditor;
|
|
NS_IF_ADDREF(*aEditor);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetFrameType(nsIAtom** aType) const
|
|
{
|
|
NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
|
|
*aType = NS_NewAtom("textControlFrame");
|
|
NS_IF_ADDREF(*aType);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetWebShell(nsIWebShell **aWebShell)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aWebShell);
|
|
|
|
*aWebShell = mWebShell;
|
|
NS_IF_ADDREF(*aWebShell);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::CreateEditor()
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
mWebShell = nsnull;
|
|
mCreatingViewer = PR_FALSE;
|
|
|
|
// create the stream observer
|
|
mTempObserver = new EnderTempObserver();
|
|
if (!mTempObserver) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
mTempObserver->SetFrame(this);
|
|
NS_ADDREF(mTempObserver);
|
|
|
|
// create the document observer
|
|
mDocObserver = new nsEnderDocumentObserver();
|
|
if (!mDocObserver) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
mDocObserver->SetFrame(this);
|
|
NS_ADDREF(mDocObserver);
|
|
|
|
// create the drag listener for the content node
|
|
if (mContent)
|
|
{
|
|
mListenerForContent = new nsEnderListenerForContent();
|
|
if (!mListenerForContent) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
mListenerForContent->SetFrame(this);
|
|
NS_ADDREF(mListenerForContent);
|
|
|
|
// get the DOM event receiver
|
|
nsCOMPtr<nsIDOMEventReceiver> contentER;
|
|
result = mContent->QueryInterface(nsIDOMEventReceiver::GetIID(), getter_AddRefs(contentER));
|
|
if NS_FAILED(result) { return result; }
|
|
if (contentER)
|
|
{
|
|
nsCOMPtr<nsIDOMDragListener> dragListenerForContent;
|
|
mListenerForContent->QueryInterface(nsIDOMDragListener::GetIID(), getter_AddRefs(dragListenerForContent));
|
|
if (dragListenerForContent)
|
|
{
|
|
result = contentER->AddEventListenerByIID(dragListenerForContent, nsIDOMDragListener::GetIID());
|
|
if NS_FAILED(result) { return result; }
|
|
}
|
|
}
|
|
}
|
|
|
|
// create the focus listener for HTML Input display content
|
|
if (mDisplayContent)
|
|
{
|
|
mFocusListenerForDisplayContent = new nsEnderFocusListenerForDisplayContent();
|
|
if (!mFocusListenerForDisplayContent) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
mFocusListenerForDisplayContent->SetFrame(this);
|
|
NS_ADDREF(mFocusListenerForDisplayContent);
|
|
// get the DOM event receiver
|
|
nsCOMPtr<nsIDOMEventReceiver> er;
|
|
result = mDisplayContent->QueryInterface(nsIDOMEventReceiver::GetIID(), getter_AddRefs(er));
|
|
if (NS_SUCCEEDED(result) && er)
|
|
result = er->AddEventListenerByIID(mFocusListenerForDisplayContent, nsIDOMFocusListener::GetIID());
|
|
// should check to see if mDisplayContent or mContent has focus and call CreateSubDoc instead if it does
|
|
// do something with result
|
|
}
|
|
|
|
nsCOMPtr<nsIHTMLEditor> theEditor;
|
|
result = nsComponentManager::CreateInstance(kHTMLEditorCID,
|
|
nsnull,
|
|
nsIHTMLEditor::GetIID(), getter_AddRefs(theEditor));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!theEditor) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
mEditor = do_QueryInterface(theEditor);
|
|
if (!mEditor) { return NS_ERROR_NO_INTERFACE; }
|
|
return NS_OK;
|
|
}
|
|
|
|
nsGfxTextControlFrame::nsGfxTextControlFrame()
|
|
: mWebShell(0), mCreatingViewer(PR_FALSE),
|
|
mTempObserver(0), mDocObserver(0),
|
|
mNotifyOnInput(PR_FALSE),
|
|
mIsProcessing(PR_FALSE),
|
|
mNeedsStyleInit(PR_TRUE),
|
|
mFramePresContext(nsnull),
|
|
mCachedState(nsnull),
|
|
mWeakReferent(this),
|
|
mFrameConstructor(nsnull),
|
|
mDisplayFrame(nsnull),
|
|
mDidSetFocus(PR_FALSE),
|
|
mPassThroughMouseEvents(eUninitialized)
|
|
{
|
|
}
|
|
|
|
nsGfxTextControlFrame::~nsGfxTextControlFrame()
|
|
{
|
|
nsresult result;
|
|
if (mDisplayFrame) {
|
|
mFrameConstructor->RemoveMappingsForFrameSubtree(mFramePresContext,
|
|
mDisplayFrame, nsnull);
|
|
mDisplayFrame->Destroy(mFramePresContext);
|
|
}
|
|
if (mTempObserver)
|
|
{
|
|
if (mWebShell) {
|
|
nsCOMPtr<nsIDocumentLoader> docLoader;
|
|
mWebShell->GetDocumentLoader(*getter_AddRefs(docLoader));
|
|
if (docLoader) {
|
|
docLoader->RemoveObserver(mTempObserver);
|
|
}
|
|
}
|
|
mTempObserver->SetFrame(nsnull);
|
|
NS_RELEASE(mTempObserver);
|
|
}
|
|
|
|
// remove the focus listener from the display content, if any
|
|
if (mDisplayContent && mFocusListenerForDisplayContent)
|
|
{
|
|
nsCOMPtr<nsIDOMEventReceiver> er;
|
|
result = mDisplayContent->QueryInterface(nsIDOMEventReceiver::GetIID(), getter_AddRefs(er));
|
|
if (NS_SUCCEEDED(result) && er)
|
|
{
|
|
er->RemoveEventListenerByIID(mFocusListenerForDisplayContent, nsIDOMFocusListener::GetIID());
|
|
}
|
|
mFocusListenerForDisplayContent->SetFrame(nsnull);
|
|
NS_RELEASE(mFocusListenerForDisplayContent);
|
|
}
|
|
|
|
// remove the drag listener from the frame's content node, if any
|
|
if (mContent && mListenerForContent)
|
|
{
|
|
// checking errors below does not good, I'm in a void method
|
|
// I only check the minimum required to be sure it all works right
|
|
nsCOMPtr<nsIDOMEventReceiver> contentER;
|
|
result = mContent->QueryInterface(nsIDOMEventReceiver::GetIID(), getter_AddRefs(contentER));
|
|
if (NS_SUCCEEDED(result) && contentER)
|
|
{
|
|
nsCOMPtr<nsIDOMDragListener> dragListenerForContent;
|
|
mListenerForContent->QueryInterface(nsIDOMDragListener::GetIID(), getter_AddRefs(dragListenerForContent));
|
|
if (dragListenerForContent)
|
|
{
|
|
contentER->RemoveEventListenerByIID(dragListenerForContent, nsIDOMDragListener::GetIID());
|
|
}
|
|
}
|
|
mListenerForContent->SetFrame(nsnull);
|
|
NS_RELEASE(mListenerForContent);
|
|
}
|
|
|
|
if (mEventListener)
|
|
{
|
|
if (mEditor)
|
|
{
|
|
// remove selection listener
|
|
nsCOMPtr<nsIDOMSelection>selection;
|
|
result = mEditor->GetSelection(getter_AddRefs(selection));
|
|
if (NS_SUCCEEDED(result) && selection)
|
|
{
|
|
nsCOMPtr<nsIDOMSelectionListener>selListener;
|
|
selListener = do_QueryInterface(mEventListener);
|
|
if (selListener) {
|
|
selection->RemoveSelectionListener(selListener);
|
|
}
|
|
}
|
|
// remove all other listeners from embedded document
|
|
nsCOMPtr<nsIDOMDocument>domDoc;
|
|
result = mEditor->GetDocument(getter_AddRefs(domDoc));
|
|
if (NS_SUCCEEDED(result) && domDoc)
|
|
{
|
|
nsCOMPtr<nsIDOMEventReceiver> er;
|
|
result = domDoc->QueryInterface(nsIDOMEventReceiver::GetIID(), getter_AddRefs(er));
|
|
if (NS_SUCCEEDED(result) && er)
|
|
{
|
|
// remove key listener
|
|
nsCOMPtr<nsIDOMKeyListener>keyListener;
|
|
keyListener = do_QueryInterface(mEventListener);
|
|
if (keyListener)
|
|
er->RemoveEventListenerByIID(keyListener, nsIDOMKeyListener::GetIID());
|
|
// remove mouse listener
|
|
nsCOMPtr<nsIDOMMouseListener>mouseListener;
|
|
mouseListener = do_QueryInterface(mEventListener);
|
|
if (mouseListener)
|
|
er->RemoveEventListenerByIID(mouseListener, nsIDOMMouseListener::GetIID());
|
|
// remove focus listener
|
|
nsCOMPtr<nsIDOMFocusListener>focusListener;
|
|
focusListener = do_QueryInterface(mEventListener);
|
|
if (focusListener)
|
|
er->RemoveEventListenerByIID(focusListener, nsIDOMFocusListener::GetIID());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mEditor = 0; // editor must be destroyed before the webshell!
|
|
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
|
|
if(webShellWin)
|
|
webShellWin->Destroy();
|
|
mWebShell = nsnull; // This is where it was released before. Not sure if
|
|
// there is ordering depending on it.
|
|
if (mDocObserver)
|
|
{
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDoc);
|
|
if (doc)
|
|
{
|
|
doc->RemoveObserver(mDocObserver);
|
|
}
|
|
mDocObserver->SetFrame(nsnull);
|
|
NS_RELEASE(mDocObserver);
|
|
}
|
|
|
|
if (mCachedState) {
|
|
delete mCachedState;
|
|
mCachedState = nsnull;
|
|
}
|
|
}
|
|
|
|
NS_METHOD nsGfxTextControlFrame::HandleEvent(nsIPresContext* aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus* aEventStatus)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aPresContext);
|
|
NS_ENSURE_ARG_POINTER(aEvent);
|
|
NS_ENSURE_ARG_POINTER(aEventStatus);
|
|
|
|
if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
|
|
return NS_OK;
|
|
}
|
|
|
|
*aEventStatus = nsEventStatus_eConsumeDoDefault; // this is the default
|
|
|
|
/* the handling of mouse messages here has two purposes:
|
|
* 1) to create a subdoc if one doesn't exist on click, and to pass
|
|
* mouse messages along to the content of the subdoc in the case
|
|
* where we created it in response to a click.
|
|
* 2) to call MouseClicked
|
|
*/
|
|
switch (aEvent->message) {
|
|
case NS_MOUSE_LEFT_BUTTON_DOWN:
|
|
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
|
|
case NS_MOUSE_RIGHT_BUTTON_DOWN:
|
|
// don't pass through a click if we're already handling a click
|
|
if (eGotDown != mPassThroughMouseEvents)
|
|
{
|
|
mPassThroughMouseEvents = eGotDown;
|
|
if (!mWebShell) {
|
|
NS_ENSURE_SUCCESS(CreateSubDoc(nsnull), NS_ERROR_FAILURE);
|
|
}
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
return RedispatchMouseEventToSubDoc(aPresContext, aEvent, aEventStatus, PR_TRUE);
|
|
}
|
|
break;
|
|
|
|
case NS_MOUSE_LEFT_BUTTON_UP:
|
|
case NS_MOUSE_MIDDLE_BUTTON_UP:
|
|
case NS_MOUSE_RIGHT_BUTTON_UP:
|
|
// only pass through the mouseUp if we're the one who handled the mouseDown
|
|
if (eGotDown==mPassThroughMouseEvents)
|
|
{
|
|
mPassThroughMouseEvents = eGotUp;
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
return RedispatchMouseEventToSubDoc(aPresContext, aEvent, aEventStatus, PR_FALSE);
|
|
}
|
|
break;
|
|
|
|
case NS_MOUSE_LEFT_CLICK:
|
|
case NS_MOUSE_MIDDLE_CLICK:
|
|
case NS_MOUSE_RIGHT_CLICK:
|
|
MouseClicked(aPresContext);
|
|
// only pass through the mouseClick if we're the one who handled the mouseUp
|
|
if (eGotUp==mPassThroughMouseEvents)
|
|
{
|
|
mPassThroughMouseEvents = eGotClick;
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
return RedispatchMouseEventToSubDoc(aPresContext, aEvent, aEventStatus, PR_FALSE);
|
|
}
|
|
break;
|
|
|
|
case NS_MOUSE_LEFT_DOUBLECLICK:
|
|
case NS_MOUSE_MIDDLE_DOUBLECLICK:
|
|
case NS_MOUSE_RIGHT_DOUBLECLICK:
|
|
mPassThroughMouseEvents = eGotClick;
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
return RedispatchMouseEventToSubDoc(aPresContext, aEvent, aEventStatus, PR_FALSE);
|
|
break;
|
|
|
|
case NS_MOUSE_MOVE:
|
|
// only pass through the mouseMove if we're the one who handled the mouseDown
|
|
if (eGotDown==mPassThroughMouseEvents)
|
|
{
|
|
if (mWebShell) {
|
|
return RedispatchMouseEventToSubDoc(aPresContext, aEvent, aEventStatus, PR_FALSE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NS_DRAGDROP_ENTER:
|
|
case NS_DRAGDROP_OVER:
|
|
case NS_DRAGDROP_DROP:
|
|
case NS_DRAGDROP_EXIT:
|
|
// currently unused
|
|
break;
|
|
|
|
case NS_DRAGDROP_GESTURE:
|
|
// this currently seems to have no effect
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
return RedispatchMouseEventToSubDoc(aPresContext, aEvent, aEventStatus, PR_FALSE);
|
|
break;
|
|
|
|
case NS_KEY_PRESS:
|
|
if (NS_KEY_EVENT == aEvent->eventStructType) {
|
|
nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
|
|
if (NS_VK_RETURN == keyEvent->keyCode)
|
|
{
|
|
EnterPressed(aPresContext);
|
|
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
}
|
|
else if (NS_VK_SPACE == keyEvent->keyCode)
|
|
{
|
|
MouseClicked(aPresContext);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::RedispatchMouseEventToSubDoc(nsIPresContext* aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus* aEventStatus,
|
|
PRBool aAdjustForView)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aPresContext);
|
|
NS_ENSURE_ARG_POINTER(aEvent);
|
|
NS_ENSURE_ARG_POINTER(aEventStatus);
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
NS_ENSURE_SUCCESS(mWebShell->GetContentViewer(getter_AddRefs(viewer)), NS_ERROR_FAILURE);
|
|
if (viewer)
|
|
{
|
|
nsCOMPtr<nsIDocumentViewer> docv;
|
|
viewer->QueryInterface(kIDocumentViewerIID, getter_AddRefs(docv));
|
|
if (docv)
|
|
{
|
|
nsCOMPtr<nsIPresContext> cx;
|
|
NS_ENSURE_SUCCESS(docv->GetPresContext(*(getter_AddRefs(cx))), NS_ERROR_FAILURE);
|
|
if (cx)
|
|
{
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
NS_ENSURE_SUCCESS(cx->GetShell(getter_AddRefs(shell)), NS_ERROR_FAILURE);
|
|
if (shell)
|
|
{
|
|
nsIFrame * rootFrame;
|
|
NS_ENSURE_SUCCESS(shell->GetRootFrame(&rootFrame), NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIViewManager> vm;
|
|
NS_ENSURE_SUCCESS(shell->GetViewManager(getter_AddRefs(vm)), NS_ERROR_FAILURE);
|
|
if (vm)
|
|
{
|
|
// create a new mouse event
|
|
nsMouseEvent event;
|
|
event = *((nsMouseEvent*)aEvent);
|
|
// if we're told to, translate the event point based on the view of this text control
|
|
if (PR_TRUE==aAdjustForView)
|
|
{
|
|
nsIView * view = nsnull;
|
|
GetView(aPresContext, &view);
|
|
NS_ASSERTION(view, "text control frame has no view");
|
|
if (!view) { return NS_ERROR_NULL_POINTER;}
|
|
nsRect viewBounds;
|
|
view->GetBounds(viewBounds);
|
|
event.point.x -= viewBounds.x;
|
|
event.point.y -= viewBounds.y;
|
|
}
|
|
// translate the event point based on this frame's border and padding
|
|
nsSize size;
|
|
GetSize(size);
|
|
nsRect subBounds;
|
|
nsMargin border;
|
|
nsMargin padding;
|
|
border.SizeTo(0, 0, 0, 0);
|
|
padding.SizeTo(0, 0, 0, 0);
|
|
const nsStyleSpacing* spacing;
|
|
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing);
|
|
spacing->CalcBorderFor(this, border);
|
|
spacing->CalcPaddingFor(this, padding);
|
|
CalcSizeOfSubDocInTwips(border, padding, size, subBounds);
|
|
event.point.x -= (border.left + padding.left);
|
|
if (0>event.point.x) {
|
|
event.point.x = 0;
|
|
}
|
|
else if (event.point.x > subBounds.width) {
|
|
event.point.x = subBounds.width-1;
|
|
}
|
|
event.point.y -= (border.top + padding.top);
|
|
if (0>event.point.y) {
|
|
event.point.y = 0;
|
|
}
|
|
else if (event.point.y > subBounds.height) {
|
|
event.point.x = subBounds.height-1;
|
|
}
|
|
|
|
// translate the event point to pixels for consumption by the embedded view manager
|
|
nsCOMPtr<nsIDeviceContext> dc;
|
|
aPresContext->GetDeviceContext(getter_AddRefs(dc));
|
|
NS_ASSERTION(dc, "text control frame has no dc");
|
|
if (!dc) { return NS_ERROR_NULL_POINTER;}
|
|
float t2p;
|
|
dc->GetAppUnitsToDevUnits(t2p);
|
|
|
|
event.point.x = NSTwipsToIntPixels(event.point.x, t2p);
|
|
event.point.y = NSTwipsToIntPixels(event.point.y, t2p);
|
|
NS_ENSURE_SUCCESS(vm->DispatchEvent(&event, aEventStatus), NS_ERROR_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsGfxTextControlFrame::EnterPressed(nsIPresContext* aPresContext)
|
|
{
|
|
if (mFormFrame && mFormFrame->CanSubmit(*this)) {
|
|
nsIContent *formContent = nsnull;
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
mFormFrame->GetContent(&formContent);
|
|
if (nsnull != formContent) {
|
|
nsEvent event;
|
|
event.eventStructType = NS_EVENT;
|
|
event.message = NS_FORM_SUBMIT;
|
|
formContent->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
NS_RELEASE(formContent);
|
|
}
|
|
|
|
if (nsEventStatus_eConsumeNoDefault != status) {
|
|
mFormFrame->OnSubmit(aPresContext, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
nsWidgetInitData*
|
|
nsGfxTextControlFrame::GetWidgetInitData(nsIPresContext* aPresContext)
|
|
{
|
|
return nsnull;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetText(nsString* aText, PRBool aInitialValue)
|
|
{
|
|
nsresult result = NS_CONTENT_ATTR_NOT_THERE;
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if ((NS_FORM_INPUT_TEXT == type) || (NS_FORM_INPUT_PASSWORD == type))
|
|
{
|
|
if (PR_TRUE==aInitialValue)
|
|
{
|
|
result = nsFormControlHelper::GetInputElementValue(mContent, aText, aInitialValue);
|
|
}
|
|
else
|
|
{
|
|
if (PR_TRUE==IsInitialized())
|
|
{
|
|
if (mEditor)
|
|
{
|
|
nsString format ("text/plain");
|
|
mEditor->OutputToString(*aText, format, 0);
|
|
}
|
|
// we've never built our editor, so the content attribute is the value
|
|
else
|
|
{
|
|
result = nsFormControlHelper::GetInputElementValue(mContent, aText, aInitialValue);
|
|
}
|
|
}
|
|
else {
|
|
if (mCachedState) {
|
|
*aText = *mCachedState;
|
|
result = NS_OK;
|
|
} else {
|
|
result = nsFormControlHelper::GetInputElementValue(mContent, aText, aInitialValue);
|
|
}
|
|
}
|
|
}
|
|
RemoveNewlines(*aText);
|
|
}
|
|
else
|
|
{
|
|
nsIDOMHTMLTextAreaElement* textArea = nsnull;
|
|
result = mContent->QueryInterface(kIDOMHTMLTextAreaElementIID, (void**)&textArea);
|
|
if ((NS_OK == result) && textArea) {
|
|
if (PR_TRUE == aInitialValue) {
|
|
result = textArea->GetDefaultValue(*aText);
|
|
}
|
|
else {
|
|
result = textArea->GetValue(*aText);
|
|
}
|
|
NS_RELEASE(textArea);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::AttributeChanged(nsIPresContext* aPresContext,
|
|
nsIContent* aChild,
|
|
PRInt32 aNameSpaceID,
|
|
nsIAtom* aAttribute,
|
|
PRInt32 aHint)
|
|
{
|
|
if (PR_FALSE==IsInitialized()) {return NS_ERROR_NOT_INITIALIZED;}
|
|
nsresult result = NS_OK;
|
|
|
|
if (nsHTMLAtoms::value == aAttribute)
|
|
{
|
|
if (mEditor)
|
|
{
|
|
nsString value;
|
|
GetText(&value, PR_TRUE); // get the initial value from the content attribute
|
|
mEditor->EnableUndo(PR_FALSE); // wipe out undo info
|
|
SetTextControlFrameState(value); // set new text value
|
|
mEditor->EnableUndo(PR_TRUE); // fire up a new txn stack
|
|
}
|
|
if (aHint != NS_STYLE_HINT_REFLOW)
|
|
nsFormFrame::StyleChangeReflow(aPresContext, this);
|
|
}
|
|
else if (nsHTMLAtoms::maxlength == aAttribute)
|
|
{
|
|
PRInt32 maxLength;
|
|
nsresult rv = GetMaxLength(&maxLength);
|
|
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
{
|
|
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
|
{ // set the maxLength attribute
|
|
htmlEditor->SetMaxTextLength(maxLength);
|
|
// if maxLength>docLength, we need to truncate the doc content
|
|
}
|
|
else { // unset the maxLength attribute
|
|
htmlEditor->SetMaxTextLength(-1);
|
|
}
|
|
}
|
|
}
|
|
else if (mEditor && nsHTMLAtoms::readonly == aAttribute)
|
|
{
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
nsresult rv = DoesAttributeExist(nsHTMLAtoms::readonly);
|
|
PRUint32 flags;
|
|
mEditor->GetFlags(&flags);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
|
{ // set readonly
|
|
flags |= nsIHTMLEditor::eEditorReadonlyMask;
|
|
presShell->SetCaretEnabled(PR_FALSE);
|
|
}
|
|
else
|
|
{ // unset readonly
|
|
flags &= ~(nsIHTMLEditor::eEditorReadonlyMask);
|
|
presShell->SetCaretEnabled(PR_TRUE);
|
|
}
|
|
mEditor->SetFlags(flags);
|
|
}
|
|
else if (mEditor && nsHTMLAtoms::disabled == aAttribute)
|
|
{
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
nsresult rv = DoesAttributeExist(nsHTMLAtoms::disabled);
|
|
PRUint32 flags;
|
|
mEditor->GetFlags(&flags);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != rv)
|
|
{ // set readonly
|
|
flags |= nsIHTMLEditor::eEditorDisabledMask;
|
|
presShell->SetCaretEnabled(PR_FALSE);
|
|
nsCOMPtr<nsIDocument> doc;
|
|
presShell->GetDocument(getter_AddRefs(doc));
|
|
NS_ASSERTION(doc, "null document");
|
|
if (!doc) { return NS_ERROR_NULL_POINTER; }
|
|
doc->SetDisplaySelection(PR_FALSE);
|
|
}
|
|
else
|
|
{ // unset readonly
|
|
flags &= ~(nsIHTMLEditor::eEditorDisabledMask);
|
|
presShell->SetCaretEnabled(PR_TRUE);
|
|
nsCOMPtr<nsIDocument> doc;
|
|
presShell->GetDocument(getter_AddRefs(doc));
|
|
NS_ASSERTION(doc, "null document");
|
|
if (!doc) { return NS_ERROR_NULL_POINTER; }
|
|
doc->SetDisplaySelection(PR_TRUE);
|
|
}
|
|
mEditor->SetFlags(flags);
|
|
}
|
|
else if (nsHTMLAtoms::size == aAttribute && aHint != NS_STYLE_HINT_REFLOW) {
|
|
nsFormFrame::StyleChangeReflow(aPresContext, this);
|
|
}
|
|
// Allow the base class to handle common attributes supported
|
|
// by all form elements...
|
|
else {
|
|
result = nsFormControlFrame::AttributeChanged(aPresContext, aChild, aNameSpaceID, aAttribute, aHint);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::DoesAttributeExist(nsIAtom *aAtt)
|
|
{
|
|
nsresult result = NS_CONTENT_ATTR_NOT_THERE;
|
|
nsIHTMLContent* content = nsnull;
|
|
mContent->QueryInterface(kIHTMLContentIID, (void**) &content);
|
|
if (nsnull != content)
|
|
{
|
|
nsHTMLValue value;
|
|
result = content->GetHTMLAttribute(aAtt, value);
|
|
NS_RELEASE(content);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// aSizeOfSubdocContainer is in pixels, not twips
|
|
nsresult
|
|
nsGfxTextControlFrame::CreateSubDoc(nsRect *aSizeOfSubdocContainer)
|
|
{
|
|
if (!mFramePresContext) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (!IsInitialized() && !mCreatingViewer)
|
|
{
|
|
// if the editor hasn't been created yet, create it
|
|
if (!mEditor)
|
|
{
|
|
rv = CreateEditor();
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textAreaElement = do_QueryInterface(mContent);
|
|
nsCOMPtr<nsIDOMNSHTMLInputElement> inputElement = do_QueryInterface(mContent);
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
if (textAreaElement)
|
|
textAreaElement->GetControllers(getter_AddRefs(controllers));
|
|
else if (inputElement)
|
|
inputElement->GetControllers(getter_AddRefs(controllers));
|
|
else
|
|
return rv = NS_ERROR_FAILURE;
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
PRUint32 count;
|
|
PRBool found = PR_FALSE;
|
|
rv = controllers->GetControllerCount(&count);
|
|
for (PRUint32 i = 0; i < count; i ++)
|
|
{
|
|
nsCOMPtr<nsIController> controller;
|
|
rv = controllers->GetControllerAt(i, getter_AddRefs(controller));
|
|
if (NS_SUCCEEDED(rv) && controller)
|
|
{
|
|
nsCOMPtr<nsIEditorController> editController = do_QueryInterface(controller);
|
|
if (editController)
|
|
{
|
|
editController->SetEditor(mEditor);
|
|
found = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!found)
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_ASSERTION(mEditor, "null EDITOR after attempt to create.");
|
|
}
|
|
|
|
// initialize the subdoc, if it hasn't already been constructed
|
|
// if the size is not 0 and there is a src, create the web shell
|
|
|
|
if (!mWebShell)
|
|
{
|
|
nsSize size;
|
|
GetSize(size);
|
|
nsRect subBounds;
|
|
if (aSizeOfSubdocContainer)
|
|
{
|
|
subBounds = *aSizeOfSubdocContainer;
|
|
}
|
|
else
|
|
{
|
|
nsMargin border;
|
|
nsMargin padding;
|
|
border.SizeTo(0, 0, 0, 0);
|
|
padding.SizeTo(0, 0, 0, 0);
|
|
// Get the CSS border
|
|
const nsStyleSpacing* spacing;
|
|
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing);
|
|
spacing->CalcBorderFor(this, border);
|
|
spacing->CalcPaddingFor(this, padding);
|
|
CalcSizeOfSubDocInTwips(border, padding, size, subBounds);
|
|
float t2p;
|
|
mFramePresContext->GetTwipsToPixels(&t2p);
|
|
subBounds.x = NSToCoordRound(subBounds.x * t2p);
|
|
subBounds.y = NSToCoordRound(subBounds.y * t2p);
|
|
subBounds.width = NSToCoordRound(subBounds.width * t2p);
|
|
subBounds.height = NSToCoordRound(subBounds.height * t2p);
|
|
}
|
|
|
|
rv = CreateWebShell(mFramePresContext, size);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
#ifdef NOISY
|
|
printf("%p webshell in CreateSubDoc set to bounds: x=%d, y=%d, w=%d, h=%d\n", mWebShell.get(), subBounds.x, subBounds.y, subBounds.width, subBounds.height);
|
|
#endif
|
|
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
|
|
NS_ENSURE_TRUE(webShellWin, NS_ERROR_FAILURE);
|
|
webShellWin->SetPositionAndSize(subBounds.x, subBounds.y,
|
|
subBounds.width, subBounds.height, PR_FALSE);
|
|
}
|
|
mCreatingViewer=PR_TRUE;
|
|
|
|
#ifdef NEW_WEBSHELL_INTERFACES
|
|
// create document
|
|
nsCOMPtr<nsIDocument> doc;
|
|
rv = NS_NewHTMLDocument(getter_AddRefs(doc));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!doc) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
// create document content
|
|
nsCOMPtr<nsIHTMLContent> htmlElement;
|
|
nsCOMPtr<nsIHTMLContent> headElement;
|
|
nsCOMPtr<nsIHTMLContent> bodyElement;
|
|
// create the root
|
|
rv = NS_NewHTMLHtmlElement(getter_AddRefs(htmlElement), nsHTMLAtoms::html);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!htmlElement) { return NS_ERROR_NULL_POINTER; }
|
|
// create the head
|
|
nsIAtom* headAtom = NS_NewAtom("head");
|
|
if (!headAtom) { return NS_ERROR_OUT_OF_MEMORY; }
|
|
rv = NS_NewHTMLHeadElement(getter_AddRefs(headElement), headAtom);
|
|
NS_RELEASE(headAtom);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!headElement) { return NS_ERROR_NULL_POINTER; }
|
|
headElement->SetDocument(doc, PR_FALSE);
|
|
// create the body
|
|
rv = NS_NewHTMLBodyElement(getter_AddRefs(bodyElement), nsHTMLAtoms::body);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!bodyElement) { return NS_ERROR_NULL_POINTER; }
|
|
bodyElement->SetDocument(doc, PR_FALSE);
|
|
// put the head and body into the root
|
|
rv = htmlElement->AppendChildTo(headElement, PR_FALSE);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
rv = htmlElement->AppendChildTo(bodyElement, PR_FALSE);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
|
|
// load the document into the webshell
|
|
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
|
|
if (!domDoc) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIDOMElement> htmlDOMElement = do_QueryInterface(htmlElement);
|
|
if (!htmlDOMElement) { return NS_ERROR_NULL_POINTER; }
|
|
rv = mWebShell->SetDocument(domDoc, htmlDOMElement);
|
|
#else
|
|
nsAutoString url(EMPTY_DOCUMENT);
|
|
rv = mWebShell->LoadURL(url.GetUnicode()); // URL string with a default nsnull value for post Data
|
|
#endif
|
|
|
|
// force an incremental reflow of the text control
|
|
/* XXX: this is to get the view/webshell positioned correctly.
|
|
I don't know why it's required, it looks like this code positions the view and webshell
|
|
exactly the same way reflow does, but reflow works and the code above does not
|
|
when the text control is in a view which is scrolled.
|
|
*/
|
|
nsCOMPtr<nsIReflowCommand> cmd;
|
|
rv = NS_NewHTMLReflowCommand(getter_AddRefs(cmd), this, nsIReflowCommand::StyleChanged);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!cmd) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
rv = mFramePresContext->GetShell(getter_AddRefs(shell));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!shell) { return NS_ERROR_NULL_POINTER; }
|
|
rv = shell->EnterReflowLock();
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
rv = shell->AppendReflowCommand(cmd);
|
|
// must do this next line regardless of result of AppendReflowCommand
|
|
shell->ExitReflowLock(PR_TRUE, PR_TRUE);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
void nsGfxTextControlFrame::CalcSizeOfSubDocInTwips(const nsMargin &aBorder,
|
|
const nsMargin &aPadding,
|
|
const nsSize &aFrameSize,
|
|
nsRect &aSubBounds)
|
|
{
|
|
|
|
// XXX: the point here is to make a single-line edit field as wide as it wants to be,
|
|
// so it will scroll horizontally if the characters take up more space than the field
|
|
aSubBounds.x = aBorder.left + aPadding.left;
|
|
aSubBounds.y = aBorder.top + aPadding.top;
|
|
aSubBounds.width = (aFrameSize.width - (aBorder.left + aPadding.left + aBorder.right + aPadding.right));
|
|
aSubBounds.height = (aFrameSize.height - (aBorder.top + aPadding.top + aBorder.bottom + aPadding.bottom));
|
|
}
|
|
|
|
PRBool
|
|
nsGfxTextControlFrame::GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues,
|
|
nsString* aValues, nsString* aNames)
|
|
{
|
|
if (!aValues || !aNames) { return PR_FALSE; }
|
|
|
|
nsAutoString name;
|
|
nsresult result = GetName(&name);
|
|
if ((aMaxNumValues <= 0) || (NS_CONTENT_ATTR_NOT_THERE == result)) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
aNames[0] = name;
|
|
aNumValues = 1;
|
|
|
|
GetText(&(aValues[0]), PR_FALSE);
|
|
// XXX: error checking
|
|
return PR_TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
nsGfxTextControlFrame::Reset(nsIPresContext* aPresContext)
|
|
{
|
|
nsAutoString value;
|
|
nsresult valStatus = GetText(&value, PR_TRUE);
|
|
NS_ASSERTION((NS_SUCCEEDED(valStatus)), "GetText failed");
|
|
if (NS_SUCCEEDED(valStatus))
|
|
{
|
|
SetTextControlFrameState(value);
|
|
}
|
|
}
|
|
|
|
NS_METHOD
|
|
nsGfxTextControlFrame::Paint(nsIPresContext* aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect,
|
|
nsFramePaintLayer aWhichLayer)
|
|
{
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer)
|
|
{
|
|
nsAutoString text(" ");
|
|
nsRect rect(0, 0, mRect.width, mRect.height);
|
|
PaintTextControl(aPresContext, aRenderingContext, aDirtyRect,
|
|
text, mStyleContext, rect);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsGfxTextControlFrame::PaintTextControlBackground(nsIPresContext* aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect,
|
|
nsFramePaintLayer aWhichLayer)
|
|
{
|
|
// we paint our own border, but everything else is painted by the mWebshell
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer)
|
|
{
|
|
nsAutoString text(" ");
|
|
nsRect rect(0, 0, mRect.width, mRect.height);
|
|
PaintTextControl(aPresContext, aRenderingContext, aDirtyRect,
|
|
text, mStyleContext, rect);
|
|
}
|
|
}
|
|
|
|
// stolen directly from nsContainerFrame
|
|
void
|
|
nsGfxTextControlFrame::PaintChild(nsIPresContext* aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect,
|
|
nsIFrame* aFrame,
|
|
nsFramePaintLayer aWhichLayer)
|
|
{
|
|
nsIView *pView;
|
|
aFrame->GetView(aPresContext, &pView);
|
|
if (nsnull == pView) {
|
|
nsRect kidRect;
|
|
aFrame->GetRect(kidRect);
|
|
nsFrameState state;
|
|
aFrame->GetFrameState(&state);
|
|
|
|
// Compute the constrained damage area; set the overlap flag to
|
|
// PR_TRUE if any portion of the child frame intersects the
|
|
// dirty rect.
|
|
nsRect damageArea;
|
|
PRBool overlap;
|
|
if (NS_FRAME_OUTSIDE_CHILDREN & state) {
|
|
// If the child frame has children that leak out of our box
|
|
// then we don't constrain the damageArea to just the childs
|
|
// bounding rect.
|
|
damageArea = aDirtyRect;
|
|
overlap = PR_TRUE;
|
|
}
|
|
else {
|
|
// Compute the intersection of the dirty rect and the childs
|
|
// rect (both are in our coordinate space). This limits the
|
|
// damageArea to just the portion that intersects the childs
|
|
// rect.
|
|
overlap = damageArea.IntersectRect(aDirtyRect, kidRect);
|
|
#ifdef NS_DEBUG
|
|
if (!overlap && (0 == kidRect.width) && (0 == kidRect.height)) {
|
|
overlap = PR_TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (overlap) {
|
|
// Translate damage area into the kids coordinate
|
|
// system. Translate rendering context into the kids
|
|
// coordinate system.
|
|
damageArea.x -= kidRect.x;
|
|
damageArea.y -= kidRect.y;
|
|
aRenderingContext.PushState();
|
|
aRenderingContext.Translate(kidRect.x, kidRect.y);
|
|
|
|
// Paint the kid
|
|
aFrame->Paint(aPresContext, aRenderingContext, damageArea, aWhichLayer);
|
|
PRBool clipState;
|
|
aRenderingContext.PopState(clipState);
|
|
|
|
#ifdef NS_DEBUG
|
|
// Draw a border around the child
|
|
if (nsIFrameDebug::GetShowFrameBorders() && !kidRect.IsEmpty()) {
|
|
aRenderingContext.SetColor(NS_RGB(255,0,0));
|
|
aRenderingContext.DrawRect(kidRect);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGfxTextControlFrame::PaintTextControl(nsIPresContext* aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect,
|
|
nsString& aText,
|
|
nsIStyleContext* aStyleContext,
|
|
nsRect& aRect)
|
|
{
|
|
// XXX: aText is currently unused!
|
|
const nsStyleDisplay* disp = (const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
|
|
if (disp->mVisible)
|
|
{
|
|
nsCompatibility mode;
|
|
aPresContext->GetCompatibilityMode(&mode);
|
|
const nsStyleSpacing* mySpacing = (const nsStyleSpacing*)aStyleContext->GetStyleData(eStyleStruct_Spacing);
|
|
PRIntn skipSides = 0;
|
|
nsRect rect(0, 0, mRect.width, mRect.height);
|
|
const nsStyleColor* color = (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
|
|
aDirtyRect, rect, *color, *mySpacing, 0, 0);
|
|
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
|
|
aDirtyRect, rect, *mySpacing, aStyleContext, skipSides);
|
|
|
|
if (!mWebShell)
|
|
{
|
|
if (mDisplayFrame) {
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect, mDisplayFrame, NS_FRAME_PAINT_LAYER_FOREGROUND);
|
|
//mDisplayFrame->Paint(aPresContext, aRenderingContext, aDirtyRect, NS_FRAME_PAINT_LAYER_FOREGROUND);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//XXX: this needs to be fixed for HTML output
|
|
void nsGfxTextControlFrame::GetTextControlFrameState(nsString& aValue)
|
|
{
|
|
aValue = ""; // initialize out param
|
|
|
|
if (mEditor && PR_TRUE==IsInitialized())
|
|
{
|
|
nsString format ("text/plain");
|
|
PRUint32 flags = 0;
|
|
|
|
if (PR_TRUE==IsPlainTextControl()) {
|
|
flags |= nsIDocumentEncoder::OutputBodyOnly; // OutputNoDoctype if head info needed
|
|
}
|
|
|
|
nsFormControlHelper::nsHTMLTextWrap wrapProp;
|
|
nsresult result = nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result)
|
|
{
|
|
if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Hard)
|
|
{
|
|
flags |= nsIDocumentEncoder::OutputFormatted;
|
|
}
|
|
}
|
|
|
|
mEditor->OutputToString(aValue, format, flags);
|
|
}
|
|
// otherwise, just return our text attribute
|
|
else {
|
|
if (mCachedState) {
|
|
aValue = *mCachedState;
|
|
} else {
|
|
GetText(&aValue, PR_TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void nsGfxTextControlFrame::SetTextControlFrameState(const nsString& aValue)
|
|
{
|
|
if (mEditor && PR_TRUE==IsInitialized())
|
|
{
|
|
nsAutoString currentValue;
|
|
nsString format ("text/plain");
|
|
nsresult result = mEditor->OutputToString(currentValue, format, 0);
|
|
if (PR_TRUE==IsSingleLineTextControl()) {
|
|
RemoveNewlines(currentValue);
|
|
}
|
|
if (PR_FALSE==currentValue.Equals(aValue)) // this is necessary to avoid infinite recursion
|
|
{
|
|
nsCOMPtr<nsIDOMDocument>domDoc;
|
|
result = mEditor->GetDocument(getter_AddRefs(domDoc));
|
|
if (NS_FAILED(result)) return;
|
|
if (!domDoc) return;
|
|
|
|
result = mEditor->SelectAll();
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (!htmlEditor) return;
|
|
|
|
// get the flags, remove readonly and disabled, set the value, restore flags
|
|
PRUint32 flags, savedFlags;
|
|
mEditor->GetFlags(&savedFlags);
|
|
flags = savedFlags;
|
|
flags &= ~(nsIHTMLEditor::eEditorDisabledMask);
|
|
flags &= ~(nsIHTMLEditor::eEditorReadonlyMask);
|
|
mEditor->SetFlags(flags);
|
|
htmlEditor->InsertText(aValue);
|
|
mEditor->SetFlags(savedFlags);
|
|
}
|
|
}
|
|
else {
|
|
if (mCachedState) delete mCachedState;
|
|
mCachedState = new nsString(aValue);
|
|
NS_ASSERTION(mCachedState, "Error: new nsString failed!");
|
|
//if (!mCachedState) rv = NS_ERROR_OUT_OF_MEMORY;
|
|
if (mDisplayContent)
|
|
{
|
|
const PRUnichar *text = mCachedState->GetUnicode();
|
|
PRInt32 len = mCachedState->Length();
|
|
mDisplayContent->SetText(text, len, PR_TRUE);
|
|
if (mContent)
|
|
{
|
|
nsIDocument *doc;
|
|
mContent->GetDocument(doc);
|
|
if (doc)
|
|
{
|
|
doc->ContentChanged(mContent, nsnull);
|
|
NS_RELEASE(doc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP nsGfxTextControlFrame::SetProperty(nsIPresContext* aPresContext, nsIAtom* aName, const nsString& aValue)
|
|
{
|
|
if (PR_FALSE==mIsProcessing)
|
|
{
|
|
mIsProcessing = PR_TRUE;
|
|
if (nsHTMLAtoms::value == aName)
|
|
{
|
|
if (mEditor) {
|
|
mEditor->EnableUndo(PR_FALSE); // wipe out undo info
|
|
}
|
|
SetTextControlFrameState(aValue); // set new text value
|
|
if (mEditor) {
|
|
mEditor->EnableUndo(PR_TRUE); // fire up a new txn stack
|
|
}
|
|
}
|
|
else {
|
|
return Inherited::SetProperty(aPresContext, aName, aValue);
|
|
}
|
|
mIsProcessing = PR_FALSE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsGfxTextControlFrame::GetProperty(nsIAtom* aName, nsString& aValue)
|
|
{
|
|
// Return the value of the property from the widget it is not null.
|
|
// If widget is null, assume the widget is GFX-rendered and return a member variable instead.
|
|
|
|
if (nsHTMLAtoms::value == aName) {
|
|
GetTextControlFrameState(aValue);
|
|
}
|
|
else {
|
|
return Inherited::GetProperty(aName, aValue);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsGfxTextControlFrame::SetFocus(PRBool aOn, PRBool aRepaint)
|
|
{
|
|
// !! IF REMOVING THIS ANY CODE HERE
|
|
// !! READ HIDE THIS AND BELOW
|
|
//
|
|
// There are 3 cases where focus can get set:
|
|
// 1) from script
|
|
// 2) from tabbing into it
|
|
// 3) from clicking on it
|
|
//
|
|
// If removing any of this code PLEASE read comment below
|
|
nsresult result = NS_OK;
|
|
if (!mWebShell)
|
|
{
|
|
result = CreateSubDoc(nsnull);
|
|
if (NS_FAILED(result)) return;
|
|
}
|
|
if (aOn) {
|
|
|
|
nsIContentViewer *viewer = nsnull;
|
|
mWebShell->GetContentViewer(&viewer);
|
|
if (viewer) {
|
|
nsIDocumentViewer* docv = nsnull;
|
|
viewer->QueryInterface(kIDocumentViewerIID, (void**) &docv);
|
|
if (nsnull != docv) {
|
|
nsIPresContext* cx = nsnull;
|
|
docv->GetPresContext(cx);
|
|
if (nsnull != cx) {
|
|
nsIPresShell *shell = nsnull;
|
|
cx->GetShell(&shell);
|
|
if (nsnull != shell) {
|
|
nsIFrame * rootFrame;
|
|
shell->GetRootFrame(&rootFrame);
|
|
|
|
nsIViewManager *vm = nsnull;
|
|
shell->GetViewManager(&vm);
|
|
if (nsnull != vm) {
|
|
nsIView *rootview = nsnull;
|
|
vm->GetRootView(rootview);
|
|
if (rootview) {
|
|
// instead of using the rootview's widget we must find the deepest
|
|
// the deepest view and use its widget
|
|
nsIWidget* widget = GetDeepestWidget(rootview);
|
|
if (widget) {
|
|
// XXX Here we need to remember whether we set focus on the widget
|
|
// Later this is used to decided to continue to dispatch a Focus
|
|
// notification into the DOM. So if we reach here, it means
|
|
// a Focus message will be dispatched to the nsEnderEventListner
|
|
// and setting this to true won't propigate into the DOM, because we
|
|
// got here via the DOM
|
|
// See: nsEnderEventListener::Focus
|
|
result = widget->SetFocus();
|
|
mDidSetFocus = PR_TRUE;
|
|
NS_RELEASE(widget);
|
|
}
|
|
}
|
|
NS_RELEASE(vm);
|
|
}
|
|
NS_RELEASE(shell);
|
|
}
|
|
NS_RELEASE(cx);
|
|
}
|
|
NS_RELEASE(docv);
|
|
}
|
|
NS_RELEASE(viewer);
|
|
}
|
|
}
|
|
else {
|
|
mWebShell->RemoveFocus();
|
|
}
|
|
}
|
|
/* --------------------- Ender methods ---------------------- */
|
|
|
|
|
|
nsresult
|
|
nsGfxTextControlFrame::CreateWebShell(nsIPresContext* aPresContext,
|
|
const nsSize& aSize)
|
|
{
|
|
nsresult rv;
|
|
|
|
mWebShell = do_CreateInstance(kWebShellCID);
|
|
NS_ENSURE_TRUE(mWebShell, NS_ERROR_FAILURE);
|
|
|
|
// pass along marginwidth and marginheight so sub document can use it
|
|
mWebShell->SetMarginWidth(0);
|
|
mWebShell->SetMarginHeight(0);
|
|
|
|
/* our parent must be a webshell. we need to get our prefs from our parent */
|
|
nsCOMPtr<nsISupports> container;
|
|
aPresContext->GetContainer(getter_AddRefs(container));
|
|
NS_ENSURE_TRUE(container, NS_ERROR_UNEXPECTED);
|
|
|
|
nsCOMPtr<nsIWebShell> outerShell = do_QueryInterface(container);
|
|
NS_ENSURE_TRUE(outerShell, NS_ERROR_UNEXPECTED);
|
|
|
|
nsCOMPtr<nsIPref> outerPrefs; //connect the prefs
|
|
outerShell->GetPrefs(*getter_AddRefs(outerPrefs));
|
|
NS_ENSURE_TRUE(outerPrefs, NS_ERROR_UNEXPECTED);
|
|
|
|
mWebShell->SetPrefs(outerPrefs);
|
|
|
|
float t2p;
|
|
aPresContext->GetTwipsToPixels(&t2p);
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
rv = aPresContext->GetShell(getter_AddRefs(presShell));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
|
|
// create, init, set the parent of the view
|
|
nsIView* view;
|
|
rv = nsComponentManager::CreateInstance(kCViewCID, nsnull, kIViewIID,
|
|
(void **)&view);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
|
|
nsIView* parView;
|
|
nsPoint origin;
|
|
GetOffsetFromView(aPresContext, origin, &parView);
|
|
|
|
nsRect viewBounds(origin.x, origin.y, aSize.width, aSize.height);
|
|
#ifdef NOISY
|
|
printf("%p view bounds: x=%d, y=%d, w=%d, h=%d\n", view, origin.x, origin.y, aSize.width, aSize.height);
|
|
#endif
|
|
|
|
nsCOMPtr<nsIViewManager> viewMan;
|
|
presShell->GetViewManager(getter_AddRefs(viewMan));
|
|
rv = view->Init(viewMan, viewBounds, parView);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
viewMan->InsertChild(parView, view, 0);
|
|
rv = view->CreateWidget(kCChildCID);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
SetView(aPresContext, view);
|
|
|
|
// if the visibility is hidden, reflect that in the view
|
|
const nsStyleDisplay* display;
|
|
GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display));
|
|
if (NS_STYLE_VISIBILITY_VISIBLE != display->mVisible) {
|
|
view->SetVisibility(nsViewVisibility_kHide);
|
|
}
|
|
|
|
const nsStyleSpacing* spacing;
|
|
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing);
|
|
nsMargin border;
|
|
spacing->CalcBorderFor(this, border);
|
|
|
|
nsIWidget* widget;
|
|
view->GetWidget(widget);
|
|
nsRect webBounds(NSToCoordRound(border.left * t2p),
|
|
NSToCoordRound(border.top * t2p),
|
|
NSToCoordRound((aSize.width - border.right) * t2p),
|
|
NSToCoordRound((aSize.height - border.bottom) * t2p));
|
|
|
|
rv = mWebShell->Init(widget->GetNativeData(NS_NATIVE_WIDGET),
|
|
webBounds.x, webBounds.y,
|
|
webBounds.width, webBounds.height,
|
|
nsScrollPreference_kAuto, // auto scrolling
|
|
PR_FALSE // turn off plugin hosting
|
|
);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
NS_RELEASE(widget);
|
|
|
|
#ifdef NEW_WEBSHELL_INTERFACES
|
|
mWebShell->SetDocLoaderObserver(mTempObserver);
|
|
#else
|
|
nsCOMPtr<nsIDocumentLoader> docLoader;
|
|
mWebShell->GetDocumentLoader(*getter_AddRefs(docLoader));
|
|
if (docLoader) {
|
|
docLoader->AddObserver(mTempObserver);
|
|
}
|
|
#endif
|
|
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
|
|
NS_ENSURE_TRUE(webShellWin, NS_ERROR_FAILURE);
|
|
webShellWin->SetVisibility(PR_TRUE);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
PRInt32
|
|
nsGfxTextControlFrame::CalculateSizeNavQuirks (nsIPresContext* aPresContext,
|
|
nsIRenderingContext* aRendContext,
|
|
nsIFormControlFrame* aFrame,
|
|
const nsSize& aCSSSize,
|
|
nsInputDimensionSpec& aSpec,
|
|
nsSize& aDesiredSize,
|
|
nsSize& aMinSize,
|
|
PRBool& aWidthExplicit,
|
|
PRBool& aHeightExplicit,
|
|
nscoord& aRowHeight,
|
|
nsMargin& aBorder,
|
|
nsMargin& aPadding)
|
|
{
|
|
nscoord charWidth = 0;
|
|
aWidthExplicit = PR_FALSE;
|
|
aHeightExplicit = PR_FALSE;
|
|
|
|
aDesiredSize.width = CSS_NOTSET;
|
|
aDesiredSize.height = CSS_NOTSET;
|
|
|
|
// Quirks does not use rowAttr
|
|
nsHTMLValue colAttr;
|
|
nsresult colStatus;
|
|
nsHTMLValue rowAttr;
|
|
nsresult rowStatus;
|
|
if (NS_ERROR_FAILURE == GetColRowSizeAttr(aFrame,
|
|
aSpec.mColSizeAttr, colAttr, colStatus,
|
|
aSpec.mRowSizeAttr, rowAttr, rowStatus)) {
|
|
return 0;
|
|
}
|
|
|
|
// Get the Font Metrics for the Control
|
|
// without it we can't calculate the size
|
|
nsCOMPtr<nsIFontMetrics> fontMet;
|
|
nsFormControlHelper::GetFrameFontFM(aPresContext, aFrame, getter_AddRefs(fontMet));
|
|
if (fontMet) {
|
|
aRendContext->SetFont(fontMet);
|
|
|
|
// Figure out the number of columns
|
|
// and set that as the default col size
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == colStatus) { // col attr will provide width
|
|
PRInt32 col = ((colAttr.GetUnit() == eHTMLUnit_Pixel) ? colAttr.GetPixelValue() : colAttr.GetIntValue());
|
|
col = (col <= 0) ? 1 : col; // XXX why a default of 1 char, why hide it
|
|
aSpec.mColDefaultSize = col;
|
|
}
|
|
charWidth = nsFormControlHelper::CalcNavQuirkSizing(aPresContext,
|
|
aRendContext, fontMet,
|
|
aFrame, aSpec, aDesiredSize);
|
|
aMinSize.width = aDesiredSize.width;
|
|
|
|
// XXX I am commenting this out below to let CSS
|
|
// override the column setting - rods
|
|
|
|
// If COLS was not set then check to see if CSS has the width set
|
|
//if (NS_CONTENT_ATTR_HAS_VALUE != colStatus) { // col attr will provide width
|
|
if (CSS_NOTSET != aCSSSize.width) { // css provides width
|
|
NS_ASSERTION(aCSSSize.width >= 0, "form control's computed width is < 0");
|
|
if (NS_INTRINSICSIZE != aCSSSize.width) {
|
|
aDesiredSize.width = aCSSSize.width;
|
|
aWidthExplicit = PR_TRUE;
|
|
}
|
|
}
|
|
//}
|
|
|
|
aDesiredSize.height = aDesiredSize.height * aSpec.mRowDefaultSize;
|
|
if (CSS_NOTSET != aCSSSize.height) { // css provides height
|
|
NS_ASSERTION(aCSSSize.height > 0, "form control's computed height is <= 0");
|
|
if (NS_INTRINSICSIZE != aCSSSize.height) {
|
|
aDesiredSize.height = aCSSSize.height;
|
|
aHeightExplicit = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
NS_ASSERTION(fontMet, "Couldn't get Font Metrics");
|
|
aDesiredSize.width = 300; // arbitrary values
|
|
aDesiredSize.width = 1500;
|
|
}
|
|
|
|
aRowHeight = aDesiredSize.height;
|
|
aMinSize.height = aDesiredSize.height;
|
|
|
|
PRInt32 numRows = (aRowHeight > 0) ? (aDesiredSize.height / aRowHeight) : 0;
|
|
|
|
return numRows;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::ReflowNavQuirks(nsIPresContext* aPresContext,
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus,
|
|
nsMargin& aBorder,
|
|
nsMargin& aPadding)
|
|
{
|
|
nsMargin borderPadding;
|
|
borderPadding.SizeTo(0, 0, 0, 0);
|
|
// Get the CSS border
|
|
const nsStyleSpacing* spacing;
|
|
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing);
|
|
|
|
// This calculates the reflow size
|
|
// get the css size and let the frame use or override it
|
|
nsSize styleSize;
|
|
GetStyleSize(aPresContext, aReflowState, styleSize);
|
|
|
|
nsSize desiredSize;
|
|
nsSize minSize;
|
|
|
|
PRBool widthExplicit, heightExplicit;
|
|
PRInt32 ignore;
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if ((NS_FORM_INPUT_TEXT == type) || (NS_FORM_INPUT_PASSWORD == type)) {
|
|
PRInt32 width = 0;
|
|
if (NS_CONTENT_ATTR_HAS_VALUE != GetSizeFromContent(&width)) {
|
|
width = GetDefaultColumnWidth();
|
|
}
|
|
nsInputDimensionSpec textSpec(nsnull, PR_FALSE, nsnull,
|
|
nsnull, width,
|
|
PR_FALSE, nsnull, 1);
|
|
CalculateSizeNavQuirks(aPresContext, aReflowState.rendContext, this, styleSize,
|
|
textSpec, desiredSize, minSize, widthExplicit,
|
|
heightExplicit, ignore, aBorder, aPadding);
|
|
} else {
|
|
nsInputDimensionSpec areaSpec(nsHTMLAtoms::cols, PR_FALSE, nsnull,
|
|
nsnull, GetDefaultColumnWidth(),
|
|
PR_FALSE, nsHTMLAtoms::rows, 1);
|
|
CalculateSizeNavQuirks(aPresContext, aReflowState.rendContext, this, styleSize,
|
|
areaSpec, desiredSize, minSize, widthExplicit,
|
|
heightExplicit, ignore, aBorder, aPadding);
|
|
}
|
|
if (widthExplicit) {
|
|
desiredSize.width += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right;
|
|
}
|
|
if (heightExplicit) {
|
|
desiredSize.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom;
|
|
}
|
|
|
|
aDesiredSize.width = desiredSize.width;
|
|
aDesiredSize.height = desiredSize.height;
|
|
aDesiredSize.ascent = aDesiredSize.height;
|
|
aDesiredSize.descent = 0;
|
|
|
|
if (aDesiredSize.maxElementSize) {
|
|
aDesiredSize.maxElementSize->width = widthExplicit?desiredSize.width:minSize.width;
|
|
aDesiredSize.maxElementSize->height = heightExplicit?desiredSize.height:minSize.height;
|
|
}
|
|
|
|
// In Nav Quirks mode we only add in extra size for padding
|
|
nsMargin padding;
|
|
padding.SizeTo(0, 0, 0, 0);
|
|
spacing->CalcPaddingFor(this, padding);
|
|
|
|
// Check to see if style was responsible
|
|
// for setting the height or the width
|
|
PRBool addBorder = PR_FALSE;
|
|
PRInt32 width;
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == GetSizeFromContent(&width)) {
|
|
// if a size attr gets incorrectly
|
|
// put on a textarea it comes back as -1
|
|
if (width > -1) {
|
|
addBorder = (width < GetDefaultColumnWidth()) && !widthExplicit;
|
|
}
|
|
}
|
|
|
|
if (addBorder) {
|
|
if (CSS_NOTSET != styleSize.width ||
|
|
CSS_NOTSET != styleSize.height) { // css provides width
|
|
nsMargin border;
|
|
border.SizeTo(0, 0, 0, 0);
|
|
spacing->CalcBorderFor(this, border);
|
|
if (CSS_NOTSET != styleSize.width) { // css provides width
|
|
aDesiredSize.width += border.left + border.right;
|
|
}
|
|
if (CSS_NOTSET != styleSize.height) { // css provides heigth
|
|
aDesiredSize.height += border.top + border.bottom;
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsGfxTextControlFrame::GetColRowSizeAttr(nsIFormControlFrame* aFrame,
|
|
nsIAtom * aColSizeAttr,
|
|
nsHTMLValue & aColSize,
|
|
nsresult & aColStatus,
|
|
nsIAtom * aRowSizeAttr,
|
|
nsHTMLValue & aRowSize,
|
|
nsresult & aRowStatus)
|
|
{
|
|
nsIContent* iContent = nsnull;
|
|
aFrame->GetFormContent((nsIContent*&) iContent);
|
|
if (!iContent) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsIHTMLContent* hContent = nsnull;
|
|
nsresult result = iContent->QueryInterface(kIHTMLContentIID, (void**)&hContent);
|
|
if ((NS_OK != result) || !hContent) {
|
|
NS_RELEASE(iContent);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
aColStatus = NS_CONTENT_ATTR_NOT_THERE;
|
|
if (nsnull != aColSizeAttr) {
|
|
aColStatus = hContent->GetHTMLAttribute(aColSizeAttr, aColSize);
|
|
}
|
|
|
|
aRowStatus= NS_CONTENT_ATTR_NOT_THERE;
|
|
if (nsnull != aRowSizeAttr) {
|
|
aRowStatus = hContent->GetHTMLAttribute(aRowSizeAttr, aRowSize);
|
|
}
|
|
|
|
NS_RELEASE(hContent);
|
|
NS_RELEASE(iContent);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
PRInt32
|
|
nsGfxTextControlFrame::CalculateSizeStandard (nsIPresContext* aPresContext,
|
|
nsIRenderingContext* aRendContext,
|
|
nsIFormControlFrame* aFrame,
|
|
const nsSize& aCSSSize,
|
|
nsInputDimensionSpec& aSpec,
|
|
nsSize& aDesiredSize,
|
|
nsSize& aMinSize,
|
|
PRBool& aWidthExplicit,
|
|
PRBool& aHeightExplicit,
|
|
nscoord& aRowHeight,
|
|
nsMargin& aBorder,
|
|
nsMargin& aPadding)
|
|
{
|
|
nscoord charWidth = 0;
|
|
aWidthExplicit = PR_FALSE;
|
|
aHeightExplicit = PR_FALSE;
|
|
|
|
aDesiredSize.width = CSS_NOTSET;
|
|
aDesiredSize.height = CSS_NOTSET;
|
|
|
|
nsHTMLValue colAttr;
|
|
nsresult colStatus;
|
|
nsHTMLValue rowAttr;
|
|
nsresult rowStatus;
|
|
if (NS_ERROR_FAILURE == GetColRowSizeAttr(aFrame,
|
|
aSpec.mColSizeAttr, colAttr, colStatus,
|
|
aSpec.mRowSizeAttr, rowAttr, rowStatus)) {
|
|
return 0;
|
|
}
|
|
|
|
float p2t;
|
|
aPresContext->GetScaledPixelsToTwips(&p2t);
|
|
|
|
// determine the width, char height, row height
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == colStatus) { // col attr will provide width
|
|
PRInt32 col = ((colAttr.GetUnit() == eHTMLUnit_Pixel) ? colAttr.GetPixelValue() : colAttr.GetIntValue());
|
|
col = (col <= 0) ? 1 : col; // XXX why a default of 1 char, why hide it
|
|
charWidth = nsFormControlHelper::GetTextSize(aPresContext, aFrame, col, aDesiredSize, aRendContext);
|
|
aMinSize.width = aDesiredSize.width;
|
|
} else {
|
|
charWidth = nsFormControlHelper::GetTextSize(aPresContext, aFrame, aSpec.mColDefaultSize, aDesiredSize, aRendContext);
|
|
aMinSize.width = aDesiredSize.width;
|
|
if (CSS_NOTSET != aCSSSize.width) { // css provides width
|
|
NS_ASSERTION(aCSSSize.width >= 0, "form control's computed width is < 0");
|
|
if (NS_INTRINSICSIZE != aCSSSize.width) {
|
|
aDesiredSize.width = aCSSSize.width;
|
|
aWidthExplicit = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
nscoord fontHeight = 0;
|
|
//nscoord fontLeading = 0;
|
|
// get leading
|
|
nsCOMPtr<nsIFontMetrics> fontMet;
|
|
nsFormControlHelper::GetFrameFontFM(aPresContext, aFrame, getter_AddRefs(fontMet));
|
|
if (fontMet) {
|
|
aRendContext->SetFont(fontMet);
|
|
fontMet->GetHeight(fontHeight);
|
|
// leading is NOT suppose to be added in
|
|
//fontMet->GetLeading(fontLeading);
|
|
//aDesiredSize.height += fontLeading;
|
|
}
|
|
aRowHeight = aDesiredSize.height;
|
|
aMinSize.height = aDesiredSize.height;
|
|
PRInt32 numRows = 0;
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == rowStatus) { // row attr will provide height
|
|
PRInt32 rowAttrInt = ((rowAttr.GetUnit() == eHTMLUnit_Pixel)
|
|
? rowAttr.GetPixelValue() : rowAttr.GetIntValue());
|
|
numRows = (rowAttrInt > 0) ? rowAttrInt : 1;
|
|
aDesiredSize.height = aDesiredSize.height * numRows;
|
|
} else {
|
|
aDesiredSize.height = aDesiredSize.height * aSpec.mRowDefaultSize;
|
|
if (CSS_NOTSET != aCSSSize.height) { // css provides height
|
|
NS_ASSERTION(aCSSSize.height > 0, "form control's computed height is <= 0");
|
|
if (NS_INTRINSICSIZE != aCSSSize.height) {
|
|
aDesiredSize.height = aCSSSize.height;
|
|
aHeightExplicit = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
numRows = (aRowHeight > 0) ? (aDesiredSize.height / aRowHeight) : 0;
|
|
if (numRows == 1) {
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if (NS_FORM_TEXTAREA == type) {
|
|
aDesiredSize.height += fontHeight;
|
|
}
|
|
}
|
|
|
|
return numRows;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::ReflowStandard(nsIPresContext* aPresContext,
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus,
|
|
nsMargin& aBorder,
|
|
nsMargin& aPadding)
|
|
{
|
|
// get the css size and let the frame use or override it
|
|
nsSize styleSize;
|
|
GetStyleSize(aPresContext, aReflowState, styleSize);
|
|
|
|
nsSize desiredSize;
|
|
nsSize minSize;
|
|
|
|
PRBool widthExplicit, heightExplicit;
|
|
PRInt32 ignore;
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if ((NS_FORM_INPUT_TEXT == type) || (NS_FORM_INPUT_PASSWORD == type)) {
|
|
PRInt32 width = 0;
|
|
if (NS_CONTENT_ATTR_HAS_VALUE != GetSizeFromContent(&width)) {
|
|
width = GetDefaultColumnWidth();
|
|
}
|
|
nsInputDimensionSpec textSpec(nsnull, PR_FALSE, nsnull,
|
|
nsnull, width,
|
|
PR_FALSE, nsnull, 1);
|
|
CalculateSizeStandard(aPresContext, aReflowState.rendContext, this, styleSize,
|
|
textSpec, desiredSize, minSize, widthExplicit,
|
|
heightExplicit, ignore, aBorder, aPadding);
|
|
} else {
|
|
nsInputDimensionSpec areaSpec(nsHTMLAtoms::cols, PR_FALSE, nsnull,
|
|
nsnull, GetDefaultColumnWidth(),
|
|
PR_FALSE, nsHTMLAtoms::rows, 1);
|
|
CalculateSizeStandard(aPresContext, aReflowState.rendContext, this, styleSize,
|
|
areaSpec, desiredSize, minSize, widthExplicit,
|
|
heightExplicit, ignore, aBorder, aPadding);
|
|
}
|
|
|
|
// CalculateSize makes calls in the nsFormControlHelper that figures
|
|
// out the entire size of the control when in NavQuirks mode. For the
|
|
// textarea, this means the scrollbar sizes hav already been added to
|
|
// its overall size and do not need to be added here.
|
|
if (NS_FORM_TEXTAREA == type) {
|
|
float p2t;
|
|
aPresContext->GetPixelsToTwips(&p2t);
|
|
|
|
nscoord scrollbarWidth = 0;
|
|
nscoord scrollbarHeight = 0;
|
|
float scale;
|
|
nsCOMPtr<nsIDeviceContext> dx;
|
|
aPresContext->GetDeviceContext(getter_AddRefs(dx));
|
|
if (dx) {
|
|
float sbWidth;
|
|
float sbHeight;
|
|
dx->GetCanonicalPixelScale(scale);
|
|
dx->GetScrollBarDimensions(sbWidth, sbHeight);
|
|
scrollbarWidth = PRInt32(sbWidth * scale);
|
|
scrollbarHeight = PRInt32(sbHeight * scale);
|
|
} else {
|
|
scrollbarWidth = GetScrollbarWidth(p2t);
|
|
scrollbarHeight = scrollbarWidth;
|
|
}
|
|
|
|
if (!heightExplicit) {
|
|
desiredSize.height += scrollbarHeight;
|
|
minSize.height += scrollbarHeight;
|
|
}
|
|
if (!widthExplicit) {
|
|
desiredSize.width += scrollbarWidth;
|
|
minSize.width += scrollbarWidth;
|
|
}
|
|
}
|
|
desiredSize.width += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom;
|
|
desiredSize.height += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right;
|
|
|
|
aDesiredSize.width = desiredSize.width;
|
|
aDesiredSize.height = desiredSize.height;
|
|
aDesiredSize.ascent = aDesiredSize.height;
|
|
aDesiredSize.descent = 0;
|
|
|
|
if (aDesiredSize.maxElementSize) {
|
|
aDesiredSize.maxElementSize->width = minSize.width;
|
|
aDesiredSize.maxElementSize->height = minSize.height;
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::Reflow(nsIPresContext* aPresContext,
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
const nsHTMLReflowState& aReflowState,
|
|
nsReflowStatus& aStatus)
|
|
{
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
|
("enter nsGfxTextControlFrame::Reflow: aMaxSize=%d,%d",
|
|
aReflowState.availableWidth, aReflowState.availableHeight));
|
|
|
|
NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
|
|
|
|
// add ourself as an nsIFormControlFrame
|
|
if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) {
|
|
nsFormFrame::AddFormControlFrame(aPresContext, *NS_STATIC_CAST(nsIFrame*, this));
|
|
}
|
|
|
|
// Figure out if we are doing Quirks or Standard
|
|
nsCompatibility mode;
|
|
aPresContext->GetCompatibilityMode(&mode);
|
|
|
|
nsMargin border;
|
|
border.SizeTo(0, 0, 0, 0);
|
|
nsMargin padding;
|
|
padding.SizeTo(0, 0, 0, 0);
|
|
// Get the CSS border
|
|
const nsStyleSpacing* spacing;
|
|
GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing);
|
|
spacing->CalcBorderFor(this, border);
|
|
spacing->CalcPaddingFor(this, padding);
|
|
|
|
// calculate the the desired size for the text control
|
|
// use the suggested size if it has been set
|
|
nsresult rv = NS_OK;
|
|
nsHTMLReflowState suggestedReflowState(aReflowState);
|
|
if ((kSuggestedNotSet != mSuggestedWidth) ||
|
|
(kSuggestedNotSet != mSuggestedHeight)) {
|
|
// Honor the suggested width and/or height.
|
|
if (kSuggestedNotSet != mSuggestedWidth) {
|
|
suggestedReflowState.mComputedWidth = mSuggestedWidth;
|
|
aDesiredSize.width = mSuggestedWidth;
|
|
}
|
|
|
|
if (kSuggestedNotSet != mSuggestedHeight) {
|
|
suggestedReflowState.mComputedHeight = mSuggestedHeight;
|
|
aDesiredSize.height = mSuggestedHeight;
|
|
}
|
|
rv = NS_OK;
|
|
|
|
aDesiredSize.ascent = aDesiredSize.height;
|
|
aDesiredSize.descent = 0;
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
} else {
|
|
|
|
// this is the right way
|
|
// Quirks mode will NOT obey CSS border and padding
|
|
// GetDesiredSize calculates the size without CSS borders
|
|
// the nsLeafFrame::Reflow will add in the borders
|
|
if (eCompatibility_NavQuirks == mode) {
|
|
rv = ReflowNavQuirks(aPresContext, aDesiredSize, aReflowState, aStatus, border, padding);
|
|
} else {
|
|
rv = ReflowStandard(aPresContext, aDesiredSize, aReflowState, aStatus, border, padding);
|
|
}
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
|
if (aReflowState.mComputedWidth > aDesiredSize.width) {
|
|
aDesiredSize.width = aReflowState.mComputedWidth;
|
|
}
|
|
}
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
|
|
if (aReflowState.mComputedHeight > aDesiredSize.height) {
|
|
aDesiredSize.height = aReflowState.mComputedHeight;
|
|
}
|
|
}
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
}
|
|
|
|
#ifdef NOISY
|
|
printf ("exit nsGfxTextControlFrame::Reflow: size=%d,%d",
|
|
aDesiredSize.width, aDesiredSize.height);
|
|
#endif
|
|
|
|
float t2p, p2t;
|
|
mFramePresContext->GetTwipsToPixels(&t2p);
|
|
mFramePresContext->GetPixelsToTwips(&p2t);
|
|
// resize the sub document within the defined rect
|
|
// the sub-document will fit inside the border
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
nsRect subBounds;
|
|
nsRect subBoundsInPixels;
|
|
nsSize desiredSize(aDesiredSize.width, aDesiredSize.height);
|
|
CalcSizeOfSubDocInTwips(border, padding, desiredSize, subBounds);
|
|
subBoundsInPixels.x = NSToCoordRound(subBounds.x * t2p);
|
|
subBoundsInPixels.y = NSToCoordRound(subBounds.y * t2p);
|
|
subBoundsInPixels.width = NSToCoordRound(subBounds.width * t2p);
|
|
subBoundsInPixels.height = NSToCoordRound(subBounds.height * t2p);
|
|
if (eReflowReason_Initial == aReflowState.reason)
|
|
{
|
|
if (!mWebShell)
|
|
{ // if we haven't already created a webshell, then create something to hold the initial text
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if ((PR_FALSE==IsSingleLineTextControl()) || (NS_FORM_INPUT_PASSWORD == type))
|
|
{ // password controls and multi-line text areas get their subdoc right away
|
|
rv = CreateSubDoc(&subBoundsInPixels);
|
|
}
|
|
else
|
|
{ // single line text controls get a display frame rather than a subdoc.
|
|
// the subdoc will be created when the frame first gets focus
|
|
// create anonymous text content
|
|
nsCOMPtr<nsIContent> content;
|
|
rv = NS_NewTextNode(getter_AddRefs(content));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!content) { return NS_ERROR_NULL_POINTER; }
|
|
nsIDocument* doc;
|
|
mContent->GetDocument(doc);
|
|
content->SetDocument(doc, PR_FALSE);
|
|
NS_RELEASE(doc);
|
|
mContent->AppendChildTo(content, PR_FALSE);
|
|
|
|
// set the value of the text node
|
|
content->QueryInterface(nsITextContent::GetIID(), getter_AddRefs(mDisplayContent));
|
|
if (!mDisplayContent) {return NS_ERROR_NO_INTERFACE; }
|
|
nsAutoString value;
|
|
GetText(&value, PR_FALSE); // get the text value, either from input element attribute or cached state
|
|
PRInt32 len = value.Length();
|
|
if (0<len)
|
|
{
|
|
// for password fields, set the display text to '*', one per character
|
|
// XXX: the replacement character should be controllable via CSS
|
|
// for normal text fields, set the display text normally
|
|
if (NS_FORM_INPUT_PASSWORD == type)
|
|
{
|
|
PRUnichar *initialPasswordText;
|
|
initialPasswordText = new PRUnichar[len+1];
|
|
if (!initialPasswordText) { return NS_ERROR_NULL_POINTER; }
|
|
PRInt32 i=0;
|
|
for (; i<len; i++) {
|
|
initialPasswordText[i] = PASSWORD_REPLACEMENT_CHAR;
|
|
}
|
|
mDisplayContent->SetText(initialPasswordText, len, PR_TRUE);
|
|
delete [] initialPasswordText;
|
|
}
|
|
else
|
|
{
|
|
const PRUnichar *initialText;
|
|
initialText = value.GetUnicode();
|
|
mDisplayContent->SetText(initialText, len, PR_TRUE);
|
|
}
|
|
}
|
|
|
|
// create the pseudo frame for the anonymous content
|
|
if (mDisplayFrame) {
|
|
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, mDisplayFrame, nsnull);
|
|
rv = mDisplayFrame->Destroy(aPresContext);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
rv = NS_NewBlockFrame(shell, (nsIFrame**)&mDisplayFrame, NS_BLOCK_SPACE_MGR);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!mDisplayFrame) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
// create the style context for the anonymous frame
|
|
nsCOMPtr<nsIStyleContext> styleContext;
|
|
rv = aPresContext->ResolvePseudoStyleContextFor(content,
|
|
nsHTMLAtoms::mozSingleLineTextControlFrame,
|
|
mStyleContext,
|
|
PR_FALSE,
|
|
getter_AddRefs(styleContext));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!styleContext) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
// create a text frame and put it inside the block frame
|
|
nsIFrame *textFrame;
|
|
rv = NS_NewTextFrame(shell, &textFrame);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!textFrame) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIStyleContext> textStyleContext;
|
|
rv = aPresContext->ResolvePseudoStyleContextFor(content,
|
|
nsHTMLAtoms::mozSingleLineTextControlFrame,
|
|
styleContext,
|
|
PR_FALSE,
|
|
getter_AddRefs(textStyleContext));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!textStyleContext) { return NS_ERROR_NULL_POINTER; }
|
|
textFrame->Init(aPresContext, content, mDisplayFrame, textStyleContext, nsnull);
|
|
textFrame->SetInitialChildList(aPresContext, nsnull, nsnull);
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
rv = aPresContext->GetShell(getter_AddRefs(presShell));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!presShell) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIFrameManager> frameManager;
|
|
rv = presShell->GetFrameManager(getter_AddRefs(frameManager));
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
if (!frameManager) { return NS_ERROR_NULL_POINTER; }
|
|
frameManager->SetPrimaryFrameFor(content, textFrame);
|
|
|
|
rv = mDisplayFrame->Init(aPresContext, content, this, styleContext, nsnull);
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
|
|
mDisplayFrame->SetInitialChildList(aPresContext, nsnull, textFrame);
|
|
}
|
|
}
|
|
}
|
|
nsCOMPtr<nsIBaseWindow> webShellWin(do_QueryInterface(mWebShell));
|
|
if (webShellWin)
|
|
{
|
|
if (mDisplayFrame)
|
|
{
|
|
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, mDisplayFrame, nsnull);
|
|
mDisplayFrame->Destroy(mFramePresContext);
|
|
mDisplayFrame = nsnull;
|
|
}
|
|
#ifdef NOISY
|
|
printf("%p webshell in reflow set to bounds: x=%d, y=%d, w=%d, h=%d\n", mWebShell.get(), subBoundsInPixels.x, subBoundsInPixels.y, subBoundsInPixels.width, subBoundsInPixels.height);
|
|
#endif
|
|
webShellWin->SetPositionAndSize(subBoundsInPixels.x, subBoundsInPixels.y,
|
|
subBoundsInPixels.width, subBoundsInPixels.height, PR_FALSE);
|
|
}
|
|
else
|
|
{
|
|
// pass the reflow to mDisplayFrame, forcing him to fit
|
|
// mDisplayFrame->SetSuggestedSize(subBounds.width, subBounds.height);
|
|
if (mDisplayFrame)
|
|
{
|
|
// fix any possible pixel roundoff error (the webshell is sized in whole pixel units,
|
|
// and we need to make sure the text is painted in exactly the same place using either frame or shell.)
|
|
subBounds.x = NSToCoordRound(subBoundsInPixels.x * p2t);
|
|
subBounds.y = NSToCoordRound(subBoundsInPixels.y * p2t);
|
|
subBounds.width = NSToCoordRound(subBoundsInPixels.width * p2t);
|
|
subBounds.height = NSToCoordRound(subBoundsInPixels.height * p2t);
|
|
|
|
// build the data structures for reflowing mDisplayFrame
|
|
nsSize availSize(subBounds.width, subBounds.height);
|
|
nsHTMLReflowMetrics kidSize(&availSize);
|
|
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mDisplayFrame,
|
|
availSize);
|
|
|
|
// Send the WillReflow notification, and reflow the child frame
|
|
mDisplayFrame->WillReflow(aPresContext);
|
|
mDisplayFrame->MoveTo(aPresContext, subBounds.x, subBounds.y);
|
|
nsIView* view;
|
|
mDisplayFrame->GetView(aPresContext, &view);
|
|
if (view) {
|
|
nsContainerFrame::PositionFrameView(aPresContext, mDisplayFrame, view);
|
|
}
|
|
nsReflowStatus status;
|
|
rv = mDisplayFrame->Reflow(aPresContext, kidSize, kidReflowState, status);
|
|
// notice how status is ignored here
|
|
#ifdef NOISY
|
|
printf("%p mDisplayFrame resized to: x=%d, y=%d, w=%d, h=%d\n", mWebShell.get(), subBounds.x, subBounds.y, subBounds.width, subBounds.height);
|
|
#endif
|
|
mDisplayFrame->SetRect(aPresContext, subBounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
|
("exit nsGfxTextControlFrame::Reflow: size=%d,%d",
|
|
aDesiredSize.width, aDesiredSize.height));
|
|
|
|
// This code below will soon be changed over for NSPR logging
|
|
// It is used to figure out what font and font size the textarea or text field
|
|
// are and compares it to the know NavQuirks size
|
|
#ifdef DEBUG_rods
|
|
//#ifdef NS_DEBUG
|
|
{
|
|
nsFont font(aPresContext->GetDefaultFixedFontDeprecated());
|
|
GetFont(aPresContext, font);
|
|
nsCOMPtr<nsIDeviceContext> deviceContext;
|
|
aPresContext->GetDeviceContext(getter_AddRefs(deviceContext));
|
|
|
|
nsIFontMetrics* fontMet;
|
|
deviceContext->GetMetricsFor(font, fontMet);
|
|
|
|
const nsFont& normal = aPresContext->GetDefaultFixedFontDeprecated();
|
|
PRInt32 scaler;
|
|
aPresContext->GetFontScaler(&scaler);
|
|
float scaleFactor = nsStyleUtil::GetScalingFactor(scaler);
|
|
PRInt32 fontSize = nsStyleUtil::FindNextSmallerFontSize(font.size, (PRInt32)normal.size,
|
|
scaleFactor)+1;
|
|
PRBool doMeasure = PR_FALSE;
|
|
nsILookAndFeel::nsMetricNavFontID fontId;
|
|
|
|
nsFont defFont(aPresContext->GetDefaultFixedFontDeprecated());
|
|
if (font.name == defFont.name) {
|
|
fontId = nsILookAndFeel::eMetricSize_Courier;
|
|
doMeasure = PR_TRUE;
|
|
} else {
|
|
nsAutoString sansSerif("sans-serif");
|
|
if (font.name == sansSerif) {
|
|
fontId = nsILookAndFeel::eMetricSize_SansSerif;
|
|
doMeasure = PR_TRUE;
|
|
}
|
|
}
|
|
NS_RELEASE(fontMet);
|
|
|
|
if (doMeasure) {
|
|
nsCOMPtr<nsILookAndFeel> lf;
|
|
aPresContext->GetLookAndFeel(getter_AddRefs(lf));
|
|
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if (NS_FORM_TEXTAREA == type) {
|
|
if (fontSize > -1) {
|
|
nsSize size;
|
|
lf->GetNavSize(nsILookAndFeel::eMetricSize_TextArea, fontId, fontSize, size);
|
|
COMPARE_QUIRK_SIZE("nsGfxText(textarea)", size.width, size.height) // text area
|
|
}
|
|
} else {
|
|
if (fontSize > -1) {
|
|
nsSize size;
|
|
lf->GetNavSize(nsILookAndFeel::eMetricSize_TextField, fontId, fontSize, size);
|
|
COMPARE_QUIRK_SIZE("nsGfxText(field)", size.width, size.height) // text field
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsGfxTextControlFrame::RequiresWidget(PRBool &aRequiresWidget)
|
|
{
|
|
aRequiresWidget = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetPresShellFor(nsIWebShell* aWebShell, nsIPresShell** aPresShell)
|
|
{
|
|
if (!aWebShell || !aPresShell) { return NS_ERROR_NULL_POINTER; }
|
|
nsresult result = NS_ERROR_NULL_POINTER;
|
|
*aPresShell = nsnull;
|
|
nsIContentViewer* cv = nsnull;
|
|
aWebShell->GetContentViewer(&cv);
|
|
if (nsnull != cv)
|
|
{
|
|
nsIDocumentViewer* docv = nsnull;
|
|
cv->QueryInterface(kIDocumentViewerIID, (void**) &docv);
|
|
if (nsnull != docv)
|
|
{
|
|
nsIPresContext* cx;
|
|
docv->GetPresContext(cx);
|
|
if (nsnull != cx)
|
|
{
|
|
result = cx->GetShell(aPresShell);
|
|
NS_RELEASE(cx);
|
|
}
|
|
NS_RELEASE(docv);
|
|
}
|
|
NS_RELEASE(cv);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetFirstNodeOfType(const nsString& aTag, nsIDOMDocument *aDOMDoc, nsIDOMNode **aNode)
|
|
{
|
|
if (!aDOMDoc || !aNode) { return NS_ERROR_NULL_POINTER; }
|
|
*aNode=nsnull;
|
|
nsCOMPtr<nsIDOMNodeList>nodeList;
|
|
nsresult result = aDOMDoc->GetElementsByTagName(aTag, getter_AddRefs(nodeList));
|
|
if ((NS_SUCCEEDED(result)) && nodeList)
|
|
{
|
|
PRUint32 count;
|
|
nodeList->GetLength(&count);
|
|
result = nodeList->Item(0, aNode);
|
|
if (!aNode) { result = NS_ERROR_NULL_POINTER; }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsGfxTextControlFrame::GetFirstFrameForType(const nsString& aTag, nsIPresShell *aPresShell,
|
|
nsIDOMDocument *aDOMDoc, nsIFrame **aResult)
|
|
{
|
|
if (!aPresShell || !aDOMDoc || !aResult) { return NS_ERROR_NULL_POINTER; }
|
|
nsresult result;
|
|
*aResult = nsnull;
|
|
nsCOMPtr<nsIDOMNode>node;
|
|
result = GetFirstNodeOfType(aTag, aDOMDoc, getter_AddRefs(node));
|
|
if ((NS_SUCCEEDED(result)) && node)
|
|
{
|
|
nsCOMPtr<nsIContent>content = do_QueryInterface(node);
|
|
if (content)
|
|
{
|
|
result = aPresShell->GetPrimaryFrameFor(content, aResult);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// XXX: wouldn't it be nice to get this from the style context!
|
|
PRBool nsGfxTextControlFrame::IsSingleLineTextControl() const
|
|
{
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if ((NS_FORM_INPUT_TEXT==type) || (NS_FORM_INPUT_PASSWORD==type)) {
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// XXX: wouldn't it be nice to get this from the style context!
|
|
PRBool nsGfxTextControlFrame::IsPlainTextControl() const
|
|
{
|
|
// need to check HTML attribute of mContent and/or CSS.
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool nsGfxTextControlFrame::IsPasswordTextControl() const
|
|
{
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if (NS_FORM_INPUT_PASSWORD==type) {
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// so we don't have to keep an extra flag around, just see if
|
|
// we've allocated the event listener or not.
|
|
PRBool nsGfxTextControlFrame::IsInitialized() const
|
|
{
|
|
return (PRBool)(mEditor && mEventListener);
|
|
}
|
|
|
|
PRInt32
|
|
nsGfxTextControlFrame::GetWidthInCharacters() const
|
|
{
|
|
// see if there's a COL attribute, if so it wins
|
|
nsCOMPtr<nsIHTMLContent> content;
|
|
nsresult result = mContent->QueryInterface(nsIHTMLContent::GetIID(), getter_AddRefs(content));
|
|
if (NS_SUCCEEDED(result) && content)
|
|
{
|
|
nsHTMLValue resultValue;
|
|
result = content->GetHTMLAttribute(nsHTMLAtoms::cols, resultValue);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result)
|
|
{
|
|
if (resultValue.GetUnit() == eHTMLUnit_Integer)
|
|
{
|
|
return (resultValue.GetIntValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
// otherwise, see if CSS has a width specified. If so, work backwards to get the
|
|
// number of characters this width represents.
|
|
|
|
|
|
// otherwise, the default is just returned.
|
|
return GetDefaultColumnWidth();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::InstallEditor()
|
|
{
|
|
nsresult result = NS_ERROR_NULL_POINTER;
|
|
if (mEditor)
|
|
{
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
result = GetPresShellFor(mWebShell, getter_AddRefs(presShell));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!presShell) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
// set the scrolling behavior
|
|
nsCOMPtr<nsIViewManager> vm;
|
|
presShell->GetViewManager(getter_AddRefs(vm));
|
|
if (vm)
|
|
{
|
|
nsIScrollableView *sv=nsnull;
|
|
vm->GetRootScrollableView(&sv);
|
|
if (sv) {
|
|
if (PR_TRUE==IsSingleLineTextControl()) {
|
|
sv->SetScrollPreference(nsScrollPreference_kNeverScroll);
|
|
} else {
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
if (NS_FORM_TEXTAREA == type) {
|
|
nsScrollPreference scrollPref = nsScrollPreference_kAlwaysScroll;
|
|
nsFormControlHelper::nsHTMLTextWrap wrapProp;
|
|
result = nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result) {
|
|
if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Soft ||
|
|
wrapProp == nsFormControlHelper::eHTMLTextWrap_Hard) {
|
|
scrollPref = nsScrollPreference_kAuto;
|
|
}
|
|
}
|
|
sv->SetScrollPreference(scrollPref);
|
|
}
|
|
}
|
|
// views are not refcounted
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
presShell->GetDocument(getter_AddRefs(doc));
|
|
NS_ASSERTION(doc, "null document");
|
|
if (!doc) { return NS_ERROR_NULL_POINTER; }
|
|
mDoc = do_QueryInterface(doc);
|
|
if (!mDoc) { return NS_ERROR_NULL_POINTER; }
|
|
if (mDocObserver) {
|
|
doc->AddObserver(mDocObserver);
|
|
}
|
|
|
|
PRUint32 editorFlags = 0;
|
|
if (IsPlainTextControl())
|
|
editorFlags |= nsIHTMLEditor::eEditorPlaintextMask;
|
|
if (IsSingleLineTextControl())
|
|
editorFlags |= nsIHTMLEditor::eEditorSingleLineMask;
|
|
if (IsPasswordTextControl())
|
|
editorFlags |= nsIHTMLEditor::eEditorPasswordMask;
|
|
|
|
// initialize the editor
|
|
result = mEditor->Init(mDoc, presShell, editorFlags);
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
// set data from the text control into the editor
|
|
result = InitializeTextControl(presShell, mDoc);
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
// install our own event handlers before the editor's event handlers
|
|
result = InstallEventListeners();
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
// finish editor initialization, including event handler installation
|
|
result = mEditor->PostCreate();
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
// check to see if mContent has focus, and if so tell the webshell.
|
|
nsIEventStateManager *manager;
|
|
result = mFramePresContext->GetEventStateManager(&manager);
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!manager) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
nsIContent *focusContent=nsnull;
|
|
result = manager->GetFocusedContent(&focusContent);
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (focusContent)
|
|
{
|
|
if (mContent==focusContent)
|
|
{
|
|
// XXX WebShell redesign work
|
|
SetFocus();
|
|
}
|
|
}
|
|
NS_RELEASE(manager);
|
|
}
|
|
mCreatingViewer = PR_FALSE;
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::InstallEventListeners()
|
|
{
|
|
nsresult result;
|
|
|
|
// get the DOM event receiver
|
|
nsCOMPtr<nsIDOMEventReceiver> er;
|
|
result = mDoc->QueryInterface(nsIDOMEventReceiver::GetIID(), getter_AddRefs(er));
|
|
if (!er) { result = NS_ERROR_NULL_POINTER; }
|
|
|
|
// get the view from the webshell
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
result = GetPresShellFor(mWebShell, getter_AddRefs(presShell));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!presShell) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIViewManager> vm;
|
|
presShell->GetViewManager(getter_AddRefs(vm));
|
|
if (!vm) { return NS_ERROR_NULL_POINTER; }
|
|
nsIScrollableView *sv=nsnull;
|
|
vm->GetRootScrollableView(&sv);
|
|
if (!sv) { return NS_ERROR_NULL_POINTER; }
|
|
nsIView *view;
|
|
sv->QueryInterface(nsIView::GetIID(), (void **)&view);
|
|
if (!view) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
// we need to hook up our listeners before the editor is initialized
|
|
result = NS_NewEnderEventListener(getter_AddRefs(mEventListener));
|
|
if (NS_FAILED(result)) { return result ; }
|
|
if (!mEventListener) { return NS_ERROR_NULL_POINTER; }
|
|
mEventListener->SetFrame(this);
|
|
mEventListener->SetInnerPresShell(presShell);
|
|
mEventListener->SetPresContext(mFramePresContext);
|
|
mEventListener->SetView(view);
|
|
|
|
nsCOMPtr<nsIDOMKeyListener> keyListener = do_QueryInterface(mEventListener);
|
|
if (!keyListener) { return NS_ERROR_NO_INTERFACE; }
|
|
result = er->AddEventListenerByIID(keyListener, nsIDOMKeyListener::GetIID());
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
nsCOMPtr<nsIDOMMouseListener> mouseListener = do_QueryInterface(mEventListener);
|
|
if (!mouseListener) { return NS_ERROR_NO_INTERFACE; }
|
|
result = er->AddEventListenerByIID(mouseListener, nsIDOMMouseListener::GetIID());
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
nsCOMPtr<nsIDOMFocusListener> focusListener = do_QueryInterface(mEventListener);
|
|
if (!focusListener) { return NS_ERROR_NO_INTERFACE; }
|
|
result = er->AddEventListenerByIID(focusListener, nsIDOMFocusListener::GetIID());
|
|
if (NS_FAILED(result)) { return result; }
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::InitializeTextControl(nsIPresShell *aPresShell, nsIDOMDocument *aDoc)
|
|
{
|
|
nsresult result;
|
|
if (!aPresShell || !aDoc) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
/* needing a frame here is a hack. We can't remove this hack until we can
|
|
* set presContext info before style resolution on the webshell
|
|
*/
|
|
nsIFrame *frame;
|
|
result = aPresShell->GetRootFrame(&frame);
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!frame) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
PRInt32 type;
|
|
GetType(&type);
|
|
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (!htmlEditor) { return NS_ERROR_NO_INTERFACE; }
|
|
|
|
nsCOMPtr<nsIPresContext>presContext;
|
|
aPresShell->GetPresContext(getter_AddRefs(presContext));
|
|
NS_ASSERTION(presContext, "null presentation context");
|
|
if (!presContext) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
/* set all style that propogates from the text control to its content
|
|
* into the presContext for the webshell.
|
|
* what I would prefer to do is hand the webshell my own
|
|
* pres context at creation, rather than having it create its own.
|
|
*/
|
|
|
|
nsFont font(presContext->GetDefaultFixedFontDeprecated());
|
|
GetFont(presContext, font);
|
|
const nsStyleFont* controlFont;
|
|
GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)controlFont);
|
|
presContext->SetDefaultFont(font);
|
|
presContext->SetDefaultFixedFont(font);
|
|
|
|
const nsStyleColor* controlColor;
|
|
GetStyleData(eStyleStruct_Color, (const nsStyleStruct *&)controlColor);
|
|
presContext->SetDefaultColor(controlColor->mColor);
|
|
presContext->SetDefaultBackgroundColor(controlColor->mBackgroundColor);
|
|
presContext->SetDefaultBackgroundImageRepeat(controlColor->mBackgroundRepeat);
|
|
presContext->SetDefaultBackgroundImageAttachment(controlColor->mBackgroundAttachment);
|
|
presContext->SetDefaultBackgroundImageOffset(controlColor->mBackgroundXPosition, controlColor->mBackgroundYPosition);
|
|
presContext->SetDefaultBackgroundImage(controlColor->mBackgroundImage);
|
|
|
|
/* HACK:
|
|
* since I don't yet have a hook for setting info on the pres context before style is
|
|
* resolved, I need to call remap style on the root frame's style context.
|
|
* The above code for setting presContext data should happen on a presContext that
|
|
* I create and pass into the webshell, rather than having the webshell create its own
|
|
*/
|
|
nsCOMPtr<nsIStyleContext> sc;
|
|
result = frame->GetStyleContext(getter_AddRefs(sc));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (nsnull==sc) { return NS_ERROR_NULL_POINTER; }
|
|
sc->RemapStyle(presContext);
|
|
// end HACK
|
|
|
|
// now that the style context is initialized, initialize the content
|
|
nsAutoString value;
|
|
if (mCachedState) {
|
|
value = *mCachedState;
|
|
delete mCachedState;
|
|
mCachedState = nsnull;
|
|
} else {
|
|
GetText(&value, PR_TRUE);
|
|
}
|
|
mEditor->EnableUndo(PR_FALSE);
|
|
|
|
PRInt32 maxLength;
|
|
result = GetMaxLength(&maxLength);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result) {
|
|
htmlEditor->SetMaxTextLength(maxLength);
|
|
}
|
|
|
|
nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor);
|
|
if (mailEditor)
|
|
{
|
|
PRBool wrapToContainerWidth = PR_TRUE;
|
|
if (PR_TRUE==IsSingleLineTextControl())
|
|
{ // no wrapping for single line text controls
|
|
result = mailEditor->SetBodyWrapWidth(-1);
|
|
wrapToContainerWidth = PR_FALSE;
|
|
}
|
|
else
|
|
{ // if WRAP="OFF", turn wrapping off in the editor
|
|
nsFormControlHelper::nsHTMLTextWrap wrapProp;
|
|
result = nsFormControlHelper::GetWrapPropertyEnum(mContent, wrapProp);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result)
|
|
{
|
|
if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Off)
|
|
{
|
|
result = mailEditor->SetBodyWrapWidth(-1);
|
|
wrapToContainerWidth = PR_FALSE;
|
|
}
|
|
if (wrapProp == nsFormControlHelper::eHTMLTextWrap_Hard)
|
|
{
|
|
PRInt32 widthInCharacters = GetWidthInCharacters();
|
|
result = mailEditor->SetBodyWrapWidth(widthInCharacters);
|
|
wrapToContainerWidth = PR_FALSE;
|
|
}
|
|
} else {
|
|
wrapToContainerWidth = PR_FALSE;
|
|
}
|
|
}
|
|
if (PR_TRUE==wrapToContainerWidth)
|
|
{ // if we didn't set wrapping explicitly, turn on default wrapping here
|
|
result = mailEditor->SetBodyWrapWidth(0);
|
|
}
|
|
NS_ASSERTION((NS_SUCCEEDED(result)), "error setting body wrap width");
|
|
if (NS_FAILED(result)) { return result; }
|
|
}
|
|
|
|
nsCOMPtr<nsIEditor>editor = do_QueryInterface(mEditor);
|
|
NS_ASSERTION(editor, "bad QI to nsIEditor from mEditor");
|
|
if (editor)
|
|
{
|
|
nsCOMPtr<nsIDOMSelection>selection;
|
|
result = editor->GetSelection(getter_AddRefs(selection));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!selection) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIDOMNode>bodyNode;
|
|
nsAutoString bodyTag = "body";
|
|
result = GetFirstNodeOfType(bodyTag, aDoc, getter_AddRefs(bodyNode));
|
|
if (NS_SUCCEEDED(result) && bodyNode)
|
|
{
|
|
result = mEditor->SelectAll();
|
|
if (NS_SUCCEEDED(result))
|
|
{
|
|
if (0!=value.Length())
|
|
{
|
|
result = htmlEditor->InsertText(value);
|
|
if (NS_FAILED(result)) { return result; }
|
|
// collapse selection to beginning of text
|
|
nsCOMPtr<nsIDOMNode>firstChild;
|
|
result = bodyNode->GetFirstChild(getter_AddRefs(firstChild));
|
|
if (NS_FAILED(result)) { return result; }
|
|
selection->Collapse(firstChild, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// finish initializing editor
|
|
mEditor->EnableUndo(PR_TRUE);
|
|
|
|
// set readonly and disabled states
|
|
if (mContent)
|
|
{
|
|
PRUint32 flags=0;
|
|
if (IsPlainTextControl()) {
|
|
flags |= nsIHTMLEditor::eEditorPlaintextMask;
|
|
}
|
|
if (IsSingleLineTextControl()) {
|
|
flags |= nsIHTMLEditor::eEditorSingleLineMask;
|
|
}
|
|
if (IsPasswordTextControl()) {
|
|
flags |= nsIHTMLEditor::eEditorPasswordMask;
|
|
}
|
|
nsCOMPtr<nsIContent> content;
|
|
result = mContent->QueryInterface(nsIContent::GetIID(), getter_AddRefs(content));
|
|
if (NS_SUCCEEDED(result) && content)
|
|
{
|
|
PRInt32 nameSpaceID;
|
|
content->GetNameSpaceID(nameSpaceID);
|
|
nsAutoString resultValue;
|
|
result = content->GetAttribute(nameSpaceID, nsHTMLAtoms::readonly, resultValue);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result) {
|
|
flags |= nsIHTMLEditor::eEditorReadonlyMask;
|
|
aPresShell->SetCaretEnabled(PR_FALSE);
|
|
}
|
|
result = content->GetAttribute(nameSpaceID, nsHTMLAtoms::disabled, resultValue);
|
|
if (NS_CONTENT_ATTR_NOT_THERE != result)
|
|
{
|
|
flags |= nsIHTMLEditor::eEditorDisabledMask;
|
|
aPresShell->SetCaretEnabled(PR_FALSE);
|
|
nsCOMPtr<nsIDocument>doc = do_QueryInterface(aDoc);
|
|
if (doc) {
|
|
doc->SetDisplaySelection(PR_FALSE);
|
|
}
|
|
}
|
|
}
|
|
mEditor->SetFlags(flags);
|
|
|
|
// turn on oninput notifications now that I'm done manipulating the editable content
|
|
mNotifyOnInput = PR_TRUE;
|
|
|
|
// add the selection listener
|
|
nsCOMPtr<nsIDOMSelection>selection;
|
|
if (mEditor && mEventListener)
|
|
{
|
|
result = mEditor->GetSelection(getter_AddRefs(selection));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (!selection) { return NS_ERROR_NULL_POINTER; }
|
|
nsCOMPtr<nsIDOMSelectionListener> selectionListener = do_QueryInterface(mEventListener);
|
|
if (!selectionListener) { return NS_ERROR_NO_INTERFACE; }
|
|
selection->AddSelectionListener(selectionListener);
|
|
if (NS_FAILED(result)) { return result; }
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// this is where we propogate a content changed event
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::InternalContentChanged()
|
|
{
|
|
NS_PRECONDITION(mContent, "illegal to call unless we map to a content node");
|
|
|
|
if (!mContent) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
if (PR_FALSE==mNotifyOnInput) {
|
|
return NS_OK; // if notification is turned off, just return ok
|
|
}
|
|
|
|
// Dispatch the change event
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsGUIEvent event;
|
|
event.eventStructType = NS_GUI_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_FORM_INPUT;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
|
|
// Have the content handle the event, propogating it according to normal DOM rules.
|
|
nsresult result = mContent->HandleDOMEvent(mFramePresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
|
|
// update commands via controllers interface, if present
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
nsCOMPtr<nsIDOMNSHTMLInputElement> textInputDOMElement = do_QueryInterface(mContent);
|
|
if (textInputDOMElement) {
|
|
result = textInputDOMElement->GetControllers(getter_AddRefs(controllers));
|
|
}
|
|
else
|
|
{
|
|
nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textAreaDOMElement = do_QueryInterface(mContent);
|
|
if (textAreaDOMElement) {
|
|
result = textAreaDOMElement->GetControllers(getter_AddRefs(controllers));
|
|
}
|
|
}
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (controllers)
|
|
{
|
|
nsCOMPtr<nsIDOMXULCommandDispatcher> commandDispatcher;
|
|
result = controllers->GetCommandDispatcher(getter_AddRefs(commandDispatcher));
|
|
if (NS_FAILED(result)) { return result; }
|
|
if (commandDispatcher)
|
|
{
|
|
nsAutoString commandString("furby");
|
|
result = commandDispatcher->UpdateCommands(commandString);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void nsGfxTextControlFrame::RemoveNewlines(nsString &aString)
|
|
{
|
|
// strip CR/LF
|
|
static const char badChars[] = {10, 13, 0};
|
|
aString.StripChars(badChars);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::GetAdditionalChildListName(PRInt32 aIndex,
|
|
nsIAtom **aListName) const
|
|
{
|
|
if (aIndex == 0) {
|
|
*aListName = nsLayoutAtoms::editorDisplayList;
|
|
NS_IF_ADDREF(*aListName);
|
|
}
|
|
|
|
return nsTextControlFrame::GetAdditionalChildListName(aIndex, aListName);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::FirstChild(nsIAtom* aListName, nsIFrame** aFirstChild) const
|
|
{
|
|
if (nsLayoutAtoms::editorDisplayList) {
|
|
*aFirstChild = mDisplayFrame;
|
|
return NS_OK;
|
|
}
|
|
|
|
return nsTextControlFrame::FirstChild(aListName, aFirstChild);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::Destroy(nsIPresContext* aPresContext)
|
|
{
|
|
if (mDisplayFrame) {
|
|
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, mDisplayFrame, nsnull);
|
|
mDisplayFrame->Destroy(aPresContext);
|
|
mDisplayFrame=nsnull;
|
|
}
|
|
return nsTextControlFrame::Destroy(aPresContext);
|
|
}
|
|
|
|
#ifdef NS_DEBUG
|
|
NS_IMETHODIMP
|
|
nsGfxTextControlFrame::List(nsIPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
|
|
{
|
|
IndentBy(out, aIndent);
|
|
ListTag(out);
|
|
nsIView* view;
|
|
GetView(aPresContext, &view);
|
|
if (nsnull != view) {
|
|
fprintf(out, " [view=%p]", view);
|
|
}
|
|
fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
|
|
if (0 != mState) {
|
|
fprintf(out, " [state=%08x]", mState);
|
|
}
|
|
fputs("<\n", out);
|
|
|
|
// Dump out frames contained in interior web-shell
|
|
if (mWebShell) {
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
mWebShell->GetContentViewer(getter_AddRefs(viewer));
|
|
if (viewer) {
|
|
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(viewer));
|
|
if (docv) {
|
|
nsCOMPtr<nsIPresContext> cx;
|
|
docv->GetPresContext(*getter_AddRefs(cx));
|
|
if (cx) {
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
cx->GetShell(getter_AddRefs(shell));
|
|
if (shell) {
|
|
nsIFrame* rootFrame;
|
|
shell->GetRootFrame(&rootFrame);
|
|
if (rootFrame) {
|
|
nsIFrameDebug* frameDebug;
|
|
|
|
if (NS_SUCCEEDED(rootFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
|
|
frameDebug->List(aPresContext, out, aIndent + 1);
|
|
}
|
|
nsCOMPtr<nsIDocument> doc;
|
|
docv->GetDocument(*getter_AddRefs(doc));
|
|
if (doc) {
|
|
nsCOMPtr<nsIContent> rootContent(getter_AddRefs(doc->GetRootContent()));
|
|
if (rootContent) {
|
|
rootContent->List(out, aIndent + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IndentBy(out, aIndent);
|
|
fputs(">\n", out);
|
|
|
|
if (mDisplayFrame) {
|
|
nsIFrameDebug* frameDebug;
|
|
|
|
IndentBy(out, aIndent);
|
|
nsAutoString tmp;
|
|
fputs("<\n", out);
|
|
if (NS_SUCCEEDED(mDisplayFrame->QueryInterface(nsIFrameDebug::GetIID(), (void**)&frameDebug))) {
|
|
frameDebug->List(aPresContext, out, aIndent + 1);
|
|
}
|
|
IndentBy(out, aIndent);
|
|
fputs(">\n", out);
|
|
}
|
|
|
|
|
|
return NS_OK;
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* EnderFrameLoadingInfo
|
|
******************************************************************************/
|
|
class EnderFrameLoadingInfo : public nsISupports
|
|
{
|
|
public:
|
|
EnderFrameLoadingInfo(const nsSize& aSize);
|
|
|
|
// nsISupports interface...
|
|
NS_DECL_ISUPPORTS
|
|
|
|
protected:
|
|
virtual ~EnderFrameLoadingInfo() {}
|
|
|
|
public:
|
|
nsSize mFrameSize;
|
|
};
|
|
|
|
EnderFrameLoadingInfo::EnderFrameLoadingInfo(const nsSize& aSize)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
mFrameSize = aSize;
|
|
}
|
|
|
|
/*
|
|
* Implementation of ISupports methods...
|
|
*/
|
|
NS_IMPL_ISUPPORTS(EnderFrameLoadingInfo,kISupportsIID);
|
|
|
|
|
|
/*******************************************************************************
|
|
* nsEnderDocumentObserver
|
|
******************************************************************************/
|
|
NS_IMPL_ADDREF(nsEnderDocumentObserver);
|
|
NS_IMPL_RELEASE(nsEnderDocumentObserver);
|
|
|
|
nsEnderDocumentObserver::nsEnderDocumentObserver()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsEnderDocumentObserver::~nsEnderDocumentObserver()
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
nsEnderDocumentObserver::QueryInterface(const nsIID& aIID,
|
|
void** aInstancePtr)
|
|
{
|
|
NS_PRECONDITION(nsnull != aInstancePtr, "null pointer");
|
|
if (nsnull == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(kIDocumentObserverIID)) {
|
|
*aInstancePtr = (void*) ((nsIStreamObserver*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*) ((nsISupports*)((nsIDocumentObserver*)this));
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEnderDocumentObserver::SetFrame(nsGfxTextControlFrame *aFrame)
|
|
{
|
|
mFrame = aFrame;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::BeginUpdate(nsIDocument *aDocument)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::EndUpdate(nsIDocument *aDocument)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::BeginLoad(nsIDocument *aDocument)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::EndLoad(nsIDocument *aDocument)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::EndReflow(nsIDocument *aDocument, nsIPresShell* aShell)
|
|
{ return NS_OK; }
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::ContentChanged(nsIDocument *aDocument,
|
|
nsIContent* aContent,
|
|
nsISupports* aSubContent)
|
|
{
|
|
nsresult result = NS_OK;
|
|
if (mFrame) {
|
|
result = mFrame->InternalContentChanged();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::ContentStatesChanged(nsIDocument* aDocument,
|
|
nsIContent* aContent1,
|
|
nsIContent* aContent2)
|
|
{ return NS_OK; }
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::AttributeChanged(nsIDocument *aDocument,
|
|
nsIContent* aContent,
|
|
PRInt32 aNameSpaceID,
|
|
nsIAtom* aAttribute,
|
|
PRInt32 aHint)
|
|
{ return NS_OK; }
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::ContentAppended(nsIDocument *aDocument,
|
|
nsIContent* aContainer,
|
|
PRInt32 aNewIndexInContainer)
|
|
{
|
|
nsresult result = NS_OK;
|
|
if (mFrame) {
|
|
result = mFrame->InternalContentChanged();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::ContentInserted(nsIDocument *aDocument,
|
|
nsIContent* aContainer,
|
|
nsIContent* aChild,
|
|
PRInt32 aIndexInContainer)
|
|
{
|
|
nsresult result = NS_OK;
|
|
if (mFrame) {
|
|
result = mFrame->InternalContentChanged();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::ContentReplaced(nsIDocument *aDocument,
|
|
nsIContent* aContainer,
|
|
nsIContent* aOldChild,
|
|
nsIContent* aNewChild,
|
|
PRInt32 aIndexInContainer)
|
|
{
|
|
nsresult result = NS_OK;
|
|
if (mFrame) {
|
|
result = mFrame->InternalContentChanged();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::ContentRemoved(nsIDocument *aDocument,
|
|
nsIContent* aContainer,
|
|
nsIContent* aChild,
|
|
PRInt32 aIndexInContainer)
|
|
{
|
|
nsresult result = NS_OK;
|
|
if (mFrame) {
|
|
result = mFrame->InternalContentChanged();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::StyleSheetAdded(nsIDocument *aDocument,
|
|
nsIStyleSheet* aStyleSheet)
|
|
{ return NS_OK; }
|
|
NS_IMETHODIMP nsEnderDocumentObserver::StyleSheetRemoved(nsIDocument *aDocument,
|
|
nsIStyleSheet* aStyleSheet)
|
|
{ return NS_OK; }
|
|
NS_IMETHODIMP nsEnderDocumentObserver::StyleSheetDisabledStateChanged(nsIDocument *aDocument,
|
|
nsIStyleSheet* aStyleSheet,
|
|
PRBool aDisabled)
|
|
{ return NS_OK; }
|
|
NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleChanged(nsIDocument *aDocument,
|
|
nsIStyleSheet* aStyleSheet,
|
|
nsIStyleRule* aStyleRule,
|
|
PRInt32 aHint)
|
|
{ return NS_OK; }
|
|
NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleAdded(nsIDocument *aDocument,
|
|
nsIStyleSheet* aStyleSheet,
|
|
nsIStyleRule* aStyleRule)
|
|
{ return NS_OK; }
|
|
NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleRemoved(nsIDocument *aDocument,
|
|
nsIStyleSheet* aStyleSheet,
|
|
nsIStyleRule* aStyleRule)
|
|
{ return NS_OK; }
|
|
|
|
NS_IMETHODIMP nsEnderDocumentObserver::DocumentWillBeDestroyed(nsIDocument *aDocument)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* nsEnderEventListener
|
|
******************************************************************************/
|
|
|
|
nsresult
|
|
NS_NewEnderEventListener(nsIEnderEventListener ** aInstancePtr)
|
|
{
|
|
nsEnderEventListener* it = new nsEnderEventListener();
|
|
if (nsnull == it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return it->QueryInterface(nsIEnderEventListener::GetIID(), (void **) aInstancePtr);
|
|
}
|
|
|
|
NS_IMPL_ADDREF(nsEnderEventListener)
|
|
|
|
NS_IMPL_RELEASE(nsEnderEventListener)
|
|
|
|
|
|
nsEnderEventListener::nsEnderEventListener()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mView = nsnull;
|
|
|
|
// needed for when mouse down set focus on native widgets
|
|
mSkipFocusDispatch = PR_FALSE;
|
|
|
|
// other fields are objects that initialize themselves
|
|
}
|
|
|
|
nsEnderEventListener::~nsEnderEventListener()
|
|
{
|
|
// all refcounted objects are held as nsCOMPtrs, clear themselves
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEnderEventListener::SetFrame(nsGfxTextControlFrame *aFrame)
|
|
{
|
|
mFrame.SetReference(aFrame->WeakReferent());
|
|
if (aFrame)
|
|
{
|
|
aFrame->GetContent(getter_AddRefs(mContent));
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
if (nsnull == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
nsIDOMKeyListener *tmp = this;
|
|
nsISupports *tmp2 = tmp;
|
|
*aInstancePtr = (void*) tmp2;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
|
|
static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID);
|
|
if (aIID.Equals(kIDOMEventListenerIID)) {
|
|
nsIDOMKeyListener *kl = (nsIDOMKeyListener*)this;
|
|
nsIDOMEventListener *temp = kl;
|
|
*aInstancePtr = (void*)temp;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
|
|
if (aIID.Equals(nsIDOMKeyListener::GetIID())) {
|
|
*aInstancePtr = (void*)(nsIDOMKeyListener*)this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(nsIDOMMouseListener::GetIID())) {
|
|
*aInstancePtr = (void*)(nsIDOMMouseListener*)this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(nsIDOMFocusListener::GetIID())) {
|
|
*aInstancePtr = (void*)(nsIDOMFocusListener*)this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(nsIDOMSelectionListener::GetIID())) {
|
|
*aInstancePtr = (void*)(nsIDOMSelectionListener*)this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(nsIEnderEventListener::GetIID())) {
|
|
*aInstancePtr = (void*)(nsIEnderEventListener*)this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
/*================== nsIKeyListener =========================*/
|
|
|
|
nsresult
|
|
nsEnderEventListener::KeyDown(nsIDOMEvent* aKeyEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMKeyEvent>keyEvent;
|
|
keyEvent = do_QueryInterface(aKeyEvent);
|
|
if (!keyEvent) { //non-key event passed to keydown. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
if (gfxFrame && mContent)
|
|
{
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsKeyEvent event;
|
|
event.eventStructType = NS_KEY_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_KEY_DOWN;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
keyEvent->GetKeyCode(&(event.keyCode));
|
|
event.charCode = 0;
|
|
keyEvent->GetShiftKey(&(event.isShift));
|
|
keyEvent->GetCtrlKey(&(event.isControl));
|
|
keyEvent->GetAltKey(&(event.isAlt));
|
|
keyEvent->GetMetaKey(&(event.isMeta));
|
|
|
|
nsIEventStateManager *manager=nsnull;
|
|
result = mContext->GetEventStateManager(&manager);
|
|
if (NS_SUCCEEDED(result) && manager)
|
|
{
|
|
//1. Give event to event manager for pre event state changes and generation of synthetic events.
|
|
result = manager->PreHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
|
|
//2. Give event to the DOM for third party and JS use.
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
}
|
|
|
|
//3. In this case, the frame does no processing of the event
|
|
|
|
//4. Give event to event manager for post event state changes and generation of synthetic events.
|
|
gfxFrame = mFrame.Reference(); // check for deletion
|
|
if (gfxFrame && NS_SUCCEEDED(result)) {
|
|
result = manager->PostHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
}
|
|
NS_RELEASE(manager);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMKeyEvent>keyEvent;
|
|
keyEvent = do_QueryInterface(aKeyEvent);
|
|
if (!keyEvent) { //non-key event passed to keydown. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
if (gfxFrame && mContent)
|
|
{
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsKeyEvent event;
|
|
event.eventStructType = NS_KEY_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_KEY_UP;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
keyEvent->GetKeyCode(&(event.keyCode));
|
|
event.charCode = 0;
|
|
keyEvent->GetShiftKey(&(event.isShift));
|
|
keyEvent->GetCtrlKey(&(event.isControl));
|
|
keyEvent->GetAltKey(&(event.isAlt));
|
|
keyEvent->GetMetaKey(&(event.isMeta));
|
|
|
|
nsIEventStateManager *manager=nsnull;
|
|
result = mContext->GetEventStateManager(&manager);
|
|
if (NS_SUCCEEDED(result) && manager)
|
|
{
|
|
//1. Give event to event manager for pre event state changes and generation of synthetic events.
|
|
result = manager->PreHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
|
|
//2. Give event to the DOM for third party and JS use.
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
}
|
|
|
|
//3. In this case, the frame does no processing of the event
|
|
|
|
//4. Give event to event manager for post event state changes and generation of synthetic events.
|
|
gfxFrame = mFrame.Reference(); // check for deletion
|
|
if (gfxFrame && NS_SUCCEEDED(result)) {
|
|
result = manager->PostHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
}
|
|
NS_RELEASE(manager);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMKeyEvent>keyEvent;
|
|
keyEvent = do_QueryInterface(aKeyEvent);
|
|
if (!keyEvent) { //non-key event passed to keydown. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
if (gfxFrame && mContent && mContext && mView)
|
|
{
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsKeyEvent event;
|
|
event.eventStructType = NS_KEY_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_KEY_PRESS;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
keyEvent->GetKeyCode(&(event.keyCode));
|
|
keyEvent->GetCharCode(&(event.charCode));
|
|
keyEvent->GetShiftKey(&(event.isShift));
|
|
keyEvent->GetCtrlKey(&(event.isControl));
|
|
keyEvent->GetAltKey(&(event.isAlt));
|
|
keyEvent->GetMetaKey(&(event.isMeta));
|
|
|
|
nsIEventStateManager *manager=nsnull;
|
|
result = mContext->GetEventStateManager(&manager);
|
|
if (NS_SUCCEEDED(result) && manager)
|
|
{
|
|
//1. Give event to event manager for pre event state changes and generation of synthetic events.
|
|
result = manager->PreHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
|
|
//2. Give event to the DOM for third party and JS use.
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
}
|
|
|
|
//3. Give event to the frame for browser default processing
|
|
gfxFrame = mFrame.Reference(); // check for deletion
|
|
if (gfxFrame && NS_SUCCEEDED(result)) {
|
|
result = gfxFrame->HandleEvent(mContext, &event, &status);
|
|
}
|
|
|
|
//4. Give event to event manager for post event state changes and generation of synthetic events.
|
|
gfxFrame = mFrame.Reference(); // check for deletion
|
|
if (gfxFrame && NS_SUCCEEDED(result)) {
|
|
result = manager->PostHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
}
|
|
NS_RELEASE(manager);
|
|
|
|
if(event.flags & NS_EVENT_FLAG_STOP_DISPATCH)
|
|
{
|
|
aKeyEvent->PreventCapture();
|
|
aKeyEvent->PreventBubble();
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*=============== nsIMouseListener ======================*/
|
|
|
|
nsresult
|
|
nsEnderEventListener::DispatchMouseEvent(nsIDOMMouseEvent *aEvent, PRInt32 aEventType)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
// The ESM has already dispatched the "click" event to DOM
|
|
// so we need to ignore it here or we will get double notifications
|
|
if (aEventType == NS_MOUSE_LEFT_CLICK ||
|
|
aEventType == NS_MOUSE_MIDDLE_CLICK ||
|
|
aEventType == NS_MOUSE_RIGHT_CLICK) {
|
|
return result;
|
|
}
|
|
|
|
if (aEvent)
|
|
{
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
if (gfxFrame)
|
|
{
|
|
// Dispatch the event
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsMouseEvent event;
|
|
event.eventStructType = NS_MOUSE_EVENT;
|
|
event.widget = nsnull;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
aEvent->GetShiftKey(&(event.isShift));
|
|
aEvent->GetCtrlKey(&(event.isControl));
|
|
aEvent->GetAltKey(&(event.isAlt));
|
|
PRUint16 clickCount;
|
|
aEvent->GetClickCount(&clickCount);
|
|
event.clickCount = clickCount;
|
|
event.message = aEventType;
|
|
GetWidgetForView(mView, event.widget);
|
|
NS_ASSERTION(event.widget, "null widget in mouse event redispatch. right mouse click will crash!");
|
|
|
|
nsIEventStateManager *manager=nsnull;
|
|
result = mContext->GetEventStateManager(&manager);
|
|
if (NS_SUCCEEDED(result) && manager)
|
|
{
|
|
//1. Give event to event manager for pre event state changes and generation of synthetic events.
|
|
result = manager->PreHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
|
|
//2. Give event to the DOM for third party and JS use.
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
}
|
|
|
|
//3. Give event to the frame for browser default processing
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = gfxFrame->HandleEvent(mContext, &event, &status);
|
|
}
|
|
|
|
//4. Give event to event manager for post event state changes and generation of synthetic events.
|
|
gfxFrame = mFrame.Reference(); // check for deletion
|
|
if (gfxFrame && NS_SUCCEEDED(result)) {
|
|
result = manager->PostHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
}
|
|
NS_IF_RELEASE(manager);
|
|
|
|
if ((aEventType == NS_MOUSE_LEFT_BUTTON_DOWN) ||
|
|
(aEventType == NS_MOUSE_MIDDLE_BUTTON_DOWN) ||
|
|
(aEventType == NS_MOUSE_RIGHT_BUTTON_DOWN))
|
|
{
|
|
// Call consume focus events on the inner event state manager to prevent its
|
|
// PostHandleEvent from immediately blurring us.
|
|
nsCOMPtr<nsIPresContext> pc;
|
|
mInnerShell->GetPresContext(getter_AddRefs(pc));
|
|
|
|
nsCOMPtr<nsIEventStateManager> esm;
|
|
pc->GetEventStateManager(getter_AddRefs(esm));
|
|
esm->ConsumeFocusEvents(PR_TRUE);
|
|
// Now set the focus in to the widget.
|
|
mFrame->SetFocus();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// This makes sure the the mSkipFocusDispatch gets set to false
|
|
class SemiphoreFocusDispatch {
|
|
PRBool * mBool;
|
|
public:
|
|
SemiphoreFocusDispatch(PRBool * aBool) :mBool(NULL) { if (aBool) {mBool = aBool; *mBool = PR_TRUE;} }
|
|
~SemiphoreFocusDispatch() { if (mBool) *mBool = PR_FALSE; }
|
|
};
|
|
|
|
nsresult
|
|
nsEnderEventListener::MouseDown(nsIDOMEvent* aEvent)
|
|
{
|
|
SemiphoreFocusDispatch skipFocusDispatch(&mSkipFocusDispatch);
|
|
mSkipFocusDispatch = PR_TRUE;
|
|
|
|
nsCOMPtr<nsIDOMMouseEvent>mouseEvent;
|
|
mouseEvent = do_QueryInterface(aEvent);
|
|
if (!mouseEvent) { //non-key event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (mContent && mContext && mView)
|
|
{
|
|
PRUint16 button;
|
|
mouseEvent->GetButton(&button);
|
|
PRInt32 eventType;
|
|
switch(button)
|
|
{
|
|
case 1: //XXX: I can't believe there isn't a symbol for this!
|
|
eventType = NS_MOUSE_LEFT_BUTTON_DOWN;
|
|
break;
|
|
case 2: //XXX: I can't believe there isn't a symbol for this!
|
|
eventType = NS_MOUSE_MIDDLE_BUTTON_DOWN;
|
|
break;
|
|
case 3: //XXX: I can't believe there isn't a symbol for this!
|
|
eventType = NS_MOUSE_RIGHT_BUTTON_DOWN;
|
|
break;
|
|
default:
|
|
NS_ASSERTION(0, "bad button type");
|
|
return NS_OK;
|
|
}
|
|
result = DispatchMouseEvent(mouseEvent, eventType);
|
|
}
|
|
mSkipFocusDispatch = PR_FALSE;
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::MouseUp(nsIDOMEvent* aEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMMouseEvent>mouseEvent;
|
|
mouseEvent = do_QueryInterface(aEvent);
|
|
if (!mouseEvent) { //non-key event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (mContent && mContext && mView)
|
|
{
|
|
PRUint16 button;
|
|
mouseEvent->GetButton(&button);
|
|
PRInt32 eventType;
|
|
switch(button)
|
|
{
|
|
case 1:
|
|
eventType = NS_MOUSE_LEFT_BUTTON_UP;
|
|
break;
|
|
case 2:
|
|
eventType = NS_MOUSE_MIDDLE_BUTTON_UP;
|
|
break;
|
|
case 3:
|
|
eventType = NS_MOUSE_RIGHT_BUTTON_UP;
|
|
break;
|
|
default:
|
|
NS_ASSERTION(0, "bad button type");
|
|
return NS_OK;
|
|
}
|
|
result = DispatchMouseEvent(mouseEvent, eventType);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::MouseClick(nsIDOMEvent* aEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMMouseEvent>mouseEvent;
|
|
mouseEvent = do_QueryInterface(aEvent);
|
|
if (!mouseEvent) { //non-key event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (mContent && mContext && mView)
|
|
{
|
|
// Dispatch the event
|
|
PRUint16 button;
|
|
mouseEvent->GetButton(&button);
|
|
PRInt32 eventType;
|
|
switch(button)
|
|
{
|
|
case 1:
|
|
eventType = NS_MOUSE_LEFT_CLICK;
|
|
break;
|
|
case 2:
|
|
eventType = NS_MOUSE_MIDDLE_CLICK;
|
|
break;
|
|
case 3:
|
|
eventType = NS_MOUSE_RIGHT_CLICK;
|
|
break;
|
|
default:
|
|
NS_ASSERTION(0, "bad button type");
|
|
return NS_OK;
|
|
}
|
|
result = DispatchMouseEvent(mouseEvent, eventType);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::MouseDblClick(nsIDOMEvent* aEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMMouseEvent>mouseEvent;
|
|
mouseEvent = do_QueryInterface(aEvent);
|
|
if (!mouseEvent) { //non-key event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (mContent && mContext && mView)
|
|
{
|
|
// Dispatch the event
|
|
PRUint16 button;
|
|
mouseEvent->GetButton(&button);
|
|
PRInt32 eventType;
|
|
switch(button)
|
|
{
|
|
case 1:
|
|
eventType = NS_MOUSE_LEFT_DOUBLECLICK;
|
|
break;
|
|
case 2:
|
|
eventType = NS_MOUSE_MIDDLE_DOUBLECLICK;
|
|
break;
|
|
case 3:
|
|
eventType = NS_MOUSE_RIGHT_DOUBLECLICK;
|
|
break;
|
|
default:
|
|
NS_ASSERTION(0, "bad button type");
|
|
return NS_OK;
|
|
}
|
|
result = DispatchMouseEvent(mouseEvent, eventType);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::MouseOver(nsIDOMEvent* aEvent)
|
|
{
|
|
/*
|
|
nsCOMPtr<nsIDOMMouseEvent>mouseEvent;
|
|
mouseEvent = do_QueryInterface(aEvent);
|
|
if (!mouseEvent) { //non-key event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (mContent && mContext && mView)
|
|
{
|
|
// XXX: Need to synthesize MouseEnter here
|
|
result = DispatchMouseEvent(mouseEvent, NS_MOUSE_MOVE);
|
|
}
|
|
|
|
return result;
|
|
*/
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::MouseOut(nsIDOMEvent* aEvent)
|
|
{
|
|
nsCOMPtr<nsIDOMMouseEvent>mouseEvent;
|
|
mouseEvent = do_QueryInterface(aEvent);
|
|
if (!mouseEvent) { //non-key event passed in. bad things.
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
if (mContent && mContext && mView)
|
|
{
|
|
result = DispatchMouseEvent(mouseEvent, NS_MOUSE_EXIT);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*=============== nsIFocusListener ======================*/
|
|
|
|
nsresult
|
|
nsEnderEventListener::Focus(nsIDOMEvent* aEvent)
|
|
{
|
|
/*
|
|
// In this case, the focus has all ready been set because of the mouse down
|
|
// and setting it on the native widget causes an event to be dispatched
|
|
// and this listener then gets call. So we want to skip it here
|
|
// this is probably NOt need when native widgets are removed
|
|
if (mSkipFocusDispatch == PR_TRUE) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMUIEvent>uiEvent;
|
|
uiEvent = do_QueryInterface(aEvent);
|
|
if (!uiEvent) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result = NS_OK;
|
|
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
|
|
// Here are notified that we received focus, this event
|
|
// may come as a result of JS or of the native Widget getting
|
|
// the focus set on it
|
|
// Check here to see if the GfxText was able to set focus, if it did
|
|
// the we want to skip this notification
|
|
// If this came from the DOM (and not the widget) then we DO
|
|
// want to do the notification
|
|
if (gfxFrame && mContent && mView && !gfxFrame->DidSetFocus())
|
|
{
|
|
mTextValue = "";
|
|
gfxFrame->GetText(&mTextValue, PR_FALSE);
|
|
// Dispatch the event
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsGUIEvent event;
|
|
event.eventStructType = NS_GUI_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_FOCUS_CONTENT;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
|
|
nsIEventStateManager *manager=nsnull;
|
|
result = mContext->GetEventStateManager(&manager);
|
|
if (NS_SUCCEEDED(result) && manager)
|
|
{
|
|
//1. Give event to event manager for pre event state changes and generation of synthetic events.
|
|
result = manager->PreHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
|
|
//2. Give event to the DOM for third party and JS use.
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
}
|
|
|
|
//3. In this case, the frame does no processing of the event
|
|
|
|
//4. Give event to event manager for post event state changes and generation of synthetic events.
|
|
gfxFrame = mFrame.Reference(); // check for deletion
|
|
if (gfxFrame && NS_SUCCEEDED(result)) {
|
|
result = manager->PostHandleEvent(mContext, &event, gfxFrame, &status, mView);
|
|
}
|
|
NS_RELEASE(manager);
|
|
}
|
|
}
|
|
*/
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderEventListener::Blur(nsIDOMEvent* aEvent)
|
|
{
|
|
/*
|
|
nsCOMPtr<nsIDOMUIEvent>uiEvent;
|
|
uiEvent = do_QueryInterface(aEvent);
|
|
if (!uiEvent) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
|
|
if (gfxFrame && mContent && mView)
|
|
{
|
|
nsString currentValue;
|
|
gfxFrame->GetText(¤tValue, PR_FALSE);
|
|
if (PR_FALSE==currentValue.Equals(mTextValue))
|
|
{
|
|
// Dispatch the change event
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsGUIEvent event;
|
|
event.eventStructType = NS_GUI_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_FORM_CHANGE;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
|
|
// Have the content handle the event.
|
|
mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
}
|
|
|
|
// XXX No longer dispatching event
|
|
// this notification has already taken place
|
|
// this causes two blur notifcations to be sent
|
|
// I removed this
|
|
// rods - 11/12/99
|
|
// Dispatch the change event
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsGUIEvent event;
|
|
event.eventStructType = NS_GUI_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_BLUR_CONTENT;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
|
|
gfxFrame->SetShouldSetFocus();
|
|
|
|
// Have the content handle the event.
|
|
mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
|
|
}
|
|
*/
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEnderEventListener::NotifySelectionChanged()
|
|
{
|
|
nsGfxTextControlFrame *gfxFrame = mFrame.Reference();
|
|
if (gfxFrame && mContent)
|
|
{
|
|
// Dispatch the event
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
nsGUIEvent event;
|
|
event.eventStructType = NS_GUI_EVENT;
|
|
event.widget = nsnull;
|
|
event.message = NS_FORM_SELECTED;
|
|
event.flags = NS_EVENT_FLAG_INIT;
|
|
|
|
// Have the content handle the event.
|
|
mContent->HandleDOMEvent(mContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
|
|
|
// Now have the frame handle the event
|
|
gfxFrame->HandleEvent(mContext, &event, &status);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* nsEnderFocusListenerForDisplayContent
|
|
******************************************************************************/
|
|
|
|
NS_IMPL_ADDREF(nsEnderFocusListenerForDisplayContent);
|
|
NS_IMPL_RELEASE(nsEnderFocusListenerForDisplayContent);
|
|
|
|
nsresult
|
|
nsEnderFocusListenerForDisplayContent::QueryInterface(const nsIID& aIID,
|
|
void** aInstancePtr)
|
|
{
|
|
NS_PRECONDITION(nsnull != aInstancePtr, "null pointer");
|
|
if (nsnull == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(nsIDOMFocusListener::GetIID())) {
|
|
*aInstancePtr = (void*) ((nsIDOMFocusListener*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*) ((nsISupports*)((nsIDOMFocusListener*)this));
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
nsEnderFocusListenerForDisplayContent::nsEnderFocusListenerForDisplayContent() :
|
|
mFrame(nsnull)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsEnderFocusListenerForDisplayContent::~nsEnderFocusListenerForDisplayContent()
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
nsEnderFocusListenerForDisplayContent::HandleEvent(nsIDOMEvent* aEvent)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsEnderFocusListenerForDisplayContent::Focus(nsIDOMEvent* aEvent)
|
|
{
|
|
if (mFrame)
|
|
{
|
|
mFrame->CreateSubDoc(nsnull);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsEnderFocusListenerForDisplayContent::Blur (nsIDOMEvent* aEvent)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEnderFocusListenerForDisplayContent::SetFrame(nsGfxTextControlFrame *aFrame)
|
|
{
|
|
mFrame = aFrame; // frames are not ref counted
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* EnderTempObserver
|
|
******************************************************************************/
|
|
// XXX temp implementation
|
|
|
|
NS_IMPL_ADDREF(EnderTempObserver);
|
|
NS_IMPL_RELEASE(EnderTempObserver);
|
|
|
|
EnderTempObserver::EnderTempObserver()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mFirstCall = PR_TRUE;
|
|
}
|
|
|
|
EnderTempObserver::~EnderTempObserver()
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
EnderTempObserver::QueryInterface(const nsIID& aIID,
|
|
void** aInstancePtr)
|
|
{
|
|
NS_PRECONDITION(nsnull != aInstancePtr, "null pointer");
|
|
if (nsnull == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(kIDocumentLoaderObserverIID)) {
|
|
*aInstancePtr = (void*) ((nsIDocumentLoaderObserver*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*) ((nsISupports*)((nsIDocumentLoaderObserver*)this));
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
// document loader observer implementation
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::OnStartDocumentLoad(nsIDocumentLoader* loader,
|
|
nsIURI* aURL,
|
|
const char* aCommand)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::OnEndDocumentLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsresult aStatus,
|
|
nsIDocumentLoaderObserver * aObserver)
|
|
{
|
|
if (PR_TRUE==mFirstCall)
|
|
{
|
|
mFirstCall = PR_FALSE;
|
|
if (mFrame) {
|
|
mFrame->InstallEditor();
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::OnStartURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsIContentViewer* aViewer)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::OnProgressURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
PRUint32 aProgress,
|
|
PRUint32 aProgressMax)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::OnStatusURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsString& aMsg)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::OnEndURLLoad(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
nsresult aStatus)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::HandleUnknownContentType(nsIDocumentLoader* loader,
|
|
nsIChannel* channel,
|
|
const char *aContentType,
|
|
const char *aCommand)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
EnderTempObserver::SetFrame(nsGfxTextControlFrame *aFrame)
|
|
{
|
|
mFrame = aFrame;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* nsEnderListenerForContent
|
|
******************************************************************************/
|
|
|
|
NS_IMPL_ADDREF(nsEnderListenerForContent);
|
|
NS_IMPL_RELEASE(nsEnderListenerForContent);
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::QueryInterface(const nsIID& aIID,
|
|
void** aInstancePtr)
|
|
{
|
|
NS_PRECONDITION(nsnull != aInstancePtr, "null pointer");
|
|
if (nsnull == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(NS_GET_IID(nsIDOMMouseListener))) {
|
|
*aInstancePtr = (void*) ((nsIDOMMouseListener*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(NS_GET_IID(nsIDOMDragListener))) {
|
|
*aInstancePtr = (void*) ((nsIDOMDragListener*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*) ((nsISupports*)((nsIDOMFocusListener*)this));
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
nsEnderListenerForContent::nsEnderListenerForContent() :
|
|
mFrame(nsnull)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsEnderListenerForContent::~nsEnderListenerForContent()
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::HandleEvent(nsIDOMEvent* aEvent)
|
|
{
|
|
printf("frame forContent generic HandleEvent\n");
|
|
return NS_OK;
|
|
}
|
|
|
|
/* XXX:
|
|
drag events should be forwarded to the editor's own drag event listener?
|
|
*/
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::DragGesture(nsIDOMEvent* aDragEvent)
|
|
{
|
|
printf("frame forContent DragGesture\n");
|
|
// ...figure out if a drag should be started...
|
|
|
|
// ...until we have this implemented, just eat the drag event so it
|
|
// ...doesn't leak out into the rest of the app/handlers.
|
|
aDragEvent->PreventBubble();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::DragEnter(nsIDOMEvent* aDragEvent)
|
|
{
|
|
printf("frame forContent DragEnter\n");
|
|
// see nsTextEditorDragListener
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::DragOver(nsIDOMEvent* aDragEvent)
|
|
{
|
|
printf("frame forContent DragOver\n");
|
|
// see nsTextEditorDragListener
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::DragExit(nsIDOMEvent* aDragEvent)
|
|
{
|
|
printf("frame forContent DragExit\n");
|
|
// see nsTextEditorDragListener
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsEnderListenerForContent::DragDrop(nsIDOMEvent* aMouseEvent)
|
|
{
|
|
printf("frame forContent DragDrop\n");
|
|
// see nsTextEditorDragListener
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEnderListenerForContent::SetFrame(nsGfxTextControlFrame *aFrame)
|
|
{
|
|
mFrame = aFrame; // frames are not ref counted
|
|
return NS_OK;
|
|
}
|
|
|