With this checkin, ender-based gfx rendered text controls now work properly both as HTML text controls and XUL text fields.

GFX text controls are not enabled by default.  The primary goal of the next few days is to stabilize the tree, so I thought it would be inappropriate to enable the new
feature by default. But you can still set your nglayout.widget.mode pref to enable them.

Here's what I did:
1) backed out a small part of Simon & Kin's fix to nsGFXTextControlFrame that was mistakenly setting up the text control's webshell as a frame.  It still (correctly)
isn't doing that, but it does not set the webshell's prefs from the outer webshell.
2) for output, I now ask for format="text/plain" rather than "text/html", since (for now) these are all plain text edit controls.  Soon, this will depend on the type of
edit control
3) fixed some ownership issues between the frame, the editor, and the subdocument being edited.  This fixes an assertion on dialog destruction if the dialog included
a GFX-rendered text widget, and some memory leaks.
4) set up DOM key listeners on the editor to propogate events from the editor to the parent document, so things like form submission on Enter, and onKeyUp
handlers work.  More work is needed here for other kinds of events.
This commit is contained in:
buster%netscape.com 1999-07-25 18:04:51 +00:00
Родитель 4270360d20
Коммит d40d356cd3
2 изменённых файлов: 169 добавлений и 56 удалений

Просмотреть файл

@ -98,7 +98,11 @@ static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
static NS_DEFINE_IID(kIDOMKeyListenerIID, NS_IDOMKEYLISTENER_IID);
#ifndef NECKO // about:blank is broken in netlib
#define EMPTY_DOCUMENT "resource:/res/html/empty_doc.html"
#else // but works great in the new necko lib
#define EMPTY_DOCUMENT "about:blank"
#endif
//#define NOISY
@ -124,6 +128,17 @@ NS_NewGfxTextControlFrame(nsIFrame** aNewFrame)
return result;
}
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::InitTextControl()
{
@ -206,6 +221,7 @@ nsGfxTextControlFrame::~nsGfxTextControlFrame()
}
}
}
mEditor = do_QueryInterface(nsnull); // editor must be destroyed before the webshell!
if (nsnull != mWebShell)
{
@ -214,6 +230,11 @@ nsGfxTextControlFrame::~nsGfxTextControlFrame()
}
if (mDocObserver)
{
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDoc);
if (doc)
{
doc->RemoveObserver(mDocObserver);
}
mDocObserver->SetFrame(nsnull);
NS_RELEASE(mDocObserver);
}
@ -263,7 +284,7 @@ nsGfxTextControlFrame::GetText(nsString* aText, PRBool aInitialValue)
else
{
if (PR_TRUE==IsInitialized()) {
nsString format ("text/html");
nsString format ("text/plain");
mEditor->OutputToString(*aText, format, 0);
}
else {
@ -405,8 +426,8 @@ nsGfxTextControlFrame::DoesAttributeExist(nsIAtom *aAtt)
void
nsGfxTextControlFrame::PostCreateWidget(nsIPresContext* aPresContext,
nscoord& aWidth,
nscoord& aHeight)
nscoord& aWidth,
nscoord& aHeight)
{
nsresult rv;
// initialize the webshell, if it hasn't already been constructed
@ -464,9 +485,9 @@ nsGfxTextControlFrame::Reset()
NS_METHOD
nsGfxTextControlFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer)
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer)
{
if (mWebShell)
{
@ -502,11 +523,11 @@ nsGfxTextControlFrame::PaintTextControlBackground(nsIPresContext& aPresContext,
void
nsGfxTextControlFrame::PaintTextControl(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsString& aText,
nsIStyleContext* aStyleContext,
nsRect& aRect)
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);
@ -527,8 +548,8 @@ void nsGfxTextControlFrame::GetTextControlFrameState(nsString& aValue)
aValue = ""; // initialize out param
if (PR_TRUE==IsInitialized()) {
nsString format ("text/html");
mEditor->OutputToString(aValue, format, 0);
nsString format ("text/plain");
mEditor->OutputToString(aValue, format, nsIEditor::EditorOutputNoDoctype);
}
}
@ -537,7 +558,7 @@ void nsGfxTextControlFrame::SetTextControlFrameState(const nsString& aValue)
if (PR_TRUE==IsInitialized())
{
nsAutoString currentValue;
nsString format ("text/html");
nsString format ("text/plain");
nsresult result = mEditor->OutputToString(currentValue, format, 0);
if (PR_TRUE==IsSingleLineTextControl()) {
RemoveNewlines(currentValue);
@ -603,7 +624,7 @@ NS_IMETHODIMP nsGfxTextControlFrame::GetProperty(nsIAtom* aName, nsString& aValu
nsresult
nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext,
const nsSize& aSize)
const nsSize& aSize)
{
nsresult rv;
nsIContent* content;
@ -631,6 +652,7 @@ nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext,
mWebShell->SetName(frameName.GetUnicode());
}
*/
#endif
// 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
@ -641,7 +663,10 @@ nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext,
{
nsIWebShell* outerShell = nsnull;
container->QueryInterface(kIWebShellIID, (void**) &outerShell);
if (nsnull != outerShell) {
if (nsnull != outerShell)
{
/* test
outerShell->AddChild(mWebShell);
// connect the container...
@ -651,7 +676,7 @@ nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext,
mWebShell->SetContainer(outerContainer);
NS_RELEASE(outerContainer);
}
*/
nsIPref* outerPrefs = nsnull; // connect the prefs
outerShell->GetPrefs(outerPrefs);
if (nsnull != outerPrefs)
@ -663,7 +688,6 @@ nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext,
}
NS_RELEASE(container);
}
#endif
float t2p;
aPresContext.GetTwipsToPixels(&t2p);
@ -724,9 +748,9 @@ nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext,
NS_IMETHODIMP
nsGfxTextControlFrame::Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
("enter nsGfxTextControlFrame::Reflow: aMaxSize=%d,%d",
@ -963,14 +987,12 @@ nsGfxTextControlFrame::InstallEditor()
}
}
nsCOMPtr<nsIDOMDocument> domDoc;
nsCOMPtr<nsIDocument> 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; }
mDoc = do_QueryInterface(doc);
if (!mDoc) { return NS_ERROR_NULL_POINTER; }
if (mDocObserver) {
doc->AddObserver(mDocObserver);
}
@ -980,9 +1002,11 @@ nsGfxTextControlFrame::InstallEditor()
if (NS_SUCCEEDED(result) && mKeyListener)
{
mKeyListener->SetFrame(this);
mKeyListener->SetPresContext(mFramePresContext);
// get the DOM event receiver
nsCOMPtr<nsIDOMEventReceiver> er;
result = domDoc->QueryInterface(kIDOMEventReceiverIID, getter_AddRefs(er));
result = mDoc->QueryInterface(kIDOMEventReceiverIID, getter_AddRefs(er));
if (!er) { result = NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result)) {
result = er->AddEventListenerByIID(mKeyListener, kIDOMKeyListenerIID);
@ -992,9 +1016,9 @@ nsGfxTextControlFrame::InstallEditor()
}
}
result = mEditor->Init(domDoc, presShell);
result = mEditor->Init(mDoc, presShell);
if (NS_SUCCEEDED(result)) {
result = InitializeTextControl(presShell, domDoc);
result = InitializeTextControl(presShell, mDoc);
}
}
return result;
@ -1200,7 +1224,7 @@ 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");
nsString format ("text/plain");
mEditor->OutputToString(textValue, format, 0);
if (IsSingleLineTextControl()) {
RemoveNewlines(textValue);
@ -1254,6 +1278,15 @@ NS_IMPL_ISUPPORTS(EnderFrameLoadingInfo,kISupportsIID);
NS_IMPL_ADDREF(nsEnderDocumentObserver);
NS_IMPL_RELEASE(nsEnderDocumentObserver);
nsEnderDocumentObserver::nsEnderDocumentObserver()
{
NS_INIT_REFCNT();
}
nsEnderDocumentObserver::~nsEnderDocumentObserver()
{
printf("destroying nsEnderDocumentObserver\n");
}
nsresult
nsEnderDocumentObserver::QueryInterface(const nsIID& aIID,
@ -1405,8 +1438,11 @@ NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule)
{ return NS_OK; }
NS_IMETHODIMP nsEnderDocumentObserver::DocumentWillBeDestroyed(nsIDocument *aDocument)
{ return NS_OK; }
{
return NS_OK;
}
@ -1428,6 +1464,26 @@ NS_IMPL_ADDREF(nsEnderKeyListener)
NS_IMPL_RELEASE(nsEnderKeyListener)
nsEnderKeyListener::nsEnderKeyListener()
{
NS_INIT_REFCNT();
}
nsEnderKeyListener::~nsEnderKeyListener()
{
}
void
nsEnderKeyListener::SetFrame(nsGfxTextControlFrame *aFrame)
{
mFrame = aFrame;
if (mFrame)
{
mFrame->GetContent(getter_AddRefs(mContent));
}
}
nsresult
nsEnderKeyListener::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
@ -1462,40 +1518,74 @@ nsEnderKeyListener::HandleEvent(nsIDOMEvent* aEvent)
nsresult
nsEnderKeyListener::KeyDown(nsIDOMEvent* aKeyEvent)
{
PRUint32 keyCode;
nsCOMPtr<nsIDOMUIEvent>uiEvent;
uiEvent = do_QueryInterface(aKeyEvent);
if (!uiEvent) { //non-key event passed to keydown. bad things.
return NS_OK;
}
if (NS_SUCCEEDED(uiEvent->GetKeyCode(&keyCode)))
if (mFrame && mContent)
{
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;
}
}
// Dispatch the NS_FORM_CHANGE event
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;
uiEvent->GetKeyCode(&(event.keyCode));
uiEvent->GetCharCode(&(event.charCode));
uiEvent->GetShiftKey(&(event.isShift));
uiEvent->GetCtrlKey(&(event.isControl));
uiEvent->GetAltKey(&(event.isAlt));
// Have the content handle the event.
mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status);
// Now have the frame handle the event
mFrame->HandleEvent(*mContext, &event, status);
}
return nsEventStatus_eIgnore;
return NS_OK;
}
nsresult
nsEnderKeyListener::KeyUp(nsIDOMEvent* aKeyEvent)
{
return nsEventStatus_eIgnore;
nsCOMPtr<nsIDOMUIEvent>uiEvent;
uiEvent = do_QueryInterface(aKeyEvent);
if (!uiEvent) { //non-key event passed to keydown. bad things.
return NS_OK;
}
if (mFrame && 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;
uiEvent->GetKeyCode(&(event.keyCode));
uiEvent->GetCharCode(&(event.charCode));
uiEvent->GetShiftKey(&(event.isShift));
uiEvent->GetCtrlKey(&(event.isControl));
uiEvent->GetAltKey(&(event.isAlt));
// Have the content handle the event.
mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status);
// Now have the frame handle the event
mFrame->HandleEvent(*mContext, &event, status);
}
return NS_OK;
}
nsresult
nsEnderKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
{
return nsEventStatus_eIgnore;
return NS_OK;
}
@ -1511,6 +1601,11 @@ nsEnderKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
NS_IMPL_ADDREF(EnderTempObserver);
NS_IMPL_RELEASE(EnderTempObserver);
EnderTempObserver::~EnderTempObserver()
{
printf("destroyed EnderTempObserver\n");
}
nsresult
EnderTempObserver::QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)

Просмотреть файл

@ -25,10 +25,11 @@
#include "nsITextEditor.h"
#include "nsIDocumentObserver.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMDocument.h"
#include "nsIPresContext.h"
#include "nsIContent.h"
class nsIContent;
class nsIFrame;
class nsIPresContext;
class nsIWebShell;
class nsGfxTextControlFrame;
@ -48,7 +49,7 @@ public:
NS_IMETHOD SetFrame(nsGfxTextControlFrame *aFrame);
virtual ~EnderTempObserver() {};
virtual ~EnderTempObserver();
// nsISupports
NS_DECL_ISUPPORTS
@ -81,11 +82,11 @@ protected:
class nsEnderDocumentObserver : public nsIDocumentObserver
{
public:
nsEnderDocumentObserver() { NS_INIT_REFCNT(); }
nsEnderDocumentObserver();
NS_IMETHOD SetFrame(nsGfxTextControlFrame *aFrame);
virtual ~nsEnderDocumentObserver() {};
virtual ~nsEnderDocumentObserver();
// nsISupports
NS_DECL_ISUPPORTS
@ -159,13 +160,16 @@ nsresult NS_NewEnderKeyListener(nsEnderKeyListener ** aInstancePtrResult);
class nsEnderKeyListener : public nsIDOMKeyListener
{
public:
/** the default destructor */
virtual ~nsEnderKeyListener() {};
virtual ~nsEnderKeyListener();
/** SetFrame sets the frame we send event messages to, when necessary
* @param aEditor the frame, can be null, not ref counted (guaranteed to outlive us!)
*/
void SetFrame(nsGfxTextControlFrame *aFrame) {mFrame = aFrame;}
void SetFrame(nsGfxTextControlFrame *aFrame);
void SetPresContext(nsIPresContext *aCx) {mContext = do_QueryInterface(aCx);}
/*interfaces for addref and release and queryinterface*/
NS_DECL_ISUPPORTS
@ -183,10 +187,12 @@ protected:
/** the default constructor. Protected, use the factory to create an instance.
* @see NS_NewEnderKeyListener
*/
nsEnderKeyListener() {NS_INIT_REFCNT();};
nsEnderKeyListener();
protected:
nsGfxTextControlFrame *mFrame; // not ref counted
nsGfxTextControlFrame *mFrame; // not ref counted
nsCOMPtr<nsIPresContext> mContext; // ref counted
nsCOMPtr<nsIContent> mContent; // ref counted
};
@ -204,6 +210,16 @@ class nsGfxTextControlFrame : public nsTextControlFrame
public:
nsGfxTextControlFrame();
virtual ~nsGfxTextControlFrame();
/** nsIFrame override of Init.
* all we do here is cache the pres context for later use
*/
NS_IMETHOD Init(nsIPresContext& aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow);
NS_IMETHOD InitTextControl();
// nsIFormControlFrame
@ -294,11 +310,13 @@ protected:
PRBool mCreatingViewer;
EnderTempObserver* mTempObserver;
nsEnderDocumentObserver *mDocObserver;
nsCOMPtr<nsEnderKeyListener> mKeyListener;
nsCOMPtr<nsITextEditor>mEditor;
nsCOMPtr<nsEnderKeyListener> mKeyListener; // ref counted
nsCOMPtr<nsITextEditor> mEditor; // ref counted
nsCOMPtr<nsIDOMDocument> mDoc; // ref counted
nsNativeTextControlFrame *mDummyFrame; //DUMMY
PRBool mNeedsStyleInit;
PRBool mDummyInitialized; //DUMMY
nsIPresContext *mFramePresContext; // not ref counted
};
#endif