Bug 538813. Make about:cache and about:cache-entry pretty. r=bzbarsky
authorSteffen Wilberg <steffen.wilberg@web.de>
Fri, 02 Jul 2010 16:56:09 -0400
changeset 47157 c626a2ff4d1b0b570142a6ffdbbee1bcb8e1030c
parent 47156 22e19fe61752600d4ff4b29749852f47abe96f20
child 47158 29884ff43099a0ce0d60f507f2e1307bb9ca4443
push id14254
push userbzbarsky@mozilla.com
push dateFri, 02 Jul 2010 20:56:34 +0000
treeherdermozilla-central@29884ff43099 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs538813
milestone2.0b2pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 538813. Make about:cache and about:cache-entry pretty. r=bzbarsky
netwerk/cache/nsDiskCacheDevice.cpp
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/protocol/about/nsAboutCache.cpp
netwerk/protocol/about/nsAboutCacheEntry.cpp
toolkit/themes/pinstripe/global/jar.mn
toolkit/themes/winstripe/global/aboutCache.css
toolkit/themes/winstripe/global/aboutCacheEntry.css
toolkit/themes/winstripe/global/jar.mn
--- a/netwerk/cache/nsDiskCacheDevice.cpp
+++ b/netwerk/cache/nsDiskCacheDevice.cpp
@@ -185,28 +185,31 @@ NS_IMETHODIMP nsDiskCacheDeviceInfo::Get
 }
 
 /* readonly attribute string usageReport; */
 NS_IMETHODIMP nsDiskCacheDeviceInfo::GetUsageReport(char ** usageReport)
 {
     NS_ENSURE_ARG_POINTER(usageReport);
     nsCString buffer;
     
-    buffer.AssignLiteral("\n<tr>\n<td><b>Cache Directory:</b></td>\n<td><tt> ");
+    buffer.AssignLiteral("  <tr>\n"
+                         "    <th>Cache Directory:</th>\n"
+                         "    <td>");
     nsCOMPtr<nsILocalFile> cacheDir;
     nsAutoString           path;
     mDevice->getCacheDirectory(getter_AddRefs(cacheDir)); 
     nsresult rv = cacheDir->GetPath(path);
     if (NS_SUCCEEDED(rv)) {
         AppendUTF16toUTF8(path, buffer);
     } else {
         buffer.AppendLiteral("directory unavailable");
     }
-    buffer.AppendLiteral("</tt></td>\n</tr>\n");
-    // buffer.Append("<tr><td><b>Files:</b></td><td><tt> XXX</tt></td></tr>");
+    buffer.AppendLiteral("</td>\n"
+                         "  </tr>\n");
+
     *usageReport = ToNewCString(buffer);
     if (!*usageReport) return NS_ERROR_OUT_OF_MEMORY;
 
     return NS_OK;
 }
 
 /* readonly attribute unsigned long entryCount; */
 NS_IMETHODIMP nsDiskCacheDeviceInfo::GetEntryCount(PRUint32 *aEntryCount)
--- a/netwerk/cache/nsDiskCacheDeviceSQL.cpp
+++ b/netwerk/cache/nsDiskCacheDeviceSQL.cpp
@@ -273,29 +273,32 @@ nsOfflineCacheDeviceInfo::GetDescription
   *aDescription = NS_strdup("Offline cache device");
   return *aDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 NS_IMETHODIMP
 nsOfflineCacheDeviceInfo::GetUsageReport(char ** usageReport)
 {
   nsCAutoString buffer;
-  buffer.AppendLiteral("\n<tr>\n<td><b>Cache Directory:</b></td>\n<td><tt> ");
-  
+  buffer.AssignLiteral("  <tr>\n"
+                       "    <th>Cache Directory:</th>\n"
+                       "    <td>");
   nsILocalFile *cacheDir = mDevice->CacheDirectory();
   if (!cacheDir)
     return NS_OK;
 
   nsAutoString path;
   nsresult rv = cacheDir->GetPath(path);
   if (NS_SUCCEEDED(rv))
     AppendUTF16toUTF8(path, buffer);
   else
     buffer.AppendLiteral("directory unavailable");
-  buffer.AppendLiteral("</tt></td>\n</tr>\n");
+  
+  buffer.AppendLiteral("</td>\n"
+                       "  </tr>\n");
 
   *usageReport = ToNewCString(buffer);
   if (!*usageReport)
     return NS_ERROR_OUT_OF_MEMORY;
 
   return NS_OK;
 }
 
--- a/netwerk/cache/nsMemoryCacheDevice.cpp
+++ b/netwerk/cache/nsMemoryCacheDevice.cpp
@@ -532,20 +532,23 @@ nsMemoryCacheDeviceInfo::GetDescription(
 
 
 NS_IMETHODIMP
 nsMemoryCacheDeviceInfo::GetUsageReport(char ** result)
 {
     NS_ENSURE_ARG_POINTER(result);
     nsCString  buffer;
 
-    buffer.AssignLiteral("\n<tr>\n<td><b>Inactive storage:</b></td>\n<td><tt> ");
+    buffer.AssignLiteral("  <tr>\n"
+                         "    <th>Inactive storage:</th>\n"
+                         "    <td>");
     buffer.AppendInt(mDevice->mInactiveSize / 1024);
-    buffer.AppendLiteral(" KiB</tt></td>\n</tr>\n");
-    
+    buffer.AppendLiteral(" KiB</td>\n"
+                         "  </tr>\n");
+
     *result = ToNewCString(buffer);
     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsMemoryCacheDeviceInfo::GetEntryCount(PRUint32 * result)
--- a/netwerk/protocol/about/nsAboutCache.cpp
+++ b/netwerk/protocol/about/nsAboutCache.cpp
@@ -15,19 +15,20 @@
  * The Original Code is mozilla.org 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):
- *   Alexey Chernyak <alexeyc@bigfoot.com> (XHTML 1.1 conversion)
  *   Henrik Gemal <mozilla@gemal.dk>
  *   Darin Fisher <darin@netscape.com>
+ *   Alexey Chernyak <alexeyc@bigfoot.com> (XHTML 1.1 conversion)
+ *   Steffen Wilberg <steffen.wilberg@web.de> (new layout)
  *
  * 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
@@ -91,44 +92,56 @@ nsAboutCache::NewChannel(nsIURI *aURI, n
     // Init: (block size, maximum length)
     rv = NS_NewStorageStream(256, (PRUint32)-1, getter_AddRefs(storageStream));
     if (NS_FAILED(rv)) return rv;
 
     rv = storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
     if (NS_FAILED(rv)) return rv;
 
     mBuffer.AssignLiteral(
-                   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-                   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
-                   "    \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
-                   "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
-                   "<head>\n<title>Information about the Cache Service</title>\n</head>\n"
-                   "<body>\n<div>\n");
+      "<!DOCTYPE html>\n"
+      "<html>\n"
+      "<head>\n"
+      "  <title>Information about the Cache Service</title>\n"
+      "  <link rel=\"stylesheet\" "
+      "href=\"chrome://global/skin/about.css\" type=\"text/css\"/>\n"
+      "  <link rel=\"stylesheet\" "
+      "href=\"chrome://global/skin/aboutCache.css\" type=\"text/css\"/>\n"
+      "</head>\n"
+      "<body class=\"aboutPageWideContainer\">\n"
+      "<h1>Information about the Cache Service</h1>\n");
 
     outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten);
 
     rv = ParseURI(aURI, mDeviceID);
     if (NS_FAILED(rv)) return rv;
 
     mStream = outputStream;
+
+    // nsCacheService::VisitEntries calls nsMemoryCacheDevice::Visit,
+    // nsDiskCacheDevice::Visit and nsOfflineCacheDevice::Visit,
+    // each of which call
+    //   1. VisitDevice (for about:cache),
+    //   2. VisitEntry in a loop (for about:cache?device=disk etc.)
     rv = cacheService->VisitEntries(this);
     mBuffer.Truncate();
     if (rv == NS_ERROR_NOT_AVAILABLE) {
         mBuffer.AppendLiteral("<h2>The cache is disabled.</h2>\n");
     }
     else if (NS_FAILED(rv)) {
         return rv;
     }
 
     if (!mDeviceID.IsEmpty()) {
-        mBuffer.AppendLiteral("</pre>\n");
+        mBuffer.AppendLiteral("</table>\n");
     }
-    mBuffer.AppendLiteral("</div>\n</body>\n</html>\n");
+    mBuffer.AppendLiteral("</body>\n"
+                          "</html>\n");
     outputStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten);
-        
+
     nsCOMPtr<nsIInputStream> inStr;
 
     rv = storageStream->NewInputStream(0, getter_AddRefs(inStr));
     if (NS_FAILED(rv)) return rv;
 
     nsIChannel* channel;
     rv = NS_NewInputStreamChannel(&channel, aURI, inStr,
                                   NS_LITERAL_CSTRING("text/html"),
@@ -146,70 +159,105 @@ nsAboutCache::GetURIFlags(nsIURI *aURI, 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAboutCache::VisitDevice(const char *deviceID,
                           nsICacheDeviceInfo *deviceInfo,
                           PRBool *visitEntries)
 {
-    PRUint32 bytesWritten, value;
+    PRUint32 bytesWritten, value, entryCount;
     nsXPIDLCString str;
 
     *visitEntries = PR_FALSE;
 
     if (mDeviceID.IsEmpty() || mDeviceID.Equals(deviceID)) {
 
         // We need mStream for this
         if (!mStream)
           return NS_ERROR_FAILURE;
 	
         // Write out the Cache Name
         deviceInfo->GetDescription(getter_Copies(str));
 
         mBuffer.AssignLiteral("<h2>");
         mBuffer.Append(str);
-        mBuffer.AppendLiteral("</h2>\n<br />\n"
-                              "<table>\n");
+        mBuffer.AppendLiteral("</h2>\n"
+                              "<table id=\"");
+        mBuffer.Append(deviceID);
+        mBuffer.AppendLiteral("\">\n");
 
         // Write out cache info
+        // Number of entries
+        mBuffer.AppendLiteral("  <tr>\n"
+                              "    <th>Number of entries:</th>\n"
+                              "    <td>");
+        entryCount = 0;
+        deviceInfo->GetEntryCount(&entryCount);
+        mBuffer.AppendInt(entryCount);
+        mBuffer.AppendLiteral("</td>\n"
+                              "  </tr>\n");
 
-        mBuffer.AppendLiteral("\n<tr>\n<td><b>Number of entries:</b></td>\n");
-        value = 0;
-        deviceInfo->GetEntryCount(&value);
-        mBuffer.AppendLiteral("<td><tt>");
-        mBuffer.AppendInt(value);
-        mBuffer.AppendLiteral("</tt></td>\n</tr>\n"
-                              "\n<tr>\n<td><b>Maximum storage size:</b></td>\n");
+        // Maximum storage size
+        mBuffer.AppendLiteral("  <tr>\n"
+                              "    <th>Maximum storage size:</th>\n"
+                              "    <td>");
         value = 0;
         deviceInfo->GetMaximumSize(&value);
-        mBuffer.AppendLiteral("<td><tt>");
         mBuffer.AppendInt(value/1024);
-        mBuffer.AppendLiteral(" KiB</tt></td>\n</tr>\n"
-                              "\n<tr>\n<td><b>Storage in use:</b></td>\n"
-                              "<td><tt>");
+        mBuffer.AppendLiteral(" KiB</td>\n"
+                              "  </tr>\n");
+
+        // Storage in use
+        mBuffer.AppendLiteral("  <tr>\n"
+                              "    <th>Storage in use:</th>\n"
+                              "    <td>");
         value = 0;
         deviceInfo->GetTotalSize(&value);
         mBuffer.AppendInt(value/1024);
-        mBuffer.AppendLiteral(" KiB</tt></td>\n</tr>\n");
+        mBuffer.AppendLiteral(" KiB</td>\n"
+                              "  </tr>\n");
 
         deviceInfo->GetUsageReport(getter_Copies(str));
         mBuffer.Append(str);
-        mBuffer.AppendLiteral("</table>\n\n<br />");
 
-        if (mDeviceID.IsEmpty()) {
-            mBuffer.AppendLiteral("\n<a href=\"about:cache?device=");
-            mBuffer.Append(deviceID);
-            mBuffer.AppendLiteral("\">List Cache Entries</a>\n"
-                                  "<hr />\n");
-        } else {
-            *visitEntries = PR_TRUE;
-            mBuffer.AppendLiteral("<hr />\n<pre>\n");
+        if (mDeviceID.IsEmpty()) { // The about:cache case
+            if (entryCount != 0) { // Add the "List Cache Entries" link
+                mBuffer.AppendLiteral("  <tr>\n"
+                                      "    <th><a href=\"about:cache?device=");
+                mBuffer.Append(deviceID);
+                mBuffer.AppendLiteral("\">List Cache Entries</a></th>\n"
+                                      "  </tr>\n");
+            }
+            mBuffer.AppendLiteral("</table>\n");
+        } else { // The about:cache?device=disk etc. case
+            mBuffer.AppendLiteral("</table>\n");
+            if (entryCount != 0) {
+                *visitEntries = PR_TRUE;
+                mBuffer.AppendLiteral("<hr/>\n"
+                                      "<table id=\"entries\">\n"
+                                      "  <colgroup>\n"
+                                      "   <col id=\"col-key\">\n"
+                                      "   <col id=\"col-dataSize\">\n"
+                                      "   <col id=\"col-fetchCount\">\n"
+                                      "   <col id=\"col-lastModified\">\n"
+                                      "   <col id=\"col-expires\">\n"
+                                      "  </colgroup>\n"
+                                      "  <thead>\n"
+                                      "    <tr>\n"
+                                      "      <th>Key</th>\n"
+                                      "      <th>Data size</th>\n"
+                                      "      <th>Fetch count</th>\n"
+                                      "      <th>Last modified</th>\n"
+                                      "      <th>Expires</th>\n"
+                                      "    </tr>\n"
+                                      "  </thead>\n");
+            }
         }
-        
+
         mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAboutCache::VisitEntry(const char *deviceID,
@@ -241,65 +289,67 @@ nsAboutCache::VisitEntry(const char *dev
     url += clientID;
     url.AppendLiteral("&amp;sb=");
     url += streamBased ? '1' : '0';
     url.AppendLiteral("&amp;key=");
     char* escapedKey = nsEscapeHTML(key.get());
     url += escapedKey; // key
 
     // Entry start...
+    mBuffer.AssignLiteral("  <tr>\n");
 
     // URI
-    mBuffer.AssignLiteral("<b>           Key:</b> <a href=\"");
+    mBuffer.AppendLiteral("    <td><a href=\"");
     mBuffer.Append(url);
     mBuffer.AppendLiteral("\">");
     mBuffer.Append(escapedKey);
     nsMemory::Free(escapedKey);
-    mBuffer.AppendLiteral("</a>");
+    mBuffer.AppendLiteral("</a></td>\n");
 
     // Content length
     PRUint32 length = 0;
     entryInfo->GetDataSize(&length);
-
-    mBuffer.AppendLiteral("\n<b>     Data size:</b> ");
+    mBuffer.AppendLiteral("    <td>");
     mBuffer.AppendInt(length);
-    mBuffer.AppendLiteral(" bytes");
+    mBuffer.AppendLiteral(" bytes</td>\n");
 
     // Number of accesses
     PRInt32 fetchCount = 0;
     entryInfo->GetFetchCount(&fetchCount);
-
-    mBuffer.AppendLiteral("\n<b>   Fetch count:</b> ");
+    mBuffer.AppendLiteral("    <td>");
     mBuffer.AppendInt(fetchCount);
+    mBuffer.AppendLiteral("</td>\n");
 
     // vars for reporting time
     char buf[255];
     PRUint32 t;
 
     // Last modified time
-    mBuffer.AppendLiteral("\n<b> Last modified:</b> ");
+    mBuffer.AppendLiteral("    <td>");
     entryInfo->GetLastModified(&t);
     if (t) {
         PrintTimeString(buf, sizeof(buf), t);
         mBuffer.Append(buf);
     } else
         mBuffer.AppendLiteral("No last modified time");
+    mBuffer.AppendLiteral("</td>\n");
 
     // Expires time
-    mBuffer.AppendLiteral("\n<b>       Expires:</b> ");
+    mBuffer.AppendLiteral("    <td>");
     entryInfo->GetExpirationTime(&t);
     if (t < 0xFFFFFFFF) {
         PrintTimeString(buf, sizeof(buf), t);
         mBuffer.Append(buf);
     } else {
         mBuffer.AppendLiteral("No expiration time");
     }
+    mBuffer.AppendLiteral("</td>\n");
 
     // Entry is done...
-    mBuffer.AppendLiteral("\n\n");
+    mBuffer.AppendLiteral("  </tr>\n");
 
     mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten);
 
     *visitNext = PR_TRUE;
     return NS_OK;
 }
 
 
--- a/netwerk/protocol/about/nsAboutCacheEntry.cpp
+++ b/netwerk/protocol/about/nsAboutCacheEntry.cpp
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Darin Fisher <darin@netscape.com> (original author)
  *   Alexey Chernyak <alexeyc@bigfoot.com> (XHTML 1.1 conversion)
+ *   Steffen Wilberg <steffen.wilberg@web.de> (new layout)
  *
  * 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
@@ -120,17 +121,17 @@ nsAboutCacheEntry::NewChannel(nsIURI *ur
     NS_ENSURE_ARG_POINTER(uri);
     nsresult rv;
 
     nsCOMPtr<nsIInputStream> stream;
     rv = GetContentStream(uri, getter_AddRefs(stream));
     if (NS_FAILED(rv)) return rv;
 
     return NS_NewInputStreamChannel(result, uri, stream,
-                                    NS_LITERAL_CSTRING("application/xhtml+xml"),
+                                    NS_LITERAL_CSTRING("text/html"),
                                     NS_LITERAL_CSTRING("utf-8"));
 }
 
 NS_IMETHODIMP
 nsAboutCacheEntry::GetURIFlags(nsIURI *aURI, PRUint32 *result)
 {
     *result = nsIAboutModule::HIDE_FROM_ABOUTABOUT;
     return NS_OK;
@@ -154,35 +155,38 @@ nsAboutCacheEntry::GetContentStream(nsIU
     // Init: (block size, maximum length)
     rv = NS_NewStorageStream(256, PRUint32(-1), getter_AddRefs(storageStream));
     if (NS_FAILED(rv)) return rv;
 
     rv = storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
     if (NS_FAILED(rv)) return rv;
 
     buffer.AssignLiteral(
-                  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
-                  "    \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
-                  "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
-                  "<head>\n<title>Cache entry information</title>\n"
-                  "<style type=\"text/css\">\npre {\n  margin: 0;\n}\n"
-                  "td:first-child {\n  text-align: right;\n  vertical-align: top;\n"
-                  "  line-height: 0.8em;\n}\n</style>\n</head>\n<body>\n");
+      "<!DOCTYPE html>\n"
+      "<html>\n"
+      "<head>\n"
+      "  <title>Cache entry information</title>\n"
+      "  <link rel=\"stylesheet\" "
+      "href=\"chrome://global/skin/about.css\" type=\"text/css\"/>\n"
+      "  <link rel=\"stylesheet\" "
+      "href=\"chrome://global/skin/aboutCacheEntry.css\" type=\"text/css\"/>\n"
+      "</head>\n"
+      "<body>\n"
+      "<h1>Cache entry information</h1>\n");
     outputStream->Write(buffer.get(), buffer.Length(), &n);
 
     if (descriptor)
         rv = WriteCacheEntryDescription(outputStream, descriptor);
     else
         rv = WriteCacheEntryUnavailable(outputStream);
     if (NS_FAILED(rv)) return rv;
 
     buffer.AssignLiteral("</body>\n</html>\n");
     outputStream->Write(buffer.get(), buffer.Length(), &n);
-        
+
     nsCOMPtr<nsIInputStream> inStr;
     PRUint32 size;
 
     rv = storageStream->GetLength(&size);
     if (NS_FAILED(rv)) return rv;
 
     return storageStream->NewInputStream(0, result);
 }
@@ -233,39 +237,44 @@ static void PrintTimeString(char *buf, P
     PRExplodedTime et;
     PRTime t_usec = SecondsToPRTime(t_sec);
     PR_ExplodeTime(t_usec, PR_LocalTimeParameters, &et);
     PR_FormatTime(buf, bufsize, "%Y-%m-%d %H:%M:%S", &et);
 }
 
 #define APPEND_ROW(label, value) \
     PR_BEGIN_MACRO \
-    buffer.AppendLiteral("<tr><td><tt><b>"); \
+    buffer.AppendLiteral("  <tr>\n" \
+                         "    <th>"); \
     buffer.AppendLiteral(label); \
-    buffer.AppendLiteral(":</b></tt></td>\n<td><pre>"); \
+    buffer.AppendLiteral(":</th>\n" \
+                         "    <td>"); \
     buffer.Append(value); \
-    buffer.AppendLiteral("</pre></td></tr>\n"); \
+    buffer.AppendLiteral("</td>\n" \
+                         "  </tr>\n"); \
     PR_END_MACRO
 
 nsresult
 nsAboutCacheEntry::WriteCacheEntryDescription(nsIOutputStream *outputStream,
                                               nsICacheEntryDescriptor *descriptor)
 {
     nsresult rv;
     nsCString buffer;
     PRUint32 n;
 
     nsCAutoString str;
 
     rv = descriptor->GetKey(str);
     if (NS_FAILED(rv)) return rv;
 
     buffer.SetCapacity(4096);
-    buffer.AssignLiteral("<table>"
-                         "<tr><td><tt><b>key:</b></tt></td><td>");
+    buffer.AssignLiteral("<table>\n"
+                         "  <tr>\n"
+                         "    <th>key:</th>\n"
+                         "    <td id=\"td-key\">");
 
     // Test if the key is actually a URI
     nsCOMPtr<nsIURI> uri;
     PRBool isJS = PR_FALSE;
     PRBool isData = PR_FALSE;
 
     rv = NS_NewURI(getter_AddRefs(uri), str);
     // javascript: and data: URLs should not be linkified
@@ -281,18 +290,18 @@ nsAboutCacheEntry::WriteCacheEntryDescri
         buffer.AppendLiteral("\">");
         buffer.Append(escapedStr);
         buffer.AppendLiteral("</a>");
         uri = 0;
     }
     else
         buffer.Append(escapedStr);
     nsMemory::Free(escapedStr);
-    buffer.AppendLiteral("</td></tr>\n");
-
+    buffer.AppendLiteral("</td>\n"
+                         "  </tr>\n");
 
     // temp vars for reporting
     char timeBuf[255];
     PRUint32 u = 0;
     PRInt32  i = 0;
     nsCAutoString s;
 
     // Fetch Count
@@ -357,55 +366,62 @@ nsAboutCacheEntry::WriteCacheEntryDescri
     if (securityInfo) {
         APPEND_ROW("Security", "This is a secure document.");
     } else {
         APPEND_ROW("Security",
                    "This document does not have any security info associated with it.");
     }
 
     buffer.AppendLiteral("</table>\n"
-                         "<hr />\n<table>");
+                         "<hr/>\n"
+                         "<table>\n");
     // Meta Data
     // let's just look for some well known (HTTP) meta data tags, for now.
 
     // Client ID
     nsXPIDLCString str2;
     descriptor->GetClientID(getter_Copies(str2));
     if (!str2.IsEmpty())  APPEND_ROW("Client", str2);
 
 
-    mBuffer = &buffer;  // make it available for VisitMetaDataElement()
+    mBuffer = &buffer;  // make it available for VisitMetaDataElement().
+    // nsCacheEntryDescriptor::VisitMetaData calls
+    // nsCacheEntry.h VisitMetaDataElements, which returns
+    // nsCacheMetaData::VisitElements, which calls
+    // nsAboutCacheEntry::VisitMetaDataElement (below) in a loop.
     descriptor->VisitMetaData(this);
     mBuffer = nsnull;
 
-    buffer.AppendLiteral("</table>\n"
-                         "<hr />\n<pre>");
+    buffer.AppendLiteral("</table>\n");
     outputStream->Write(buffer.get(), buffer.Length(), &n);
 
     buffer.Truncate();
 
     // Provide a hexdump of the data
-    nsCOMPtr<nsIInputStream> stream;
-    descriptor->OpenInputStream(0, getter_AddRefs(stream));
-    if (stream) {
-        PRUint32 hexDumpState = 0;
-        char chunk[4096];
-        while (dataSize) {
-            PRUint32 count = PR_MIN(dataSize, sizeof(chunk));
-            if (NS_FAILED(stream->Read(chunk, count, &n)) || n == 0)
-                break;
-            dataSize -= n;
-            HexDump(&hexDumpState, chunk, n, buffer);
+    if (dataSize) { // don't draw an <hr> if the Data Size is 0.
+        nsCOMPtr<nsIInputStream> stream;
+        descriptor->OpenInputStream(0, getter_AddRefs(stream));
+        if (stream) {
+            buffer.AssignLiteral("<hr/>\n"
+                                 "<pre>");
+            PRUint32 hexDumpState = 0;
+            char chunk[4096];
+            while (dataSize) {
+                PRUint32 count = PR_MIN(dataSize, sizeof(chunk));
+                if (NS_FAILED(stream->Read(chunk, count, &n)) || n == 0)
+                    break;
+                dataSize -= n;
+                HexDump(&hexDumpState, chunk, n, buffer);
+                outputStream->Write(buffer.get(), buffer.Length(), &n);
+                buffer.Truncate();
+            }
+            buffer.AssignLiteral("</pre>\n");
             outputStream->Write(buffer.get(), buffer.Length(), &n);
-            buffer.Truncate();
-        }
+      }
     }
-
-    buffer.AssignLiteral("</pre>");
-    outputStream->Write(buffer.get(), buffer.Length(), &n);
     return NS_OK;
 }
 
 nsresult
 nsAboutCacheEntry::WriteCacheEntryUnavailable(nsIOutputStream *outputStream)
 {
     PRUint32 n;
     NS_NAMED_LITERAL_CSTRING(buffer,
@@ -463,20 +479,22 @@ nsAboutCacheEntry::ParseURI(nsIURI *uri,
 // nsICacheMetaDataVisitor implementation
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsAboutCacheEntry::VisitMetaDataElement(const char * key,
                                         const char * value,
                                         PRBool *     keepGoing)
 {
-    mBuffer->AppendLiteral("<tr><td><tt><b>");
+    mBuffer->AppendLiteral("  <tr>\n"
+                           "    <th>");
     mBuffer->Append(key);
-    mBuffer->AppendLiteral(":</b></tt></td>\n<td><pre>");
+    mBuffer->AppendLiteral(":</th>\n"
+                           "    <td>");
     char* escapedValue = nsEscapeHTML(value);
     mBuffer->Append(escapedValue);
     nsMemory::Free(escapedValue);
-    mBuffer->AppendLiteral("</pre></td></tr>\n");
+    mBuffer->AppendLiteral("</td>\n"
+                           "  </tr>\n");
 
     *keepGoing = PR_TRUE;
     return NS_OK;
 }
-
--- a/toolkit/themes/pinstripe/global/jar.mn
+++ b/toolkit/themes/pinstripe/global/jar.mn
@@ -1,13 +1,15 @@
 toolkit.jar:
 % skin global classic/1.0 %skin/classic/global/
   skin/classic/global/10pct_transparent_grey.png
   skin/classic/global/50pct_transparent_grey.png
   skin/classic/global/about.css                                      (../../winstripe/global/about.css)
+  skin/classic/global/aboutCache.css                                 (../../winstripe/global/aboutCache.css)
+  skin/classic/global/aboutCacheEntry.css                            (../../winstripe/global/aboutCacheEntry.css)
   skin/classic/global/aboutMemory.css                                (../../winstripe/global/aboutMemory.css)
   skin/classic/global/aboutSupport.css                               (../../winstripe/global/aboutSupport.css)
   skin/classic/global/appPicker.css                                  (../../winstripe/global/appPicker.css)
   skin/classic/global/arrow.css
   skin/classic/global/autocomplete.css
   skin/classic/global/button.css
   skin/classic/global/checkbox.css
   skin/classic/global/colorpicker.css
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/winstripe/global/aboutCache.css
@@ -0,0 +1,92 @@
+/* ***** 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
+ * Steffen Wilberg <steffen.wilberg@web.de>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * 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 ***** */
+
+h2 {
+  margin-top: 2em;
+}
+
+table {
+  table-layout: fixed;
+  width: 100%;
+  margin-bottom: 1em;
+  padding: 0.5em 0;
+  -moz-border-radius: 10px;
+}
+
+#disk { background-color: lightblue; }
+#memory { background-color: lightgreen; }
+#offline { background-color: plum; }
+
+th {
+  width: 14em;
+  white-space: nowrap;
+  text-align: right;
+}
+
+td {
+  font-family: -moz-fixed;
+  word-wrap: break-word;
+}
+
+#col-key {
+  width: 60%;
+}
+#col-dataSize, #col-fetchCount,
+#col-lastModified, #col-expires {
+  width: 13%;
+}
+
+#entries > tbody > tr:nth-child(odd) {
+  background: #fcfcfc;
+}
+#entries > tbody > tr:nth-child(even) {
+  background: #f4f4f4;
+}
+
+#entries > tbody > tr > td {
+  padding: .5em 0;
+  text-align: center;
+}
+
+#entries > thead > tr > th {
+  text-align: center;
+  white-space: normal;
+}
+
+#entries > thead > tr > th:first-child,
+#entries > tbody > tr > td:first-child {
+  text-align: left;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/winstripe/global/aboutCacheEntry.css
@@ -0,0 +1,61 @@
+/* ***** 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
+ * Steffen Wilberg <steffen.wilberg@web.de>.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * 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 ***** */
+
+body {
+  display: table;
+}
+
+table {
+  table-layout: fixed;
+  width: 100%;
+}
+
+th {
+  width: 12em;
+  word-wrap: break-word;
+  vertical-align: top;
+  text-align: right;
+}
+
+td {
+  display: block;
+  font-family: -moz-fixed;
+  white-space: pre-wrap;
+}
+
+#td-key {
+  word-wrap: break-word;
+}
--- a/toolkit/themes/winstripe/global/jar.mn
+++ b/toolkit/themes/winstripe/global/jar.mn
@@ -1,14 +1,16 @@
 toolkit.jar:
 % skin global classic/1.0 %skin/classic/global/ os=WINNT osversion<6
 % skin global classic/1.0 %skin/classic/global/ os!=WINNT
 # NOTE: If you add a new file here, you'll need to add it to the aero
 # section at the bottom of this file
         skin/classic/global/about.css
+        skin/classic/global/aboutCache.css
+        skin/classic/global/aboutCacheEntry.css
         skin/classic/global/aboutMemory.css
         skin/classic/global/aboutSupport.css
         skin/classic/global/appPicker.css
         skin/classic/global/arrow.css
 *       skin/classic/global/autocomplete.css
         skin/classic/global/button.css
         skin/classic/global/checkbox.css
         skin/classic/global/colorpicker.css
@@ -165,16 +167,18 @@ toolkit.jar:
         skin/classic/global/tree/sort-dsc-classic.png            (tree/sort-dsc-classic.png)
         skin/classic/global/tree/twisty-clsd.png                 (tree/twisty-clsd.png)
         skin/classic/global/tree/twisty-open.png                 (tree/twisty-open.png)
 
 #ifdef XP_WIN
 toolkit.jar:
 % skin global classic/1.0 %skin/classic/aero/global/ os=WINNT osversion>=6
         skin/classic/aero/global/about.css
+        skin/classic/aero/global/aboutCache.css
+        skin/classic/aero/global/aboutCacheEntry.css
         skin/classic/aero/global/aboutMemory.css
         skin/classic/aero/global/aboutSupport.css
         skin/classic/aero/global/appPicker.css
         skin/classic/aero/global/arrow.css
 *       skin/classic/aero/global/autocomplete.css
         skin/classic/aero/global/button.css
         skin/classic/aero/global/checkbox.css
         skin/classic/aero/global/colorpicker.css