diff --git a/mozilla/content/html/content/public/Makefile.in b/mozilla/content/html/content/public/Makefile.in
index 72e95bd808b..a6623baa95c 100644
--- a/mozilla/content/html/content/public/Makefile.in
+++ b/mozilla/content/html/content/public/Makefile.in
@@ -61,6 +61,7 @@ EXPORTS = \
nsIRadioVisitor.h \
nsIRadioGroupContainer.h \
nsITextControlElement.h \
+ nsIFileControlElement.h \
nsIFormSubmission.h \
nsIFrameSetElement.h \
$(NULL)
diff --git a/mozilla/content/html/content/public/nsIFileControlElement.h b/mozilla/content/html/content/public/nsIFileControlElement.h
new file mode 100755
index 00000000000..ad18f362841
--- /dev/null
+++ b/mozilla/content/html/content/public/nsIFileControlElement.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking (Original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsIFileControlElement_h___
+#define nsIFileControlElement_h___
+
+#include "nsISupports.h"
+class nsAString;
+
+// IID for the nsIFileControl interface
+#define NS_IFILECONTROLELEMENT_IID \
+{ 0x1f6a32fd, 0x9cda, 0x43e9, \
+ { 0x90, 0xef, 0x18, 0x0a, 0xd5, 0xe6, 0xcd, 0xa9 } }
+
+/**
+ * This interface is used for the file control frame to store its value away
+ * into the content.
+ */
+class nsIFileControlElement : public nsISupports {
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFILECONTROLELEMENT_IID)
+
+ /**
+ * Gets filename to be uploaded when this control is submitted
+ */
+ virtual void GetFileName(nsAString& aFileName) = 0;
+
+ /**
+ * Sets filename to be uploaded when this control is submitted
+ */
+ virtual void SetFileName(const nsAString& aFileName) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileControlElement,
+ NS_IFILECONTROLELEMENT_IID)
+
+#endif // nsIFileControlElement_h___
diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp
index 8a5b3aab2fb..0d3f1cb5825 100644
--- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp
@@ -39,6 +39,7 @@
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMNSHTMLInputElement.h"
#include "nsITextControlElement.h"
+#include "nsIFileControlElement.h"
#include "nsIDOMNSEditableElement.h"
#include "nsIRadioControlElement.h"
#include "nsIRadioVisitor.h"
@@ -149,7 +150,8 @@ class nsHTMLInputElement : public nsGenericHTMLFormElement,
public nsITextControlElement,
public nsIRadioControlElement,
public nsIPhonetic,
- public nsIDOMNSEditableElement
+ public nsIDOMNSEditableElement,
+ public nsIFileControlElement
{
public:
nsHTMLInputElement(nsINodeInfo *aNodeInfo, PRBool aFromParser);
@@ -217,6 +219,10 @@ public:
// nsITextControlElement
NS_IMETHOD TakeTextFrameValue(const nsAString& aValue);
NS_IMETHOD SetValueChanged(PRBool aValueChanged);
+
+ // nsIFileControlElement
+ virtual void GetFileName(nsAString& aFileName);
+ virtual void SetFileName(const nsAString& aFileName);
// nsIRadioControlElement
NS_IMETHOD RadioSetChecked(PRBool aNotify);
@@ -231,7 +237,6 @@ public:
*/
virtual already_AddRefed GetRadioGroupContainer();
-
protected:
// Helper method
nsresult SetValueInternal(const nsAString& aValue,
@@ -323,6 +328,17 @@ protected:
* The current value of the input if it has been changed from the deafault
*/
char* mValue;
+ /**
+ * The value of the input if it is a file input. This is the filename used
+ * when uploading a file. It is vital that this is kept separate from mValue
+ * so that it won't be possible to 'leak' the value from a text-input to a
+ * file-input. Additionally, the logic for this value is kept as simple as
+ * possible to avoid accidental errors where the wrong filename is used.
+ * Therefor the filename is always owned by this member, never by the frame.
+ * Whenever the frame wants to change the filename it has to call
+ * SetFileName to update this member.
+ */
+ nsAutoPtr mFileName;
};
//
@@ -361,6 +377,7 @@ NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLInputElement,
NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLInputElement)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLInputElement)
NS_INTERFACE_MAP_ENTRY(nsITextControlElement)
+ NS_INTERFACE_MAP_ENTRY(nsIFileControlElement)
NS_INTERFACE_MAP_ENTRY(nsIRadioControlElement)
NS_INTERFACE_MAP_ENTRY(nsIPhonetic)
NS_INTERFACE_MAP_ENTRY(imgIDecoderObserver)
@@ -390,7 +407,6 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
switch (mType) {
case NS_FORM_INPUT_TEXT:
case NS_FORM_INPUT_PASSWORD:
- case NS_FORM_INPUT_FILE:
if (GET_BOOLBIT(mBitField, BF_VALUE_CHANGED)) {
// We don't have our default value anymore. Set our value on
// the clone.
@@ -401,6 +417,11 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, PRBool aDeep,
it->SetValueInternal(value, nsnull);
}
break;
+ case NS_FORM_INPUT_FILE:
+ if (mFileName) {
+ it->mFileName = new nsString(*mFileName);
+ }
+ break;
case NS_FORM_INPUT_RADIO:
case NS_FORM_INPUT_CHECKBOX:
if (GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED)) {
@@ -621,8 +642,7 @@ nsHTMLInputElement::SetSize(PRUint32 aValue)
NS_IMETHODIMP
nsHTMLInputElement::GetValue(nsAString& aValue)
{
- if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD ||
- mType == NS_FORM_INPUT_FILE) {
+ if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) {
// No need to flush here, if there's no frame created for this
// input yet, there won't be a value in it (that we don't already
// have) even if we force it to be created
@@ -654,6 +674,17 @@ nsHTMLInputElement::GetValue(nsAString& aValue)
return NS_OK;
}
+ if (mType == NS_FORM_INPUT_FILE) {
+ if (mFileName) {
+ aValue = *mFileName;
+ }
+ else {
+ aValue.Truncate();
+ }
+
+ return NS_OK;
+ }
+
// Treat value == defaultValue for other input elements
if (!GetAttr(kNameSpaceID_None, nsHTMLAtoms::value, aValue) &&
(mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX)) {
@@ -673,22 +704,28 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
{
// check security. Note that setting the value to the empty string is always
// OK and gives pages a way to clear a file input if necessary.
- if (mType == NS_FORM_INPUT_FILE && !aValue.IsEmpty()) {
- nsIScriptSecurityManager *securityManager =
- nsContentUtils::GetSecurityManager();
+ if (mType == NS_FORM_INPUT_FILE) {
+ if (!aValue.IsEmpty()) {
+ nsIScriptSecurityManager *securityManager =
+ nsContentUtils::GetSecurityManager();
- PRBool enabled;
- nsresult rv =
- securityManager->IsCapabilityEnabled("UniversalFileRead", &enabled);
- NS_ENSURE_SUCCESS(rv, rv);
+ PRBool enabled;
+ nsresult rv =
+ securityManager->IsCapabilityEnabled("UniversalFileRead", &enabled);
+ NS_ENSURE_SUCCESS(rv, rv);
- if (!enabled) {
- // setting the value of a "FILE" input widget requires the
- // UniversalFileRead privilege
- return NS_ERROR_DOM_SECURITY_ERR;
+ if (!enabled) {
+ // setting the value of a "FILE" input widget requires the
+ // UniversalFileRead privilege
+ return NS_ERROR_DOM_SECURITY_ERR;
+ }
}
+ SetFileName(aValue);
}
- SetValueInternal(aValue, nsnull);
+ else {
+ SetValueInternal(aValue, nsnull);
+ }
+
return NS_OK;
}
@@ -703,12 +740,34 @@ nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
return NS_OK;
}
+void
+nsHTMLInputElement::GetFileName(nsAString& aValue)
+{
+ if (mFileName) {
+ aValue = *mFileName;
+ }
+ else {
+ aValue.Truncate();
+ }
+}
+
+void
+nsHTMLInputElement::SetFileName(const nsAString& aValue)
+{
+ // No big deal if |new| fails, we simply won't submit the file
+ mFileName = aValue.IsEmpty() ? nsnull : new nsString(aValue);
+
+ SetValueChanged(PR_TRUE);
+}
+
nsresult
nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
nsITextControlFrame* aFrame)
{
- if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD ||
- mType == NS_FORM_INPUT_FILE) {
+ NS_PRECONDITION(mType != NS_FORM_INPUT_FILE,
+ "Don't call SetValueInternal for file inputs");
+
+ if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) {
nsITextControlFrame* textControlFrame = aFrame;
nsIFormControlFrame* formControlFrame = textControlFrame;
@@ -726,9 +785,6 @@ nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
// File frames always own the value (if the frame is there).
// Text frames have a bit that says whether they own the value.
PRBool frameOwnsValue = PR_FALSE;
- if (mType == NS_FORM_INPUT_FILE && formControlFrame) {
- frameOwnsValue = PR_TRUE;
- }
if (textControlFrame) {
textControlFrame->OwnsValue(&frameOwnsValue);
}
@@ -749,6 +805,10 @@ nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
return mValue ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
+ if (mType == NS_FORM_INPUT_FILE) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
// If the value of a hidden input was changed, we mark it changed so that we
// will know we need to save / restore the value. Yes, we are overloading
// the meaning of ValueChanged just a teensy bit to save a measly byte of
@@ -1799,10 +1859,10 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
// process).
PRInt8 newType = aResult.GetEnumValue();
if (newType == NS_FORM_INPUT_FILE) {
- // If the type is being changed to file, set the element value
- // to the empty string. This is for security.
- // Call SetValueInternal so that this doesn't accidentally get caught
- // in the security checks in SetValue.
+ // These calls aren't strictly needed any more since we'll never
+ // confuse values and filenames. However they're there for backwards
+ // compat.
+ SetFileName(EmptyString());
SetValueInternal(EmptyString(), nsnull);
}
@@ -2136,7 +2196,7 @@ nsHTMLInputElement::Reset()
case NS_FORM_INPUT_FILE:
{
// Resetting it to blank should not perform security check
- rv = SetValueInternal(EmptyString(), nsnull);
+ SetFileName(EmptyString());
break;
}
// Value is the same as defaultValue for hidden inputs
@@ -2274,22 +2334,23 @@ nsHTMLInputElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
//
nsCOMPtr file;
- if (StringBeginsWith(value, NS_LITERAL_STRING("file:"),
- nsCaseInsensitiveStringComparator())) {
- // Converts the URL string into the corresponding nsIFile if possible.
- // A local file will be created if the URL string begins with file://.
- rv = NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(value),
- getter_AddRefs(file));
+ if (mFileName) {
+ if (StringBeginsWith(*mFileName, NS_LITERAL_STRING("file:"),
+ nsCaseInsensitiveStringComparator())) {
+ // Converts the URL string into the corresponding nsIFile if possible.
+ // A local file will be created if the URL string begins with file://.
+ rv = NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(*mFileName),
+ getter_AddRefs(file));
+ }
+ if (!file) {
+ // this is no "file://", try as local file
+ nsCOMPtr localFile;
+ rv = NS_NewLocalFile(*mFileName, PR_FALSE, getter_AddRefs(localFile));
+ file = localFile;
+ }
}
- if (!file) {
- // this is no "file://", try as local file
- nsCOMPtr localFile;
- rv = NS_NewLocalFile(value, PR_FALSE, getter_AddRefs(localFile));
- file = localFile;
- }
-
- if (NS_SUCCEEDED(rv)) {
+ if (file) {
//
// Get the leaf path name (to be submitted as the value)
@@ -2359,7 +2420,7 @@ nsHTMLInputElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
// If we can't even make a truncated filename, submit empty string
// rather than sending everything
//
- aFormSubmission->AddNameFilePair(this, name, value,
+ aFormSubmission->AddNameFilePair(this, name, EmptyString(),
nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
PR_FALSE);
return rv;
@@ -2412,7 +2473,6 @@ nsHTMLInputElement::SaveState()
case NS_FORM_INPUT_PASSWORD:
break;
case NS_FORM_INPUT_TEXT:
- case NS_FORM_INPUT_FILE:
case NS_FORM_INPUT_HIDDEN:
{
if (GET_BOOLBIT(mBitField, BF_VALUE_CHANGED)) {
@@ -2431,6 +2491,17 @@ nsHTMLInputElement::SaveState()
}
break;
}
+ case NS_FORM_INPUT_FILE:
+ {
+ if (mFileName) {
+ rv = GetPrimaryPresState(this, &state);
+ if (state) {
+ rv = state->SetStateProperty(NS_LITERAL_STRING("f"), *mFileName);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "value save failed!");
+ }
+ }
+ break;
+ }
}
if (GET_BOOLBIT(mBitField, BF_DISABLED_CHANGED)) {
@@ -2514,7 +2585,6 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
}
case NS_FORM_INPUT_TEXT:
- case NS_FORM_INPUT_FILE:
case NS_FORM_INPUT_HIDDEN:
{
nsAutoString value;
@@ -2525,6 +2595,16 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
}
break;
}
+ case NS_FORM_INPUT_FILE:
+ {
+ nsAutoString value;
+ rv = aState->GetStateProperty(NS_LITERAL_STRING("f"), value);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "value restore failed!");
+ if (rv == NS_STATE_PROPERTY_EXISTS) {
+ SetFileName(value);
+ }
+ break;
+ }
}
nsAutoString disabled;
diff --git a/mozilla/layout/forms/nsFileControlFrame.cpp b/mozilla/layout/forms/nsFileControlFrame.cpp
index 4ecb73d3570..90916ba9aa9 100644
--- a/mozilla/layout/forms/nsFileControlFrame.cpp
+++ b/mozilla/layout/forms/nsFileControlFrame.cpp
@@ -66,7 +66,7 @@
#include "nsINodeInfo.h"
#include "nsIDOMEventReceiver.h"
#include "nsILocalFile.h"
-#include "nsITextControlElement.h"
+#include "nsIFileControlElement.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
@@ -85,8 +85,7 @@ NS_NewFileControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
nsFileControlFrame::nsFileControlFrame(nsStyleContext* aContext):
nsAreaFrame(aContext),
mTextFrame(nsnull),
- mCachedState(nsnull),
- mDidPreDestroy(PR_FALSE)
+ mCachedState(nsnull)
{
//Shrink the area around its contents
SetFlags(NS_BLOCK_SHRINK_WRAP);
@@ -110,54 +109,13 @@ nsFileControlFrame::~nsFileControlFrame()
}
}
-void
-nsFileControlFrame::PreDestroy()
-{
- // Toss the value into the control from the anonymous content, which is about
- // to get lost. Note that if the page is being torn down then the anonymous
- // content may no longer have access to its frame. But _we_ can access that
- // frame. So if it's there, get the value from the frame
- if (mTextContent) {
- nsAutoString value;
- if (mTextFrame) {
- // Second arg doesn't really matter here...
- mTextFrame->GetValue(value, PR_TRUE);
- } else {
- // Get from the content
- nsCOMPtr input = do_QueryInterface(mTextContent);
- input->GetValue(value);
- }
-
- // Have it take the value, just like when input type=text goes away
- nsCOMPtr fileInput = do_QueryInterface(mContent);
- fileInput->TakeTextFrameValue(value);
- }
- mDidPreDestroy = PR_TRUE;
-}
-
void
nsFileControlFrame::Destroy()
{
- if (!mDidPreDestroy) {
- PreDestroy();
- }
mTextFrame = nsnull;
nsAreaFrame::Destroy();
}
-void
-nsFileControlFrame::RemovedAsPrimaryFrame()
-{
- if (!mDidPreDestroy) {
- PreDestroy();
- }
-#ifdef DEBUG
- else {
- NS_ERROR("RemovedAsPrimaryFrame called after PreDestroy");
- }
-#endif
-}
-
NS_IMETHODIMP
nsFileControlFrame::CreateAnonymousContent(nsPresContext* aPresContext,
nsISupportsArray& aChildList)
@@ -177,18 +135,17 @@ nsFileControlFrame::CreateAnonymousContent(nsPresContext* aPresContext,
content.swap(mTextContent);
- nsCOMPtr fileContent = do_QueryInterface(mContent);
-
if (mTextContent) {
mTextContent->SetAttr(kNameSpaceID_None, nsHTMLAtoms::type, NS_LITERAL_STRING("text"), PR_FALSE);
nsCOMPtr textControl = do_QueryInterface(mTextContent);
if (textControl) {
- if (fileContent) {
+ nsCOMPtr fileControl = do_QueryInterface(mContent);
+ if (fileControl) {
// Initialize value when we create the content in case the value was set
// before we got here
nsAutoString value;
- fileContent->GetValue(value);
+ fileControl->GetFileName(value);
textControl->SetValue(value);
}
@@ -211,6 +168,7 @@ nsFileControlFrame::CreateAnonymousContent(nsPresContext* aPresContext,
mBrowse = do_QueryInterface(content);
if (mBrowse) {
mBrowse->SetAttr(kNameSpaceID_None, nsHTMLAtoms::type, NS_LITERAL_STRING("button"), PR_FALSE);
+ nsCOMPtr fileContent = do_QueryInterface(mContent);
nsCOMPtr browseControl = do_QueryInterface(mBrowse);
if (fileContent && browseControl) {
PRInt32 tabIndex;
@@ -361,6 +319,11 @@ nsFileControlFrame::MouseClick(nsIDOMEvent* aMouseEvent)
result = localFile->GetPath(unicodePath);
if (!unicodePath.IsEmpty()) {
mTextFrame->SetFormProperty(nsHTMLAtoms::value, unicodePath);
+ nsCOMPtr fileControl = do_QueryInterface(mContent);
+ if (fileControl) {
+ fileControl->SetFileName(unicodePath);
+ }
+
// May need to fire an onchange here
mTextFrame->CheckFireOnChange();
return NS_OK;
@@ -587,12 +550,10 @@ nsFileControlFrame::GetFormProperty(nsIAtom* aName, nsAString& aValue) const
if (mCachedState) {
aValue.Assign(*mCachedState);
} else if (mTextContent) {
- nsCOMPtr textControl =
- do_QueryInterface(mTextContent);
- NS_ASSERTION(textControl,
- " element not implementing nsIDOMHTMLInputElement?");
-
- textControl->GetValue(aValue);
+ nsCOMPtr fileControl = do_QueryInterface(mTextContent);
+ if (fileControl) {
+ fileControl->GetFileName(aValue);
+ }
}
}
return NS_OK;
diff --git a/mozilla/layout/forms/nsFileControlFrame.h b/mozilla/layout/forms/nsFileControlFrame.h
index 54fc7e615a3..d183b26d65d 100644
--- a/mozilla/layout/forms/nsFileControlFrame.h
+++ b/mozilla/layout/forms/nsFileControlFrame.h
@@ -75,8 +75,6 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
- virtual void RemovedAsPrimaryFrame();
-
virtual void Destroy();
#ifdef NS_DEBUG
@@ -193,16 +191,8 @@ private:
void SyncAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
PRBool aWhichControls);
- /**
- * We call this when we are being destroyed or removed from the PFM.
- * @param aPresContext the current pres context
- */
- void PreDestroy();
-
NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
NS_IMETHOD_(nsrefcnt) Release() { return 1; }
-
- PRBool mDidPreDestroy; // has PreDestroy been called
};
#endif