| /* |
| * Copyright (C) 2011 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "JSPopStateEvent.h" |
| |
| #include "DOMWrapperWorld.h" |
| #include "JSHistory.h" |
| #include <JavaScriptCore/HeapInlines.h> |
| #include <JavaScriptCore/JSCJSValueInlines.h> |
| |
| namespace WebCore { |
| using namespace JSC; |
| |
| JSValue JSPopStateEvent::state(JSGlobalObject& lexicalGlobalObject) const |
| { |
| if (m_state) { |
| // We cannot use a cached object if we are in a different world than the one it was created in. |
| if (isWorldCompatible(lexicalGlobalObject, m_state.get())) |
| return m_state.get(); |
| ASSERT_NOT_REACHED(); |
| } |
| |
| // Save the lexicalGlobalObject value to the m_state member of a JSPopStateEvent, and return it, for convenience. |
| auto cacheState = [&lexicalGlobalObject, this] (JSC::JSValue eventState) { |
| m_state.set(lexicalGlobalObject.vm(), this, eventState); |
| return eventState; |
| }; |
| |
| PopStateEvent& event = wrapped(); |
| |
| if (JSC::JSValue eventState = event.state()) { |
| // We need to make sure a PopStateEvent does not leak objects in its lexicalGlobalObject property across isolated DOM worlds. |
| // Ideally, we would check that the worlds have different privileges but that's not possible yet. |
| if (!isWorldCompatible(lexicalGlobalObject, eventState)) { |
| if (auto serializedValue = event.trySerializeState(lexicalGlobalObject)) |
| eventState = serializedValue->deserialize(lexicalGlobalObject, globalObject()); |
| else |
| eventState = jsNull(); |
| } |
| return cacheState(eventState); |
| } |
| |
| History* history = event.history(); |
| if (!history || !event.serializedState()) |
| return cacheState(jsNull()); |
| |
| // There's no cached value from a previous invocation, nor a lexicalGlobalObject value was provided by the |
| // event, but there is a history object, so first we need to see if the lexicalGlobalObject object has been |
| // deserialized through the history object already. |
| // The current history lexicalGlobalObject object might've changed in the meantime, so we need to take care |
| // of using the correct one, and always share the same deserialization with history.lexicalGlobalObject. |
| |
| bool isSameState = history->isSameAsCurrentState(event.serializedState()); |
| JSValue result; |
| |
| if (isSameState) { |
| JSHistory* jsHistory = jsCast<JSHistory*>(toJS(&lexicalGlobalObject, globalObject(), *history).asCell()); |
| result = jsHistory->state(lexicalGlobalObject); |
| } else |
| result = event.serializedState()->deserialize(lexicalGlobalObject, globalObject()); |
| |
| return cacheState(result); |
| } |
| |
| void JSPopStateEvent::visitAdditionalChildren(JSC::SlotVisitor& visitor) |
| { |
| wrapped().state().visit(visitor); |
| } |
| |
| } // namespace WebCore |