/* -*- 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.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #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 "nsIContent.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLTextAreaElement.h" #include "nsCSSRendering.h" #include "nsIDeviceContext.h" #include "nsIFontMetrics.h" #include "nsILookAndFeel.h" #include "nsIComponentManager.h" #include "nsIWebShell.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 "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" #ifdef SingleSignon #include "prmem.h" #include "nsIURL.h" #include "nsIWalletService.h" #include "nsIServiceManager.h" static NS_DEFINE_IID(kIWalletServiceIID, NS_IWALLETSERVICE_IID); static NS_DEFINE_IID(kWalletServiceCID, NS_WALLETSERVICE_CID); #endif 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(kLookAndFeelCID, NS_LOOKANDFEEL_CID); static NS_DEFINE_IID(kILookAndFeelIID, NS_ILOOKANDFEEL_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kIWebShellContainerIID, NS_IWEB_SHELL_CONTAINER_IID); static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_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(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID); static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENT_OBSERVER_IID); static NS_DEFINE_IID(kITextEditorIID, NS_ITEXTEDITOR_IID); static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID); static NS_DEFINE_IID(kIHTMLEditorIID, NS_IHTMLEDITOR_IID); static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID); static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID); static NS_DEFINE_CID(kEditorCID, NS_EDITOR_CID); static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID); static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID); static NS_DEFINE_IID(kIDOMKeyListenerIID, NS_IDOMKEYLISTENER_IID); #define EMPTY_DOCUMENT "resource:/res/html/empty_doc.html" //#define NOISY extern nsresult NS_NewNativeTextControlFrame(nsIFrame** aNewFrame); nsresult NS_NewGfxTextControlFrame(nsIFrame** aNewFrame) { NS_PRECONDITION(aNewFrame, "null OUT ptr"); if (nsnull == aNewFrame) { return NS_ERROR_NULL_POINTER; } *aNewFrame = new nsGfxTextControlFrame; if (nsnull == aNewFrame) { return NS_ERROR_OUT_OF_MEMORY; } nsresult result = ((nsGfxTextControlFrame*)(*aNewFrame))->InitTextControl(); if (NS_FAILED(result)) { // can't properly initialized ender, probably it isn't installed //NS_RELEASE(*aNewFrame); // XXX: need to release allocated ender text frame! result = NS_NewNativeTextControlFrame(aNewFrame); } return result; } NS_IMETHODIMP nsGfxTextControlFrame::InitTextControl() { 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); if (PR_TRUE==IsPlainTextControl()) { nsCOMPtr theEditor; result = nsComponentManager::CreateInstance(kTextEditorCID, nsnull, kITextEditorIID, 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; } } else { nsCOMPtr theEditor; result = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, kIHTMLEditorIID, 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; } } // allocate mDummy here to self-check native text control impl. vs. ender text control impl. //NS_NewNativeTextControlFrame((nsIFrame **)&mDummyFrame); //DUMMY // mDummyInitialized = PR_TRUE; //DUMMY return NS_OK; } nsGfxTextControlFrame::nsGfxTextControlFrame() : mWebShell(0), mCreatingViewer(PR_FALSE), mTempObserver(0), mDocObserver(0), mDummyFrame(0), mNeedsStyleInit(PR_TRUE), mDummyInitialized(PR_FALSE) // DUMMY { } nsGfxTextControlFrame::~nsGfxTextControlFrame() { if (mTempObserver) { mTempObserver->SetFrame(nsnull); NS_RELEASE(mTempObserver); } if (mKeyListener) { nsCOMPtreditor = do_QueryInterface(mEditor); NS_ASSERTION(editor, "bad QI to nsIEditor from mEditor"); if (editor) { nsCOMPtrdomDoc; nsresult result = editor->GetDocument(getter_AddRefs(domDoc)); if (NS_SUCCEEDED(result) && domDoc) { nsCOMPtr er; result = domDoc->QueryInterface(kIDOMEventReceiverIID, getter_AddRefs(er)); if (NS_SUCCEEDED(result) && er) { er->RemoveEventListenerByIID(mKeyListener, kIDOMKeyListenerIID); } } } } mEditor = do_QueryInterface(nsnull); // editor must be destroyed before the webshell! if (nsnull != mWebShell) { mWebShell->Destroy(); NS_RELEASE(mWebShell); } if (mDocObserver) { mDocObserver->SetFrame(nsnull); NS_RELEASE(mDocObserver); } // this will be a leak -- NS_IF_RELEASE(mDummyFrame); } void nsGfxTextControlFrame::EnterPressed(nsIPresContext& aPresContext) { if (mFormFrame && mFormFrame->CanSubmit(*this)) { nsIContent *formContent = nsnull; mFormFrame->GetContent(&formContent); if (nsnull != formContent) { nsEvent event; nsEventStatus status = nsEventStatus_eIgnore; event.eventStructType = NS_EVENT; event.message = NS_FORM_SUBMIT; formContent->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); NS_RELEASE(formContent); } 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()) { nsString format ("text/html"); mEditor->OutputToString(*aText, format, 0); } 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, nsIAtom* aAttribute, PRInt32 aHint) { if (PR_FALSE==IsInitialized()) {return NS_ERROR_NOT_INITIALIZED;} nsresult result = NS_OK; if (nsHTMLAtoms::value == aAttribute) { 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 nsFormFrame::StyleChangeReflow(aPresContext, this); } else if (nsHTMLAtoms::maxlength == aAttribute) { PRInt32 maxLength; nsresult rv = GetMaxLength(&maxLength); if (NS_CONTENT_ATTR_NOT_THERE != rv) { // set the maxLength attribute mEditor->SetMaxTextLength(maxLength); // if maxLength>docLength, we need to truncate the doc content } else { // unset the maxLength attribute mEditor->SetMaxTextLength(-1); } } else if (nsHTMLAtoms::readonly == aAttribute) { nsCOMPtr 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 |= TEXT_EDITOR_FLAG_READONLY; presShell->SetCaretEnabled(PR_FALSE); } else { // unset readonly flags &= ~(TEXT_EDITOR_FLAG_READONLY); presShell->SetCaretEnabled(PR_TRUE); } mEditor->SetFlags(flags); } else if (nsHTMLAtoms::disabled == aAttribute) { nsCOMPtr 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 |= TEXT_EDITOR_FLAG_DISABLED; presShell->SetCaretEnabled(PR_FALSE); nsCOMPtr 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 &= ~(TEXT_EDITOR_FLAG_DISABLED); presShell->SetCaretEnabled(PR_TRUE); nsCOMPtr 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) { nsFormFrame::StyleChangeReflow(aPresContext, this); } // Allow the base class to handle common attributes supported // by all form elements... else { result = nsFormControlFrame::AttributeChanged(aPresContext, aChild, aAttribute, aHint); } // DUMMY if (mDummyFrame) { nsresult dummyResult = mDummyFrame->AttributeChanged(aPresContext, aChild, aAttribute, aHint); NS_ASSERTION((NS_SUCCEEDED(dummyResult)), "dummy frame attribute changed failed."); } // END DUMMY 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; } void nsGfxTextControlFrame::PostCreateWidget(nsIPresContext* aPresContext, nscoord& aWidth, nscoord& aHeight) { nsresult rv; // initialize the webshell, if it hasn't already been constructed // if the size is not 0 and there is a src, create the web shell if (aPresContext && (aWidth >= 0) && (aHeight >= 0)) { if (nsnull == mWebShell) { nsSize maxSize(aWidth, aHeight); rv = CreateWebShell(*aPresContext, maxSize); NS_ASSERTION(nsnull!=mWebShell, "null web shell after attempt to create."); } if (nsnull != mWebShell) { mCreatingViewer=PR_TRUE; nsAutoString url(EMPTY_DOCUMENT); rv = mWebShell->LoadURL(url.GetUnicode()); // URL string with a default nsnull value for post Data } } } 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() { 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 (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); } } 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 (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); } } } 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) { const nsStyleSpacing* mySpacing = (const nsStyleSpacing*)aStyleContext->GetStyleData(eStyleStruct_Spacing); PRIntn skipSides = 0; nsRect rect(0, 0, mRect.width, mRect.height); //PaintTextControl(aPresContext, aRenderingContext, text, mStyleContext, rect); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *mySpacing, aStyleContext, skipSides); } } void nsGfxTextControlFrame::GetTextControlFrameState(nsString& aValue) { aValue = ""; // initialize out param if (PR_TRUE==IsInitialized()) { nsString format ("text/html"); mEditor->OutputToString(aValue, format, 0); } } void nsGfxTextControlFrame::SetTextControlFrameState(const nsString& aValue) { if (PR_TRUE==IsInitialized()) { nsAutoString currentValue; nsString format ("text/html"); 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 { nsCOMPtreditor = do_QueryInterface(mEditor); NS_ASSERTION(editor, "bad QI to nsIEditor from mEditor"); if (editor) { nsCOMPtrselection; result = editor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(result) && selection) { nsCOMPtrdomDoc; editor->GetDocument(getter_AddRefs(domDoc)); if (domDoc) { nsCOMPtr bodyNode; nsAutoString bodyTag = "body"; result = GetFirstNodeOfType(bodyTag, domDoc, getter_AddRefs(bodyNode)); SelectAllTextContent(bodyNode, selection); mEditor->InsertText(aValue); } } } } } } NS_IMETHODIMP nsGfxTextControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) { if (nsHTMLAtoms::value == aName) { mEditor->EnableUndo(PR_FALSE); // wipe out undo info SetTextControlFrameState(aValue); // set new text value mEditor->EnableUndo(PR_TRUE); // fire up a new txn stack } else { return nsFormControlFrame::SetProperty(aName, aValue); } 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 nsFormControlFrame::GetProperty(aName, aValue); } return NS_OK; } /* --------------------- Ender methods ---------------------- */ nsresult nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext, const nsSize& aSize) { nsresult rv; nsIContent* content; GetContent(&content); // ??? rv = nsComponentManager::CreateInstance(kWebShellCID, nsnull, kIWebShellIID, (void**)&mWebShell); if (NS_OK != rv) { NS_ASSERTION(0, "could not create web widget"); return rv; } // pass along marginwidth, marginheight, scrolling so sub document can use it mWebShell->SetMarginWidth(0); mWebShell->SetMarginHeight(0); nsCompatibility mode; aPresContext.GetCompatibilityMode(&mode); #if 0 mWebShell->SetIsFrame(PR_TRUE); /* XXX nsString frameName; if (GetName(content, frameName)) { mWebShell->SetName(frameName.GetUnicode()); } */ // If our container is a web-shell, inform it that it has a new // child. If it's not a web-shell then some things will not operate // properly. nsISupports* container; aPresContext.GetContainer(&container); if (nsnull != container) { nsIWebShell* outerShell = nsnull; container->QueryInterface(kIWebShellIID, (void**) &outerShell); if (nsnull != outerShell) { outerShell->AddChild(mWebShell); // connect the container... nsIWebShellContainer* outerContainer = nsnull; container->QueryInterface(kIWebShellContainerIID, (void**) &outerContainer); if (nsnull != outerContainer) { mWebShell->SetContainer(outerContainer); NS_RELEASE(outerContainer); } nsIPref* outerPrefs = nsnull; // connect the prefs outerShell->GetPrefs(outerPrefs); if (nsnull != outerPrefs) { mWebShell->SetPrefs(outerPrefs); NS_RELEASE(outerPrefs); } NS_RELEASE(outerShell); } NS_RELEASE(container); } #endif float t2p; aPresContext.GetTwipsToPixels(&t2p); nsCOMPtr presShell; aPresContext.GetShell(getter_AddRefs(presShell)); // create, init, set the parent of the view nsIView* view; rv = nsComponentManager::CreateInstance(kCViewCID, nsnull, kIViewIID, (void **)&view); if (NS_OK != rv) { NS_ASSERTION(0, "Could not create view for nsHTMLFrame"); return rv; } nsIView* parView; nsPoint origin; GetOffsetFromView(origin, &parView); nsRect viewBounds(origin.x, origin.y, aSize.width, aSize.height); nsCOMPtr viewMan; presShell->GetViewManager(getter_AddRefs(viewMan)); rv = view->Init(viewMan, viewBounds, parView); viewMan->InsertChild(parView, view, 0); rv = view->CreateWidget(kCChildCID); SetView(view); // if the visibility is hidden, reflect that in the view const nsStyleDisplay* display; GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); if (NS_STYLE_VISIBILITY_HIDDEN == 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)); mWebShell->Init(widget->GetNativeData(NS_NATIVE_WIDGET), webBounds.x, webBounds.y, webBounds.width, webBounds.height); NS_RELEASE(content); NS_RELEASE(widget); mWebShell->SetObserver(mTempObserver); mWebShell->Show(); return NS_OK; } NS_IMETHODIMP nsGfxTextControlFrame::Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aMetrics, 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"); nsresult rv = nsFormControlFrame::Reflow(aPresContext, aMetrics, aReflowState, aStatus); #ifdef NOISY printf ("exit nsGfxTextControlFrame::Reflow: size=%d,%d", aMetrics.width, aMetrics.height); #endif // resize the sub document if (NS_SUCCEEDED(rv) && mWebShell) { // get the border const nsStyleSpacing* spacing; GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); nsMargin border; spacing->CalcBorderFor(this, border); float t2p; aPresContext.GetTwipsToPixels(&t2p); nsRect subBounds; // 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 subBounds.x = NSToCoordRound(border.left * t2p); subBounds.y = NSToCoordRound(border.top * t2p); subBounds.width = NSToCoordRound((aMetrics.width - (border.left + border.right)) * t2p); subBounds.height = NSToCoordRound((aMetrics.height - (border.top + border.bottom)) * t2p); mWebShell->SetBounds(subBounds.x, subBounds.y, 106, 20); mWebShell->SetBounds(subBounds.x, subBounds.y, subBounds.width, subBounds.height); mWebShell->Repaint(PR_TRUE); #ifdef NOISY printf("webshell set to (%d, %d, %d %d)\n", border.left, border.top, (aMetrics.width - (border.left + border.right)), (aMetrics.height - (border.top + border.bottom))); #endif } NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsGfxTextControlFrame::Reflow: size=%d,%d", aMetrics.width, aMetrics.height)); // DUMMY if (mDummyFrame) { if (!mDummyInitialized) { mDummyFrame->Init(aPresContext, mContent, mParent, mStyleContext, nsnull); mDummyInitialized = PR_TRUE; } nsHTMLReflowMetrics metrics = aMetrics; nsHTMLReflowState reflowState = aReflowState; nsReflowStatus status = aStatus; nsresult dummyResult = mDummyFrame->Reflow(aPresContext, metrics, reflowState, status); NS_ASSERTION((NS_SUCCEEDED(dummyResult)), "dummy frame reflow failed."); if (aMetrics.width != metrics.width) { printf("CT: different widths\n"); NS_ASSERTION(0, "CT: different widths\n"); } if (aMetrics.height != metrics.height) { printf("CT: different heights\n"); NS_ASSERTION(0, "CT: different heights\n"); } } // END DUMMY 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; nsCOMPtrnodeList; 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; nsCOMPtrnode; result = GetFirstNodeOfType(aTag, aDOMDoc, getter_AddRefs(node)); if ((NS_SUCCEEDED(result)) && node) { nsCOMPtrcontent = do_QueryInterface(node); if (content) { result = aPresShell->GetPrimaryFrameFor(content, aResult); } } return result; } // XXX: this really should use a content iterator over the whole document // looking for the first and last text node nsresult nsGfxTextControlFrame::SelectAllTextContent(nsIDOMNode *aBodyNode, nsIDOMSelection *aSelection) { if (!aBodyNode || !aSelection) { return NS_ERROR_NULL_POINTER; } nsCOMPtrfirstChild, lastChild; nsresult result = aBodyNode->GetFirstChild(getter_AddRefs(firstChild)); if ((NS_SUCCEEDED(result)) && firstChild) { result = aBodyNode->GetLastChild(getter_AddRefs(lastChild)); if ((NS_SUCCEEDED(result)) && lastChild) { aSelection->Collapse(firstChild, 0); nsCOMPtrtext = do_QueryInterface(lastChild); if (text) { PRUint32 length; text->GetLength(&length); aSelection->Extend(lastChild, length); } } } 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 key listener or not. PRBool nsGfxTextControlFrame::IsInitialized() const { return (PRBool)(nsnull!=mEditor.get() && nsnull!=mKeyListener.get()); } NS_IMETHODIMP nsGfxTextControlFrame::InstallEditor() { nsresult result = NS_ERROR_NULL_POINTER; if (mEditor) { nsCOMPtr presShell; result = GetPresShellFor(mWebShell, getter_AddRefs(presShell)); if (NS_FAILED(result)) { return result; } if (!presShell) { return NS_ERROR_NULL_POINTER; } // set the scrolling behavior if (PR_TRUE==IsSingleLineTextControl()) { nsCOMPtr vm; presShell->GetViewManager(getter_AddRefs(vm)); if (vm) { nsIScrollableView *sv=nsnull; vm->GetRootScrollableView(&sv); if (sv) { sv->SetScrollPreference(nsScrollPreference_kNeverScroll); // views are not refcounted } } } nsCOMPtr domDoc; nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); NS_ASSERTION(doc, "null document"); if (!doc) { return NS_ERROR_NULL_POINTER; } domDoc = do_QueryInterface(doc); if (!domDoc) { return NS_ERROR_NULL_POINTER; } if (mDocObserver) { doc->AddObserver(mDocObserver); } // we need to hook up our key listener before the editor is initialized result = NS_NewEnderKeyListener(getter_AddRefs(mKeyListener)); if (NS_SUCCEEDED(result) && mKeyListener) { mKeyListener->SetFrame(this); // get the DOM event receiver nsCOMPtr er; result = domDoc->QueryInterface(kIDOMEventReceiverIID, getter_AddRefs(er)); if (!er) { result = NS_ERROR_NULL_POINTER; } if (NS_SUCCEEDED(result)) { result = er->AddEventListenerByIID(mKeyListener, kIDOMKeyListenerIID); } if (NS_FAILED(result)) { // either we couldn't get er, or we couldn't add the listener mKeyListener = do_QueryInterface(nsnull); // null out the listener, it's useless } } result = mEditor->Init(domDoc, presShell); if (NS_SUCCEEDED(result)) { result = InitializeTextControl(presShell, domDoc); } } return result; } NS_IMETHODIMP nsGfxTextControlFrame::InitializeTextControl(nsIPresShell *aPresShell, nsIDOMDocument *aDoc) { nsresult result; if (!aPresShell || !aDoc) { return NS_ERROR_NULL_POINTER; } nsIFrame *htmlFrame; nsAutoString htmlTag("body"); result = GetFirstFrameForType(htmlTag, aPresShell, aDoc, &htmlFrame); if (NS_SUCCEEDED(result) && htmlFrame) { PRInt32 type; GetType(&type); nsCOMPtrpresContext; aPresShell->GetPresContext(getter_AddRefs(presContext)); NS_ASSERTION(presContext, "null presentation context"); if (!presContext) { return NS_ERROR_NULL_POINTER; } /* this is the code for setting the pres context, which is MUCH better * than grabbing the imbedded HTML frame and setting it. * alas, the mechanisms for doing this are not yet in place. * what I want to do is hand the webshell my pres context at creation */ /* 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); */ nsIStyleContext* bodySC = nsnull; htmlFrame->GetStyleContext(&bodySC); nsStyleSpacing* bodySpacing = nsnull; bodySpacing = (nsStyleSpacing*)bodySC->GetMutableStyleData(eStyleStruct_Spacing); nsStyleCoord zero(0); bodySpacing->mMargin.SetLeft(zero); bodySpacing->mMargin.SetRight(zero); bodySpacing->mMargin.SetTop(zero); bodySpacing->mMargin.SetBottom(zero); bodySpacing->mPadding.SetLeft(zero); bodySpacing->mPadding.SetRight(zero); bodySpacing->mPadding.SetTop(zero); bodySpacing->mPadding.SetBottom(zero); bodySpacing->mBorder.SetLeft(zero); bodySpacing->mBorder.SetRight(zero); bodySpacing->mBorder.SetTop(zero); bodySpacing->mBorder.SetBottom(zero); nsStylePosition* bodyPosition = nsnull; bodyPosition = (nsStylePosition*)bodySC->GetMutableStyleData(eStyleStruct_Position); const nsStylePosition* controlPosition; GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)controlPosition); *bodyPosition = *controlPosition; /* qqq if (NS_FORM_INPUT_TEXT == type || NS_FORM_INPUT_PASSWORD == type) { bodyPosition->mWidth.SetIntValue(10000, eStyleUnit_Chars); } */ nsStyleFont* bodyFont = nsnull; bodyFont = (nsStyleFont*)bodySC->GetMutableStyleData(eStyleStruct_Font); //const nsStyleFont* controlFont; //GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)controlFont); //*bodyFont = *controlFont; nsFont font(presContext->GetDefaultFixedFontDeprecated()); GetFont(presContext, font); bodyFont->mFont = font; bodyFont->mFixedFont = font; nsStyleColor* bodyColor = nsnull; bodyColor = (nsStyleColor*)bodySC->GetMutableStyleData(eStyleStruct_Color); const nsStyleColor* controlColor; GetStyleData(eStyleStruct_Color, (const nsStyleStruct *&)controlColor); *bodyColor = *controlColor; nsStyleText* bodyText = nsnull; bodyText = (nsStyleText*)bodySC->GetMutableStyleData(eStyleStruct_Text); const nsStyleText* controlText; GetStyleData(eStyleStruct_Text, (const nsStyleStruct *&)controlText); *bodyText = *controlText; if (NS_FORM_INPUT_TEXT == type || NS_FORM_INPUT_PASSWORD == type) { // qqq bodyText->mWhiteSpace = NS_STYLE_WHITESPACE_MOZ_PRE_WRAP; bodyText->mWhiteSpace = NS_STYLE_WHITESPACE_PRE; } bodyText->mTextAlign = NS_STYLE_TEXT_ALIGN_LEFT; bodySC->RecalcAutomaticData(presContext); NS_RELEASE(bodySC); // now that the style context is initialized, initialize the content nsAutoString value; if (PR_TRUE == IsSingleLineTextControl()) { #ifdef SingleSignon // get name of text PRBool failed = PR_TRUE; nsAutoString name; GetName(&name); // get url name char *URLName = nsnull; nsIURI* docURL = nsnull; nsIDocument* doc = nsnull; mContent->GetDocument(doc); if (nsnull != doc) { docURL = doc->GetDocumentURL(); NS_RELEASE(doc); if (nsnull != docURL) { #ifdef NECKO char* spec; #else const char* spec; #endif (void)docURL->GetSpec(&spec); if (nsnull != spec) { URLName = (char*)PR_Malloc(PL_strlen(spec)+1); PL_strcpy(URLName, spec); } #ifdef NECKO nsCRT::free(spec); #endif NS_RELEASE(docURL); } } if (nsnull != URLName) { // invoke single-signon to get previously-used value of text nsIWalletService *service; nsresult res = nsServiceManager::GetService(kWalletServiceCID, kIWalletServiceIID, (nsISupports **)&service); if ((NS_OK == res) && (nsnull != service)) { char* valueString = NULL; char* nameString = name.ToNewCString(); res = service->SI_RestoreSignonData(URLName, nameString, &valueString); delete[] nameString; nsServiceManager::ReleaseService(kWalletServiceCID, service); PR_FREEIF(URLName); if (valueString && *valueString) { value = valueString; failed = PR_FALSE; } } } if (failed) { GetText(&value, PR_TRUE); } #else GetText(&value, PR_TRUE); #endif } else { GetText(&value, PR_TRUE); } mEditor->EnableUndo(PR_FALSE); PRInt32 maxLength; result = GetMaxLength(&maxLength); if (NS_CONTENT_ATTR_NOT_THERE != result) { mEditor->SetMaxTextLength(maxLength); } nsCOMPtreditor = do_QueryInterface(mEditor); NS_ASSERTION(editor, "bad QI to nsIEditor from mEditor"); if (editor) { nsCOMPtrselection; result = editor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(result) && selection) { nsCOMPtrbodyNode; nsAutoString bodyTag = "body"; result = GetFirstNodeOfType(bodyTag, aDoc, getter_AddRefs(bodyNode)); if (NS_SUCCEEDED(result) && bodyNode) { result = SelectAllTextContent(bodyNode, selection); if (NS_SUCCEEDED(result)) { if (0!=value.Length()) { result = mEditor->InsertText(value); result = SelectAllTextContent(bodyNode, selection); } selection->ClearSelection(); } } } } /* SetColors(*aPresContext); if (nsFormFrame::GetDisabled(this)) { mWidget->Enable(PR_FALSE); } */ // finish initializing editor mEditor->EnableUndo(PR_TRUE); // set readonly and disabled states if (mContent) { PRUint32 flags=0; if (IsPlainTextControl()) { flags |= TEXT_EDITOR_FLAG_PLAINTEXT; } if (IsSingleLineTextControl()) { flags |= TEXT_EDITOR_FLAG_SINGLELINE; } if (IsPasswordTextControl()) { flags |= TEXT_EDITOR_FLAG_PASSWORD; } nsCOMPtr 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 |= TEXT_EDITOR_FLAG_READONLY; aPresShell->SetCaretEnabled(PR_FALSE); } result = content->GetAttribute(nameSpaceID, nsHTMLAtoms::disabled, resultValue); if (NS_CONTENT_ATTR_NOT_THERE != result) { flags |= TEXT_EDITOR_FLAG_DISABLED; aPresShell->SetCaretEnabled(PR_FALSE); nsCOMPtrdoc = do_QueryInterface(aDoc); if (doc) { doc->SetDisplaySelection(PR_FALSE); } } } mEditor->SetFlags(flags); } } else { result = NS_ERROR_NULL_POINTER; } return result; } NS_IMETHODIMP nsGfxTextControlFrame::InternalContentChanged() { if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } nsAutoString textValue; // XXX: need to check here if we're an HTML edit field or a text edit field nsString format ("text/html"); mEditor->OutputToString(textValue, format, 0); if (IsSingleLineTextControl()) { RemoveNewlines(textValue); } SetTextControlFrameState(textValue); // set new text value return NS_OK; } void nsGfxTextControlFrame::RemoveNewlines(nsString &aString) { // strip CR/LF static const char badChars[] = {10, 13, 0}; aString.StripChars(badChars); } /******************************************************************************* * 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); nsresult nsEnderDocumentObserver::QueryInterface(const nsIID& aIID, void** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIDocumentObserverIID)) { *aInstancePtrResult = (void*) ((nsIStreamObserver*)this); AddRef(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { *aInstancePtrResult = (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, 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; } /******************************************************************************* * nsEnderKeyListener ******************************************************************************/ nsresult NS_NewEnderKeyListener(nsEnderKeyListener ** aInstancePtrResult) { nsEnderKeyListener* it = new nsEnderKeyListener(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(kIDOMKeyListenerIID, (void **) aInstancePtrResult); } NS_IMPL_ADDREF(nsEnderKeyListener) NS_IMPL_RELEASE(nsEnderKeyListener) nsresult nsEnderKeyListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); if (aIID.Equals(kISupportsIID)) { *aInstancePtr = (void*)(nsISupports*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventListenerIID)) { *aInstancePtr = (void*)(nsIDOMEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMKeyListenerIID)) { *aInstancePtr = (void*)(nsIDOMKeyListener*)this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } nsresult nsEnderKeyListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } nsresult nsEnderKeyListener::KeyDown(nsIDOMEvent* aKeyEvent) { PRUint32 keyCode; nsCOMPtruiEvent; uiEvent = do_QueryInterface(aKeyEvent); if (!uiEvent) { //non-key event passed to keydown. bad things. return NS_OK; } if (NS_SUCCEEDED(uiEvent->GetKeyCode(&keyCode))) { if (nsIDOMUIEvent::VK_RETURN==keyCode) { if (mFrame) { // need the pres context. could save it from some other function, but that seems so wrong //mFrame->EnterPressed(presContext); return nsEventStatus_eConsumeNoDefault; } } } return nsEventStatus_eIgnore; } nsresult nsEnderKeyListener::KeyUp(nsIDOMEvent* aKeyEvent) { return nsEventStatus_eIgnore; } nsresult nsEnderKeyListener::KeyPress(nsIDOMEvent* aKeyEvent) { return nsEventStatus_eIgnore; } /******************************************************************************* * EnderTempObserver ******************************************************************************/ // XXX temp implementation NS_IMPL_ADDREF(EnderTempObserver); NS_IMPL_RELEASE(EnderTempObserver); nsresult EnderTempObserver::QueryInterface(const nsIID& aIID, void** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIStreamObserverIID)) { *aInstancePtrResult = (void*) ((nsIStreamObserver*)this); AddRef(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { *aInstancePtrResult = (void*) ((nsISupports*)((nsIDocumentObserver*)this)); AddRef(); return NS_OK; } return NS_NOINTERFACE; } #ifndef NECKO NS_IMETHODIMP EnderTempObserver::OnProgress(nsIURI* aURL, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK; } NS_IMETHODIMP EnderTempObserver::OnStatus(nsIURI* aURL, const PRUnichar* aMsg) { return NS_OK; } #endif NS_IMETHODIMP #ifdef NECKO EnderTempObserver::OnStartRequest(nsIChannel* channel, nsISupports *ctxt) #else EnderTempObserver::OnStartRequest(nsIURI* aURL, const char *aContentType) #endif { return NS_OK; } NS_IMETHODIMP #ifdef NECKO EnderTempObserver::OnStopRequest(nsIChannel* channel, nsISupports *ctxt, nsresult status, const PRUnichar *errorMsg) #else EnderTempObserver::OnStopRequest(nsIURI* aURL, nsresult status, const PRUnichar* aMsg) #endif { if (PR_TRUE==mFirstCall) { mFirstCall = PR_FALSE; if (mFrame) { mFrame->InstallEditor(); } } return NS_OK; } NS_IMETHODIMP EnderTempObserver::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; return NS_OK; }