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
51using WebKit::WebAudioBus;
52using WebKit::WebCookie;
53using WebKit::WebData;
54using WebKit::WebLocalizedString;
55using WebKit::WebPluginListBuilder;
56using WebKit::WebString;
57using WebKit::WebSocketStreamHandle;
58using WebKit::WebThemeEngine;
59using WebKit::WebURL;
60using WebKit::WebURLLoader;
61using WebKit::WebVector;
62
63namespace {
64
65// A simple class to cache the memory usage for a given amount of time.
66class 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
115namespace webkit_glue {
116
117static 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
199WebKitClientImpl::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
206WebKitClientImpl::~WebKitClientImpl() {
207}
208
209WebThemeEngine* 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
217WebURLLoader* WebKitClientImpl::createURLLoader() {
218  return new WebURLLoaderImpl();
219}
220
221WebSocketStreamHandle* WebKitClientImpl::createSocketStreamHandle() {
222  return new WebSocketStreamHandleImpl();
223}
224
225WebString WebKitClientImpl::userAgent(const WebURL& url) {
226  return WebString::fromUTF8(webkit_glue::GetUserAgent(url));
227}
228
229void 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
255void WebKitClientImpl::decrementStatsCounter(const char* name) {
256  base::StatsCounter(name).Decrement();
257}
258
259void WebKitClientImpl::incrementStatsCounter(const char* name) {
260  base::StatsCounter(name).Increment();
261}
262
263void 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
274void 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
285void 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
293void 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
299namespace {
300
301WebData 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
352WebData 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
403bool 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
412WebString 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
420WebString WebKitClientImpl::queryLocalizedString(
421    WebLocalizedString::Name name, int numeric_value) {
422  return queryLocalizedString(name, base::IntToString16(numeric_value));
423}
424
425WebString 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
433WebString 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
448double WebKitClientImpl::currentTime() {
449  return base::Time::Now().ToDoubleT();
450}
451
452void 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
463void WebKitClientImpl::setSharedTimerFiredFunction(void (*func)()) {
464  shared_timer_func_ = func;
465}
466
467void 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
492void WebKitClientImpl::stopSharedTimer() {
493  shared_timer_.Stop();
494}
495
496void WebKitClientImpl::callOnMainThread(void (*func)(void*), void* context) {
497  main_loop_->PostTask(FROM_HERE, NewRunnableFunction(func, context));
498}
499
500base::PlatformFile WebKitClientImpl::databaseOpenFile(
501    const WebKit::WebString& vfs_file_name, int desired_flags) {
502  return base::kInvalidPlatformFileValue;
503}
504
505int WebKitClientImpl::databaseDeleteFile(
506    const WebKit::WebString& vfs_file_name, bool sync_dir) {
507  return -1;
508}
509
510long WebKitClientImpl::databaseGetFileAttributes(
511    const WebKit::WebString& vfs_file_name) {
512  return 0;
513}
514
515long long WebKitClientImpl::databaseGetFileSize(
516    const WebKit::WebString& vfs_file_name) {
517  return 0;
518}
519
520WebKit::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)
529static 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)
546static 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)
559static 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
568static 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
587size_t WebKitClientImpl::memoryUsageMB() {
588  return getMemoryUsageMB(false);
589}
590
591size_t WebKitClientImpl::actualMemoryUsageMB() {
592  return getMemoryUsageMB(true);
593}
594
595void WebKitClientImpl::SuspendSharedTimer() {
596  ++shared_timer_suspended_;
597}
598
599void 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