| Index: Source/WebKit/chromium/src/StorageAreaProxy.cpp
 | 
| ===================================================================
 | 
| --- Source/WebKit/chromium/src/StorageAreaProxy.cpp	(revision 117067)
 | 
| +++ Source/WebKit/chromium/src/StorageAreaProxy.cpp	(working copy)
 | 
| @@ -80,29 +80,42 @@
 | 
|      return String();
 | 
|  }
 | 
|  
 | 
| -void StorageAreaProxy::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
 | 
| +String StorageAreaProxy::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
 | 
|  {
 | 
| +    WebKit::WebStorageArea::Result result = WebKit::WebStorageArea::ResultOK;
 | 
| +    WebKit::WebString oldValue;
 | 
|      if (!canAccessStorage(frame))
 | 
|          ec = QUOTA_EXCEEDED_ERR;
 | 
|      else {
 | 
| -        WebKit::WebStorageArea::Result result = WebKit::WebStorageArea::ResultOK;
 | 
| -        m_storageArea->setItem(key, value, frame->document()->url(), result);
 | 
| +        m_storageArea->setItem(key, value, frame->document()->url(), result, oldValue);
 | 
|          ec = (result == WebKit::WebStorageArea::ResultOK) ? 0 : QUOTA_EXCEEDED_ERR;
 | 
| +        String oldValueString = oldValue;
 | 
| +        if (oldValueString != value && result == WebKit::WebStorageArea::ResultOK)
 | 
| +            storageEvent(key, oldValue, value, m_storageType, frame->document()->securityOrigin(), frame);
 | 
|      }
 | 
| +    return oldValue;
 | 
|  }
 | 
|  
 | 
| -void StorageAreaProxy::removeItem(const String& key, Frame* frame)
 | 
| +String StorageAreaProxy::removeItem(const String& key, Frame* frame)
 | 
|  {
 | 
|      if (!canAccessStorage(frame))
 | 
| -        return;
 | 
| -    m_storageArea->removeItem(key, frame->document()->url());
 | 
| +        return String();
 | 
| +    WebKit::WebString oldValue;
 | 
| +    m_storageArea->removeItem(key, frame->document()->url(), oldValue);
 | 
| +    if (!oldValue.isNull())
 | 
| +        storageEvent(key, oldValue, String(), m_storageType, frame->document()->securityOrigin(), frame);
 | 
| +    return oldValue;
 | 
|  }
 | 
|  
 | 
| -void StorageAreaProxy::clear(Frame* frame)
 | 
| +bool StorageAreaProxy::clear(Frame* frame)
 | 
|  {
 | 
|      if (!canAccessStorage(frame))
 | 
| -        return;
 | 
| -    m_storageArea->clear(frame->document()->url());
 | 
| +        return false;
 | 
| +    bool clearedSomething;
 | 
| +    m_storageArea->clear(frame->document()->url(), clearedSomething);
 | 
| +    if (clearedSomething)
 | 
| +        storageEvent(String(), String(), String(), m_storageType, frame->document()->securityOrigin(), frame);
 | 
| +    return clearedSomething;
 | 
|  }
 | 
|  
 | 
|  bool StorageAreaProxy::contains(const String& key, Frame* frame) const
 | 
| @@ -110,6 +123,54 @@
 | 
|      return !getItem(key, frame).isNull();
 | 
|  }
 | 
|  
 | 
| +// FIXME: remove this method and the calls to it from our setters after multi-side patch landing is done.
 | 
| +// Copied from WebCore/storage/StorageEventDispatcher.cpp out of necessity.  It's probably best to keep it current.
 | 
| +void StorageAreaProxy::storageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Frame* sourceFrame)
 | 
| +{
 | 
| +    Page* page = sourceFrame->page();
 | 
| +    if (!page)
 | 
| +        return;
 | 
| +
 | 
| +    // We need to copy all relevant frames from every page to a vector since sending the event to one frame might mutate the frame tree
 | 
| +    // of any given page in the group or mutate the page group itself.
 | 
| +    Vector<RefPtr<Frame> > frames;
 | 
| +    if (storageType == SessionStorage) {
 | 
| +        // Send events only to our page.
 | 
| +        for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
 | 
| +            if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
 | 
| +                frames.append(frame);
 | 
| +        }
 | 
| +
 | 
| +        for (unsigned i = 0; i < frames.size(); ++i) {
 | 
| +            // FIXME: maybe only raise if the window has an onstorage listener
 | 
| +            // attached to avoid creating the Storage instance.
 | 
| +            ExceptionCode ec = 0;
 | 
| +            Storage* storage = frames[i]->domWindow()->sessionStorage(ec);
 | 
| +            if (!ec)
 | 
| +                frames[i]->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
 | 
| +        }
 | 
| +    } else {
 | 
| +        // Send events to every page.
 | 
| +        const HashSet<Page*>& pages = page->group().pages();
 | 
| +        HashSet<Page*>::const_iterator end = pages.end();
 | 
| +        for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
 | 
| +            for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
 | 
| +                if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
 | 
| +                    frames.append(frame);
 | 
| +            }
 | 
| +        }
 | 
| +
 | 
| +        for (unsigned i = 0; i < frames.size(); ++i) {
 | 
| +            // FIXME: maybe only raise if the window has an onstorage listener
 | 
| +            // attached to avoid creating the Storage instance.
 | 
| +            ExceptionCode ec = 0;
 | 
| +            Storage* storage = frames[i]->domWindow()->localStorage(ec);
 | 
| +            if (!ec)
 | 
| +                frames[i]->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
 | 
| +        }
 | 
| +    }
 | 
| +}
 | 
| +
 | 
|  bool StorageAreaProxy::canAccessStorage(Frame* frame) const
 | 
|  {
 | 
|      if (!frame->page())
 | 
| @@ -119,10 +180,18 @@
 | 
|      return !webView->permissionClient() || webView->permissionClient()->allowStorage(webFrame, m_storageType == LocalStorage);
 | 
|  }
 | 
|  
 | 
| -void StorageAreaProxy::dispatchLocalStorageEvent(PageGroup* pageGroup, const String& key, const String& oldValue, const String& newValue,
 | 
| +void StorageAreaProxy::dispatchLocalStorageEvent(const String& pageGroupName, const String& key, const String& oldValue, const String& newValue,
 | 
|                                                   SecurityOrigin* securityOrigin, const KURL& pageURL, WebKit::WebStorageArea* sourceAreaInstance, bool originatedInProcess)
 | 
|  {
 | 
| -    const HashSet<Page*>& pages = pageGroup->pages();
 | 
| +    // FIXME: Multi-sided patch engineering alert !
 | 
| +    // step 1: this method gets defined and implemented in webkit/webcore with the early return.
 | 
| +    // step 2: this method starts getting called by chromium still with the early return.
 | 
| +    // step 3: This class's setters are modified to no longer raise SessionStorage
 | 
| +    //         events for inprocess changes and this early return is removed.
 | 
| +    if (originatedInProcess)
 | 
| +        return;
 | 
| +
 | 
| +    const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroupName)->pages();
 | 
|      for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
 | 
|          for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
 | 
|              if (frame->document()->securityOrigin()->equal(securityOrigin) && !isEventSource(frame->domWindow()->optionalLocalStorage(), sourceAreaInstance)) {
 | 
| @@ -136,9 +205,9 @@
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -static Page* findPageWithSessionStorageNamespace(PageGroup* pageGroup, const WebKit::WebStorageNamespace& sessionNamespace)
 | 
| +static Page* findPageWithSessionStorageNamespace(const String& pageGroupName, const WebKit::WebStorageNamespace& sessionNamespace)
 | 
|  {
 | 
| -    const HashSet<Page*>& pages = pageGroup->pages();
 | 
| +    const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroupName)->pages();
 | 
|      for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
 | 
|          const bool createIfNeeded = true;
 | 
|          StorageNamespaceProxy* proxy = static_cast<StorageNamespaceProxy*>((*it)->sessionStorage(createIfNeeded));
 | 
| @@ -148,11 +217,19 @@
 | 
|      return 0;
 | 
|  }
 | 
|  
 | 
| -void StorageAreaProxy::dispatchSessionStorageEvent(PageGroup* pageGroup, const String& key, const String& oldValue, const String& newValue,
 | 
| +void StorageAreaProxy::dispatchSessionStorageEvent(const String& pageGroupName, const String& key, const String& oldValue, const String& newValue,
 | 
|                                                     SecurityOrigin* securityOrigin, const KURL& pageURL, const WebKit::WebStorageNamespace& sessionNamespace,
 | 
|                                                     WebKit::WebStorageArea* sourceAreaInstance, bool originatedInProcess)
 | 
|  {
 | 
| -    Page* page = findPageWithSessionStorageNamespace(pageGroup, sessionNamespace);
 | 
| +    // FIXME: Multi-sided patch engineering alert !
 | 
| +    // step 1: this method gets defined and implemented in webkit/webcore with the early return.
 | 
| +    // step 2: this method starts getting called by chromium still with the early return.
 | 
| +    // step 3: This class's setters are modified to no longer raise SessionStorage
 | 
| +    //         events for inprocess changes and this early return is removed.
 | 
| +    if (originatedInProcess)
 | 
| +        return;
 | 
| +
 | 
| +    Page* page = findPageWithSessionStorageNamespace(pageGroupName, sessionNamespace);
 | 
|      if (!page)
 | 
|          return;
 | 
|  
 | 
| 
 |