Bug 758273 - Device Storage - enumeration option to filter based on last modification date. r=smaug
authorDoug Turner <dougt@dougt.org>
Sun, 10 Jun 2012 22:50:44 -0700
changeset 96374 c21a2f60c06833d3684e138745a8089f94841d52
parent 96373 713d061c1270d4a6698278ed0692585372125347
child 96375 29d9f71b24acc147bd350d2fa6588656d5e0fff2
push id1316
push userakeybl@mozilla.com
push dateMon, 27 Aug 2012 22:37:00 +0000
treeherdermozilla-esr52@6fdf9985acfe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs758273
milestone16.0a1
Bug 758273 - Device Storage - enumeration option to filter based on last modification date. r=smaug
dom/devicestorage/nsDeviceStorage.cpp
dom/devicestorage/nsDeviceStorage.h
dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl
dom/tests/mochitest/devicestorage/Makefile.in
dom/tests/mochitest/devicestorage/devicestorage_common.js
dom/tests/mochitest/devicestorage/test_enumerate.html
dom/tests/mochitest/devicestorage/test_enumerateOptions.html
dom/tests/mochitest/devicestorage/test_lastModificationFilter.html
js/xpconnect/src/dictionary_helper_gen.conf
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -11,16 +11,17 @@
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsNetUtil.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsIPrincipal.h"
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
+#include "DictionaryHelpers.h"
 
 using namespace mozilla::dom;
 
 #include "nsDirectoryServiceDefs.h"
 
 class DeviceStorageFile : public nsISupports {
 public:
 
@@ -302,28 +303,30 @@ class nsDOMDeviceStorageCursor
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSICONTENTPERMISSIONREQUEST
   NS_DECL_NSIDOMDEVICESTORAGECURSOR
 
   nsDOMDeviceStorageCursor(nsIDOMWindow* aWindow,
                            nsIURI* aURI,
                            DeviceStorageFile* aFile,
-                           bool aEditable);
+                           bool aEditable,
+                           PRUint64 aSince);
 
 private:
   ~nsDOMDeviceStorageCursor();
 
 protected:
   nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
 
   bool mOkToCallContinue;
   nsRefPtr<DeviceStorageFile> mFile;
   nsCOMPtr<nsIURI> mURI;
   bool mEditable;
+  PRUint64 mSince;
 
   // to access mFiles
   friend class InitCursorEvent;
   friend class ContinueCursorEvent;
 };
 
 class DeviceStorageCursorRequest : public nsIContentPermissionRequest
 {
@@ -493,26 +496,40 @@ public:
     NS_DispatchToMainThread(event);
 
     return NS_OK;
   }
 
   void collectFiles(DeviceStorageFile* aFile)
   {
       // TODO - we may want to do this incrementally.
-    if (!aFile)
+    if (!aFile) {
       return;
+    }
 
     nsCOMPtr<nsISimpleEnumerator> e;
     aFile->mFile->GetDirectoryEntries(getter_AddRefs(e));
 
+    if (!e) {
+      return;
+    }
+
     nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
     nsCOMPtr<nsIFile> f;
 
     while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) {
+      nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
+
+      PRInt64 msecs;
+      f->GetLastModifiedTime(&msecs);
+
+      if (msecs < (PRInt64) cursor->mSince) {
+        continue;
+      }
+
       bool isDir;
       f->IsDirectory(&isDir);
 
       bool isFile;
       f->IsFile(&isFile);
 
       nsString fullpath;
       f->GetPath(fullpath);
@@ -529,17 +546,16 @@ public:
       nsDependentSubstring newPath = Substring(fullpath, len);
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
       dsf->setPath(newPath);
 
       if (isDir) {
         collectFiles(dsf);
       }
       else if (isFile) {
-        nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
         cursor->mFiles.AppendElement(dsf);
       }
     }
   }
 
 private:
   nsRefPtr<DeviceStorageFile> mFile;
   nsRefPtr<DOMRequest> mRequest;
@@ -556,22 +572,24 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
 NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageCursor, DOMRequest)
 NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageCursor, DOMRequest)
 
 nsDOMDeviceStorageCursor::nsDOMDeviceStorageCursor(nsIDOMWindow* aWindow,
                                                    nsIURI* aURI,
                                                    DeviceStorageFile* aFile,
-                                                   bool aEditable)
+                                                   bool aEditable,
+                                                   PRUint64 aSince)
   : DOMRequest(aWindow)
   , mOkToCallContinue(false)
   , mFile(aFile)
   , mURI(aURI)
   , mEditable(aEditable)
+  , mSince(aSince)
 {
 }
 
 nsDOMDeviceStorageCursor::~nsDOMDeviceStorageCursor()
 {
 }
 
 NS_IMETHODIMP
@@ -1238,44 +1256,94 @@ nsDOMDeviceStorage::Delete(const JS::Val
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_DELETE,
                                  win, mURI, dsf, request, true);
   }
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDeviceStorage::Enumerate(const nsAString & aPath,
-                              nsIDOMDeviceStorageCursor * *_retval NS_OUTPARAM)
+nsDOMDeviceStorage::Enumerate(const JS::Value & aName,
+                             const JS::Value & aOptions,
+                             JSContext* aCx,
+                             PRUint8 aArgc,
+                             nsIDOMDeviceStorageCursor** aRetval)
 {
-  return EnumerateInternal(aPath, _retval, false);
+  return EnumerateInternal(aName, aOptions, aCx, aArgc, false, aRetval);
 }
 
 NS_IMETHODIMP
-nsDOMDeviceStorage::EnumerateEditable(const nsAString & aPath,
-                                      nsIDOMDeviceStorageCursor * *_retval NS_OUTPARAM)
+nsDOMDeviceStorage::EnumerateEditable(const JS::Value & aName,
+                                     const JS::Value & aOptions,
+                                     JSContext* aCx,
+                                     PRUint8 aArgc,
+                                     nsIDOMDeviceStorageCursor** aRetval)
+{
+  return EnumerateInternal(aName, aOptions, aCx, aArgc, true, aRetval);
+}
+
+
+static PRTime
+ExtractDateFromOptions(JSContext* aCx, const JS::Value& aOptions)
 {
-  return EnumerateInternal(aPath, _retval, true);
+  PRTime result = 0;
+  DeviceStorageEnumerationParameters params;
+  if (!JSVAL_IS_VOID(aOptions) && !aOptions.isNull()) {
+    nsresult rv = params.Init(aCx, &aOptions);
+    if (NS_SUCCEEDED(rv) && !JSVAL_IS_VOID(params.since) && !params.since.isNull() && params.since.isObject()) {
+      JSObject* obj = JSVAL_TO_OBJECT(params.since);
+      if (JS_ObjectIsDate(aCx, obj) && js_DateIsValid(aCx, obj)) {
+        result = js_DateGetMsecSinceEpoch(aCx, obj);
+      }
+    }
+  }
+  return result;
 }
 
 nsresult
-nsDOMDeviceStorage::EnumerateInternal(const nsAString & aPath,
-                                      nsIDOMDeviceStorageCursor * *_retval NS_OUTPARAM,
-                                      bool aEditable)
+nsDOMDeviceStorage::EnumerateInternal(const JS::Value & aName,
+                                     const JS::Value & aOptions,
+                                     JSContext* aCx,
+                                     PRUint8 aArgc,
+                                     bool aEditable,
+                                     nsIDOMDeviceStorageCursor** aRetval)
 {
   nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mOwner);
   if (!win)
     return NS_ERROR_UNEXPECTED;
 
-  nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile, aPath);
+  PRTime since = 0;
+  nsString path;
+  path.SetIsVoid(true);
 
-  nsRefPtr<nsDOMDeviceStorageCursor> cursor = new nsDOMDeviceStorageCursor(win, mURI, dsf, aEditable);
-  NS_ADDREF(*_retval = cursor);
+  if (aArgc > 0) {
+    // inspect the first value to see if it is a string
+    if (JSVAL_IS_STRING(aName)) {
+      JSString* jsstr = JS_ValueToString(aCx, aName);
+      nsDependentJSString jspath;
+      jspath.init(aCx, jsstr);
+      path.Assign(jspath);
+    } else if (!JSVAL_IS_PRIMITIVE(aName)) {
+      // it also might be an options object
+      since = ExtractDateFromOptions(aCx, aName);
+    } else {
+      return NS_ERROR_FAILURE;
+    }
+      
+    if (aArgc == 2 && (JSVAL_IS_VOID(aOptions) || aOptions.isNull() || !aOptions.isObject())) {
+      return NS_ERROR_FAILURE;
+    }
+    since = ExtractDateFromOptions(aCx, aOptions);
+  }
+  
+  nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile, path);
+  nsRefPtr<nsDOMDeviceStorageCursor> cursor = new nsDOMDeviceStorageCursor(win, mURI, dsf, aEditable, since);
+  nsRefPtr<DeviceStorageCursorRequest> r = new DeviceStorageCursorRequest(cursor);
 
-  nsRefPtr<DeviceStorageCursorRequest> r = new DeviceStorageCursorRequest(cursor);
+  NS_ADDREF(*aRetval = cursor);
 
   if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
     r->Allow();
     return NS_OK;
   }
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   if (prompt) {
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -34,17 +34,18 @@ public:
 
   static void CreateDeviceStoragesFor(nsPIDOMWindow* aWin, const nsAString &aType, nsIVariant** _retval);
 
 private:
   ~nsDOMDeviceStorage();
 
 
   nsresult GetInternal(const JS::Value & aName, JSContext* aCx, nsIDOMDOMRequest * *_retval NS_OUTPARAM, bool aEditable);
-  nsresult EnumerateInternal(const nsAString & aName, nsIDOMDeviceStorageCursor * *_retval NS_OUTPARAM, bool aEditable);
+
+  nsresult EnumerateInternal(const JS::Value & aName, const JS::Value & aOptions, JSContext* aCx, PRUint8 aArgc, bool aEditable, nsIDOMDeviceStorageCursor** aRetval);
 
   PRInt32 mStorageType;
   nsCOMPtr<nsIFile> mFile;
 
   nsWeakPtr mOwner;
   nsCOMPtr<nsIURI> mURI;
 
   // nsIDOMDeviceStorage.type
--- a/dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl
+++ b/dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl
@@ -2,16 +2,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 interface nsIDOMBlob;
 interface nsIDOMDOMRequest;
 interface nsIDOMDeviceStorageCursor;
 
+dictionary DeviceStorageEnumerationParameters
+{
+  jsval since;
+};
+
 [scriptable, uuid(05C0D0C8-D698-4CCD-899C-7198A33BD7EC)]
 interface nsIDOMDeviceStorage : nsISupports
 {
     /*
      * Hint as to what kind of storage this object is.
      * May be "external", "shared", or "default".
      */
     readonly attribute DOMString type;
@@ -23,12 +28,14 @@ interface nsIDOMDeviceStorage : nsISuppo
     nsIDOMDOMRequest get(in jsval aName);
 
     [implicit_jscontext]
     nsIDOMDOMRequest getEditable(in jsval aName);
 
     [implicit_jscontext]
     nsIDOMDOMRequest delete(in jsval aName);
 
-    nsIDOMDeviceStorageCursor enumerate([optional] in DOMString directory);
+    [optional_argc, implicit_jscontext]
+    nsIDOMDeviceStorageCursor enumerate([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
 
-    nsIDOMDeviceStorageCursor enumerateEditable([optional] in DOMString directory);
+    [optional_argc, implicit_jscontext]
+    nsIDOMDeviceStorageCursor enumerateEditable([optional] in jsval aName, /* DeviceStorageEnumerationParameters */ [optional] in jsval options);
 };
--- a/dom/tests/mochitest/devicestorage/Makefile.in
+++ b/dom/tests/mochitest/devicestorage/Makefile.in
@@ -14,14 +14,16 @@ include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES	= \
 		test_sanity.html \
 		test_basic.html \
 		test_enumerate.html \
 		test_enumerateMultipleContinue.html \
 		test_overwrite.html \
 		test_dotdot.html \
+		test_enumerateOptions.html \
+		test_lastModificationFilter.html \
 		devicestorage_common.js \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
--- a/dom/tests/mochitest/devicestorage/devicestorage_common.js
+++ b/dom/tests/mochitest/devicestorage/devicestorage_common.js
@@ -1,15 +1,22 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var oldVal = false;
   
+// Array Remove - By John Resig (MIT Licensed)
+Array.prototype.remove = function(from, to) {
+  var rest = this.slice((to || from) + 1 || this.length);
+  this.length = from < 0 ? this.length + from : from;
+  return this.push.apply(this, rest);
+};
+
 function devicestorage_setup() {
   SimpleTest.waitForExplicitFinish();
   try {
     oldVal = SpecialPowers.getBoolPref("device.storage.enabled");
   } catch(e) {}
   SpecialPowers.setBoolPref("device.storage.enabled", true);
   SpecialPowers.setBoolPref("device.storage.testing", true);
   SpecialPowers.setBoolPref("device.storage.prompt.testing", true);
@@ -41,8 +48,12 @@ function randomFilename(l) {
     var result = "";
     for (var i=0; i<l; i++) {
 	var r = Math.floor(set.length * Math.random());
 	result += set.substring(r, r + 1);
     }
     return result;
 }
 
+function reportErrorAndQuit(e) {
+  ok(false, "handleError was called : " + e.target.error.name);
+  devicestorage_cleanup();
+}
--- a/dom/tests/mochitest/devicestorage/test_enumerate.html
+++ b/dom/tests/mochitest/devicestorage/test_enumerate.html
@@ -17,37 +17,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-// Array Remove - By John Resig (MIT Licensed)
-Array.prototype.remove = function(from, to) {
-  var rest = this.slice((to || from) + 1 || this.length);
-  this.length = from < 0 ? this.length + from : from;
-  return this.push.apply(this, rest);
-};
-
 devicestorage_setup();
 
 function enumerateSuccess(e) {
 
   if (e.target.result == null) {
     ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
     dump("We still have length = " + files.length);
     devicestorage_cleanup();
     return;
   }
   
-  dump("asdfasdf"+ e.target.result + "\n");
-  dump("asdfasdf"+ e.target.result.name + "\n");
-
   var filename = e.target.result.name;
 
   var index = files.indexOf(filename);
   files.remove(index);
 
   ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
 
   // clean up
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/devicestorage/test_enumerateOptions.html
@@ -0,0 +1,81 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717103
+-->
+<head>
+  <title>Test for basic sanity of the device storage API </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="devicestorage_common.js"></script>
+
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+devicestorage_setup()
+
+storage = navigator.getDeviceStorage("profile");
+
+
+throws = false;
+try {
+var cursor = storage[0].enumerate();
+} catch(e) {throws = true}
+ok(!throws, "enumerate no parameter");
+
+throws = false;
+try {
+var cursor = storage[0].enumerate("string");
+} catch(e) {throws = true}
+ok(!throws, "enumerate one string parameter");
+
+throws = false;
+try {
+var cursor = storage[0].enumerate("string", "string2");
+} catch(e) {throws = true}
+ok(throws, "enumerate two string parameter");
+
+throws = false;
+try {
+var cursor = storage[0].enumerate("string", {"since": 1});
+} catch(e) {throws = true}
+ok(!throws, "enumerate a string and object parameter");
+
+throws = false;
+try {
+var cursor = storage[0].enumerate({"path": "a"});
+} catch(e) {throws = true}
+ok(!throws, "enumerate object parameter with path");
+
+throws = false;
+try {
+var cursor = storage[0].enumerate({}, "string");
+} catch(e) {throws = true}
+ok(throws, "enumerate object then a string");
+
+throws = false;
+try {
+var cursor = storage[0].enumerate({"path": "a", "since": 0});
+} catch(e) {throws = true}
+ok(!throws, "enumerate object parameter with path");
+
+
+
+
+devicestorage_cleanup()
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/devicestorage/test_lastModificationFilter.html
@@ -0,0 +1,111 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html> <!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717103
+-->
+<head>
+  <title>Test for the device storage API </title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="devicestorage_common.js"></script>
+
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+
+function verifyAndDelete(prefix, files, e) {
+
+  if (e.target.result == null) {
+    ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
+    dump("We still have length = " + files.length + "\n");
+    dump(files + "\n");
+    devicestorage_cleanup();
+    return;
+  }
+
+  var filename = e.target.result.name;
+
+  var index = files.indexOf(filename);
+  ok(index > -1, "filename should be in the enumeration : " + e.target.result.name);
+  if (index == -1)
+    return;
+
+  files.remove(index);
+
+  // clean up
+  var storage = navigator.getDeviceStorage("profile");
+  var cleanup = storage[0].delete(prefix + "/" + filename);
+  cleanup.onsuccess = function(e) {}
+}
+
+function addFiles(prefix, files, date, callback) {
+
+  const Cc = SpecialPowers.wrap(Components).classes;
+  const Ci = Components.interfaces;
+
+  var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+
+  for (var i=0; i<files.length; i++) {
+    var f = directoryService.get("ProfD", Components.interfaces.nsIFile);
+    var path = prefix + '/' + files[i];
+    path.split("/").forEach(function(p) {
+      f.appendRelativePath(p);
+    });
+    f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+    f.lastModifiedTime = date;
+  }
+  callback();
+}
+
+
+devicestorage_setup();
+
+var prefix = "devicestorage/" + randomFilename(12)
+
+var oldFiles = ["a", "b", "c"];
+var newFiles = ["d", "e", "f"];
+
+// 157795200 is a long long time ago.
+addFiles(prefix, oldFiles, 157795200, addNewFiles);
+
+function enumerateNew() {
+
+  var storage = navigator.getDeviceStorage("profile");
+  ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
+
+// 836031600 is a long time ago
+  var cursor = storage[0].enumerate(prefix, {"since": new Date(836031600)});
+  cursor.onsuccess = function(e) {
+    verifyAndDelete(prefix, newFiles, e);
+    if (e.target.result) {
+      e.target.continue();
+    }
+  }
+
+  cursor.onerror = function (e) {
+    ok(false, "handleError was called : " + e.target.error.name);
+    devicestorage_cleanup();
+  }
+}
+
+function addNewFiles() {
+  addFiles(prefix, newFiles, Date.now(), enumerateNew);
+}
+
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -19,16 +19,17 @@ dictionaries = [
      [ 'MutationObserverInit', 'nsIDOMMutationObserver.idl' ],
      [ 'SettingsEventInit', 'nsIDOMSettingsManager.idl' ],
      [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
      [ 'DeviceProximityEventInit', 'nsIDOMDeviceProximityEvent.idl' ],
      [ 'UserProximityEventInit', 'nsIDOMUserProximityEvent.idl' ],
      [ 'DeviceLightEventInit', 'nsIDOMDeviceLightEvent.idl' ],
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
      [ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
+     [ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ]
    ]
 
 # include file names
 special_includes = [
     'nsContentUtils.h',
     'XPCQuickStubs.h'
   ]