diff options
Diffstat (limited to 'chrome/renderer/renderer_webstoragearea_impl.cc')
-rw-r--r-- | chrome/renderer/renderer_webstoragearea_impl.cc | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/chrome/renderer/renderer_webstoragearea_impl.cc b/chrome/renderer/renderer_webstoragearea_impl.cc new file mode 100644 index 0000000..c438cdfe --- /dev/null +++ b/chrome/renderer/renderer_webstoragearea_impl.cc @@ -0,0 +1,171 @@ +// 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/renderer/renderer_webstoragearea_impl.h" + +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "webkit/api/public/WebString.h" + +RendererWebStorageAreaImpl::RendererWebStorageAreaImpl( + int64 namespace_id, + const WebKit::WebString& origin) + : namespace_id_(namespace_id), + origin_(origin), + storage_area_id_(kUninitializedStorageAreaId), + lock_held_(false), + bytes_left_in_quota_(0) { +} + +RendererWebStorageAreaImpl::~RendererWebStorageAreaImpl() { +} + +void RendererWebStorageAreaImpl::lock(bool& invalidate_cache, + size_t& bytes_left_in_quota) { + EnsureInitializedAndLocked(); +} + +void RendererWebStorageAreaImpl::unlock() { + if (storage_area_id_ != kUninitializedStorageAreaId) { + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageUnlock(storage_area_id_)); + } + lock_held_ = false; +} + +unsigned RendererWebStorageAreaImpl::length() { + EnsureInitializedAndLocked(); + // Right now this is always sync. We could cache it, but I can't think of + // too many use cases where you'd repeatedly look up length() and not be + // doing so many key() lookups that the length() calls are the problem. + unsigned length; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageLength(storage_area_id_, &length)); + return length; +} + +WebKit::WebString RendererWebStorageAreaImpl::key(unsigned index, + bool& key_exception) { + EnsureInitializedAndLocked(); + // Right now this is always sync. We may want to optimize this by fetching + // chunks of keys rather than single keys (and flushing the cache on every + // mutation of the storage area) since this will most often be used to fetch + // all the keys at once. + string16 key; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageKey(storage_area_id_, index, + &key_exception, &key)); + return key; +} + +WebKit::WebString RendererWebStorageAreaImpl::getItem( + const WebKit::WebString& webkit_key) { + EnsureInitializedAndLocked(); + string16 key = webkit_key; + + // Return from our cache if possible. + CacheMap::const_iterator iterator = cached_items_.find(key); + if (iterator != cached_items_.end()) + return iterator->second; + if (cached_invalid_items_.find(key) != cached_invalid_items_.end()) + return WebKit::WebString(); // Return a "null" string. + + // The item is not in the cache, so we must do a sync IPC. Afterwards, + // add it to the cache. + string16 raw_value; + bool value_is_null; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageGetItem(storage_area_id_, key, + &raw_value, &value_is_null)); + WebKit::WebString value = value_is_null ? WebKit::WebString() + : WebKit::WebString(raw_value); + SetCache(key, value); + return value; +} + +void RendererWebStorageAreaImpl::setItem(const WebKit::WebString& key, + const WebKit::WebString& value, + bool& quota_exception) { + EnsureInitializedAndLocked(); + quota_exception = !UpdateQuota(key, value); + if (quota_exception) + return; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageSetItem(storage_area_id_, key, value)); + SetCache(key, value); +} + +void RendererWebStorageAreaImpl::removeItem(const WebKit::WebString& key) { + EnsureInitializedAndLocked(); + bool update_succeeded = UpdateQuota(key, WebKit::WebString()); + DCHECK(update_succeeded); + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageRemoveItem(storage_area_id_, key)); + SetCache(key, WebKit::WebString()); +} + +void RendererWebStorageAreaImpl::clear() { + EnsureInitializedAndLocked(); + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageClear(storage_area_id_, + &bytes_left_in_quota_)); + // A possible optimization is a flag that says our cache is 100% complete. + // This could be set here, and then future gets would never require IPC. + cached_items_.clear(); + cached_invalid_items_.clear(); +} + +void RendererWebStorageAreaImpl::EnsureInitializedAndLocked() { + if (storage_area_id_ == kUninitializedStorageAreaId) { + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageStorageAreaId(namespace_id_, origin_, + &storage_area_id_)); + } + + if (lock_held_) + return; + + bool invalidate_cache; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageLock(storage_area_id_, &invalidate_cache, + &bytes_left_in_quota_)); + lock_held_ = true; + if (invalidate_cache) { + cached_items_.clear(); + cached_invalid_items_.clear(); + } +} + +bool RendererWebStorageAreaImpl::UpdateQuota(const WebKit::WebString& key, + const WebKit::WebString& value) { + // TODO(jorlow): Remove once the bytes_left_in_quota values we're getting + // are accurate. + return true; + + size_t existing_bytes = getItem(key).length(); + size_t new_bytes = value.length(); + + if (existing_bytes < new_bytes) { + size_t delta = new_bytes - existing_bytes; + if (delta > bytes_left_in_quota_) + return false; + bytes_left_in_quota_ -= delta; + } else { + size_t delta = existing_bytes - new_bytes; + DCHECK(delta + bytes_left_in_quota_ >= bytes_left_in_quota_); + bytes_left_in_quota_ += delta; + } + return true; +} + +void RendererWebStorageAreaImpl::SetCache(const string16& key, + const WebKit::WebString& value) { + cached_items_.erase(key); + cached_invalid_items_.erase(key); + + if (!value.isNull()) + cached_items_[key] = value; + else + cached_invalid_items_.insert(key); +} |