2 * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
3 * Copyright (C) 2012 Samsung Electronics. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "AboutDataTizen.h"
23 #if ENABLE(TIZEN_WEBKIT2_ABOUT_MEMORY)
24 #include "AboutCredits.html.cpp"
25 #include "AboutTemplate.html.cpp"
27 #include "BlobRegistry.h"
28 #include "BlobRegistryImpl.h"
29 #include "JSDOMWindow.h"
30 #include "MemoryCache.h"
31 #include "MemoryStatistics.h"
32 #include "WebKitVersion.h"
33 #include "WebMemorySampler.h"
34 #include "ewk_context.h"
35 #include <WebCore/ApplicationCache.h>
36 #include <WebCore/ApplicationCacheResource.h>
37 #include <WebCore/ApplicationCacheStorage.h>
38 #include <WebCore/ApplicationCacheGroup.h>
39 #include <WebCore/PluginData.h>
40 #include <heap/Heap.h>
42 #include <runtime/JSGlobalData.h>
44 #include <sys/sysinfo.h>
45 #include <sys/utsname.h>
46 #include <wtf/text/CString.h>
47 #include <wtf/text/StringBuilder.h>
48 #if ENABLE(TIZEN_NATIVE_MEMORY_SNAPSHOT)
49 #include "InspectorMemoryAgent.h"
51 extern HashSet<Page*>* allPages;
54 using namespace WebCore;
57 const int kiloByte = 1024;
58 const int megaByte = 1024 * 1024;
59 const unsigned meminfoIndex = 10;
61 enum UNIT { BYTE, KILOBYTE, MEGABYTE, EA };
65 typedef HashMap<String, RefPtr<BlobStorageData> > BlobMap;
67 PrintFormat printFormat = PRINT_FORMAT_HTML;
69 static String header(const String& description)
71 if (printFormat == PRINT_FORMAT_SIMPLE)
72 return description + "\n";
73 else if (printFormat == PRINT_FORMAT_JSON)
76 return String("<div class='box'><div class='box-title'>")
77 + description + String("</div><table class='fixed-table'><col width=75%><col width=25%>");
80 static String footer()
82 if (printFormat == PRINT_FORMAT_SIMPLE)
84 else if (printFormat == PRINT_FORMAT_JSON)
87 return "</table></div><br>";
90 template<class T> static String numberToRow(const String& description, T number, UNIT type)
92 if (printFormat == PRINT_FORMAT_SIMPLE)
93 return description + ":" + String::number(number) + "\n";
94 else if (printFormat == PRINT_FORMAT_JSON)
95 return String("\"") + description + "\":" + String::number(number) + ",";
113 return String("<tr><td>") + description + "</td><td>" + String::number(number) + " " + unit + "</td></tr>";
116 String numberToRow(const String& description, bool truth)
118 if (printFormat == PRINT_FORMAT_SIMPLE)
119 return description + ":" + (truth?"true":"false") + "\n";
120 else if (printFormat == PRINT_FORMAT_JSON)
121 return String("\"") + description + "\":" + (truth?"true":"false") + ",";
123 return String("<tr><td>") + description + "</td><td>" + (truth?"true":"false") + "</td></tr>";
126 static String cacheTypeStatisticToRow(const String& description, const MemoryCache::TypeStatistic& statistic)
128 if (printFormat == PRINT_FORMAT_SIMPLE)
129 return description + ":"
130 + String::number(statistic.count) + " "
131 + String::number(statistic.size / kiloByte) + " "
132 + String::number(statistic.liveSize / kiloByte) + " "
133 + String::number(statistic.decodedSize / kiloByte) + "\n";
134 else if (printFormat == PRINT_FORMAT_JSON) //If dump format is 'JSON', only print the size of the cache
135 return String("\"") + description + "\":"
136 + String::number(statistic.size) + "," ;
138 return String("<tr><td>") + description + "</td>"
139 + "<td>" + String::number(statistic.count) + "</td>"
140 + "<td>" + String::number(statistic.size / kiloByte) + "</td>"
141 + "<td>" + String::number(statistic.liveSize / kiloByte) + "</td>"
142 + "<td>" + String::number(statistic.decodedSize / kiloByte) + "</td>"
146 static String appcacheStatisticToRow(const String& flag, const String& description, const int cacheSize)
148 return String("<tr><td>") + flag + "</td>"
149 + "<td style=\"word-break:break-all;\">" + description + "</td>"
150 + "<td>" + String::number(cacheSize) + "B</td>"
154 static String helpTextToRow(const String& feature, const String& description)
156 return String("<tr><td>") + feature + "</td>" + "<td style=\"word-break:break-all;\">" + description + "</td></tr>";
160 static String creditToRow(const String& credit)
162 return "<div class='box'><span class='box-title'>" + credit + "</span>"
163 "<span class='license'><a href=# onclick=\"license('" + credit + "');\">license</a> </span>"
164 "<table class='fixed-table'><col width=75%><col width=25%>"
165 "<tr><td><div id='" + credit + "_license' style='display:none;'>"
166 + getLicense(credit) + "</div></td></tr></table></div><br>";
169 static void dumpJSCTypeCountSetToTableHTML(StringBuilder& tableHTML, JSC::TypeCountSet* typeCountSet)
174 for (JSC::TypeCountSet::const_iterator iter = typeCountSet->begin(); iter != typeCountSet->end(); ++iter)
175 tableHTML.append(numberToRow(iter->first, iter->second, EA));
178 static void getLowMemoryNotifyInfo(size_t value[])
180 const char* TIZEN_MEMORY_INFO_PATH = "/sys/class/memnotify/meminfo";
182 bool foundKeyName = false;
183 FILE* fSystemMemoryInfo = fopen(TIZEN_MEMORY_INFO_PATH, "r");
185 if(fSystemMemoryInfo) {
186 while (!feof(fSystemMemoryInfo)) {
187 String strToken = getToken(fSystemMemoryInfo);
188 if (strToken.find(':') != notFound) {
189 String keyName = strToken.left(strToken.length() - 1);
191 } else if (foundKeyName) {
192 value[index++] = strToken.toInt();
193 if (index == meminfoIndex)
195 foundKeyName = false;
198 fclose(fSystemMemoryInfo);
202 String memoryPage(PrintFormat format)
204 printFormat = format;
206 if (printFormat == PRINT_FORMAT_HTML)
207 page.append(writeHeader("Memory"));
209 // generate system memory infomation
210 page.append(header("System Memory Usage"));
212 // TIZEN System Memory Info
213 size_t systemMemory[meminfoIndex];
214 getLowMemoryNotifyInfo(systemMemory);
216 page.append(numberToRow("Total RAM size", systemMemory[0] * megaByte, MEGABYTE));
217 page.append(numberToRow("Used (Mem+Reclaimable) RAM size", systemMemory[1] * megaByte, MEGABYTE));
218 page.append(numberToRow("Used (Mem+Swap) RAM size", systemMemory[2] * megaByte, MEGABYTE));
219 page.append(numberToRow("Used (Mem) RAM size", systemMemory[3] * megaByte, MEGABYTE));
220 page.append(numberToRow("Used (Swap) RAM size", systemMemory[4] * megaByte, MEGABYTE));
221 page.append(numberToRow("Free RAM size", systemMemory[6] * megaByte, MEGABYTE));
222 page.append(numberToRow("Free CMA size", systemMemory[7] * megaByte, MEGABYTE));
223 page.append(numberToRow("Available (Free+Reclaimable) RAM size", systemMemory[8] * megaByte, MEGABYTE));
224 page.append(numberToRow("Reserved Page RAM size", systemMemory[9] * megaByte, MEGABYTE));
226 page.append(footer());
228 // UI Process memps information
229 ApplicationMemoryStats applicationStats = sampleApplicationMalloc(getppid());
231 page.append(header("UI Process"));
233 page.append(numberToRow("UI Process Private CODE", applicationStats.privateCleanSize * kiloByte, KILOBYTE));
234 page.append(numberToRow("UI Process Private DATA", applicationStats.privateDirtySize * kiloByte, KILOBYTE));
235 page.append(numberToRow("UI Process PEAK", applicationStats.peak * kiloByte, KILOBYTE));
236 page.append(numberToRow("UI Process RSS", applicationStats.residentSetSize * kiloByte, KILOBYTE));
237 page.append(numberToRow("UI Process PSS", applicationStats.proportionalSetSize * kiloByte, KILOBYTE));
238 page.append(numberToRow("UI Process 3D memory", applicationStats.graphics3DSize * kiloByte, KILOBYTE));
239 page.append(numberToRow("UI Process UMP memory", applicationStats.UMPSize * kiloByte, KILOBYTE));
241 page.append(footer());
243 // Web Process memps information
244 applicationStats = sampleApplicationMalloc(getpid());
246 page.append(header("Web Process"));
248 page.append(numberToRow("Web Process Private CODE", applicationStats.privateCleanSize* kiloByte, KILOBYTE));
249 page.append(numberToRow("Web Process Private DATA", applicationStats.privateDirtySize* kiloByte, KILOBYTE));
250 page.append(numberToRow("Web Process PEAK", applicationStats.peak * kiloByte, KILOBYTE));
251 page.append(numberToRow("Web Process RSS", applicationStats.residentSetSize * kiloByte, KILOBYTE));
252 page.append(numberToRow("Web Process PSS", applicationStats.proportionalSetSize * kiloByte, KILOBYTE));
253 page.append(numberToRow("Web Process 3D memory", applicationStats.graphics3DSize * kiloByte, KILOBYTE));
254 page.append(numberToRow("Web Process UMP memory", applicationStats.UMPSize * kiloByte, KILOBYTE));
256 page.append(footer());
259 MemoryCache* cacheInc = memoryCache();
260 MemoryCache::Statistics cacheStat = cacheInc->getStatistics();
262 MemoryCache::TypeStatistic total;
263 total.count = cacheStat.images.count + cacheStat.cssStyleSheets.count
264 + cacheStat.scripts.count + cacheStat.xslStyleSheets.count + cacheStat.fonts.count;
265 total.size = cacheInc->liveSize() + cacheInc->deadSize();
266 total.liveSize = cacheInc->liveSize();
267 total.decodedSize = cacheStat.images.decodedSize
268 + cacheStat.cssStyleSheets.decodedSize + cacheStat.scripts.decodedSize
269 + cacheStat.xslStyleSheets.decodedSize + cacheStat.fonts.decodedSize;
271 // JS engine memory usage.
272 JSC::GlobalMemoryStatistics jscMemoryStat = JSC::globalMemoryStatistics();
273 JSC::Heap& mainHeap = JSDOMWindow::commonJSGlobalData()->heap;
274 OwnPtr<JSC::TypeCountSet> objectTypeCounts = mainHeap.objectTypeCounts();
275 OwnPtr<JSC::TypeCountSet> protectedObjectTypeCounts = mainHeap.protectedObjectTypeCounts();
278 struct mallinfo mallocInfo = mallinfo();
280 page.append(header("Web Process Memory Details"));
282 page.append(numberToRow("Cache used memory", total.size, KILOBYTE));
283 page.append(numberToRow("JSC used memory", jscMemoryStat.stackBytes + jscMemoryStat.JITBytes + mainHeap.capacity(), KILOBYTE));
284 page.append(numberToRow("Malloc used memory", mallocInfo.usmblks + mallocInfo.uordblks, KILOBYTE));
285 page.append(numberToRow("Total(cache+JSC+malloc) used memory", total.size + mallocInfo.usmblks + mallocInfo.uordblks + jscMemoryStat.stackBytes + jscMemoryStat.JITBytes + mainHeap.capacity(), KILOBYTE));
287 page.append(footer());
289 // generate cache information
290 if(printFormat == PRINT_FORMAT_HTML) {
291 page.append(String("<div class=\"box\"><div class=\"box-title\">Cache Information<br><div style='font-size:11px;color:#A8A8A8'>Size, Living, and Decoded are expressed in KB.</div><br></div><table class='fixed-table'><col width=75%><col width=25%>"));
292 page.append(String("<tr> <th align=left>Item</th> <th align=left>Count</th> <th align=left>Size</th> <th align=left>Living</th> <th align=left>Decoded</th></tr>"));
294 page.append(header("Cache Information"));
296 if (printFormat == PRINT_FORMAT_HTML) {
297 page.append(cacheTypeStatisticToRow("Total", total));
298 page.append(cacheTypeStatisticToRow("Images", cacheStat.images));
299 page.append(cacheTypeStatisticToRow("CSS Style Sheets", cacheStat.cssStyleSheets));
300 page.append(cacheTypeStatisticToRow("Scripts", cacheStat.scripts));
302 page.append(cacheTypeStatisticToRow("XSL Style Sheets", cacheStat.xslStyleSheets));
304 page.append(cacheTypeStatisticToRow("Fonts", cacheStat.fonts));
306 page.append(cacheTypeStatisticToRow("Images Cache", cacheStat.images));
307 page.append(cacheTypeStatisticToRow("CSS Style Sheets Cache", cacheStat.cssStyleSheets));
308 page.append(cacheTypeStatisticToRow("Scripts Cache", cacheStat.scripts));
309 page.append(cacheTypeStatisticToRow("Fonts Cache", cacheStat.fonts));
312 page.append(footer());
313 // [Native memory information]
314 #if ENABLE(TIZEN_NATIVE_MEMORY_SNAPSHOT) //Using InspectorMemoryAgent's new interface for about:memory
316 MemoryInformation info[10];
318 HashSet<Page*>::iterator end = allPages->end();
319 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
320 page.append(header((*it)->mainFrame()->loader()->documentLoader()->url().string()));
321 for (int i = 0; i < 10; ++i)
323 info_count = WebCore::InspectorMemoryAgent::getMemoryInformationForPage(info,*it);
324 for(int i=0;i<info_count && i<10;i++)
325 page.append(numberToRow(info[i].name, info[i].value, BYTE));
326 page.append(footer());
332 if (printFormat == PRINT_FORMAT_HTML) {
333 // JS Engine Memory Usage
334 page.append("<div class='box'><div class='box-title'>JS engine memory usage<br><div style='font-size:11px;color:#A8A8A8'>Stack, JIT, Heap are expressed in KB.</div><br></div><table class='fixed-table'><col width=75%><col width=25%>");
336 page.append(numberToRow("Stack size", jscMemoryStat.stackBytes, KILOBYTE));
337 page.append(numberToRow("JIT memory usage", jscMemoryStat.JITBytes, KILOBYTE));
338 page.append(numberToRow("Main heap capacity", mainHeap.capacity(), KILOBYTE));
339 page.append(numberToRow("Main heap size", mainHeap.size(), KILOBYTE));
340 page.append(numberToRow("Object count", mainHeap.objectCount(), EA));
341 page.append(numberToRow("Global object count", mainHeap.globalObjectCount(), EA));
342 page.append(numberToRow("Protected object count", mainHeap.protectedObjectCount(), EA));
343 page.append(numberToRow("Protected global object count", mainHeap.protectedGlobalObjectCount(), EA));
345 page.append(footer());
347 // JS object type counts
348 page.append(header("JS object type counts"));
349 dumpJSCTypeCountSetToTableHTML(page, objectTypeCounts.get());
350 page.append(footer());
352 // JS protected object type counts
353 page.append(header("JS protected object type counts"));
354 dumpJSCTypeCountSetToTableHTML(page, protectedObjectTypeCounts.get());
355 page.append(footer());
357 // Malloc Information
358 page.append(header("Malloc Information"));
360 page.append(numberToRow("Total space in use", mallocInfo.usmblks + mallocInfo.uordblks, KILOBYTE));
361 page.append(numberToRow("Total space in free blocks", mallocInfo.fsmblks + mallocInfo.fordblks, KILOBYTE));
362 page.append(numberToRow("Size of the arena", mallocInfo.arena, KILOBYTE));
363 page.append(numberToRow("Number of big blocks in use", mallocInfo.ordblks, EA));
364 page.append(numberToRow("Number of small blocks in use", mallocInfo.smblks, EA));
365 page.append(numberToRow("Number of header blocks in use", mallocInfo.hblks, EA));
366 page.append(numberToRow("Space in header block headers", mallocInfo.hblkhd, EA));
367 page.append(numberToRow("Space in small blocks in use", mallocInfo.usmblks, EA));
368 page.append(numberToRow("Memory in free small blocks", mallocInfo.fsmblks, EA));
369 page.append(numberToRow("Space in big blocks in use", mallocInfo.uordblks, KILOBYTE));
370 page.append(numberToRow("Memory in free big blocks", mallocInfo.fordblks, KILOBYTE));
371 page.append(footer());
373 #if ENABLE(GLOBAL_FASTMALLOC_NEW)
374 // Fast Malloc Information
375 page.append(header("Fast Malloc Information"));
377 FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics();
378 size_t fastMallocBytesInUse = fastMallocStatistics.committedVMBytes - fastMallocStatistics.freeListBytes;
379 size_t fastMallocBytesCommitted = fastMallocStatistics.committedVMBytes;
380 totalBytesInUse += fastMallocBytesInUse;
381 totalBytesCommitted += fastMallocBytesCommitted;
383 page.append(numberToRow("Fast Malloc In Use", fastMallocBytesInUse, KILOBYTE));
384 page.append(numberToRow("Fast Malloc Committed Memory", fastMallocBytesCommitted, KILOBYTE));
386 page.append(footer());
390 if(printFormat == PRINT_FORMAT_HTML)
391 page.append("</body></html>");
392 return page.toString();
395 static String appCachePage()
397 printFormat = PRINT_FORMAT_HTML;
400 page.append(writeHeader("Application Cache"));
403 cacheStorage().manifestURLs(&urls);
406 page.append(header("Application cache is empty"));
407 page.append(footer());
408 return page.toString();
411 for(size_t index = 0; index < urls.size(); index++)
413 // generate application cache infomation
414 page.append(String("<div class='box'><div class='box-title'>")
415 + urls[index].string() + String("</div><table class='fixed-table'><col width=15%><col width=70%><col width=15%>"));
417 ApplicationCacheGroup* cacheGroup = cacheStorage().cacheGroupForURL(urls[index]);
418 ApplicationCache* cache = cacheGroup->newestCache();
420 if (!cache || !cache->isComplete()) {
421 page.append("cache is incomplete");
422 page.append(footer());
425 ApplicationCache::ResourceMap::const_iterator end = cache->end();
426 for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) {
428 RefPtr<ApplicationCacheResource> resource = it->second;
429 unsigned type = resource->type();
432 if (type & ApplicationCacheResource::Master)
433 flags.append("Master");
434 if (type & ApplicationCacheResource::Manifest)
435 flags.append("Manifest");
436 if (type & ApplicationCacheResource::Explicit)
437 flags.append("Explicit");
438 if (type & ApplicationCacheResource::Foreign)
439 flags.append("Foreign");
440 if (type & ApplicationCacheResource::Fallback)
441 flags.append("Fallback");
443 page.append(appcacheStatisticToRow(flags.toString(), it->first, resource->estimatedSizeInStorage()));
445 page.append(footer());
448 return page.toString();
451 static String blobPage()
454 page.append(writeHeader("Blob internals"));
455 page.append("<div class='box'><table class='fixed-table' style=word-break:break-all; width=100%>");
457 BlobMap map = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobData();
460 page.append(header("There is no Blob data"));
461 page.append(footer());
462 return page.toString();
465 BlobMap::const_iterator it = map.begin();
466 const BlobMap::const_iterator itend = map.end();
467 for (; it != itend; ++it) {
468 // append blob object url information
469 page.append("<tr><td>" + it->first + "<ul>");
471 // append blob data information
472 RefPtr<BlobStorageData> blobData = it->second;
473 if (!blobData->contentType().isEmpty())
474 page.append("<li>Content Type:" + blobData->contentType() + "</li>");
475 if (!blobData->contentDisposition().isEmpty())
476 page.append("<li>Content Disposition:" + blobData->contentDisposition() + "</li>");
478 BlobDataItemList::const_iterator it = blobData->items().begin();
479 const BlobDataItemList::const_iterator itend = blobData->items().end();
480 for (; it != itend; ++it) {
481 const BlobDataItem& blobItem = *it;
483 switch (blobItem.type) {
484 case BlobDataItem::Data:
485 page.append("<li>Type: data</li>");
487 case BlobDataItem::File:
488 page.append("<li>Type: file</li>");
489 if (!blobItem.path.isEmpty())
490 page.append("<li>Path: " + blobItem.path + "</li>");
492 case BlobDataItem::Blob:
493 page.append("<li>Type: blob</li>");
494 if (!blobItem.url.isEmpty())
495 page.append("<li>URL: " + blobItem.url.string() + "</li>");
498 page.append("<li>Length: " + String::number(blobItem.length) + "</li>");
500 page.append("</ul></td></tr>");
503 page.append(footer());
505 return page.toString();
508 static String cachePage()
510 printFormat = PRINT_FORMAT_HTML;
513 page.append(writeHeader("Memory Cache"));
514 page.append("<div class='box'><table class='fixed-table' style=word-break:break-all; width=100%>");
516 String cachedResourceLists = memoryCache()->dumpCachedResourceLists();
517 if (cachedResourceLists.isEmpty()) {
518 page.append(header("Memory cache is empty"));
519 page.append(footer());
520 return page.toString();
523 Vector<String> cacheInfo;
524 cachedResourceLists.split('\n', cacheInfo);
526 Vector<String>::iterator iter = cacheInfo.begin();
527 for(; iter != cacheInfo.end(); ++iter)
528 page.append("<tr><td>" + *iter + "</td></tr>");
530 page.append(footer());
532 return page.toString();
535 static String creditsPage()
537 printFormat = PRINT_FORMAT_HTML;
540 page.append(writeHeader("Credits"));
541 page.append(creditToRow("WebKit"));
542 page.append(footer());
544 return page.toString();
547 static String helpPage()
549 printFormat = PRINT_FORMAT_HTML;
552 page.append(writeHeader("List of About Features"));
553 page.append("<div class='box'><table class='fixed-table' style=word-break:break-all;><col width=35%><col width=65%>");
555 page.append(helpTextToRow("about:appcache", "Application cache information"));
556 page.append(helpTextToRow("about:cache", "Memory cache information"));
557 page.append(helpTextToRow("about:credits", "License information"));
558 page.append(helpTextToRow("about:help", "List of About features"));
559 page.append(helpTextToRow("about:memory", "Memory Statistics"));
560 page.append(helpTextToRow("about:plugins", "Plugin information"));
561 page.append(helpTextToRow("about:version", "Version information"));
563 page.append(footer());
565 return page.toString();
568 static String pluginsPage()
570 printFormat = PRINT_FORMAT_HTML;
573 page.append(writeHeader("Plugin"));
574 page.append("<div class='box'><table class='fixed-table' style=word-break:break-all; width=100%>");
576 // FIXME: Ewk_Context should be obtained from Ewk_View. This will be fixed after refactoring 'about:' implementation itself.
577 Ewk_Context* context = ewk_context_default_get();
578 Vector<PluginModuleInfo> plugins = (toImpl(context->wkContext())->pluginInfoStore()).plugins();
580 if (plugins.isEmpty()) {
581 page.append(header("There is no plugin"));
582 page.append(footer());
583 return page.toString();
586 Vector<PluginModuleInfo>::const_iterator it = plugins.begin();
587 const Vector<PluginModuleInfo>::const_iterator itend = plugins.end();
588 for (; it != itend; ++it) {
589 page.append("<tr><td>");
591 PluginInfo info = (*it).info;
592 if (!info.name.isEmpty())
593 page.append(info.name);
597 if (!info.file.isEmpty())
598 page.append("<li>File: " + info.file + "</li>");
600 if (!info.desc.isEmpty())
601 page.append("<li>Description: " + info.desc + "</li>");
603 page.append("</ul></td></td>");
606 page.append(footer());
608 return page.toString();
611 static String versionPage()
613 printFormat = PRINT_FORMAT_HTML;
616 page.append(writeHeader("Version"));
617 page.append("<div class='box'><table class='fixed-table' style=word-break:break-all; width=100%>");
619 // TODO : More information(OS version, JavaScript Core version) will be added.
620 page.append(helpTextToRow("WebKit", String::format("%d.%d", WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION)));
622 HashSet<Page*>::iterator begin = allPages->begin();
623 HashSet<Page*>::iterator end = allPages->end();
626 page.append(helpTextToRow("User Agent", header((*begin)->mainFrame()->loader()->userAgent(unused))));
628 page.append(footer());
630 return page.toString();
633 String aboutData(String aboutWhat)
635 if (aboutWhat.endsWith("about:appcache", false))
636 return appCachePage();
637 if (aboutWhat.endsWith("about:blob", false))
639 if (aboutWhat.endsWith("about:cache", false))
641 if (aboutWhat.endsWith("about:credits", false))
642 return creditsPage();
643 if (aboutWhat.endsWith("about:help", false))
645 if (aboutWhat.endsWith("about:memory", false))
647 if (aboutWhat.endsWith("about:plugins", false))
648 return pluginsPage();
649 if (aboutWhat.endsWith("about:version", false))
650 return versionPage();
655 } // namespace WebKit
656 #endif // end of #if ENABLE(TIZEN_WEBKIT2_ABOUT_MEMORY)