Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "webkit/glue/webkitclient_impl.h"
      6 
      7 #if defined(OS_LINUX)
      8 #include <malloc.h>
      9 #endif
     10 
     11 #include <math.h>
     12 
     13 #include <vector>
     14 
     15 #include "base/debug/trace_event.h"
     16 #include "base/memory/singleton.h"
     17 #include "base/message_loop.h"
     18 #include "base/metrics/histogram.h"
     19 #include "base/metrics/stats_counters.h"
     20 #include "base/platform_file.h"
     21 #include "base/process_util.h"
     22 #include "base/rand_util.h"
     23 #include "base/string_number_conversions.h"
     24 #include "base/string_util.h"
     25 #include "base/synchronization/lock.h"
     26 #include "base/time.h"
     27 #include "base/utf_string_conversions.h"
     28 #include "gpu/common/gpu_trace_event.h"
     29 #include "grit/webkit_chromium_resources.h"
     30 #include "grit/webkit_resources.h"
     31 #include "grit/webkit_strings.h"
     32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCookie.h"
     33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebData.h"
     34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrameClient.h"
     35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginListBuilder.h"
     36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
     37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
     38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h"
     39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
     40 #include "webkit/glue/media/audio_decoder.h"
     41 #include "webkit/plugins/npapi/plugin_instance.h"
     42 #include "webkit/plugins/npapi/webplugininfo.h"
     43 #include "webkit/glue/webkit_glue.h"
     44 #include "webkit/glue/websocketstreamhandle_impl.h"
     45 #include "webkit/glue/weburlloader_impl.h"
     46 
     47 #if defined(OS_LINUX)
     48 #include "v8/include/v8.h"
     49 #endif
     50 
     51 using WebKit::WebAudioBus;
     52 using WebKit::WebCookie;
     53 using WebKit::WebData;
     54 using WebKit::WebLocalizedString;
     55 using WebKit::WebPluginListBuilder;
     56 using WebKit::WebString;
     57 using WebKit::WebSocketStreamHandle;
     58 using WebKit::WebThemeEngine;
     59 using WebKit::WebURL;
     60 using WebKit::WebURLLoader;
     61 using WebKit::WebVector;
     62 
     63 namespace {
     64 
     65 // A simple class to cache the memory usage for a given amount of time.
     66 class MemoryUsageCache {
     67  public:
     68   // Retrieves the Singleton.
     69   static MemoryUsageCache* GetInstance() {
     70     return Singleton<MemoryUsageCache>::get();
     71   }
     72 
     73   MemoryUsageCache() : memory_value_(0) { Init(); }
     74   ~MemoryUsageCache() {}
     75 
     76   void Init() {
     77     const unsigned int kCacheSeconds = 1;
     78     cache_valid_time_ = base::TimeDelta::FromSeconds(kCacheSeconds);
     79   }
     80 
     81   // Returns true if the cached value is fresh.
     82   // Returns false if the cached value is stale, or if |cached_value| is NULL.
     83   bool IsCachedValueValid(size_t* cached_value) {
     84     base::AutoLock scoped_lock(lock_);
     85     if (!cached_value)
     86       return false;
     87     if (base::Time::Now() - last_updated_time_ > cache_valid_time_)
     88       return false;
     89     *cached_value = memory_value_;
     90     return true;
     91   };
     92 
     93   // Setter for |memory_value_|, refreshes |last_updated_time_|.
     94   void SetMemoryValue(const size_t value) {
     95     base::AutoLock scoped_lock(lock_);
     96     memory_value_ = value;
     97     last_updated_time_ = base::Time::Now();
     98   }
     99 
    100  private:
    101   // The cached memory value.
    102   size_t memory_value_;
    103 
    104   // How long the cached value should remain valid.
    105   base::TimeDelta cache_valid_time_;
    106 
    107   // The last time the cached value was updated.
    108   base::Time last_updated_time_;
    109 
    110   base::Lock lock_;
    111 };
    112 
    113 }  // anonymous namespace
    114 
    115 namespace webkit_glue {
    116 
    117 static int ToMessageID(WebLocalizedString::Name name) {
    118   switch (name) {
    119     case WebLocalizedString::SubmitButtonDefaultLabel:
    120       return IDS_FORM_SUBMIT_LABEL;
    121     case WebLocalizedString::InputElementAltText:
    122       return IDS_FORM_INPUT_ALT;
    123     case WebLocalizedString::ResetButtonDefaultLabel:
    124       return IDS_FORM_RESET_LABEL;
    125     case WebLocalizedString::FileButtonChooseFileLabel:
    126       return IDS_FORM_FILE_BUTTON_LABEL;
    127     case WebLocalizedString::FileButtonNoFileSelectedLabel:
    128       return IDS_FORM_FILE_NO_FILE_LABEL;
    129     case WebLocalizedString::MultipleFileUploadText:
    130       return IDS_FORM_FILE_MULTIPLE_UPLOAD;
    131     case WebLocalizedString::SearchableIndexIntroduction:
    132       return IDS_SEARCHABLE_INDEX_INTRO;
    133     case WebLocalizedString::SearchMenuNoRecentSearchesText:
    134       return IDS_RECENT_SEARCHES_NONE;
    135     case WebLocalizedString::SearchMenuRecentSearchesText:
    136       return IDS_RECENT_SEARCHES;
    137     case WebLocalizedString::SearchMenuClearRecentSearchesText:
    138       return IDS_RECENT_SEARCHES_CLEAR;
    139     case WebLocalizedString::AXWebAreaText:
    140       return IDS_AX_ROLE_WEB_AREA;
    141     case WebLocalizedString::AXLinkText:
    142       return IDS_AX_ROLE_LINK;
    143     case WebLocalizedString::AXListMarkerText:
    144       return IDS_AX_ROLE_LIST_MARKER;
    145     case WebLocalizedString::AXImageMapText:
    146       return IDS_AX_ROLE_IMAGE_MAP;
    147     case WebLocalizedString::AXHeadingText:
    148       return IDS_AX_ROLE_HEADING;
    149     case WebLocalizedString::AXButtonActionVerb:
    150       return IDS_AX_BUTTON_ACTION_VERB;
    151     case WebLocalizedString::AXRadioButtonActionVerb:
    152       return IDS_AX_RADIO_BUTTON_ACTION_VERB;
    153     case WebLocalizedString::AXTextFieldActionVerb:
    154       return IDS_AX_TEXT_FIELD_ACTION_VERB;
    155     case WebLocalizedString::AXCheckedCheckBoxActionVerb:
    156       return IDS_AX_CHECKED_CHECK_BOX_ACTION_VERB;
    157     case WebLocalizedString::AXUncheckedCheckBoxActionVerb:
    158       return IDS_AX_UNCHECKED_CHECK_BOX_ACTION_VERB;
    159     case WebLocalizedString::AXLinkActionVerb:
    160       return IDS_AX_LINK_ACTION_VERB;
    161     case WebLocalizedString::KeygenMenuHighGradeKeySize:
    162       return IDS_KEYGEN_HIGH_GRADE_KEY;
    163     case WebLocalizedString::KeygenMenuMediumGradeKeySize:
    164       return IDS_KEYGEN_MED_GRADE_KEY;
    165     case WebLocalizedString::ValidationValueMissing:
    166       return IDS_FORM_VALIDATION_VALUE_MISSING;
    167     case WebLocalizedString::ValidationValueMissingForCheckbox:
    168       return IDS_FORM_VALIDATION_VALUE_MISSING_CHECKBOX;
    169     case WebLocalizedString::ValidationValueMissingForFile:
    170       return IDS_FORM_VALIDATION_VALUE_MISSING_FILE;
    171     case WebLocalizedString::ValidationValueMissingForMultipleFile:
    172       return IDS_FORM_VALIDATION_VALUE_MISSING_MULTIPLE_FILE;
    173     case WebLocalizedString::ValidationValueMissingForRadio:
    174       return IDS_FORM_VALIDATION_VALUE_MISSING_RADIO;
    175     case WebLocalizedString::ValidationValueMissingForSelect:
    176       return IDS_FORM_VALIDATION_VALUE_MISSING_SELECT;
    177     case WebLocalizedString::ValidationTypeMismatch:
    178       return IDS_FORM_VALIDATION_TYPE_MISMATCH;
    179     case WebLocalizedString::ValidationTypeMismatchForEmail:
    180       return IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL;
    181     case WebLocalizedString::ValidationTypeMismatchForMultipleEmail:
    182       return IDS_FORM_VALIDATION_TYPE_MISMATCH_MULTIPLE_EMAIL;
    183     case WebLocalizedString::ValidationTypeMismatchForURL:
    184       return IDS_FORM_VALIDATION_TYPE_MISMATCH_URL;
    185     case WebLocalizedString::ValidationPatternMismatch:
    186       return IDS_FORM_VALIDATION_PATTERN_MISMATCH;
    187     case WebLocalizedString::ValidationTooLong:
    188       return IDS_FORM_VALIDATION_TOO_LONG;
    189     case WebLocalizedString::ValidationRangeUnderflow:
    190       return IDS_FORM_VALIDATION_RANGE_UNDERFLOW;
    191     case WebLocalizedString::ValidationRangeOverflow:
    192       return IDS_FORM_VALIDATION_RANGE_OVERFLOW;
    193     case WebLocalizedString::ValidationStepMismatch:
    194       return IDS_FORM_VALIDATION_STEP_MISMATCH;
    195   }
    196   return -1;
    197 }
    198 
    199 WebKitClientImpl::WebKitClientImpl()
    200     : main_loop_(MessageLoop::current()),
    201       shared_timer_func_(NULL),
    202       shared_timer_fire_time_(0.0),
    203       shared_timer_suspended_(0) {
    204 }
    205 
    206 WebKitClientImpl::~WebKitClientImpl() {
    207 }
    208 
    209 WebThemeEngine* WebKitClientImpl::themeEngine() {
    210 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
    211   return &theme_engine_;
    212 #else
    213   return NULL;
    214 #endif
    215 }
    216 
    217 WebURLLoader* WebKitClientImpl::createURLLoader() {
    218   return new WebURLLoaderImpl();
    219 }
    220 
    221 WebSocketStreamHandle* WebKitClientImpl::createSocketStreamHandle() {
    222   return new WebSocketStreamHandleImpl();
    223 }
    224 
    225 WebString WebKitClientImpl::userAgent(const WebURL& url) {
    226   return WebString::fromUTF8(webkit_glue::GetUserAgent(url));
    227 }
    228 
    229 void WebKitClientImpl::getPluginList(bool refresh,
    230                                      WebPluginListBuilder* builder) {
    231   std::vector<webkit::npapi::WebPluginInfo> plugins;
    232   GetPlugins(refresh, &plugins);
    233 
    234   for (size_t i = 0; i < plugins.size(); ++i) {
    235     const webkit::npapi::WebPluginInfo& plugin = plugins[i];
    236 
    237     builder->addPlugin(
    238         plugin.name, plugin.desc,
    239         FilePathStringToWebString(plugin.path.BaseName().value()));
    240 
    241     for (size_t j = 0; j < plugin.mime_types.size(); ++j) {
    242       const webkit::npapi::WebPluginMimeType& mime_type = plugin.mime_types[j];
    243 
    244       builder->addMediaTypeToLastPlugin(
    245           WebString::fromUTF8(mime_type.mime_type), mime_type.description);
    246 
    247       for (size_t k = 0; k < mime_type.file_extensions.size(); ++k) {
    248         builder->addFileExtensionToLastMediaType(
    249             UTF8ToUTF16(mime_type.file_extensions[k]));
    250       }
    251     }
    252   }
    253 }
    254 
    255 void WebKitClientImpl::decrementStatsCounter(const char* name) {
    256   base::StatsCounter(name).Decrement();
    257 }
    258 
    259 void WebKitClientImpl::incrementStatsCounter(const char* name) {
    260   base::StatsCounter(name).Increment();
    261 }
    262 
    263 void WebKitClientImpl::histogramCustomCounts(
    264     const char* name, int sample, int min, int max, int bucket_count) {
    265   // Copied from histogram macro, but without the static variable caching
    266   // the histogram because name is dynamic.
    267   base::Histogram* counter =
    268       base::Histogram::FactoryGet(name, min, max, bucket_count,
    269           base::Histogram::kUmaTargetedHistogramFlag);
    270   DCHECK_EQ(name, counter->histogram_name());
    271   counter->Add(sample);
    272 }
    273 
    274 void WebKitClientImpl::histogramEnumeration(
    275     const char* name, int sample, int boundary_value) {
    276   // Copied from histogram macro, but without the static variable caching
    277   // the histogram because name is dynamic.
    278   base::Histogram* counter =
    279       base::LinearHistogram::FactoryGet(name, 1, boundary_value,
    280           boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag);
    281   DCHECK_EQ(name, counter->histogram_name());
    282   counter->Add(sample);
    283 }
    284 
    285 void WebKitClientImpl::traceEventBegin(const char* name, void* id,
    286                                        const char* extra) {
    287   TRACE_EVENT_BEGIN(name, id, extra);
    288   GPU_TRACE_EVENT_BEGIN2("webkit", name,
    289                          "id", StringPrintf("%p", id).c_str(),
    290                          "extra", extra ? extra : "");
    291 }
    292 
    293 void WebKitClientImpl::traceEventEnd(const char* name, void* id,
    294                                      const char* extra) {
    295   TRACE_EVENT_END(name, id, extra);
    296   GPU_TRACE_EVENT_END0("webkit", name);
    297 }
    298 
    299 namespace {
    300 
    301 WebData loadAudioSpatializationResource(const char* name) {
    302 #ifdef IDR_AUDIO_SPATIALIZATION_T000_P000
    303   const size_t kExpectedSpatializationNameLength = 31;
    304   if (strlen(name) != kExpectedSpatializationNameLength) {
    305     return WebData();
    306   }
    307 
    308   // Extract the azimuth and elevation from the resource name.
    309   int azimuth = 0;
    310   int elevation = 0;
    311   int values_parsed =
    312       sscanf(name, "IRC_Composite_C_R0195_T%3d_P%3d", &azimuth, &elevation);
    313   if (values_parsed != 2) {
    314     return WebData();
    315   }
    316 
    317   // The resource index values go through the elevations first, then azimuths.
    318   const int kAngleSpacing = 15;
    319 
    320   // 0 <= elevation <= 90 (or 315 <= elevation <= 345)
    321   // in increments of 15 degrees.
    322   int elevation_index =
    323       elevation <= 90 ? elevation / kAngleSpacing :
    324       7 + (elevation - 315) / kAngleSpacing;
    325   bool is_elevation_index_good = 0 <= elevation_index && elevation_index < 10;
    326 
    327   // 0 <= azimuth < 360 in increments of 15 degrees.
    328   int azimuth_index = azimuth / kAngleSpacing;
    329   bool is_azimuth_index_good = 0 <= azimuth_index && azimuth_index < 24;
    330 
    331   const int kNumberOfElevations = 10;
    332   const int kNumberOfAudioResources = 240;
    333   int resource_index = kNumberOfElevations * azimuth_index + elevation_index;
    334   bool is_resource_index_good = 0 <= resource_index &&
    335       resource_index < kNumberOfAudioResources;
    336 
    337   if (is_azimuth_index_good && is_elevation_index_good &&
    338       is_resource_index_good) {
    339     const int kFirstAudioResourceIndex = IDR_AUDIO_SPATIALIZATION_T000_P000;
    340     base::StringPiece resource =
    341         GetDataResource(kFirstAudioResourceIndex + resource_index);
    342     return WebData(resource.data(), resource.size());
    343   }
    344 #endif  // IDR_AUDIO_SPATIALIZATION_T000_P000
    345 
    346   NOTREACHED();
    347   return WebData();
    348 }
    349 
    350 }  // namespace
    351 
    352 WebData WebKitClientImpl::loadResource(const char* name) {
    353   struct {
    354     const char* name;
    355     int id;
    356   } resources[] = {
    357     { "missingImage", IDR_BROKENIMAGE },
    358     { "mediaPause", IDR_MEDIA_PAUSE_BUTTON },
    359     { "mediaPlay", IDR_MEDIA_PLAY_BUTTON },
    360     { "mediaPlayDisabled", IDR_MEDIA_PLAY_BUTTON_DISABLED },
    361     { "mediaSoundDisabled", IDR_MEDIA_SOUND_DISABLED },
    362     { "mediaSoundFull", IDR_MEDIA_SOUND_FULL_BUTTON },
    363     { "mediaSoundNone", IDR_MEDIA_SOUND_NONE_BUTTON },
    364     { "mediaSliderThumb", IDR_MEDIA_SLIDER_THUMB },
    365     { "mediaVolumeSliderThumb", IDR_MEDIA_VOLUME_SLIDER_THUMB },
    366     { "panIcon", IDR_PAN_SCROLL_ICON },
    367     { "searchCancel", IDR_SEARCH_CANCEL },
    368     { "searchCancelPressed", IDR_SEARCH_CANCEL_PRESSED },
    369     { "searchMagnifier", IDR_SEARCH_MAGNIFIER },
    370     { "searchMagnifierResults", IDR_SEARCH_MAGNIFIER_RESULTS },
    371     { "textAreaResizeCorner", IDR_TEXTAREA_RESIZER },
    372     { "tickmarkDash", IDR_TICKMARK_DASH },
    373     { "inputSpeech", IDR_INPUT_SPEECH },
    374     { "inputSpeechRecording", IDR_INPUT_SPEECH_RECORDING },
    375     { "inputSpeechWaiting", IDR_INPUT_SPEECH_WAITING },
    376     { "americanExpressCC", IDR_AUTOFILL_CC_AMEX },
    377     { "dinersCC", IDR_AUTOFILL_CC_DINERS },
    378     { "discoverCC", IDR_AUTOFILL_CC_DISCOVER },
    379     { "genericCC", IDR_AUTOFILL_CC_GENERIC },
    380     { "jcbCC", IDR_AUTOFILL_CC_JCB },
    381     { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD },
    382     { "soloCC", IDR_AUTOFILL_CC_SOLO },
    383     { "visaCC", IDR_AUTOFILL_CC_VISA },
    384   };
    385 
    386   // Check the name prefix to see if it's an audio resource.
    387   if (StartsWithASCII(name, "IRC_Composite", true)) {
    388     return loadAudioSpatializationResource(name);
    389   } else {
    390     for (size_t i = 0; i < ARRAYSIZE_UNSAFE(resources); ++i) {
    391       if (!strcmp(name, resources[i].name)) {
    392         base::StringPiece resource = GetDataResource(resources[i].id);
    393         return WebData(resource.data(), resource.size());
    394       }
    395     }
    396   }
    397   // TODO(jhawkins): Restore this NOTREACHED once WK stops sending in empty
    398   // strings. http://crbug.com/50675.
    399   //NOTREACHED() << "Unknown image resource " << name;
    400   return WebData();
    401 }
    402 
    403 bool WebKitClientImpl::loadAudioResource(
    404     WebKit::WebAudioBus* destination_bus, const char* audio_file_data,
    405     size_t data_size, double sample_rate) {
    406   return DecodeAudioFileData(destination_bus,
    407                              audio_file_data,
    408                              data_size,
    409                              sample_rate);
    410 }
    411 
    412 WebString WebKitClientImpl::queryLocalizedString(
    413     WebLocalizedString::Name name) {
    414   int message_id = ToMessageID(name);
    415   if (message_id < 0)
    416     return WebString();
    417   return GetLocalizedString(message_id);
    418 }
    419 
    420 WebString WebKitClientImpl::queryLocalizedString(
    421     WebLocalizedString::Name name, int numeric_value) {
    422   return queryLocalizedString(name, base::IntToString16(numeric_value));
    423 }
    424 
    425 WebString WebKitClientImpl::queryLocalizedString(
    426     WebLocalizedString::Name name, const WebString& value) {
    427   int message_id = ToMessageID(name);
    428   if (message_id < 0)
    429     return WebString();
    430   return ReplaceStringPlaceholders(GetLocalizedString(message_id), value, NULL);
    431 }
    432 
    433 WebString WebKitClientImpl::queryLocalizedString(
    434     WebLocalizedString::Name name,
    435     const WebString& value1,
    436     const WebString& value2) {
    437   int message_id = ToMessageID(name);
    438   if (message_id < 0)
    439     return WebString();
    440   std::vector<string16> values;
    441   values.reserve(2);
    442   values.push_back(value1);
    443   values.push_back(value2);
    444   return ReplaceStringPlaceholders(
    445       GetLocalizedString(message_id), values, NULL);
    446 }
    447 
    448 double WebKitClientImpl::currentTime() {
    449   return base::Time::Now().ToDoubleT();
    450 }
    451 
    452 void WebKitClientImpl::cryptographicallyRandomValues(
    453     unsigned char* buffer, size_t length) {
    454   uint64 bytes = 0;
    455   for (size_t i = 0; i < length; ++i) {
    456     size_t offset = i % sizeof(bytes);
    457     if (!offset)
    458       bytes = base::RandUint64();
    459     buffer[i] = reinterpret_cast<unsigned char*>(&bytes)[offset];
    460   }
    461 }
    462 
    463 void WebKitClientImpl::setSharedTimerFiredFunction(void (*func)()) {
    464   shared_timer_func_ = func;
    465 }
    466 
    467 void WebKitClientImpl::setSharedTimerFireTime(double fire_time) {
    468   shared_timer_fire_time_ = fire_time;
    469   if (shared_timer_suspended_)
    470     return;
    471 
    472   // By converting between double and int64 representation, we run the risk
    473   // of losing precision due to rounding errors. Performing computations in
    474   // microseconds reduces this risk somewhat. But there still is the potential
    475   // of us computing a fire time for the timer that is shorter than what we
    476   // need.
    477   // As the event loop will check event deadlines prior to actually firing
    478   // them, there is a risk of needlessly rescheduling events and of
    479   // needlessly looping if sleep times are too short even by small amounts.
    480   // This results in measurable performance degradation unless we use ceil() to
    481   // always round up the sleep times.
    482   int64 interval = static_cast<int64>(
    483       ceil((fire_time - currentTime()) * base::Time::kMicrosecondsPerSecond));
    484   if (interval < 0)
    485     interval = 0;
    486 
    487   shared_timer_.Stop();
    488   shared_timer_.Start(base::TimeDelta::FromMicroseconds(interval), this,
    489                       &WebKitClientImpl::DoTimeout);
    490 }
    491 
    492 void WebKitClientImpl::stopSharedTimer() {
    493   shared_timer_.Stop();
    494 }
    495 
    496 void WebKitClientImpl::callOnMainThread(void (*func)(void*), void* context) {
    497   main_loop_->PostTask(FROM_HERE, NewRunnableFunction(func, context));
    498 }
    499 
    500 base::PlatformFile WebKitClientImpl::databaseOpenFile(
    501     const WebKit::WebString& vfs_file_name, int desired_flags) {
    502   return base::kInvalidPlatformFileValue;
    503 }
    504 
    505 int WebKitClientImpl::databaseDeleteFile(
    506     const WebKit::WebString& vfs_file_name, bool sync_dir) {
    507   return -1;
    508 }
    509 
    510 long WebKitClientImpl::databaseGetFileAttributes(
    511     const WebKit::WebString& vfs_file_name) {
    512   return 0;
    513 }
    514 
    515 long long WebKitClientImpl::databaseGetFileSize(
    516     const WebKit::WebString& vfs_file_name) {
    517   return 0;
    518 }
    519 
    520 WebKit::WebString WebKitClientImpl::signedPublicKeyAndChallengeString(
    521     unsigned key_size_index,
    522     const WebKit::WebString& challenge,
    523     const WebKit::WebURL& url) {
    524   NOTREACHED();
    525   return WebKit::WebString();
    526 }
    527 
    528 #if defined(OS_LINUX)
    529 static size_t memoryUsageMBLinux() {
    530   struct mallinfo minfo = mallinfo();
    531   uint64_t mem_usage =
    532 #if defined(USE_TCMALLOC)
    533       minfo.uordblks
    534 #else
    535       (minfo.hblkhd + minfo.arena)
    536 #endif
    537       >> 20;
    538 
    539   v8::HeapStatistics stat;
    540   v8::V8::GetHeapStatistics(&stat);
    541   return mem_usage + (static_cast<uint64_t>(stat.total_heap_size()) >> 20);
    542 }
    543 #endif
    544 
    545 #if defined(OS_MACOSX)
    546 static size_t memoryUsageMBMac() {
    547   using base::ProcessMetrics;
    548   static ProcessMetrics* process_metrics =
    549       // The default port provider is sufficient to get data for the current
    550       // process.
    551       ProcessMetrics::CreateProcessMetrics(base::GetCurrentProcessHandle(),
    552                                            NULL);
    553   DCHECK(process_metrics);
    554   return process_metrics->GetPagefileUsage() >> 20;
    555 }
    556 #endif
    557 
    558 #if !defined(OS_LINUX) && !defined(OS_MACOSX)
    559 static size_t memoryUsageMBGeneric() {
    560   using base::ProcessMetrics;
    561   static ProcessMetrics* process_metrics =
    562       ProcessMetrics::CreateProcessMetrics(base::GetCurrentProcessHandle());
    563   DCHECK(process_metrics);
    564   return process_metrics->GetPagefileUsage() >> 20;
    565 }
    566 #endif
    567 
    568 static size_t getMemoryUsageMB(bool bypass_cache) {
    569   size_t current_mem_usage = 0;
    570   MemoryUsageCache* mem_usage_cache_singleton = MemoryUsageCache::GetInstance();
    571   if (!bypass_cache &&
    572       mem_usage_cache_singleton->IsCachedValueValid(&current_mem_usage))
    573     return current_mem_usage;
    574 
    575   current_mem_usage =
    576 #if defined(OS_LINUX)
    577       memoryUsageMBLinux();
    578 #elif defined(OS_MACOSX)
    579       memoryUsageMBMac();
    580 #else
    581       memoryUsageMBGeneric();
    582 #endif
    583   mem_usage_cache_singleton->SetMemoryValue(current_mem_usage);
    584   return current_mem_usage;
    585 }
    586 
    587 size_t WebKitClientImpl::memoryUsageMB() {
    588   return getMemoryUsageMB(false);
    589 }
    590 
    591 size_t WebKitClientImpl::actualMemoryUsageMB() {
    592   return getMemoryUsageMB(true);
    593 }
    594 
    595 void WebKitClientImpl::SuspendSharedTimer() {
    596   ++shared_timer_suspended_;
    597 }
    598 
    599 void WebKitClientImpl::ResumeSharedTimer() {
    600   // The shared timer may have fired or been adjusted while we were suspended.
    601   if (--shared_timer_suspended_ == 0 && !shared_timer_.IsRunning())
    602     setSharedTimerFireTime(shared_timer_fire_time_);
    603 }
    604 
    605 }  // namespace webkit_glue
    606