From 55beafe241d73c78186f2431562d450669686fc8 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sun, 5 Sep 2010 14:00:05 -0400 Subject: [PATCH] Bug 583863: Refactor implementation to deal with files that aren't on the disk. r=sicking a=blocking-fennec --HG-- extra : rebase_source : 2b3605042aea4e4c8273cdad5ec7f05af15959cc --- .../test/browser/browser_248970_b.js | 7 +- .../test/browser/browser_346337.js | 17 +- .../test/browser/browser_466937.js | 8 +- content/base/public/Makefile.in | 1 - content/base/public/nsDOMFile.h | 47 +- content/base/public/nsIDOMFile.idl | 11 +- content/base/public/nsIDOMFileInternal.idl | 46 - content/base/src/nsDOMFile.cpp | 192 ++- content/base/src/nsDOMFileReader.cpp | 45 +- content/base/src/nsDOMFileReader.h | 6 +- .../base/src/nsFileDataProtocolHandler.cpp | 17 +- content/base/src/nsFileDataProtocolHandler.h | 5 +- content/base/src/nsFormData.cpp | 13 +- content/base/src/nsFormData.h | 8 +- content/base/src/nsXMLHttpRequest.cpp | 24 - content/base/test/test_bug345339.html | 15 +- content/html/content/public/Makefile.in | 1 - .../html/content/public/nsFormSubmission.h | 5 +- .../content/public/nsIFileControlElement.h | 86 -- content/html/content/src/nsFormSubmission.cpp | 41 +- .../html/content/src/nsGenericHTMLElement.h | 12 + .../html/content/src/nsHTMLInputElement.cpp | 241 ++-- content/html/content/src/nsHTMLInputElement.h | 1052 +++++++++-------- docshell/test/chrome/bug294258_window.xul | 10 +- .../base/tests/chrome/printpreview_helper.xul | 7 +- layout/forms/nsFileControlFrame.cpp | 78 +- layout/forms/nsICapturePicker.idl | 4 +- 27 files changed, 1023 insertions(+), 976 deletions(-) delete mode 100644 content/base/public/nsIDOMFileInternal.idl delete mode 100644 content/html/content/public/nsIFileControlElement.h diff --git a/browser/components/sessionstore/test/browser/browser_248970_b.js b/browser/components/sessionstore/test/browser/browser_248970_b.js index 458d7104a6f8..1fa00efaaaf9 100644 --- a/browser/components/sessionstore/test/browser/browser_248970_b.js +++ b/browser/components/sessionstore/test/browser/browser_248970_b.js @@ -45,6 +45,11 @@ function test() { return false; } + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsIFile); + filePath = file.path; + let fieldList = { "//input[@name='input']": Date.now().toString(), "//input[@name='spaced 1']": Math.random().toString(), @@ -59,7 +64,7 @@ function test() { "//textarea[1]": "", "//textarea[2]": "Some text... " + Math.random(), "//textarea[3]": "Some more text\n" + new Date(), - "//input[@type='file']": "/dev/null" + "//input[@type='file']": filePath }; function getElementByXPath(aTab, aQuery) { diff --git a/browser/components/sessionstore/test/browser/browser_346337.js b/browser/components/sessionstore/test/browser/browser_346337.js index 1f3baabc00de..e5333b227eaa 100644 --- a/browser/components/sessionstore/test/browser/browser_346337.js +++ b/browser/components/sessionstore/test/browser/browser_346337.js @@ -36,6 +36,19 @@ function test() { /** Test for Bug 346337 **/ + + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsILocalFile); + file.append("346337_test1.file"); + file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); + filePath1 = file.path; + file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsILocalFile); + file.append("346337_test2.file"); + file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); + filePath2 = file.path; let fieldList = { "//input[@name='input']": Date.now().toString(), @@ -51,8 +64,8 @@ function test() { "//textarea[1]": "", "//textarea[2]": "Some text... " + Math.random(), "//textarea[3]": "Some more text\n" + new Date(), - "//input[@type='file'][1]": ["/dev/null"], - "//input[@type='file'][2]": ["/dev/null", "/dev/stdin"] + "//input[@type='file'][1]": [filePath1], + "//input[@type='file'][2]": [filePath1, filePath2] }; function getElementByXPath(aTab, aQuery) { diff --git a/browser/components/sessionstore/test/browser/browser_466937.js b/browser/components/sessionstore/test/browser/browser_466937.js index e8cfd80456ad..a74539cd76c1 100644 --- a/browser/components/sessionstore/test/browser/browser_466937.js +++ b/browser/components/sessionstore/test/browser/browser_466937.js @@ -38,10 +38,16 @@ function test() { /** Test for Bug 466937 **/ waitForExplicitFinish(); + + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsILocalFile); + file.append("466937_test.file"); + file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); + let testPath = file.path; let testURL = "http://mochi.test:8888/browser/" + "browser/components/sessionstore/test/browser/browser_466937_sample.html"; - let testPath = "/home/user/regular.file"; let tab = gBrowser.addTab(testURL); tab.linkedBrowser.addEventListener("load", function(aEvent) { diff --git a/content/base/public/Makefile.in b/content/base/public/Makefile.in index a7580a76ab5c..c0758b948615 100644 --- a/content/base/public/Makefile.in +++ b/content/base/public/Makefile.in @@ -99,7 +99,6 @@ XPIDLSRCS = \ nsIDocumentEncoder.idl \ nsIDOMFile.idl \ nsIDOMFileReader.idl \ - nsIDOMFileInternal.idl \ nsIDOMFileList.idl \ nsIDOMFileException.idl \ nsIDOMFileError.idl \ diff --git a/content/base/public/nsDOMFile.h b/content/base/public/nsDOMFile.h index 7e984a2af5b3..0c8f67919390 100644 --- a/content/base/public/nsDOMFile.h +++ b/content/base/public/nsDOMFile.h @@ -41,34 +41,42 @@ #include "nsICharsetDetectionObserver.h" #include "nsIDOMFile.h" -#include "nsIDOMFileInternal.h" #include "nsIDOMFileList.h" #include "nsIDOMFileError.h" #include "nsIInputStream.h" #include "nsCOMArray.h" #include "nsCOMPtr.h" +#include "mozilla/AutoRestore.h" #include "nsString.h" #include "nsIWeakReference.h" #include "nsIWeakReferenceUtils.h" #include "nsIDocument.h" +#include "nsIXMLHttpRequest.h" class nsIDOMDocument; class nsIFile; class nsIInputStream; class nsDOMFile : public nsIDOMFile, - public nsIDOMFileInternal, + public nsIXHRSendable, public nsICharsetDetectionObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIDOMFILE - NS_DECL_NSIDOMFILEINTERNAL + NS_DECL_NSIXHRSENDABLE + + nsDOMFile(nsIFile *aFile, nsIDocument* aRelatedDoc, nsAString& aContentType) + : mFile(aFile), + mRelatedDoc(do_GetWeakReference(aRelatedDoc)), + mContentType(aContentType) + {} nsDOMFile(nsIFile *aFile, nsIDocument* aRelatedDoc) : mFile(aFile), mRelatedDoc(do_GetWeakReference(aRelatedDoc)) {} + ~nsDOMFile() {} // from nsICharsetDetectionObserver @@ -87,6 +95,30 @@ private: nsAString &aResult); }; +class nsDOMMemoryFile : public nsDOMFile +{ +public: + nsDOMMemoryFile(void *aMemoryBuffer, + PRUint64 aLength, + nsAString& aContentType, + nsIDocument *aRelatedDoc) + : nsDOMFile(nsnull, aRelatedDoc, aContentType), + mInternalData(aMemoryBuffer), mLength(aLength) + { } + + ~nsDOMMemoryFile() + { free(mInternalData); } + + NS_IMETHOD GetName(nsAString&); + NS_IMETHOD GetSize(PRUint64*); + NS_IMETHOD GetInternalStream(nsIInputStream**); + NS_IMETHOD GetMozFullPathInternal(nsAString&); + +protected: + void* mInternalData; + PRUint64 mLength; +}; + class nsDOMFileList : public nsIDOMFileList { public: @@ -136,4 +168,13 @@ private: PRUint16 mCode; }; +class NS_STACK_CLASS nsDOMFileInternalUrlHolder { +public: + nsDOMFileInternalUrlHolder(nsIDOMFile* aFile MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM); + ~nsDOMFileInternalUrlHolder(); + nsAutoString mUrl; +private: + MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + #endif diff --git a/content/base/public/nsIDOMFile.idl b/content/base/public/nsIDOMFile.idl index 4af299e92f40..9e63b5dfeb51 100644 --- a/content/base/public/nsIDOMFile.idl +++ b/content/base/public/nsIDOMFile.idl @@ -38,8 +38,10 @@ #include "domstubs.idl" interface nsIDOMFileError; +interface nsIInputStream; +interface nsIURI; -[scriptable, uuid(b10293e1-d531-4bdd-9b2b-4d8c1c9bc633)] +[scriptable, uuid(e72e2d6e-e267-4ea1-a798-6703d3a2c362)] interface nsIDOMFile : nsISupports { //fileName and fileSize are now deprecated attributes @@ -56,4 +58,11 @@ interface nsIDOMFile : nsISupports DOMString getAsText(in DOMString encoding); // raises(FileException) on retrieval DOMString getAsDataURL(); // raises(FileException) on retrieval DOMString getAsBinary(); // raises(FileException) on retrieval + + [noscript] readonly attribute nsIInputStream internalStream; + // The caller is responsible for releasing the internalUrl from the + // moz-filedata: protocol handler + [noscript] readonly attribute DOMString internalUrl; + // This performs no security checks! + [noscript] readonly attribute DOMString mozFullPathInternal; }; diff --git a/content/base/public/nsIDOMFileInternal.idl b/content/base/public/nsIDOMFileInternal.idl deleted file mode 100644 index a4e5dd6d461e..000000000000 --- a/content/base/public/nsIDOMFileInternal.idl +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode: IDL; 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 Corporation - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "domstubs.idl" - -interface nsIFile; - -[scriptable, uuid(047CA6C4-52B3-46F1-8976-E198B724F72F)] -interface nsIDOMFileInternal : nsISupports -{ - attribute nsIFile internalFile; -}; diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp index 05bd5a20f5fd..532f04371df7 100644 --- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -15,7 +15,7 @@ * The Original Code is mozila.org code. * * The Initial Developer of the Original Code is - * Mozilla Corporation + * Mozilla Foundation * Portions created by the Initial Developer are Copyright (C) 2007 * the Initial Developer. All Rights Reserved. * @@ -61,6 +61,7 @@ #include "nsNetUtil.h" #include "nsIUUIDGenerator.h" #include "nsFileDataProtocolHandler.h" +#include "nsStringStream.h" #include "plbase64.h" #include "prmem.h" @@ -72,7 +73,7 @@ DOMCI_DATA(File, nsDOMFile) NS_INTERFACE_MAP_BEGIN(nsDOMFile) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile) NS_INTERFACE_MAP_ENTRY(nsIDOMFile) - NS_INTERFACE_MAP_ENTRY(nsIDOMFileInternal) + NS_INTERFACE_MAP_ENTRY(nsIXHRSendable) NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(File) NS_INTERFACE_MAP_END @@ -116,12 +117,18 @@ NS_IMETHODIMP nsDOMFile::GetMozFullPath(nsAString &aFileName) { if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) { - return mFile->GetPath(aFileName); + return GetMozFullPathInternal(aFileName); } aFileName.Truncate(); return NS_OK; } +NS_IMETHODIMP +nsDOMFile::GetMozFullPathInternal(nsAString &aFilename) +{ + return mFile->GetPath(aFilename); +} + NS_IMETHODIMP nsDOMFile::GetSize(PRUint64 *aFileSize) { @@ -162,36 +169,56 @@ nsDOMFile::GetType(nsAString &aType) return NS_OK; } +NS_IMETHODIMP +nsDOMFile::GetInternalStream(nsIInputStream **aStream) +{ + return NS_NewLocalFileInputStream(aStream, mFile, -1, -1, + nsIFileInputStream::CLOSE_ON_EOF | + nsIFileInputStream::REOPEN_ON_REWIND); +} + NS_IMETHODIMP nsDOMFile::GetUrl(nsAString& aURL) { if (mURL.IsEmpty()) { - nsresult rv; - nsCOMPtr uuidgen = - do_GetService("@mozilla.org/uuid-generator;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsID id; - rv = uuidgen->GenerateUUIDInPlace(&id); - NS_ENSURE_SUCCESS(rv, rv); - - char chars[NSID_LENGTH]; - id.ToProvidedString(chars); - - nsCString url = NS_LITERAL_CSTRING(FILEDATA_SCHEME ":") + - Substring(chars + 1, chars + NSID_LENGTH - 2); + GetInternalUrl(mURL); nsCOMPtr doc = do_QueryReferent(mRelatedDoc); - if (doc) { - doc->RegisterFileDataUri(url); - nsFileDataProtocolHandler::AddFileDataEntry(url, mFile, - doc->NodePrincipal()); - } - - CopyASCIItoUTF16(url, mURL); + NS_LossyConvertUTF16toASCII shortURL(mURL); + doc->RegisterFileDataUri(shortURL); } aURL = mURL; + + return NS_OK; +} + +NS_IMETHODIMP +nsDOMFile::GetInternalUrl(nsAString& aURL) +{ + nsresult rv; + nsCOMPtr uuidgen = + do_GetService("@mozilla.org/uuid-generator;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsID id; + rv = uuidgen->GenerateUUIDInPlace(&id); + NS_ENSURE_SUCCESS(rv, rv); + + char chars[NSID_LENGTH]; + id.ToProvidedString(chars); + + nsCString url = NS_LITERAL_CSTRING(FILEDATA_SCHEME ":") + + Substring(chars + 1, chars + NSID_LENGTH - 2); + + nsCOMPtr doc = do_QueryReferent(mRelatedDoc); + if (doc) { + nsFileDataProtocolHandler::AddFileDataEntry(url, + this, + doc->NodePrincipal()); + } + + CopyASCIItoUTF16(url, aURL); return NS_OK; } @@ -202,9 +229,7 @@ nsDOMFile::GetAsText(const nsAString &aCharset, nsAString &aResult) aResult.Truncate(); nsCOMPtr stream; - nsresult rv = NS_NewLocalFileInputStream - (getter_AddRefs(stream), - mFile, -1, -1, 0); + nsresult rv = GetInternalStream(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, DOMFileResult(rv)); nsCAutoString charsetGuess; @@ -231,43 +256,33 @@ nsDOMFile::GetAsText(const nsAString &aCharset, nsAString &aResult) return ConvertStream(stream, charset.get(), aResult); } -NS_IMETHODIMP -nsDOMFile::GetInternalFile(nsIFile **aFile) -{ - NS_IF_ADDREF(*aFile = mFile); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMFile::SetInternalFile(nsIFile *aFile) -{ - mFile = aFile; - return NS_OK; -} - NS_IMETHODIMP nsDOMFile::GetAsDataURL(nsAString &aResult) { aResult.AssignLiteral("data:"); nsresult rv; - nsCOMPtr mimeService = - do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (!mContentType.Length()) { + nsCOMPtr mimeService = + do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); - nsCAutoString contentType; - rv = mimeService->GetTypeFromFile(mFile, contentType); - if (NS_SUCCEEDED(rv)) { - AppendUTF8toUTF16(contentType, aResult); + nsCAutoString contentType; + rv = mimeService->GetTypeFromFile(mFile, contentType); + if (NS_SUCCEEDED(rv)) { + CopyUTF8toUTF16(contentType, mContentType); + } + } + + if (mContentType.Length()) { + aResult.Append(mContentType); } else { aResult.AppendLiteral("application/octet-stream"); } aResult.AppendLiteral(";base64,"); nsCOMPtr stream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), - mFile, -1, -1, - nsIFileInputStream::CLOSE_ON_EOF); + rv = GetInternalStream(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, DOMFileResult(rv)); char readBuf[4096]; @@ -307,10 +322,7 @@ nsDOMFile::GetAsBinary(nsAString &aResult) aResult.Truncate(); nsCOMPtr stream; - nsresult rv = NS_NewLocalFileInputStream - (getter_AddRefs(stream), - mFile, -1, -1, - nsIFileInputStream::CLOSE_ON_EOF); + nsresult rv = GetInternalStream(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, DOMFileResult(rv)); PRUint32 numRead; @@ -423,6 +435,29 @@ nsDOMFile::GuessCharset(nsIInputStream *aStream, return NS_OK; } +NS_IMETHODIMP +nsDOMFile::GetSendInfo(nsIInputStream** aBody, + nsACString& aContentType, + nsACString& aCharset) +{ + nsresult rv; + + nsCOMPtr stream; + rv = this->GetInternalStream(getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, rv); + + nsString contentType; + rv = this->GetType(contentType); + NS_ENSURE_SUCCESS(rv, rv); + + CopyUTF16toUTF8(contentType, aContentType); + + aCharset.Truncate(); + + stream.forget(aBody); + return NS_OK; +} + NS_IMETHODIMP nsDOMFile::Notify(const char* aCharset, nsDetectionConfident aConf) { @@ -463,6 +498,39 @@ nsDOMFile::ConvertStream(nsIInputStream *aStream, return rv; } +// nsDOMMemoryFile Implementation +NS_IMETHODIMP +nsDOMMemoryFile::GetName(nsAString &aFileName) +{ + aFileName.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMMemoryFile::GetSize(PRUint64 *aFileSize) +{ + *aFileSize = mLength; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream) +{ + if (mLength > PR_INT32_MAX) + return NS_ERROR_FAILURE; + + PRInt32 l = mLength; + + return NS_NewByteInputStream(aStream, (const char*)mInternalData, l); +} + +NS_IMETHODIMP +nsDOMMemoryFile::GetMozFullPathInternal(nsAString &aFilename) +{ + aFilename.Truncate(); + return NS_OK; +} + // nsDOMFileList implementation DOMCI_DATA(FileList, nsDOMFileList) @@ -511,3 +579,17 @@ nsDOMFileError::GetCode(PRUint16* aCode) *aCode = mCode; return NS_OK; } + +nsDOMFileInternalUrlHolder::nsDOMFileInternalUrlHolder(nsIDOMFile* aFile + MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) { + MOZILLA_GUARD_OBJECT_NOTIFIER_INIT; + aFile->GetInternalUrl(mUrl); +} + +nsDOMFileInternalUrlHolder::~nsDOMFileInternalUrlHolder() { + if (!mUrl.IsEmpty()) { + nsCAutoString narrowUrl; + CopyUTF16toUTF8(mUrl, narrowUrl); + nsFileDataProtocolHandler::RemoveFileDataEntry(narrowUrl); + } +} diff --git a/content/base/src/nsDOMFileReader.cpp b/content/base/src/nsDOMFileReader.cpp index 0fdb844ed1f3..48e2b8ac513f 100644 --- a/content/base/src/nsDOMFileReader.cpp +++ b/content/base/src/nsDOMFileReader.cpp @@ -15,7 +15,7 @@ * The Original Code is mozila.org code. * * The Initial Developer of the Original Code is - * Mozilla Corporation + * Mozilla Foundation * Portions created by the Initial Developer are Copyright (C) 2007 * the Initial Developer. All Rights Reserved. * @@ -71,13 +71,13 @@ #include "nsJSEnvironment.h" #include "nsIScriptGlobalObject.h" #include "nsIDOMClassInfo.h" -#include "nsIDOMFileInternal.h" #include "nsCExternalHandlerService.h" #include "nsIStreamConverterService.h" #include "nsEventDispatcher.h" #include "nsCycleCollectionParticipant.h" #include "nsLayoutStatics.h" #include "nsIScriptObjectPrincipal.h" +#include "nsFileDataProtocolHandler.h" #define LOAD_STR "load" #define ERROR_STR "error" @@ -485,6 +485,7 @@ nsDOMFileReader::ReadFileContent(nsIDOMFile* aFile, const nsAString &aCharset, eDataFormat aDataFormat) { + nsresult rv; NS_ENSURE_TRUE(aFile, NS_ERROR_NULL_POINTER); //Implicit abort to clear any other activity going on @@ -496,26 +497,28 @@ nsDOMFileReader::ReadFileContent(nsIDOMFile* aFile, mReadyState = nsIDOMFileReader::EMPTY; FreeFileData(); + mFile = aFile; mDataFormat = aDataFormat; mCharset = aCharset; - //Obtain the nsDOMFile's underlying nsIFile - nsresult rv; - nsCOMPtr domFile(do_QueryInterface(aFile)); - rv = domFile->GetInternalFile(getter_AddRefs(mFile)); - NS_ENSURE_SUCCESS(rv, rv); - //Establish a channel with our file - nsCOMPtr uri; - rv = NS_NewFileURI(getter_AddRefs(uri), mFile); - NS_ENSURE_SUCCESS(rv, rv); + { + // Hold the internal URL alive only as long as necessary + // After the channel is created it will own whatever is backing + // the DOMFile. + nsDOMFileInternalUrlHolder urlHolder(mFile); - rv = NS_NewChannel(getter_AddRefs(mChannel), uri); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), urlHolder.mUrl); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_NewChannel(getter_AddRefs(mChannel), uri); + NS_ENSURE_SUCCESS(rv, rv); + } //Obtain the total size of the file before reading mReadTotal = -1; - mFile->GetFileSize(&mReadTotal); + mFile->GetSize(&mReadTotal); rv = mChannel->AsyncOpen(this, nsnull); NS_ENSURE_SUCCESS(rv, rv); @@ -604,7 +607,7 @@ nsDOMFileReader::GetAsText(const nsAString &aCharset, } nsresult -nsDOMFileReader::GetAsDataURL(nsIFile *aFile, +nsDOMFileReader::GetAsDataURL(nsIDOMFile *aFile, const char *aFileData, PRUint32 aDataLen, nsAString& aResult) @@ -612,14 +615,10 @@ nsDOMFileReader::GetAsDataURL(nsIFile *aFile, aResult.AssignLiteral("data:"); nsresult rv; - nsCOMPtr mimeService = - do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCAutoString contentType; - rv = mimeService->GetTypeFromFile(aFile, contentType); - if (NS_SUCCEEDED(rv)) { - AppendUTF8toUTF16(contentType, aResult); + nsString contentType; + rv = aFile->GetType(contentType); + if (NS_SUCCEEDED(rv) && !contentType.IsEmpty()) { + aResult.Append(contentType); } else { aResult.AppendLiteral("application/octet-stream"); } diff --git a/content/base/src/nsDOMFileReader.h b/content/base/src/nsDOMFileReader.h index 42922d632ba3..fdd028cac6cf 100644 --- a/content/base/src/nsDOMFileReader.h +++ b/content/base/src/nsDOMFileReader.h @@ -120,7 +120,7 @@ protected: nsresult ReadFileContent(nsIDOMFile *aFile, const nsAString &aCharset, eDataFormat aDataFormat); nsresult GetAsText(const nsAString &aCharset, const char *aFileData, PRUint32 aDataLen, nsAString &aResult); - nsresult GetAsDataURL(nsIFile *aFile, const char *aFileData, PRUint32 aDataLen, nsAString &aResult); + nsresult GetAsDataURL(nsIDOMFile *aFile, const char *aFileData, PRUint32 aDataLen, nsAString &aResult); nsresult GuessCharset(const char *aFileData, PRUint32 aDataLen, nsACString &aCharset); nsresult ConvertStream(const char *aFileData, PRUint32 aDataLen, const char *aCharset, nsAString &aResult); void DispatchError(nsresult rv); @@ -133,7 +133,7 @@ protected: } char *mFileData; - nsCOMPtr mFile; + nsCOMPtr mFile; nsString mCharset; PRUint32 mDataLen; @@ -150,7 +150,7 @@ protected: nsCOMPtr mPrincipal; nsCOMPtr mChannel; - PRInt64 mReadTotal; + PRUint64 mReadTotal; PRUint64 mReadTransferred; nsRefPtr mOnLoadEndListener; diff --git a/content/base/src/nsFileDataProtocolHandler.cpp b/content/base/src/nsFileDataProtocolHandler.cpp index 314c987fd4bf..9c1bf5db4f66 100644 --- a/content/base/src/nsFileDataProtocolHandler.cpp +++ b/content/base/src/nsFileDataProtocolHandler.cpp @@ -42,7 +42,7 @@ #include "nsNetUtil.h" #include "nsIURIWithPrincipal.h" #include "nsIPrincipal.h" -#include "nsIFileChannel.h" +#include "nsIDOMFile.h" #include "nsISerializable.h" #include "nsIClassInfo.h" #include "nsIObjectInputStream.h" @@ -55,14 +55,15 @@ static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); // Hash table struct FileDataInfo { - nsCOMPtr mFileUri; + nsCOMPtr mFile; nsCOMPtr mPrincipal; }; static nsClassHashtable* gFileDataTable; void -nsFileDataProtocolHandler::AddFileDataEntry(nsACString& aUri, nsIFile* aFile, +nsFileDataProtocolHandler::AddFileDataEntry(nsACString& aUri, + nsIDOMFile* aFile, nsIPrincipal* aPrincipal) { if (!gFileDataTable) { @@ -72,7 +73,7 @@ nsFileDataProtocolHandler::AddFileDataEntry(nsACString& aUri, nsIFile* aFile, FileDataInfo* info = new FileDataInfo; - NS_NewFileURI(getter_AddRefs(info->mFileUri), aFile); + info->mFile = aFile; info->mPrincipal = aPrincipal; gFileDataTable->Put(aUri, info); @@ -413,8 +414,14 @@ nsFileDataProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) } #endif + nsCOMPtr stream; + nsresult rv = info->mFile->GetInternalStream(getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr channel; - nsresult rv = NS_NewChannel(getter_AddRefs(channel), info->mFileUri); + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), + uri, + stream); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr owner = do_QueryInterface(info->mPrincipal); diff --git a/content/base/src/nsFileDataProtocolHandler.h b/content/base/src/nsFileDataProtocolHandler.h index 402f56a67797..b98d397b492e 100644 --- a/content/base/src/nsFileDataProtocolHandler.h +++ b/content/base/src/nsFileDataProtocolHandler.h @@ -41,7 +41,7 @@ #define FILEDATA_SCHEME "moz-filedata" -class nsIFile; +class nsIDOMFile; class nsIPrincipal; class nsFileDataProtocolHandler : public nsIProtocolHandler @@ -57,7 +57,8 @@ public: virtual ~nsFileDataProtocolHandler() {} // Methods for managing uri->file mapping - static void AddFileDataEntry(nsACString& aUri, nsIFile* aFile, + static void AddFileDataEntry(nsACString& aUri, + nsIDOMFile* aFile, nsIPrincipal* aPrincipal); static void RemoveFileDataEntry(nsACString& aUri); diff --git a/content/base/src/nsFormData.cpp b/content/base/src/nsFormData.cpp index 068964108cce..c9176d9c245b 100644 --- a/content/base/src/nsFormData.cpp +++ b/content/base/src/nsFormData.cpp @@ -36,9 +36,8 @@ #include "nsFormData.h" #include "nsIVariant.h" -#include "nsIDOMFileInternal.h" #include "nsIInputStream.h" -#include "nsIFile.h" +#include "nsIDOMFile.h" #include "nsContentUtils.h" nsFormData::nsFormData() @@ -84,7 +83,7 @@ nsFormData::AddNameValuePair(const nsAString& aName, nsresult nsFormData::AddNameFilePair(const nsAString& aName, - nsIFile* aFile) + nsIDOMFile* aFile) { FormDataTuple* data = mFormData.AppendElement(); data->name = aName; @@ -113,13 +112,9 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue) nsMemory::Free(iid); - nsCOMPtr domFile = do_QueryInterface(supports); + nsCOMPtr domFile = do_QueryInterface(supports); if (domFile) { - nsCOMPtr file; - rv = domFile->GetInternalFile(getter_AddRefs(file)); - NS_ENSURE_SUCCESS(rv, rv); - - return AddNameFilePair(aName, file); + return AddNameFilePair(aName, domFile); } } diff --git a/content/base/src/nsFormData.h b/content/base/src/nsFormData.h index 3dc745b7416b..19ca9433fce8 100644 --- a/content/base/src/nsFormData.h +++ b/content/base/src/nsFormData.h @@ -42,6 +42,8 @@ #include "nsFormSubmission.h" #include "nsTArray.h" +class nsIDOMFile; + class nsFormData : public nsIDOMFormData, public nsIXHRSendable, public nsFormSubmission @@ -59,16 +61,14 @@ public: virtual nsresult AddNameValuePair(const nsAString& aName, const nsAString& aValue); virtual nsresult AddNameFilePair(const nsAString& aName, - nsIFile* aFile); - - + nsIDOMFile* aFile); private: struct FormDataTuple { nsString name; nsString stringValue; - nsCOMPtr fileValue; + nsCOMPtr fileValue; PRBool valueIsFile; }; diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 71649c629d78..fe3921272f6d 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -63,7 +63,6 @@ #include "nsIScriptGlobalObject.h" #include "nsIDOMClassInfo.h" #include "nsIDOMElement.h" -#include "nsIDOMFileInternal.h" #include "nsIDOMWindow.h" #include "nsIMIMEService.h" #include "nsCExternalHandlerService.h" @@ -2328,29 +2327,6 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, return NS_OK; } - // nsIDOMFile? - nsCOMPtr file = do_QueryInterface(supports); - if (file) { - aCharset.Truncate(); - - nsCOMPtr internalFile; - rv = file->GetInternalFile(getter_AddRefs(internalFile)); - NS_ENSURE_SUCCESS(rv, rv); - - // Get the mimetype - nsCOMPtr mimeService = - do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mimeService->GetTypeFromFile(internalFile, aContentType); - if (NS_FAILED(rv)) { - aContentType.Truncate(); - } - - // Feed local file input stream into our upload channel - return NS_NewLocalFileInputStream(aResult, internalFile); - } - // nsIXHRSendable? nsCOMPtr sendable = do_QueryInterface(supports); if (sendable) { diff --git a/content/base/test/test_bug345339.html b/content/base/test/test_bug345339.html index 323d5c799ad2..407e268d5449 100644 --- a/content/base/test/test_bug345339.html +++ b/content/base/test/test_bug345339.html @@ -22,6 +22,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=345339 /** Test for Bug 345339 **/ SimpleTest.waitForExplicitFinish(); +var filePath; + function afterLoad() { var iframeDoc = $("testframe").contentDocument; @@ -31,8 +33,15 @@ function afterLoad() { iframeDoc.getElementById("password").value = "123456"; iframeDoc.getElementById("hidden").value = "gecko"; - netscape.security.PrivilegeManager.enablePrivilege("UniversalFileRead"); - iframeDoc.getElementById("file").value = "dummyfile.txt"; + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsILocalFile); + file.append("345339_test.file"); + file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); + filePath = file.path; + + iframeDoc.getElementById("file").value = filePath; /* Reload the page */ $("testframe").setAttribute("onload", "afterReload()"); @@ -55,7 +64,7 @@ function afterReload() { is(iframeDoc.getElementById("hidden").value, "gecko", "hidden field value preserved"); netscape.security.PrivilegeManager.enablePrivilege("UniversalFileRead"); - is(iframeDoc.getElementById("file").value, "dummyfile.txt", + is(iframeDoc.getElementById("file").value, filePath, "file field value preserved"); SimpleTest.finish(); diff --git a/content/html/content/public/Makefile.in b/content/html/content/public/Makefile.in index b5de365f6c8d..bb24b40db9be 100644 --- a/content/html/content/public/Makefile.in +++ b/content/html/content/public/Makefile.in @@ -60,7 +60,6 @@ EXPORTS = \ nsIRadioVisitor.h \ nsIRadioGroupContainer.h \ nsITextControlElement.h \ - nsIFileControlElement.h \ nsFormSubmission.h \ nsIFrameSetElement.h \ nsHTMLAudioElement.h \ diff --git a/content/html/content/public/nsFormSubmission.h b/content/html/content/public/nsFormSubmission.h index 83fbb1ccd8cf..5c26ae9d1016 100644 --- a/content/html/content/public/nsFormSubmission.h +++ b/content/html/content/public/nsFormSubmission.h @@ -52,6 +52,7 @@ class nsIDocShell; class nsIRequest; class nsISaveAsCharset; class nsIMultiplexInputStream; +class nsIDOMFile; /** * Class for form submissions; encompasses the function to call to submit as @@ -81,7 +82,7 @@ public: * @param aFile the file to submit */ virtual nsresult AddNameFilePair(const nsAString& aName, - nsIFile* aFile) = 0; + nsIDOMFile* aFile) = 0; /** * Reports whether the instance supports AddIsindex(). @@ -187,7 +188,7 @@ public: virtual nsresult AddNameValuePair(const nsAString& aName, const nsAString& aValue); virtual nsresult AddNameFilePair(const nsAString& aName, - nsIFile* aFile); + nsIDOMFile* aFile); virtual nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream); diff --git a/content/html/content/public/nsIFileControlElement.h b/content/html/content/public/nsIFileControlElement.h deleted file mode 100644 index 73cb76e2baee..000000000000 --- a/content/html/content/public/nsIFileControlElement.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- 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" -#include "nsTArray.h" -#include "nsString.h" -#include "nsCOMArray.h" - -class nsIFile; - -// 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 a readable string representing the list of files currently - * selected by this control. This value might not be a valid file name - * and should not be used for anything but displaying the filename to the - * user. - */ - virtual void GetDisplayFileName(nsAString& aFileName) = 0; - - /** - * Sets the list of filenames currently selected by this control. - */ - virtual void SetFileNames(const nsTArray& aFileNames) = 0; - - /** - * Gets a list of nsIFile objects for the files currently selected by - * this control. - */ - virtual void GetFileArray(nsCOMArray& aFiles) = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileControlElement, - NS_IFILECONTROLELEMENT_IID) - -#endif // nsIFileControlElement_h___ diff --git a/content/html/content/src/nsFormSubmission.cpp b/content/html/content/src/nsFormSubmission.cpp index 62563101e83b..d2979ba5486d 100644 --- a/content/html/content/src/nsFormSubmission.cpp +++ b/content/html/content/src/nsFormSubmission.cpp @@ -49,9 +49,8 @@ #include "nsDOMError.h" #include "nsGenericHTMLElement.h" #include "nsISaveAsCharset.h" - -// JBK added for submit move from content frame #include "nsIFile.h" +#include "nsIDOMFile.h" #include "nsDirectoryServiceDefs.h" #include "nsStringStream.h" #include "nsIURI.h" @@ -110,7 +109,7 @@ public: virtual nsresult AddNameValuePair(const nsAString& aName, const nsAString& aValue); virtual nsresult AddNameFilePair(const nsAString& aName, - nsIFile* aFile); + nsIDOMFile* aFile); virtual nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream); @@ -196,7 +195,7 @@ nsFSURLEncoded::AddIsindex(const nsAString& aValue) nsresult nsFSURLEncoded::AddNameFilePair(const nsAString& aName, - nsIFile* aFile) + nsIDOMFile* aFile) { if (!mWarnedFileControl) { SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nsnull, 0); @@ -205,7 +204,7 @@ nsFSURLEncoded::AddNameFilePair(const nsAString& aName, nsAutoString filename; if (aFile) { - aFile->GetLeafName(filename); + aFile->GetName(filename); } return AddNameValuePair(aName, filename); @@ -469,7 +468,7 @@ nsFSMultipartFormData::AddNameValuePair(const nsAString& aName, nsresult nsFSMultipartFormData::AddNameFilePair(const nsAString& aName, - nsIFile* aFile) + nsIDOMFile* aFile) { // Encode the control name nsCAutoString nameStr; @@ -477,12 +476,13 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName, NS_ENSURE_SUCCESS(rv, rv); nsCString filenameStr; - nsCAutoString contentType; + nsAutoString contentType; nsCOMPtr fileStream; if (aFile) { // Get and encode the filename nsAutoString filename; - aFile->GetLeafName(filename); + rv = aFile->GetName(filename); + NS_ENSURE_SUCCESS(rv, rv); nsCAutoString encodedFileName; rv = EncodeVal(filename, encodedFileName); NS_ENSURE_SUCCESS(rv, rv); @@ -493,20 +493,14 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName, nsLinebreakConverter::eLinebreakNet)); // Get content type - nsCOMPtr MIMEService = - do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = MIMEService->GetTypeFromFile(aFile, contentType); - if (NS_FAILED(rv)) { + rv = aFile->GetType(contentType); + if (NS_FAILED(rv) || contentType.IsEmpty()) { contentType.AssignLiteral("application/octet-stream"); } // Get input stream - rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), - aFile, -1, -1, - nsIFileInputStream::CLOSE_ON_EOF | - nsIFileInputStream::REOPEN_ON_REWIND); + rv = aFile->GetInternalStream(getter_AddRefs(fileStream)); + NS_ENSURE_SUCCESS(rv, rv); if (fileStream) { // Create buffered stream (for efficiency) nsCOMPtr bufferedStream; @@ -534,8 +528,9 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName, NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"") + nameStr + NS_LITERAL_CSTRING("\"; filename=\"") + filenameStr + NS_LITERAL_CSTRING("\"" CRLF) - + NS_LITERAL_CSTRING("Content-Type: ") + contentType - + NS_LITERAL_CSTRING(CRLF CRLF); + + NS_LITERAL_CSTRING("Content-Type: "); + AppendUTF16toUTF8(contentType, mPostDataChunk); + mPostDataChunk += NS_LITERAL_CSTRING(CRLF CRLF); // Add the file to the stream if (fileStream) { @@ -605,7 +600,7 @@ public: virtual nsresult AddNameValuePair(const nsAString& aName, const nsAString& aValue); virtual nsresult AddNameFilePair(const nsAString& aName, - nsIFile* aFile); + nsIDOMFile* aFile); virtual nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream); @@ -628,11 +623,11 @@ nsFSTextPlain::AddNameValuePair(const nsAString& aName, nsresult nsFSTextPlain::AddNameFilePair(const nsAString& aName, - nsIFile* aFile) + nsIDOMFile* aFile) { nsAutoString filename; if (aFile) { - aFile->GetLeafName(filename); + aFile->GetName(filename); } AddNameValuePair(aName, filename); diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index c4d37657c0a0..e5f510585276 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -1315,6 +1315,18 @@ NS_NewHTML##_elementName##Element(already_AddRefed aNodeInfo, \ NS_INTERFACE_TABLE_ENTRY(_class, _i6) \ NS_OFFSET_AND_INTERFACE_TABLE_END +#define NS_HTML_CONTENT_INTERFACE_TABLE7(_class, _i1, _i2, _i3, _i4, _i5, \ + _i6, _i7) \ + NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(_class) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i1) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i2) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i3) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i4) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i5) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i6) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i7) \ + NS_OFFSET_AND_INTERFACE_TABLE_END + #define NS_HTML_CONTENT_INTERFACE_TABLE8(_class, _i1, _i2, _i3, _i4, _i5, \ _i6, _i7, _i8) \ NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(_class) \ diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index f0ef08b156a0..e82752974615 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -38,7 +38,6 @@ #include "nsIDOMHTMLInputElement.h" #include "nsITextControlElement.h" -#include "nsIFileControlElement.h" #include "nsIDOMNSEditableElement.h" #include "nsIRadioVisitor.h" #include "nsIPhonetic.h" @@ -93,8 +92,8 @@ #include "nsRuleData.h" -// input type=radio -#include "nsIRadioGroupContainer.h" +// input type=radio +#include "nsIRadioGroupContainer.h" // input type=file #include "nsIFile.h" @@ -207,12 +206,13 @@ class nsHTMLInputElementState : public nsISupports mValue = aValue; } - const nsTArray& GetFilenames() { - return mFilenames; + const nsCOMArray& GetFiles() { + return mFiles; } - void SetFilenames(const nsTArray &aFilenames) { - mFilenames = aFilenames; + void SetFiles(const nsCOMArray &aFiles) { + mFiles.Clear(); + mFiles.AppendObjects(aFiles); } nsHTMLInputElementState() @@ -223,7 +223,7 @@ class nsHTMLInputElementState : public nsISupports protected: nsString mValue; - nsTArray mFilenames; + nsCOMArray mFiles; PRPackedBool mChecked; PRPackedBool mCheckedSet; }; @@ -268,21 +268,21 @@ AsyncClickHandler::Run() // Check if page is allowed to open the popup if (mPopupControlState != openAllowed) { - nsCOMPtr pm = - do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); - - if (!pm) { - return NS_OK; - } - - PRUint32 permission; - pm->TestPermission(doc->GetDocumentURI(), &permission); - if (permission == nsIPopupWindowManager::DENY_POPUP) { - nsCOMPtr domDoc = do_QueryInterface(doc); - nsGlobalWindow::FirePopupBlockedEvent(domDoc, win, nsnull, EmptyString(), EmptyString()); + nsCOMPtr pm = + do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); + + if (!pm) { return NS_OK; } - } + + PRUint32 permission; + pm->TestPermission(doc->GetDocumentURI(), &permission); + if (permission == nsIPopupWindowManager::DENY_POPUP) { + nsCOMPtr domDoc = do_QueryInterface(doc); + nsGlobalWindow::FirePopupBlockedEvent(domDoc, win, nsnull, EmptyString(), EmptyString()); + return NS_OK; + } + } // Get Loc title nsXPIDLString title; @@ -325,17 +325,24 @@ AsyncClickHandler::Run() // Set default directry and filename nsAutoString defaultName; - nsCOMArray oldFiles; - mInput->GetFileArray(oldFiles); + const nsCOMArray& oldFiles = mInput->GetFiles(); if (oldFiles.Count()) { - // set directory - nsCOMPtr parentFile; - oldFiles[0]->GetParent(getter_AddRefs(parentFile)); - if (parentFile) { - nsCOMPtr parentLocalFile = do_QueryInterface(parentFile, &rv); - if (parentLocalFile) { - filePicker->SetDisplayDirectory(parentLocalFile); + nsString path; + + oldFiles[0]->GetMozFullPathInternal(path); + + nsCOMPtr localFile; + rv = NS_NewLocalFile(path, PR_FALSE, getter_AddRefs(localFile)); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr parentFile; + rv = localFile->GetParent(getter_AddRefs(parentFile)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr parentLocalFile = do_QueryInterface(parentFile, &rv); + if (parentLocalFile) { + filePicker->SetDisplayDirectory(parentLocalFile); + } } } @@ -344,7 +351,7 @@ AsyncClickHandler::Run() // one file was selected before. if (oldFiles.Count() == 1) { nsAutoString leafName; - oldFiles[0]->GetLeafName(leafName); + oldFiles[0]->GetName(leafName); if (!leafName.IsEmpty()) { filePicker->SetDefaultString(leafName); } @@ -375,7 +382,7 @@ AsyncClickHandler::Run() return NS_OK; // Collect new selected filenames - nsTArray newFileNames; + nsCOMArray newFiles; if (multi) { nsCOMPtr iter; rv = filePicker->GetFiles(getter_AddRefs(iter)); @@ -389,7 +396,9 @@ AsyncClickHandler::Run() nsString unicodePath; rv = localFile->GetPath(unicodePath); if (!unicodePath.IsEmpty()) { - newFileNames.AppendElement(unicodePath); + nsCOMPtr domFile = + do_QueryObject(new nsDOMFile(localFile, doc)); + newFiles.AppendObject(domFile); } if (!prefSaved) { // Store the last used directory using the content pref service @@ -408,7 +417,9 @@ AsyncClickHandler::Run() nsString unicodePath; rv = localFile->GetPath(unicodePath); if (!unicodePath.IsEmpty()) { - newFileNames.AppendElement(unicodePath); + nsCOMPtr domFile= + do_QueryObject(new nsDOMFile(localFile, doc)); + newFiles.AppendObject(domFile); } // Store the last used directory using the content pref service rv = nsHTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(doc->GetDocumentURI(), @@ -418,7 +429,7 @@ AsyncClickHandler::Run() } // Set new selected files - if (!newFileNames.IsEmpty()) { + if (newFiles.Count()) { // Tell mTextFrame that this update of the value is a user initiated // change. Otherwise it'll think that the value is being set by a script // and not fire onchange when it should. @@ -428,7 +439,7 @@ AsyncClickHandler::Run() textFrame->SetFireChangeEventState(PR_TRUE); } - mInput->SetFileNames(newFileNames); + mInput->SetFiles(newFiles); if (textFrame) { textFrame->SetFireChangeEventState(oldState); // May need to fire an onchange here @@ -669,10 +680,9 @@ DOMCI_NODE_DATA(HTMLInputElement, nsHTMLInputElement) // QueryInterface implementation for nsHTMLInputElement NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLInputElement) - NS_HTML_CONTENT_INTERFACE_TABLE9(nsHTMLInputElement, + NS_HTML_CONTENT_INTERFACE_TABLE8(nsHTMLInputElement, nsIDOMHTMLInputElement, nsITextControlElement, - nsIFileControlElement, nsIPhonetic, imgIDecoderObserver, nsIImageLoadingContent, @@ -721,7 +731,14 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const } break; case NS_FORM_INPUT_FILE: - it->mFileNames = mFileNames; + if (it->GetOwnerDoc()->IsStaticDocument()) { + // We're going to be used in print preview. Since the doc is static + // we can just grab the pretty string and use it as wallpaper + GetDisplayFileName(it->mStaticDocFileList); + } else { + it->mFiles.Clear(); + it->mFiles.AppendObjects(mFiles); + } break; case NS_FORM_INPUT_RADIO: case NS_FORM_INPUT_CHECKBOX: @@ -1025,17 +1042,15 @@ nsHTMLInputElement::GetValue(nsAString& aValue) if (mType == NS_FORM_INPUT_FILE) { if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) { - if (!mFileNames.IsEmpty()) { - aValue = mFileNames[0]; + if (mFiles.Count()) { + return mFiles[0]->GetMozFullPath(aValue); } else { aValue.Truncate(); } } else { // Just return the leaf name - nsCOMArray files; - GetFileArray(files); - if (files.Count() == 0 || NS_FAILED(files[0]->GetLeafName(aValue))) { + if (mFiles.Count() == 0 || NS_FAILED(mFiles[0]->GetName(aValue))) { aValue.Truncate(); } } @@ -1065,10 +1080,11 @@ nsHTMLInputElement::SetValue(const nsAString& aValue) // UniversalFileRead privilege return NS_ERROR_DOM_SECURITY_ERR; } - SetSingleFileName(aValue); + const PRUnichar *name = PromiseFlatString(aValue).get(); + return MozSetFileNameArray(&name, 1); } else { - ClearFileNames(); + ClearFiles(); } } else { @@ -1087,12 +1103,14 @@ nsHTMLInputElement::MozGetFileNameArray(PRUint32 *aLength, PRUnichar ***aFileNam return NS_ERROR_DOM_SECURITY_ERR; } - *aLength = mFileNames.Length(); + *aLength = mFiles.Count(); PRUnichar **ret = - static_cast(NS_Alloc(mFileNames.Length() * sizeof(PRUnichar*))); + static_cast(NS_Alloc(mFiles.Count() * sizeof(PRUnichar*))); - for (PRUint32 i = 0; i < mFileNames.Length(); i++) { - ret[i] = NS_strdup(mFileNames[i].get()); + for (PRUint32 i = 0; i < mFiles.Count(); i++) { + nsString str; + mFiles[i]->GetMozFullPath(str); + ret[i] = NS_strdup(str.get()); } *aFileNames = ret; @@ -1109,12 +1127,36 @@ nsHTMLInputElement::MozSetFileNameArray(const PRUnichar **aFileNames, PRUint32 a return NS_ERROR_DOM_SECURITY_ERR; } - nsTArray fileNames(aLength); + nsCOMArray files; for (PRUint32 i = 0; i < aLength; ++i) { - fileNames.AppendElement(aFileNames[i]); + nsCOMPtr file; + if (StringBeginsWith(nsDependentString(aFileNames[i]), + NS_LITERAL_STRING("file:"), + nsASCIICaseInsensitiveStringComparator())) { + // Converts the URL string into the corresponding nsIFile if possible + // A local file will be created if the URL string begins with file:// + NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]), + getter_AddRefs(file)); + } + + if (!file) { + // this is no "file://", try as local file + nsCOMPtr localFile; + NS_NewLocalFile(nsDependentString(aFileNames[i]), + PR_FALSE, getter_AddRefs(localFile)); + file = do_QueryInterface(localFile); + } + + if (file) { + nsCOMPtr domFile = new nsDOMFile(file, GetOwnerDoc()); + files.AppendObject(domFile); + } else { + continue; // Not much we can do if the file doesn't exist + } + } - SetFileNames(fileNames); + SetFiles(files); return NS_OK; } @@ -1136,7 +1178,8 @@ nsHTMLInputElement::SetUserInput(const nsAString& aValue) if (mType == NS_FORM_INPUT_FILE) { - SetSingleFileName(aValue); + const PRUnichar* name = PromiseFlatString(aValue).get(); + return MozSetFileNameArray(&name, 1); } else { SetValueInternal(aValue, PR_TRUE, PR_TRUE); } @@ -1241,28 +1284,32 @@ nsHTMLInputElement::SetPlaceholderClass(PRBool aVisible, PRBool aNotify) } void -nsHTMLInputElement::GetDisplayFileName(nsAString& aValue) +nsHTMLInputElement::GetDisplayFileName(nsAString& aValue) const { + if (GetOwnerDoc()->IsStaticDocument()) { + aValue = mStaticDocFileList; + return; + } + aValue.Truncate(); - for (PRUint32 i = 0; i < mFileNames.Length(); ++i) { + for (PRUint32 i = 0; i < (PRUint32)mFiles.Count(); ++i) { + nsString str; + mFiles[i]->GetMozFullPath(str); if (i == 0) { - aValue.Append(mFileNames[i]); + aValue.Append(str); } else { - aValue.Append(NS_LITERAL_STRING(", ") + mFileNames[i]); + aValue.Append(NS_LITERAL_STRING(", ") + str); } } } void -nsHTMLInputElement::SetFileNames(const nsTArray& aFileNames) +nsHTMLInputElement::SetFiles(const nsCOMArray& aFiles) { - mFileNames = aFileNames; -#if DEBUG - for (PRUint32 i = 0; i < (PRUint32)aFileNames.Length(); ++i) { - NS_ASSERTION(!aFileNames[i].IsEmpty(), "Empty file name"); - } -#endif + mFiles.Clear(); + mFiles.AppendObjects(aFiles); + // No need to flush here, if there's no frame at this point we // don't need to force creation of one just to tell it about this // new value. We just want the display to update as needed. @@ -1279,37 +1326,10 @@ nsHTMLInputElement::SetFileNames(const nsTArray& aFileNames) UpdateAllValidityStates(PR_TRUE); } -void -nsHTMLInputElement::GetFileArray(nsCOMArray &aFiles) +const nsCOMArray& +nsHTMLInputElement::GetFiles() { - aFiles.Clear(); - - if (mType != NS_FORM_INPUT_FILE) { - return; - } - - for (PRUint32 i = 0; i < mFileNames.Length(); ++i) { - nsCOMPtr file; - if (StringBeginsWith(mFileNames[i], 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://. - NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(mFileNames[i]), - getter_AddRefs(file)); - } - - if (!file) { - // this is no "file://", try as local file - nsCOMPtr localFile; - NS_NewLocalFile(mFileNames[i], PR_FALSE, getter_AddRefs(localFile)); - // Wish there was a better way to downcast an already_AddRefed - file = dont_AddRef(static_cast(localFile.forget().get())); - } - - if (file) { - aFiles.AppendObject(file); - } - } + return mFiles; } nsresult @@ -1318,16 +1338,10 @@ nsHTMLInputElement::UpdateFileList() if (mFileList) { mFileList->Clear(); - nsIDocument* doc = GetOwnerDoc(); - - nsCOMArray files; - GetFileArray(files); + const nsCOMArray& files = GetFiles(); for (PRUint32 i = 0; i < (PRUint32)files.Count(); ++i) { - nsRefPtr domFile = new nsDOMFile(files[i], doc); - if (domFile) { - if (!mFileList->Append(domFile)) { - return NS_ERROR_FAILURE; - } + if (!mFileList->Append(files[i])) { + return NS_ERROR_FAILURE; } } } @@ -1819,7 +1833,7 @@ nsHTMLInputElement::Click() nsEventStatus status = nsEventStatus_eIgnore; SET_BOOLBIT(mBitField, BF_HANDLING_CLICK, PR_TRUE); - if (mType == NS_FORM_INPUT_FILE){ + if (mType == NS_FORM_INPUT_FILE){ FireAsyncClickHandler(); } nsEventDispatcher::Dispatch(static_cast(this), context, @@ -2561,7 +2575,7 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID, // This call isn't strictly needed any more since we'll never // confuse values and filenames. However it's there for backwards // compat. - ClearFileNames(); + ClearFiles(); } HandleTypeChange(newType); @@ -2882,7 +2896,7 @@ nsHTMLInputElement::SetDefaultValueAsValue() case NS_FORM_INPUT_FILE: { // Resetting it to blank should not perform security check - ClearFileNames(); + ClearFiles(); break; } // Value is the same as defaultValue for hidden inputs @@ -3007,8 +3021,7 @@ nsHTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission) if (mType == NS_FORM_INPUT_FILE) { // Submit files - nsCOMArray files; - GetFileArray(files); + const nsCOMArray& files = GetFiles(); for (PRUint32 i = 0; i < (PRUint32)files.Count(); ++i) { aFormSubmission->AddNameFilePair(name, files[i]); @@ -3100,13 +3113,13 @@ nsHTMLInputElement::SaveState() } case NS_FORM_INPUT_FILE: { - if (!mFileNames.IsEmpty()) { + if (mFiles.Count()) { inputState = new nsHTMLInputElementState(); if (!inputState) { return NS_ERROR_OUT_OF_MEMORY; } - inputState->SetFilenames(mFileNames); + inputState->SetFiles(mFiles); } break; } @@ -3253,7 +3266,8 @@ nsHTMLInputElement::RestoreState(nsPresState* aState) } case NS_FORM_INPUT_FILE: { - SetFileNames(inputState->GetFilenames()); + const nsCOMArray& files = inputState->GetFiles(); + SetFiles(files); break; } } @@ -3662,8 +3676,7 @@ nsHTMLInputElement::IsValueMissing() } case NS_FORM_INPUT_FILE: { - nsCOMArray files; - GetFileArray(files); + const nsCOMArray& files = GetFiles(); return !files.Count(); } default: diff --git a/content/html/content/src/nsHTMLInputElement.h b/content/html/content/src/nsHTMLInputElement.h index 4161a7b55243..5864a7cfd183 100644 --- a/content/html/content/src/nsHTMLInputElement.h +++ b/content/html/content/src/nsHTMLInputElement.h @@ -1,80 +1,83 @@ -/* -*- 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 Communicator client code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Pierre Phaneuf - * - * Alternatively, the contents of this file may be used under the terms of - * either of 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 nsHTMLInputElement_h__ -#define nsHTMLInputElement_h__ - -#include "nsGenericHTMLElement.h" -#include "nsImageLoadingContent.h" -#include "nsIDOMHTMLInputElement.h" -#include "nsITextControlElement.h" -#include "nsIPhonetic.h" -#include "nsIDOMNSEditableElement.h" -#include "nsIFileControlElement.h" - -#include "nsTextEditorState.h" -#include "nsCOMPtr.h" -#include "nsIConstraintValidation.h" - -// -// Accessors for mBitField -// -#define BF_DISABLED_CHANGED 0 -#define BF_HANDLING_CLICK 1 -#define BF_VALUE_CHANGED 2 -#define BF_CHECKED_CHANGED 3 -#define BF_CHECKED 4 -#define BF_HANDLING_SELECT_EVENT 5 -#define BF_SHOULD_INIT_CHECKED 6 -#define BF_PARSER_CREATING 7 -#define BF_IN_INTERNAL_ACTIVATE 8 -#define BF_CHECKED_IS_TOGGLED 9 -#define BF_INDETERMINATE 10 -#define BF_INHIBIT_RESTORATION 11 - -#define GET_BOOLBIT(bitfield, field) (((bitfield) & (0x01 << (field))) \ - ? PR_TRUE : PR_FALSE) -#define SET_BOOLBIT(bitfield, field, b) ((b) \ - ? ((bitfield) |= (0x01 << (field))) \ - : ((bitfield) &= ~(0x01 << (field)))) - -class nsDOMFileList; - +/* -*- 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 Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsHTMLInputElement_h__ +#define nsHTMLInputElement_h__ + +#include "nsGenericHTMLElement.h" +#include "nsImageLoadingContent.h" +#include "nsIDOMHTMLInputElement.h" +#include "nsITextControlElement.h" +#include "nsIPhonetic.h" +#include "nsIDOMNSEditableElement.h" + +#include "nsTextEditorState.h" +#include "nsCOMPtr.h" +#include "nsIConstraintValidation.h" +#include "nsDOMFile.h" + +// +// Accessors for mBitField +// +#define BF_DISABLED_CHANGED 0 +#define BF_HANDLING_CLICK 1 +#define BF_VALUE_CHANGED 2 +#define BF_CHECKED_CHANGED 3 +#define BF_CHECKED 4 +#define BF_HANDLING_SELECT_EVENT 5 +#define BF_SHOULD_INIT_CHECKED 6 +#define BF_PARSER_CREATING 7 +#define BF_IN_INTERNAL_ACTIVATE 8 +#define BF_CHECKED_IS_TOGGLED 9 +#define BF_INDETERMINATE 10 +#define BF_INHIBIT_RESTORATION 11 + +#define GET_BOOLBIT(bitfield, field) (((bitfield) & (0x01 << (field))) \ + ? PR_TRUE : PR_FALSE) +#define SET_BOOLBIT(bitfield, field, b) ((b) \ + ? ((bitfield) |= (0x01 << (field))) \ + : ((bitfield) &= ~(0x01 << (field)))) + +class nsDOMFileList; +class nsIRadioGroupContainer; +class nsIRadioGroupVisitor; +class nsIRadioVisitor; + class UploadLastDir : public nsIObserver, public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS @@ -103,451 +106,460 @@ private: // Directories are stored here during private browsing mode nsInterfaceHashtable mUploadLastDirStore; PRBool mInPrivateBrowsing; -}; - -class nsIRadioGroupContainer; -class nsIRadioVisitor; - -class nsHTMLInputElement : public nsGenericHTMLFormElement, - public nsImageLoadingContent, - public nsIDOMHTMLInputElement, - public nsITextControlElement, - public nsIPhonetic, - public nsIDOMNSEditableElement, - public nsIFileControlElement, - public nsIConstraintValidation -{ -public: +}; + +class nsIRadioGroupContainer; +class nsIRadioVisitor; + +class nsHTMLInputElement : public nsGenericHTMLFormElement, + public nsImageLoadingContent, + public nsIDOMHTMLInputElement, + public nsITextControlElement, + public nsIPhonetic, + public nsIDOMNSEditableElement, + public nsIConstraintValidation +{ +public: using nsIConstraintValidation::GetValidationMessage; - nsHTMLInputElement(already_AddRefed aNodeInfo, - PRUint32 aFromParser); - virtual ~nsHTMLInputElement(); - - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsIDOMNode - NS_FORWARD_NSIDOMNODE(nsGenericHTMLFormElement::) - - // nsIDOMElement - NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLFormElement::) - - // nsIDOMHTMLElement - NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLFormElement::) - - // nsIDOMHTMLInputElement - NS_DECL_NSIDOMHTMLINPUTELEMENT - - // nsIPhonetic - NS_DECL_NSIPHONETIC - - // nsIDOMNSEditableElement - NS_IMETHOD GetEditor(nsIEditor** aEditor) - { - return nsGenericHTMLElement::GetEditor(aEditor); - } - NS_IMETHOD SetUserInput(const nsAString& aInput); - - // Overriden nsIFormControl methods - NS_IMETHOD_(PRUint32) GetType() const { return mType; } - NS_IMETHOD Reset(); - NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission); - NS_IMETHOD SaveState(); - virtual PRBool RestoreState(nsPresState* aState); - virtual PRBool AllowDrop(); - - // nsIContent - virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex); - - virtual PRBool ParseAttribute(PRInt32 aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult); - virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, - PRInt32 aModType) const; - NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; - virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; - - virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); - virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); - - virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, - nsIContent* aBindingParent, - PRBool aCompileEventHandlers); - virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, - PRBool aNullParent = PR_TRUE); - - virtual void DoneCreatingElement(); - - virtual PRInt32 IntrinsicState() const; - - // nsITextControlElement - NS_IMETHOD SetValueChanged(PRBool aValueChanged); - NS_IMETHOD_(PRBool) IsSingleLineTextControl() const; - NS_IMETHOD_(PRBool) IsTextArea() const; - NS_IMETHOD_(PRBool) IsPlainTextControl() const; - NS_IMETHOD_(PRBool) IsPasswordTextControl() const; - NS_IMETHOD_(PRInt32) GetCols(); - NS_IMETHOD_(PRInt32) GetWrapCols(); - NS_IMETHOD_(PRInt32) GetRows(); - NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue); - NS_IMETHOD_(PRBool) ValueChanged() const; - NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, PRBool aIgnoreWrap) const; - NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, PRBool aUserInput); - NS_IMETHOD_(nsIEditor*) GetTextEditor(); - NS_IMETHOD_(nsISelectionController*) GetSelectionController(); - NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection(); - NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame); - NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame); - NS_IMETHOD CreateEditor(); - NS_IMETHOD_(nsIContent*) GetRootEditorNode(); - NS_IMETHOD_(nsIContent*) GetPlaceholderNode(); - NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify); - NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify); - NS_IMETHOD_(void) InitializeKeyboardEventListeners(); - NS_IMETHOD_(void) OnValueChanged(PRBool aNotify); - - // nsIFileControlElement - virtual void GetDisplayFileName(nsAString& aFileName); - virtual void GetFileArray(nsCOMArray &aFile); - virtual void SetFileNames(const nsTArray& aFileNames); - - void SetCheckedChangedInternal(PRBool aCheckedChanged); - PRBool GetCheckedChanged(); - void AddedToRadioGroup(PRBool aNotify = PR_TRUE); - void WillRemoveFromRadioGroup(PRBool aNotify); - /** - * Get the radio group container for this button (form or document) - * @return the radio group container (or null if no form or document) - */ - virtual already_AddRefed GetRadioGroupContainer(); - - /** - * Helper function returning the currently selected button in the radio group. - * Returning null if the element is not a button or if there is no selectied - * button in the group. - * - * @return the selected button (or null). - */ - already_AddRefed GetSelectedRadioButton(); - - virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; - - NS_IMETHOD FireAsyncClickHandler(); - - virtual void UpdateEditableState() - { - return UpdateEditableFormControlState(); - } - - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLInputElement, - nsGenericHTMLFormElement) - - static UploadLastDir* gUploadLastDir; + nsHTMLInputElement(already_AddRefed aNodeInfo, + PRUint32 aFromParser); + virtual ~nsHTMLInputElement(); + + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + + // nsIDOMNode + NS_FORWARD_NSIDOMNODE(nsGenericHTMLFormElement::) + + // nsIDOMElement + NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLFormElement::) + + // nsIDOMHTMLElement + NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLFormElement::) + + // nsIDOMHTMLInputElement + NS_DECL_NSIDOMHTMLINPUTELEMENT + + // nsIPhonetic + NS_DECL_NSIPHONETIC + + // nsIDOMNSEditableElement + NS_IMETHOD GetEditor(nsIEditor** aEditor) + { + return nsGenericHTMLElement::GetEditor(aEditor); + } + NS_IMETHOD SetUserInput(const nsAString& aInput); + + // Overriden nsIFormControl methods + NS_IMETHOD_(PRUint32) GetType() const { return mType; } + NS_IMETHOD Reset(); + NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission); + NS_IMETHOD SaveState(); + virtual PRBool RestoreState(nsPresState* aState); + virtual PRBool AllowDrop(); + + // nsIContent + virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex); + + virtual PRBool ParseAttribute(PRInt32 aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult); + virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, + PRInt32 aModType) const; + NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; + + virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); + virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); + + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); + + virtual void DoneCreatingElement(); + + virtual PRInt32 IntrinsicState() const; + + // nsITextControlElement + NS_IMETHOD SetValueChanged(PRBool aValueChanged); + NS_IMETHOD_(PRBool) IsSingleLineTextControl() const; + NS_IMETHOD_(PRBool) IsTextArea() const; + NS_IMETHOD_(PRBool) IsPlainTextControl() const; + NS_IMETHOD_(PRBool) IsPasswordTextControl() const; + NS_IMETHOD_(PRInt32) GetCols(); + NS_IMETHOD_(PRInt32) GetWrapCols(); + NS_IMETHOD_(PRInt32) GetRows(); + NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue); + NS_IMETHOD_(PRBool) ValueChanged() const; + NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, PRBool aIgnoreWrap) const; + NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, PRBool aUserInput); + NS_IMETHOD_(nsIEditor*) GetTextEditor(); + NS_IMETHOD_(nsISelectionController*) GetSelectionController(); + NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection(); + NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame); + NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame); + NS_IMETHOD CreateEditor(); + NS_IMETHOD_(nsIContent*) GetRootEditorNode(); + NS_IMETHOD_(nsIContent*) GetPlaceholderNode(); + NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify); + NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify); + NS_IMETHOD_(void) InitializeKeyboardEventListeners(); + NS_IMETHOD_(void) OnValueChanged(PRBool aNotify); + + // nsIFileControlElement + void GetDisplayFileName(nsAString& aFileName) const; + const nsCOMArray& GetFiles(); + void SetFiles(const nsCOMArray& aFiles); + + void SetCheckedChangedInternal(PRBool aCheckedChanged); + PRBool GetCheckedChanged(); + void AddedToRadioGroup(PRBool aNotify = PR_TRUE); + void WillRemoveFromRadioGroup(PRBool aNotify); + /** + * Get the radio group container for this button (form or document) + * @return the radio group container (or null if no form or document) + */ + virtual already_AddRefed GetRadioGroupContainer(); + + /** + * Helper function returning the currently selected button in the radio group. + * Returning null if the element is not a button or if there is no selectied + * button in the group. + * + * @return the selected button (or null). + */ + already_AddRefed GetSelectedRadioButton(); + + virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + + NS_IMETHOD FireAsyncClickHandler(); + + virtual void UpdateEditableState() + { + return UpdateEditableFormControlState(); + } + + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLInputElement, + nsGenericHTMLFormElement) + + static UploadLastDir* gUploadLastDir; // create and destroy the static UploadLastDir object for remembering // which directory was last used on a site-by-site basis static void InitUploadLastDir(); - static void DestroyUploadLastDir(); - - void MaybeLoadImage(); - - virtual nsXPCClassInfo* GetClassInfo(); - - // nsIConstraintValidation - PRBool IsTooLong(); - PRBool IsValueMissing(); - PRBool HasTypeMismatch(); - PRBool HasPatternMismatch(); - void UpdateTooLongValidityState(); - void UpdateValueMissingValidityState(); - void UpdateTypeMismatchValidityState(); - void UpdatePatternMismatchValidityState(); - void UpdateAllValidityStates(PRBool aNotify); - PRBool IsBarredFromConstraintValidation() const; - nsresult GetValidationMessage(nsAString& aValidationMessage, - ValidityStateType aType); - -protected: - // Pull IsSingleLineTextControl into our scope, otherwise it'd be hidden - // by the nsITextControlElement version. - using nsGenericHTMLFormElement::IsSingleLineTextControl; - - /** - * The ValueModeType specifies how the value IDL attribute should behave. - * - * See: http://dev.w3.org/html5/spec/forms.html#dom-input-value - */ - enum ValueModeType - { - // On getting, returns the value. - // On setting, sets value. - VALUE_MODE_VALUE, - // On getting, returns the value if present or the empty string. - // On setting, sets the value. - VALUE_MODE_DEFAULT, - // On getting, returns the value if present or "on". - // On setting, sets the value. - VALUE_MODE_DEFAULT_ON, - // On getting, returns "C:\fakepath\" followed by the file name of the - // first file of the selected files if any. - // On setting the empty string, empties the selected files list, otherwise - // throw the INVALID_STATE_ERR exception. - VALUE_MODE_FILENAME - }; - - /** - * This helper method returns true if aValue is a valid email address. - * This is following the HTML5 specification: - * http://dev.w3.org/html5/spec/forms.html#valid-e-mail-address - * - * @param aValue the email address to check. - * @result whether the given string is a valid email address. - */ - static PRBool IsValidEmailAddress(const nsAString& aValue); - - /** - * This helper method returns true if aValue is a valid email address list. - * Email address list is a list of email address separated by comas (,) which - * can be surrounded by space charecters. - * This is following the HTML5 specification: - * http://dev.w3.org/html5/spec/forms.html#valid-e-mail-address-list - * - * @param aValue the email address list to check. - * @result whether the given string is a valid email address list. - */ - static PRBool IsValidEmailAddressList(const nsAString& aValue); - - /** - * This helper method returns true if the aPattern pattern matches aValue. - * aPattern should not contain leading and trailing slashes (/). - * The pattern has to match the entire value not just a subset. - * aDocument must be a valid pointer (not null). - * - * This is following the HTML5 specification: - * http://dev.w3.org/html5/spec/forms.html#attr-input-pattern - * - * @param aValue the string to check. - * @param aPattern the string defining the pattern. - * @param aDocument the owner document of the element. - * @result whether the given string is matches the pattern. - */ - static PRBool IsPatternMatching(nsAString& aValue, nsAString& aPattern, - nsIDocument* aDocument); - - // Helper method - nsresult SetValueInternal(const nsAString& aValue, - PRBool aUserInput, - PRBool aSetValueChanged); - - void ClearFileNames() { - nsTArray fileNames; - SetFileNames(fileNames); - } - - void SetSingleFileName(const nsAString& aFileName) { - nsAutoTArray fileNames; - fileNames.AppendElement(aFileName); - SetFileNames(fileNames); - } - - nsresult SetIndeterminateInternal(PRBool aValue, - PRBool aShouldInvalidate); - - nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd); - - /** - * Get the name if it exists and return whether it did exist - * @param aName the name returned [OUT] - * @param true if the name is empty, false otherwise - */ - PRBool GetNameIfExists(nsAString& aName) { - GetAttr(kNameSpaceID_None, nsGkAtoms::name, aName); - return !aName.IsEmpty(); - } - - /** - * Called when an attribute is about to be changed - */ - virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, - const nsAString* aValue, PRBool aNotify); - /** - * Called when an attribute has just been changed - */ - virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, - const nsAString* aValue, PRBool aNotify); - - /** - * Dispatch a select event. Returns true if the event was not cancelled. - */ - PRBool DispatchSelectEvent(nsPresContext* aPresContext); - - void SelectAll(nsPresContext* aPresContext); - PRBool IsImage() const - { - return AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, - nsGkAtoms::image, eIgnoreCase); - } - - virtual PRBool AcceptAutofocus() const - { - return PR_TRUE; - } - - /** - * Fire the onChange event - */ - void FireOnChange(); - - /** - * Visit a the group of radio buttons this radio belongs to - * @param aVisitor the visitor to visit with - */ - nsresult VisitGroup(nsIRadioVisitor* aVisitor, PRBool aFlushContent); - - /** - * Do all the work that |SetChecked| does (radio button handling, etc.), but - * take an |aNotify| parameter. - */ - nsresult DoSetChecked(PRBool aValue, PRBool aNotify, PRBool aSetValueChanged); - - /** - * Do all the work that |SetCheckedChanged| does (radio button handling, - * etc.), but take an |aNotify| parameter that lets it avoid flushing content - * when it can. - */ - void DoSetCheckedChanged(PRBool aCheckedChanged, PRBool aNotify); - - /** - * Actually set checked and notify the frame of the change. - * @param aValue the value of checked to set - */ - void SetCheckedInternal(PRBool aValue, PRBool aNotify); - - /** - * Syntax sugar to make it easier to check for checked - */ - PRBool GetChecked() const - { - return GET_BOOLBIT(mBitField, BF_CHECKED); - } - - nsresult RadioSetChecked(PRBool aNotify); - void SetCheckedChanged(PRBool aCheckedChanged); - - /** - * MaybeSubmitForm looks for a submit input or a single text control - * and submits the form if either is present. - */ - nsresult MaybeSubmitForm(nsPresContext* aPresContext); - - /** - * Update mFileList with the currently selected file. - */ - nsresult UpdateFileList(); - - /** - * Determine whether the editor needs to be initialized explicitly for - * a particular event. - */ - PRBool NeedToInitializeEditorForEvent(nsEventChainPreVisitor& aVisitor) const; - - /** - * Get the value mode of the element, depending of the type. - */ - ValueModeType GetValueMode() const; - - /** - * Get the mutable state of the element. - * When the element isn't mutable (immutable), the value or checkedness - * should not be changed by the user. - * - * See: http://dev.w3.org/html5/spec/forms.html#concept-input-mutable - */ - PRBool IsMutable() const; - - /** - * Returns if the readonly attribute applies for the current type. - */ - PRBool DoesReadOnlyApply() const; - - /** - * Returns if the required attribute applies for the current type. - */ - PRBool DoesRequiredApply() const; - - /** - * Returns if the pattern attribute applies for the current type. - */ - PRBool DoesPatternApply() const; - - void FreeData(); - nsTextEditorState *GetEditorState() const; - - /** - * Manages the internal data storage across type changes. - */ - void HandleTypeChange(PRUint8 aNewType); - - /** - * Sanitize the value of the element depending of its current type. - * See: http://www.whatwg.org/specs/web-apps/current-work/#value-sanitization-algorithm - */ - void SanitizeValue(nsAString& aValue); - - /** - * Returns whether the placeholder attribute applies for the current type. - */ - bool PlaceholderApplies() const { return IsSingleLineTextControlInternal(PR_FALSE, mType); } - - /** - * Set the current default value to the value of the input element. - */ - nsresult SetDefaultValueAsValue(); - - nsCOMPtr mControllers; - - /** - * The type of this input () as an integer. - * @see nsIFormControl.h (specifically NS_FORM_INPUT_*) - */ - PRUint8 mType; - /** - * A bitfield containing our booleans - * @see GET_BOOLBIT / SET_BOOLBIT macros and BF_* field identifiers - */ - PRInt16 mBitField; - /* - * In mInputData, the mState field is used if IsSingleLineTextControl returns - * true and mValue is used otherwise. We have to be careful when handling it - * on a type change. - * - * Accessing the mState member should be done using the GetEditorState function, - * which returns null if the state is not present. - */ - union InputData { - /** - * The current value of the input if it has been changed from the default - */ - char* mValue; - /** - * The state of the text editor associated with the text/password input - */ - nsTextEditorState* mState; - } mInputData; - /** - * The value of the input if it is a file input. This is the list of filenames - * 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 list of filenames is always owned by this member, never by - * the frame. Whenever the frame wants to change the filename it has to call - * SetFileNames to update this member. - */ - nsTArray mFileNames; - - nsRefPtr mFileList; -}; - -#endif + static void DestroyUploadLastDir(); + + void MaybeLoadImage(); + + virtual nsXPCClassInfo* GetClassInfo(); + + static nsHTMLInputElement* FromContent(nsIContent *aContent) + { + if (aContent->NodeInfo()->Equals(nsGkAtoms::input, kNameSpaceID_XHTML)) + return static_cast(aContent); + return NULL; + } + + // nsIConstraintValidation + PRBool IsTooLong(); + PRBool IsValueMissing(); + PRBool HasTypeMismatch(); + PRBool HasPatternMismatch(); + void UpdateTooLongValidityState(); + void UpdateValueMissingValidityState(); + void UpdateTypeMismatchValidityState(); + void UpdatePatternMismatchValidityState(); + void UpdateAllValidityStates(PRBool aNotify); + PRBool IsBarredFromConstraintValidation() const; + nsresult GetValidationMessage(nsAString& aValidationMessage, + ValidityStateType aType); + +protected: + // Pull IsSingleLineTextControl into our scope, otherwise it'd be hidden + // by the nsITextControlElement version. + using nsGenericHTMLFormElement::IsSingleLineTextControl; + + /** + * The ValueModeType specifies how the value IDL attribute should behave. + * + * See: http://dev.w3.org/html5/spec/forms.html#dom-input-value + */ + enum ValueModeType + { + // On getting, returns the value. + // On setting, sets value. + VALUE_MODE_VALUE, + // On getting, returns the value if present or the empty string. + // On setting, sets the value. + VALUE_MODE_DEFAULT, + // On getting, returns the value if present or "on". + // On setting, sets the value. + VALUE_MODE_DEFAULT_ON, + // On getting, returns "C:\fakepath\" followed by the file name of the + // first file of the selected files if any. + // On setting the empty string, empties the selected files list, otherwise + // throw the INVALID_STATE_ERR exception. + VALUE_MODE_FILENAME + }; + + /** + * This helper method returns true if aValue is a valid email address. + * This is following the HTML5 specification: + * http://dev.w3.org/html5/spec/forms.html#valid-e-mail-address + * + * @param aValue the email address to check. + * @result whether the given string is a valid email address. + */ + static PRBool IsValidEmailAddress(const nsAString& aValue); + + /** + * This helper method returns true if aValue is a valid email address list. + * Email address list is a list of email address separated by comas (,) which + * can be surrounded by space charecters. + * This is following the HTML5 specification: + * http://dev.w3.org/html5/spec/forms.html#valid-e-mail-address-list + * + * @param aValue the email address list to check. + * @result whether the given string is a valid email address list. + */ + static PRBool IsValidEmailAddressList(const nsAString& aValue); + + /** + * This helper method returns true if the aPattern pattern matches aValue. + * aPattern should not contain leading and trailing slashes (/). + * The pattern has to match the entire value not just a subset. + * aDocument must be a valid pointer (not null). + * + * This is following the HTML5 specification: + * http://dev.w3.org/html5/spec/forms.html#attr-input-pattern + * + * @param aValue the string to check. + * @param aPattern the string defining the pattern. + * @param aDocument the owner document of the element. + * @result whether the given string is matches the pattern. + */ + static PRBool IsPatternMatching(nsAString& aValue, nsAString& aPattern, + nsIDocument* aDocument); + + // Helper method + nsresult SetValueInternal(const nsAString& aValue, + PRBool aUserInput, + PRBool aSetValueChanged); + + void ClearFiles() { + nsCOMArray files; + SetFiles(files); + } + + void SetSingleFile(nsIDOMFile* aFile) { + nsCOMArray files; + nsCOMPtr file = aFile; + files.AppendObject(file); + SetFiles(files); + } + + nsresult SetIndeterminateInternal(PRBool aValue, + PRBool aShouldInvalidate); + + nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd); + + /** + * Get the name if it exists and return whether it did exist + * @param aName the name returned [OUT] + * @param true if the name is empty, false otherwise + */ + PRBool GetNameIfExists(nsAString& aName) { + GetAttr(kNameSpaceID_None, nsGkAtoms::name, aName); + return !aName.IsEmpty(); + } + + /** + * Called when an attribute is about to be changed + */ + virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAString* aValue, PRBool aNotify); + /** + * Called when an attribute has just been changed + */ + virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAString* aValue, PRBool aNotify); + + /** + * Dispatch a select event. Returns true if the event was not cancelled. + */ + PRBool DispatchSelectEvent(nsPresContext* aPresContext); + + void SelectAll(nsPresContext* aPresContext); + PRBool IsImage() const + { + return AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::image, eIgnoreCase); + } + + virtual PRBool AcceptAutofocus() const + { + return PR_TRUE; + } + + /** + * Fire the onChange event + */ + void FireOnChange(); + + /** + * Visit a the group of radio buttons this radio belongs to + * @param aVisitor the visitor to visit with + */ + nsresult VisitGroup(nsIRadioVisitor* aVisitor, PRBool aFlushContent); + + /** + * Do all the work that |SetChecked| does (radio button handling, etc.), but + * take an |aNotify| parameter. + */ + nsresult DoSetChecked(PRBool aValue, PRBool aNotify, PRBool aSetValueChanged); + + /** + * Do all the work that |SetCheckedChanged| does (radio button handling, + * etc.), but take an |aNotify| parameter that lets it avoid flushing content + * when it can. + */ + void DoSetCheckedChanged(PRBool aCheckedChanged, PRBool aNotify); + + /** + * Actually set checked and notify the frame of the change. + * @param aValue the value of checked to set + */ + void SetCheckedInternal(PRBool aValue, PRBool aNotify); + + /** + * Syntax sugar to make it easier to check for checked + */ + PRBool GetChecked() const + { + return GET_BOOLBIT(mBitField, BF_CHECKED); + } + + nsresult RadioSetChecked(PRBool aNotify); + void SetCheckedChanged(PRBool aCheckedChanged); + + /** + * MaybeSubmitForm looks for a submit input or a single text control + * and submits the form if either is present. + */ + nsresult MaybeSubmitForm(nsPresContext* aPresContext); + + /** + * Update mFileList with the currently selected file. + */ + nsresult UpdateFileList(); + + /** + * Determine whether the editor needs to be initialized explicitly for + * a particular event. + */ + PRBool NeedToInitializeEditorForEvent(nsEventChainPreVisitor& aVisitor) const; + + /** + * Get the value mode of the element, depending of the type. + */ + ValueModeType GetValueMode() const; + + /** + * Get the mutable state of the element. + * When the element isn't mutable (immutable), the value or checkedness + * should not be changed by the user. + * + * See: http://dev.w3.org/html5/spec/forms.html#concept-input-mutable + */ + PRBool IsMutable() const; + + /** + * Returns if the readonly attribute applies for the current type. + */ + PRBool DoesReadOnlyApply() const; + + /** + * Returns if the required attribute applies for the current type. + */ + PRBool DoesRequiredApply() const; + + /** + * Returns if the pattern attribute applies for the current type. + */ + PRBool DoesPatternApply() const; + + void FreeData(); + nsTextEditorState *GetEditorState() const; + + /** + * Manages the internal data storage across type changes. + */ + void HandleTypeChange(PRUint8 aNewType); + + /** + * Sanitize the value of the element depending of its current type. + * See: http://www.whatwg.org/specs/web-apps/current-work/#value-sanitization-algorithm + */ + void SanitizeValue(nsAString& aValue); + + /** + * Returns whether the placeholder attribute applies for the current type. + */ + bool PlaceholderApplies() const { return IsSingleLineTextControlInternal(PR_FALSE, mType); } + + /** + * Set the current default value to the value of the input element. + */ + nsresult SetDefaultValueAsValue(); + + nsCOMPtr mControllers; + + /** + * The type of this input () as an integer. + * @see nsIFormControl.h (specifically NS_FORM_INPUT_*) + */ + PRUint8 mType; + /** + * A bitfield containing our booleans + * @see GET_BOOLBIT / SET_BOOLBIT macros and BF_* field identifiers + */ + PRInt16 mBitField; + /* + * In mInputData, the mState field is used if IsSingleLineTextControl returns + * true and mValue is used otherwise. We have to be careful when handling it + * on a type change. + * + * Accessing the mState member should be done using the GetEditorState function, + * which returns null if the state is not present. + */ + union InputData { + /** + * The current value of the input if it has been changed from the default + */ + char* mValue; + /** + * The state of the text editor associated with the text/password input + */ + nsTextEditorState* mState; + } mInputData; + /** + * The value of the input if it is a file input. This is the list of filenames + * 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 list of filenames is always owned by this member, never by + * the frame. Whenever the frame wants to change the filename it has to call + * SetFileNames to update this member. + */ + nsCOMArray mFiles; + + nsRefPtr mFileList; + + nsString mStaticDocFileList; +}; + +#endif diff --git a/docshell/test/chrome/bug294258_window.xul b/docshell/test/chrome/bug294258_window.xul index 8ceab4d0be57..f1f2cb343b8e 100644 --- a/docshell/test/chrome/bug294258_window.xul +++ b/docshell/test/chrome/bug294258_window.xul @@ -43,7 +43,13 @@ // Change the data for each of the form fields, and reload. $("text").value = "text value"; $("checkbox").checked = true; - $("file").value = "file value"; + var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsILocalFile); + file.append("294258_test.file"); + file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); + filePath = file.path; + $("file").value = filePath; $("textarea").value = "textarea value"; $("radio1").checked = true; $("select").selectedIndex = 2; @@ -56,7 +62,7 @@ // Verify that none of the form data has changed. is($("text").value, "text value", "Text value changed"); is($("checkbox").checked, true, "Checkbox value changed"); - is($("file").value, "file value", "File value changed"); + is($("file").value, filePath, "File value changed"); is($("textarea").value, "textarea value", "Textarea value changed"); is($("radio1").checked, true, "Radio value changed"); is($("select").selectedIndex, 2, "Select value changed"); diff --git a/layout/base/tests/chrome/printpreview_helper.xul b/layout/base/tests/chrome/printpreview_helper.xul index 41c5df677915..fe5332ea727c 100644 --- a/layout/base/tests/chrome/printpreview_helper.xul +++ b/layout/base/tests/chrome/printpreview_helper.xul @@ -18,6 +18,11 @@ var ctx1; var ctx2; var counter = 0; +var file = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("TmpD", Components.interfaces.nsILocalFile); +filePath = file.path; + function printpreview() { gWbp = window.frames[1].QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebBrowserPrint); @@ -155,7 +160,7 @@ var emptyFormElements = var formElements = ["", "", - "", + "", "", "", "", diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index 290d63807bc2..2e08cf8f9041 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -65,7 +65,7 @@ #include "nsINodeInfo.h" #include "nsIDOMEventTarget.h" #include "nsILocalFile.h" -#include "nsIFileControlElement.h" +#include "nsHTMLInputElement.h" #include "nsNodeInfoManager.h" #include "nsContentCreatorFunctions.h" #include "nsContentUtils.h" @@ -90,6 +90,7 @@ #include "nsHTMLInputElement.h" #include "nsICapturePicker.h" #include "nsIFileURL.h" +#include "nsDOMFile.h" #define SYNC_TEXT 0x1 #define SYNC_BUTTON 0x2 @@ -235,20 +236,21 @@ nsFileControlFrame::CreateAnonymousContent(nsTArray& aElements) mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type, NS_LITERAL_STRING("text"), PR_FALSE); - nsCOMPtr textControl = do_QueryInterface(mTextContent); - if (textControl) { - 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; - fileControl->GetDisplayFileName(value); - textControl->SetValue(value); - } + nsHTMLInputElement* inputElement = + nsHTMLInputElement::FromContent(mContent); + NS_ASSERTION(inputElement, "Why is our content not a ?"); - textControl->SetTabIndex(-1); - textControl->SetReadOnly(PR_TRUE); - } + // Initialize value when we create the content in case the value was set + // before we got here + nsAutoString value; + inputElement->GetDisplayFileName(value); + + nsCOMPtr textControl = do_QueryInterface(mTextContent); + NS_ASSERTION(textControl, "Why is the we created not a ?"); + textControl->SetValue(value); + + textControl->SetTabIndex(-1); + textControl->SetReadOnly(PR_TRUE); if (!aElements.AppendElement(mTextContent)) return NS_ERROR_OUT_OF_MEMORY; @@ -398,9 +400,11 @@ nsFileControlFrame::CaptureMouseListener::MouseClick(nsIDOMEvent* aMouseEvent) // Get parent nsIDOMWindowInternal object. nsIContent* content = mFrame->GetContent(); - nsCOMPtr inputElem = do_QueryInterface(content); - nsCOMPtr fileControl = do_QueryInterface(content); - if (!content || !inputElem || !fileControl) + if (!content) + return NS_ERROR_FAILURE; + + nsHTMLInputElement* inputElement = nsHTMLInputElement::FromContent(content); + if (!inputElement) return NS_ERROR_FAILURE; nsCOMPtr doc = content->GetDocument(); @@ -443,21 +447,13 @@ nsFileControlFrame::CaptureMouseListener::MouseClick(nsIDOMEvent* aMouseEvent) return NS_OK; } - nsCOMPtr uri; - rv = capturePicker->GetUri(getter_AddRefs(uri)); + nsCOMPtr domFile; + rv = capturePicker->GetFile(getter_AddRefs(domFile)); NS_ENSURE_SUCCESS(rv, rv); - nsTArray newFileNames; - if (uri) { - nsCOMPtr fileURL = do_QueryInterface(uri); - if (!fileURL) - return NS_ERROR_UNEXPECTED; - - nsCAutoString spec; - rv = uri->GetSpec(spec); - NS_ENSURE_SUCCESS(rv, rv); - - newFileNames.AppendElement(NS_ConvertUTF8toUTF16(spec)); + nsCOMArray newFiles; + if (domFile) { + newFiles.AppendObject(domFile); } else { return NS_ERROR_FAILURE; } @@ -465,13 +461,13 @@ nsFileControlFrame::CaptureMouseListener::MouseClick(nsIDOMEvent* aMouseEvent) // XXXkhuey we really should have a better UI story than the tired old // uneditable text box with the file name inside. // Set new selected files - if (!newFileNames.IsEmpty()) { + if (newFiles.Count()) { // Tell mTextFrame that this update of the value is a user initiated // change. Otherwise it'll think that the value is being set by a script // and not fire onchange when it should. PRBool oldState = mFrame->mTextFrame->GetFireChangeEventState(); mFrame->mTextFrame->SetFireChangeEventState(PR_TRUE); - fileControl->SetFileNames(newFileNames); + inputElement->SetFiles(newFiles); mFrame->mTextFrame->SetFireChangeEventState(oldState); // May need to fire an onchange here @@ -491,12 +487,9 @@ nsFileControlFrame::BrowseMouseListener::MouseClick(nsIDOMEvent* aMouseEvent) if (!ShouldProcessMouseClick(aMouseEvent)) return NS_OK; - nsIContent* content = mFrame->GetContent(); - if (content->IsHTML() && content->Tag() == nsGkAtoms::input) { - nsHTMLInputElement* input = static_cast(content); - return input->FireAsyncClickHandler(); - } - return NS_OK; + nsHTMLInputElement* input = + nsHTMLInputElement::FromContent(mFrame->GetContent()); + return input ? input->FireAsyncClickHandler() : NS_OK; } nscoord @@ -643,10 +636,11 @@ nsFileControlFrame::GetFormProperty(nsIAtom* aName, nsAString& aValue) const aValue.Truncate(); // initialize out param if (nsGkAtoms::value == aName) { - nsCOMPtr fileControl = - do_QueryInterface(mContent); - if (fileControl) { - fileControl->GetDisplayFileName(aValue); + nsHTMLInputElement* inputElement = + nsHTMLInputElement::FromContent(mContent); + + if (inputElement) { + inputElement->GetDisplayFileName(aValue); } } return NS_OK; diff --git a/layout/forms/nsICapturePicker.idl b/layout/forms/nsICapturePicker.idl index 148e22258a35..3d552cd88860 100644 --- a/layout/forms/nsICapturePicker.idl +++ b/layout/forms/nsICapturePicker.idl @@ -39,7 +39,7 @@ #include "nsISupports.idl" interface nsIDOMWindow; -interface nsIURI; +interface nsIDOMFile; [scriptable, uuid(a4e2b2de-5712-4f80-aabb-7de3a747f227)] interface nsICapturePicker : nsISupports @@ -88,7 +88,7 @@ interface nsICapturePicker : nsISupports * Get the captured image/video/audio. This may be a data URI, file URI, * or a moz-filedata reference URI. */ - readonly attribute nsIURI uri; + readonly attribute nsIDOMFile file; // The MIME type of the captured content. Cannot be set after calling show() attribute AString type;