Commit c7fd0cbd authored by jorlow@chromium.org's avatar jorlow@chromium.org

Refactor DOM storage to be more object oriented. All the DOMStorageDispatcher...

Refactor DOM storage to be more object oriented.  All the DOMStorageDispatcher hosts (which are each owned by one ResourceMessageFilter) for the same profile share a WebKit context, and each one of those contexts owns a DOMStorageContext.  The DOMStorageContext owns storage namespace objects which own storage area objects which wrap their WebKit counterparts.

Not only is this cleaner code wise and more efficient (we're not duplicating WebStorageNamespaces and Areas for each DOMStorageDispatcherHost) but this is necessary for events and locking.

TEST=none
BUG=none

Review URL: http://codereview.chromium.org/192003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25609 0039d316-1c4b-4281-b951-d872f2087c98
parent b4599a15
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
#include "base/file_path.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/in_process_webkit/storage_area.h"
#include "chrome/browser/in_process_webkit/storage_namespace.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
DOMStorageContext::DOMStorageContext(WebKitContext* webkit_context)
: last_storage_area_id_(kFirstStorageAreaId),
last_storage_namespace_id_(kFirstStorageNamespaceId),
webkit_context_(webkit_context) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
}
DOMStorageContext::~DOMStorageContext() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
// The storage namespace destructor unregisters the storage namespace, so
// our iterator becomes invalid. Thus we just keep deleting the first item
// until there are none left.
while (!storage_namespace_map_.empty())
delete storage_namespace_map_.begin()->second;
}
StorageNamespace* DOMStorageContext::LocalStorage() {
StorageNamespace* storage_namespace = GetStorageNamespace(
kLocalStorageNamespaceId);
if (storage_namespace)
return storage_namespace;
FilePath data_path = webkit_context_->data_path();
FilePath dir_path;
if (!data_path.empty())
dir_path = data_path.AppendASCII("localStorage");
return StorageNamespace::CreateLocalStorageNamespace(this, dir_path);
}
StorageNamespace* DOMStorageContext::NewSessionStorage() {
return StorageNamespace::CreateSessionStorageNamespace(this);
}
void DOMStorageContext::RegisterStorageArea(StorageArea* storage_area) {
int64 id = storage_area->id();
DCHECK(!GetStorageArea(id));
storage_area_map_[id] = storage_area;
}
void DOMStorageContext::UnregisterStorageArea(StorageArea* storage_area) {
int64 id = storage_area->id();
DCHECK(GetStorageArea(id));
storage_area_map_.erase(id);
}
StorageArea* DOMStorageContext::GetStorageArea(int64 id) {
StorageAreaMap::iterator iter = storage_area_map_.find(id);
if (iter == storage_area_map_.end())
return NULL;
return iter->second;
}
void DOMStorageContext::RegisterStorageNamespace(
StorageNamespace* storage_namespace) {
int64 id = storage_namespace->id();
DCHECK(!GetStorageNamespace(id));
storage_namespace_map_[id] = storage_namespace;
}
void DOMStorageContext::UnregisterStorageNamespace(
StorageNamespace* storage_namespace) {
int64 id = storage_namespace->id();
DCHECK(GetStorageNamespace(id));
storage_namespace_map_.erase(id);
}
StorageNamespace* DOMStorageContext::GetStorageNamespace(int64 id) {
StorageNamespaceMap::iterator iter = storage_namespace_map_.find(id);
if (iter == storage_namespace_map_.end())
return NULL;
return iter->second;
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
#include "base/file_path.h"
#include "base/hash_tables.h"
class StorageArea;
class StorageNamespace;
class WebKitContext;
// This is owned by WebKitContext and is all the dom storage information that's
// shared by all the ResourceMessageFilter/DOMStorageDispatcherHosts that share
// the same profile. The specifics of responsibilities are fairly well
// documented here and in StorageNamespace and StorageArea.
class DOMStorageContext {
public:
explicit DOMStorageContext(WebKitContext* webkit_context);
~DOMStorageContext();
// Get the local storage instance. The pointer is owned by this class.
StorageNamespace* LocalStorage();
// Get a new session storage namespace (but it's still owned by this class).
StorageNamespace* NewSessionStorage();
// Allocate a new storage ___ id.
int64 AllocateStorageAreaId() { return ++last_storage_area_id_; }
int64 AllocateStorageNamespaceId() { return ++last_storage_namespace_id_; }
// Various storage area methods. The storage area is owned by one of the
// namespaces that's owned by this class.
void RegisterStorageArea(StorageArea* storage_area);
void UnregisterStorageArea(StorageArea* storage_area);
StorageArea* GetStorageArea(int64 id);
// Get a namespace from an id. What's returned is owned by this class. The
// caller of GetStorageNamespace must immediately register itself with the
// returned StorageNamespace.
void RegisterStorageNamespace(StorageNamespace* storage_namespace);
void UnregisterStorageNamespace(StorageNamespace* storage_namespace);
StorageNamespace* GetStorageNamespace(int64 id);
// The special ID used for local storage.
static const int64 kLocalStorageNamespaceId = 0;
private:
// The last used storage_area_id and storage_namespace_id's.
static const int64 kFirstStorageAreaId = 1;
int64 last_storage_area_id_;
static const int64 kFirstStorageNamespaceId = 1;
int64 last_storage_namespace_id_;
// We're owned by this WebKit context. Used while instantiating LocalStorage.
WebKitContext* webkit_context_;
// Maps ids to StorageAreas. We do NOT own these objects. StorageNamespace
// (which does own them) will notify us when we should remove the entries.
typedef base::hash_map<int64, StorageArea*> StorageAreaMap;
StorageAreaMap storage_area_map_;
// Maps ids to StorageNamespaces. We own these objects.
typedef base::hash_map<int64, StorageNamespace*> StorageNamespaceMap;
StorageNamespaceMap storage_namespace_map_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContext);
};
#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
......@@ -7,18 +7,13 @@
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/in_process_webkit/storage_area.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "ipc/ipc_message.h"
class WebKitContext;
class DOMStorageContext;
class WebKitThread;
namespace WebKit {
class WebStorageArea;
class WebStorageNamespace;
class WebString;
}
// This class handles the logistics of DOM Storage within the browser process.
// It mostly ferries information between IPCs and the WebKit implementations,
// but it also handles some special cases like when renderer processes die.
......@@ -58,19 +53,11 @@ class DOMStorageDispatcherHost :
void OnRemoveItem(int64 storage_area_id, const string16& key);
void OnClear(int64 storage_area_id, IPC::Message* reply_msg);
// Get a WebStorageNamespace or WebStorageArea based from its ID. Only call
// on the WebKit thread.
WebKit::WebStorageArea* GetStorageArea(int64 id);
WebKit::WebStorageNamespace* GetStorageNamespace(int64 id);
// Add a WebStorageNamespace or WebStorageArea and get a new unique ID for
// it. Only call on the WebKit thread.
int64 AddStorageArea(WebKit::WebStorageArea* new_storage_area);
int64 AddStorageNamespace(WebKit::WebStorageNamespace* new_namespace);
// Get the path to the LocalStorage directory. Calculate it if we haven't
// already. Only call on the WebKit thread.
WebKit::WebString GetLocalStoragePath();
// A shortcut for accessing our context.
DOMStorageContext* Context() {
DCHECK(!shutdown_);
return webkit_context_->GetDOMStorageContext();
}
// Data shared between renderer processes with the same profile.
scoped_refptr<WebKitContext> webkit_context_;
......@@ -81,22 +68,6 @@ class DOMStorageDispatcherHost :
// Only set on the IO thread.
IPC::Message::Sender* message_sender_;
// The last used storage_area_id and storage_namespace_id's. Only use on the
// WebKit thread.
int64 last_storage_area_id_;
int64 last_storage_namespace_id_;
// Used to maintain a mapping between storage_area_id's used in IPC messages
// and the actual WebStorageArea instances. Only use on the WebKit thread.
typedef base::hash_map<int64, WebKit::WebStorageArea*> StorageAreaMap;
StorageAreaMap storage_area_map_;
// Mapping between storage_namespace_id's used in IPC messages and the
// WebStorageNamespace instances. Only use on the WebKit thread.
typedef base::hash_map<int64, WebKit::WebStorageNamespace*>
StorageNamespaceMap;
StorageNamespaceMap storage_namespace_map_;
// Has this dispatcher ever handled a message. If not, then we can skip
// the entire shutdown procedure. This is only set to true on the IO thread
// and must be true if we're reading it on the WebKit thread.
......
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#include "chrome/browser/in_process_webkit/storage_area.h"
#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
#include "webkit/api/public/WebStorageArea.h"
#include "webkit/api/public/WebString.h"
using WebKit::WebStorageArea;
StorageArea::StorageArea(const string16& origin, WebStorageArea* storage_area,
int64 id)
: origin_(origin),
storage_area_(storage_area),
id_(id) {
}
StorageArea::~StorageArea() {
}
unsigned StorageArea::Length() {
return storage_area_->length();
}
NullableString16 StorageArea::Key(unsigned index) {
return storage_area_->key(index);
}
NullableString16 StorageArea::GetItem(const string16& key) {
return storage_area_->getItem(key);
}
void StorageArea::SetItem(const string16& key, const string16& value,
bool* quota_exception) {
storage_area_->setItem(key, value, *quota_exception);
}
void StorageArea::RemoveItem(const string16& key) {
storage_area_->removeItem(key);
}
void StorageArea::Clear() {
storage_area_->clear();
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_STORAGE_AREA_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_STORAGE_AREA_H_
#include "base/hash_tables.h"
#include "base/nullable_string16.h"
namespace WebKit {
class WebStorageArea;
}
// Only use on the WebKit thread. StorageNamespace manages our registration
// with DOMStorageContext.
class StorageArea {
public:
StorageArea(const string16& origin, WebKit::WebStorageArea* storage_area,
int64 id);
~StorageArea();
unsigned Length();
NullableString16 Key(unsigned index);
NullableString16 GetItem(const string16& key);
void SetItem(const string16& key, const string16& value,
bool* quota_xception);
void RemoveItem(const string16& key);
void Clear();
int64 id() const { return id_; }
private:
// The origin this storage area represents.
string16 origin_;
// The storage area we wrap.
WebKit::WebStorageArea* storage_area_;
// Our storage area id. Unique to our parent WebKitContext.
int64 id_;
DISALLOW_IMPLICIT_CONSTRUCTORS(StorageArea);
};
#if defined(COMPILER_GCC)
namespace __gnu_cxx {
template<>
struct hash<StorageArea*> {
std::size_t operator()(StorageArea* const& p) const {
return reinterpret_cast<std::size_t>(p);
}
};
} // namespace __gnu_cxx
#endif
#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_STORAGE_AREA_H_
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#include "chrome/browser/in_process_webkit/storage_namespace.h"
#include "base/file_path.h"
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
#include "chrome/browser/in_process_webkit/storage_area.h"
#include "webkit/api/public/WebStorageArea.h"
#include "webkit/api/public/WebStorageNamespace.h"
#include "webkit/api/public/WebString.h"
#include "webkit/glue/webkit_glue.h"
using WebKit::WebStorageArea;
using WebKit::WebStorageNamespace;
using WebKit::WebString;
/* static */
StorageNamespace* StorageNamespace::CreateLocalStorageNamespace(
DOMStorageContext* dom_storage_context, const FilePath& dir_path) {
int64 id = dom_storage_context->kLocalStorageNamespaceId;
DCHECK(!dom_storage_context->GetStorageNamespace(id));
WebString path = webkit_glue::FilePathToWebString(dir_path);
WebStorageNamespace* web_storage_namespace =
WebStorageNamespace::createLocalStorageNamespace(path);
return new StorageNamespace(dom_storage_context, web_storage_namespace, id,
true);
}
/* static */
StorageNamespace* StorageNamespace::CreateSessionStorageNamespace(
DOMStorageContext* dom_storage_context) {
int64 id = dom_storage_context->AllocateStorageNamespaceId();
DCHECK(!dom_storage_context->GetStorageNamespace(id));
WebStorageNamespace* web_storage_namespace =
WebStorageNamespace::createSessionStorageNamespace();
return new StorageNamespace(dom_storage_context, web_storage_namespace, id,
false);
}
StorageNamespace::StorageNamespace(DOMStorageContext* dom_storage_context,
WebStorageNamespace* storage_namespace,
int64 id, bool is_local_storage)
: dom_storage_context_(dom_storage_context),
storage_namespace_(storage_namespace),
id_(id),
is_local_storage_(is_local_storage) {
DCHECK(dom_storage_context_);
DCHECK(storage_namespace_);
dom_storage_context_->RegisterStorageNamespace(this);
}
StorageNamespace::~StorageNamespace() {
dom_storage_context_->UnregisterStorageNamespace(this);
OriginToStorageAreaMap::iterator iter = origin_to_storage_area_.begin();
OriginToStorageAreaMap::iterator end = origin_to_storage_area_.end();
while (iter != end) {
dom_storage_context_->UnregisterStorageArea(iter->second);
delete iter->second;
++iter;
}
}
StorageArea* StorageNamespace::GetStorageArea(const string16& origin) {
// We may have already created it for another dispatcher host.
OriginToStorageAreaMap::iterator iter = origin_to_storage_area_.find(origin);
if (iter != origin_to_storage_area_.end())
return iter->second;
// We need to create a new one.
int64 id = dom_storage_context_->AllocateStorageAreaId();
DCHECK(!dom_storage_context_->GetStorageArea(id));
WebStorageArea* web_storage_area =
storage_namespace_->createStorageArea(origin);
StorageArea* storage_area = new StorageArea(origin, web_storage_area, id);
origin_to_storage_area_[origin] = storage_area;
dom_storage_context_->RegisterStorageArea(storage_area);
return storage_area;
}
StorageNamespace* StorageNamespace::Copy() {
DCHECK(!is_local_storage_);
int64 id = dom_storage_context_->AllocateStorageNamespaceId();
DCHECK(!dom_storage_context_->GetStorageNamespace(id));
WebStorageNamespace* new_storage_namespace = storage_namespace_->copy();
return new StorageNamespace(dom_storage_context_, new_storage_namespace, id,
is_local_storage_);
}
void StorageNamespace::Close() {
storage_namespace_->close();
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_STORAGE_NAMESPACE_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_STORAGE_NAMESPACE_H_
#include "base/string16.h"
#include "base/hash_tables.h"
class DOMStorageContext;
class FilePath;
class StorageArea;
namespace WebKit {
class WebStorageNamespace;
}
// Only to be used on the WebKit thread.
class StorageNamespace {
public:
static StorageNamespace* CreateLocalStorageNamespace(
DOMStorageContext* dom_storage_context, const FilePath& data_dir_path);
static StorageNamespace* CreateSessionStorageNamespace(
DOMStorageContext* dom_storage_context);
~StorageNamespace();
StorageArea* GetStorageArea(const string16& origin);
StorageNamespace* Copy();
void Close();
int64 id() const { return id_; }
private:
// Called by the static factory methods above.
StorageNamespace(DOMStorageContext* dom_storage_context,
WebKit::WebStorageNamespace* web_storage_namespace,
int64 id, bool is_local_storage);
// All the storage areas we own.
typedef base::hash_map<string16, StorageArea*> OriginToStorageAreaMap;
OriginToStorageAreaMap origin_to_storage_area_;
// The DOMStorageContext that owns us.
DOMStorageContext* dom_storage_context_;
// The WebKit storage namespace we manage.
WebKit::WebStorageNamespace* storage_namespace_;
// Our id. Unique to our parent WebKitContext class.
int64 id_;
// Is this a local storage namespace.
bool is_local_storage_;
DISALLOW_IMPLICIT_CONSTRUCTORS(StorageNamespace);
};
#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_STORAGE_NAMESPACE_H_
......@@ -4,10 +4,29 @@
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
WebKitContext::WebKitContext(const FilePath& data_path, bool is_incognito)
: data_path_(data_path),
is_incognito_(is_incognito) {
}
WebKitContext::~WebKitContext() {
// If a dom storage context was ever created, we need to destroy it on the
// WebKit thread. Luckily we're guaranteed that the WebKit thread is still
// alive since the ResourceDispatcherHost (which owns the WebKit thread) goes
// away after all the ResourceMessageFilters and the profiles (i.e. all the
// objects with a reference to us).
if (dom_storage_context_.get()) {
MessageLoop* loop = ChromeThread::GetMessageLoop(ChromeThread::WEBKIT);
loop->DeleteSoon(FROM_HERE, dom_storage_context_.release());
}
}
DOMStorageContext* WebKitContext::GetDOMStorageContext() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
if (!dom_storage_context_.get())
dom_storage_context_.reset(new DOMStorageContext(this));
return dom_storage_context_.get();
}
......@@ -7,6 +7,9 @@
#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
class DOMStorageContext;
// There's one WebKitContext per profile. Various DispatcherHost classes
// have a pointer to the Context to store shared state.
......@@ -17,12 +20,19 @@ class WebKitContext : public base::RefCountedThreadSafe<WebKitContext> {
const FilePath& data_path() const { return data_path_; }
bool is_incognito() const { return is_incognito_; }
// Initialized lazily. Pointer is valid for the lifetime of this instance.
DOMStorageContext* GetDOMStorageContext();
private:
friend class base::RefCountedThreadSafe<WebKitContext>;
~WebKitContext();
FilePath data_path_;
bool is_incognito_;
// Copies of profile data that can be accessed on any thread.
const FilePath data_path_;
const bool is_incognito_;
// The state for DOM Storage.
scoped_ptr<DOMStorageContext> dom_storage_context_;
DISALLOW_IMPLICIT_CONSTRUCTORS(WebKitContext);
};
......
......@@ -27,8 +27,6 @@ void WebKitThread::Shutdown() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
DCHECK(io_message_loop_);
// TODO(jorlow): Start flushing LocalStorage?
AutoLock lock(io_message_loop_lock_);
io_message_loop_ = NULL;
}
......@@ -48,24 +46,23 @@ bool WebKitThread::PostIOThreadTask(
}
WebKitThread::InternalWebKitThread::InternalWebKitThread()
: ChromeThread(ChromeThread::WEBKIT),
webkit_client_(NULL) {
: ChromeThread(ChromeThread::WEBKIT) {
}
WebKitThread::InternalWebKitThread::~InternalWebKitThread() {
}
void WebKitThread::InternalWebKitThread::Init() {
DCHECK(!webkit_client_);
webkit_client_ = new BrowserWebKitClientImpl;
DCHECK(webkit_client_);
WebKit::initialize(webkit_client_);
DCHECK(!webkit_client_.get());
webkit_client_.reset(new BrowserWebKitClientImpl);
WebKit::initialize(webkit_client_.get());
// If possible, post initialization tasks to this thread (rather than doing
// them now) so we don't block the IO thread any longer than we have to.
}
void WebKitThread::InternalWebKitThread::CleanUp() {
// TODO(jorlow): Block on LocalStorage being 100% shut down.
DCHECK(webkit_client_);
DCHECK(webkit_client_.get());
WebKit::shutdown();
delete webkit_client_;
}
MessageLoop* WebKitThread::InitializeThread() {
......
......@@ -49,14 +49,15 @@ class WebKitThread {
class InternalWebKitThread : public ChromeThread {
public:
InternalWebKitThread();
virtual ~InternalWebKitThread() { }
virtual ~InternalWebKitThread();
// Does the actual initialization and shutdown of WebKit. Called at the
// beginning and end of the thread's lifetime.
virtual void Init();
virtual void CleanUp();
private:
BrowserWebKitClientImpl* webkit_client_;
// The WebKitClient implementation. Only access on WebKit thread.
scoped_ptr<BrowserWebKitClientImpl> webkit_client_;
};
// Returns the WebKit thread's message loop or NULL if we're in
......
......@@ -1471,8 +1471,14 @@
'browser/importer/toolbar_importer.h',
'browser/in_process_webkit/browser_webkitclient_impl.cc',
'browser/in_process_webkit/browser_webkitclient_impl.h',
'browser/in_process_webkit/dom_storage_context.cc',
'browser/in_process_webkit/dom_storage_context.h',
'browser/in_process_webkit/dom_storage_dispatcher_host.cc',
'browser/in_process_webkit/dom_storage_dispatcher_host.h',
'browser/in_process_webkit/storage_area.cc',
'browser/in_process_webkit/storage_area.h',
'browser/in_process_webkit/storage_namespace.cc',
'browser/in_process_webkit/storage_namespace.h',
'browser/in_process_webkit/webkit_context.cc',
'browser/in_process_webkit/webkit_context.h',
'browser/in_process_webkit/webkit_thread.cc',
......
......@@ -273,6 +273,14 @@ WebString FilePathStringToWebString(const FilePath::StringType& str) {
#endif
}
FilePath WebStringToFilePath(const WebKit::WebString& str) {
return FilePath(WebStringToFilePathString(str));
}
WebKit::WebString FilePathToWebString(const FilePath& file_path) {
return FilePathStringToWebString(file_path.value());
}
std::string GetWebKitVersion() {
return StringPrintf("%d.%d", WEBKIT_VERSION_MAJOR, WEBKIT_VERSION_MINOR);
}
......
......@@ -108,6 +108,8 @@ bool ShouldForcefullyTerminatePluginProcess();
// File path string conversions.
FilePath::StringType WebStringToFilePathString(const WebKit::WebString& str);
WebKit::WebString FilePathStringToWebString(const FilePath::StringType& str);
FilePath WebStringToFilePath(const WebKit::WebString& str);
WebKit::WebString FilePathToWebString(const FilePath& file_path);
// Returns a WebCanvas pointer associated with the given Skia canvas.
WebKit::WebCanvas* ToWebCanvas(skia::PlatformCanvas*);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment