Commit 1ef223dc authored by zimmermann@webkit.org's avatar zimmermann@webkit.org

[WML] History handling / page cache / loading is buggy and depends on several hacks

https://bugs.webkit.org/show_bug.cgi?id=27707

Redesign WML history/loading handling. See ChangeLog for details.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@46418 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d6968980
2009-07-27 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
Reviewed by George Staikos.
[WML] History handling / page cache / loading is buggy and depends on several hacks
https://bugs.webkit.org/show_bug.cgi?id=27707
Add two new WML layout tests after redesigning WML history/loading handling.
* wml/enter-card-with-events-expected.txt: Added.
* wml/enter-card-with-events.html: Added.
* wml/enter-first-card-with-events-expected.txt: Added.
* wml/enter-first-card-with-events.html: Added.
* wml/resources/WMLTestCase.js:
* wml/resources/enter-card-with-events.js: Added.
(setupTestDocument):
(prepareTest):
(executeTest):
* wml/resources/enter-card-with-events.wml: Added.
* wml/resources/enter-first-card-with-events.js: Added.
(setupTestDocument):
(prepareTest):
(executeTest):
* wml/resources/enter-first-card-with-events.wml: Added.
2009-07-27 Jan Michael Alonzo <jmalonzo@webkit.org>
Add fast/canvas/image-pattern-rotate.html to Skipped as it needs
......
WML layout tests - using XHTML scripting
Tests entering cards in forward and backward directions that have intrinsic events set
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS successfullyParsed is true
TEST COMPLETE
--------
Frame: '<!--framePath //<!--frame0-->-->'
--------
Test 2/2 PASSED.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="../fast/js/resources/js-test-style.css">
<script>var relativePathToLayoutTests = "..";</script>
<script src="resources/WMLTestCase.js"></script>
<script src="../fast/js/resources/js-test-pre.js"></script>
</head>
<body>
<h1>WML layout tests - using XHTML scripting</h1>
<p id="description"></p>
<div id="console"></div>
<script src="resources/enter-card-with-events.js"></script>
</body>
</html>
WML layout tests - using XHTML scripting
Tests entering first card backwards that has intrinsic events set
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS successfullyParsed is true
TEST COMPLETE
--------
Frame: '<!--framePath //<!--frame0-->-->'
--------
Test 2/2 PASSED.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="../fast/js/resources/js-test-style.css">
<script>var relativePathToLayoutTests = "..";</script>
<script src="resources/WMLTestCase.js"></script>
<script src="../fast/js/resources/js-test-pre.js"></script>
</head>
<body>
<h1>WML layout tests - using XHTML scripting</h1>
<p id="description"></p>
<div id="console"></div>
<script src="resources/enter-first-card-with-events.js"></script>
</body>
</html>
......@@ -9,7 +9,7 @@ function createWMLElement(name) {
return testDocument.createElementNS(wmlNS, "wml:" + name);
}
function createWMLTestCase(testDescription, substitutesVariables, testName, executeImmediately) {
function createWMLTestCase(testDescription, substitutesVariables, testName, executeImmediately, needsReset) {
// Setup default test options
if (substitutesVariables == null) {
substitutesVariables = true;
......@@ -23,12 +23,18 @@ function createWMLTestCase(testDescription, substitutesVariables, testName, exec
executeImmediately = true;
}
// Some tests may want to handle resetting the page state themselves
if (needsReset == null) {
needsReset = true;
}
// Initialize JS test
description(testDescription);
bodyElement = document.getElementsByTagName("body")[0];
// Clear variable state & history
document.resetWMLPageState();
if (needsReset)
document.resetWMLPageState();
// Setup DRT specific settings
if (window.layoutTestController) {
......
/// [Name] enter-card-with-events.js
createWMLTestCase("Tests entering cards in forward and backward directions that have intrinsic events set", false, "resources/enter-card-with-events.wml", false);
var ranOnce = false;
function setupTestDocument() {
// no-op
}
function prepareTest() {
startTest(25, 15);
}
function executeTest() {
if (ranOnce)
completeTest();
else {
ranOnce = true;
startTest(25, 15);
}
}
var successfullyParsed = true;
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "http://www.wapforum.org/DTD/wml13.dtd">
<wml>
<card id="card1">
<a href="#card2">Next Card</a>
</card>
<card id="card2" onenterbackward="#card4">
<onevent type="onenterforward">
<go href="#card3"/>
</onevent>
Test FAILED. (This card is NEVER visible to the user)
</card>
<card id="card3">
<anchor>
<prev/>
Next Test
</anchor>
Test 1/2 PASSED.
</card>
<card id="card4">
Test 2/2 PASSED.
</card>
</wml>
/// [Name] enter-first-card-with-events.js
createWMLTestCase("Tests entering first card backwards that has intrinsic events set", false, "resources/enter-first-card-with-events.wml", false, false);
var ranOnce = false;
var resultIndicatorElement;
function setupTestDocument() {
resultIndicatorElement = testDocument.getElementById("resultIndicator");
}
function prepareTest() {
if (resultIndicatorElement.textContent == "DONE")
completeTest();
else
executeTest();
}
function executeTest() {
startTest(25, 15);
}
var successfullyParsed = true;
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "http://www.wapforum.org/DTD/wml13.dtd">
<wml>
<card id="card1">
<onevent type="onenterbackward">
<go href="#card3">
<setvar name="result" value="DONE"/>
</go>
</onevent>
<a href="#card2">Next Test</a>
</card>
<card id="card2">
<anchor>
<prev/>
Next Test
</anchor>
Test 1/2 PASSED.
</card>
<card id="card3">
Test 2/2 PASSED.
<p style="display: none" id="resultIndicator">$result</p>
</card>
</wml>
2009-07-27 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
Reviewed by George Staikos.
[WML] History handling / page cache / loading is buggy and depends on several hacks
https://bugs.webkit.org/show_bug.cgi?id=27707
Redesign WML history/loading handling. In detail:
- Remove FrameLoader::setForceReloadWmlDeck(). WML used to force a special loading behaviour
by calling this method from WMLGoElement & friends - instead teach FrameLoader to detect
WML content itself.
WML content is usually a standalone WML document (isWMLDocument()=true) or as special case
an XHTML document which embeds a WML document (that's the way the WML layout tests work).
Force WML loading behaviour even for XHTML document which embed WML documents. This only
applies to our layout tests, not for any real world site. Though it gives us a perfect
way to test the WML loading code even when we're not operating on a standalone WML document.
Whenever a WMLCardElement is inserted into the document it will check wheter it's inserted
in a standalone WML document or wheter the main frame document is different. If it differs
the main frame documents' "containsWMLContent" property is set to true.
-> Make FrameLoader::shouldReload() use the new frameContainsWMLContent() method, which
checks if the associated frame document is a WML document or wheter it contains WML content.
- Change FrameLoader::loadItem() to use the new frameContainsWMLContent() method for 'shouldScroll'
detection. WML documents (or those containing WML content) always want new loads even for in-page
navigation. No "scroll to anchor" mechanism should apply.
- Modify FrameLoader::canCachePageContainingThisFrame() to check for !frameContainsWMLContent().
WML pages should never be cached, potential security problem due the use of variables (per spec).
Add two new WML tests which were broken before, testing onenterforward/onenterbackward event handling
and history navigation (<prev/> task).
Tests: wml/enter-card-with-events.html
wml/enter-first-card-with-events.html
* dom/Document.cpp: Initialize new 'm_containsWMLContent' property.
(WebCore::Document::Document):
* dom/Document.h: Add new helper methods and 'm_containsWMLContent" variable (explained above).
(WebCore::Document::setContainsWMLContent):
(WebCore::Document::containsWMLContent):
* history/BackForwardList.cpp:
(WebCore::BackForwardList::clearWMLPageHistory): Renamed from clearWmlPageHistory() & slight cleanup.
* history/BackForwardList.h:
* loader/FrameLoader.cpp: Rework WML loading behaviour (explained above).
(WebCore::FrameLoader::FrameLoader):
(WebCore::frameContainsWMLContent):
(WebCore::FrameLoader::canCachePageContainingThisFrame):
(WebCore::FrameLoader::shouldReload):
(WebCore::FrameLoader::loadItem):
* loader/FrameLoader.h:
* wml/WMLCardElement.cpp:
(WebCore::WMLCardElement::handleIntrinsicEventIfNeeded): No need anymore to manually track history length.
(WebCore::WMLCardElement::insertedIntoDocument): Handle setting containsWMLContent on the main frame document.
* wml/WMLGoElement.cpp:
(WebCore::WMLGoElement::executeTask): Remove call to FrameLoader::setForceReloadWmlDeck()
* wml/WMLPageState.cpp: Remove 'm_historyLength' - no need anymore to track history length on our own.
(WebCore::WMLPageState::WMLPageState):
(WebCore::WMLPageState::dump):
(WebCore::WMLPageState::reset):
* wml/WMLPageState.h:
2009-07-27 Pavel Feldman <pfeldman@chromium.org>
Reviewed by Adam Roben.
......
......@@ -335,6 +335,9 @@ Document::Document(Frame* frame, bool isXHTML)
, m_hasOpenDatabases(false)
#endif
, m_usingGeolocation(false)
#if ENABLE(WML)
, m_containsWMLContent(false)
#endif
{
m_document.resetSkippingRef(this);
......
......@@ -1034,6 +1034,9 @@ public:
bool usingGeolocation() const { return m_usingGeolocation; };
#if ENABLE(WML)
void setContainsWMLContent(bool value) { m_containsWMLContent = value; }
bool containsWMLContent() const { return m_containsWMLContent; }
void resetWMLPageState();
void initializeWMLPageState();
#endif
......@@ -1116,6 +1119,10 @@ private:
#endif
bool m_usingGeolocation;
#if ENABLE(WML)
bool m_containsWMLContent;
#endif
};
inline bool Document::hasElementWithId(AtomicStringImpl* id) const
......
......@@ -266,11 +266,10 @@ bool BackForwardList::containsItem(HistoryItem* entry)
}
#if ENABLE(WML)
void BackForwardList::clearWmlPageHistory()
void BackForwardList::clearWMLPageHistory()
{
PassRefPtr<HistoryItem> cur = currentItem();
for (unsigned i = 0; i < m_entries.size(); ++i)
int size = m_entries.size();
for (int i = 0; i < size; ++i)
pageCache()->remove(m_entries[i].get());
m_entries.clear();
......
......@@ -97,7 +97,7 @@ public:
HistoryItemVector& entries();
#if ENABLE(WML)
void clearWmlPageHistory();
void clearWMLPageHistory();
#endif
private:
......
......@@ -271,9 +271,6 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
#ifndef NDEBUG
, m_didDispatchDidCommitLoad(false)
#endif
#if ENABLE(WML)
, m_forceReloadWmlDeck(false)
#endif
{
}
......@@ -1783,6 +1780,17 @@ void FrameLoader::addData(const char* bytes, int length)
write(bytes, length);
}
#if ENABLE(WML)
static inline bool frameContainsWMLContent(Frame* frame)
{
Document* document = frame ? frame->document() : 0;
if (!document)
return false;
return document->containsWMLContent() || document->isWMLDocument();
}
#endif
bool FrameLoader::canCachePageContainingThisFrame()
{
return m_documentLoader
......@@ -1810,6 +1818,9 @@ bool FrameLoader::canCachePageContainingThisFrame()
// application cache. <rdar://problem/5917899> tracks that work.
&& !m_documentLoader->applicationCache()
&& !m_documentLoader->candidateApplicationCacheGroup()
#endif
#if ENABLE(WML)
&& !frameContainsWMLContent(m_frame)
#endif
&& m_client->canCachePage()
;
......@@ -2963,18 +2974,11 @@ void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD
m_quickRedirectComing = lockBackForwardList && m_documentLoader && !m_isExecutingJavaScriptFormAction;
}
#if ENABLE(WML)
void FrameLoader::setForceReloadWmlDeck(bool reload)
{
m_forceReloadWmlDeck = reload;
}
#endif
bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
{
#if ENABLE(WML)
// As for WML deck, sometimes it's supposed to be reloaded even if the same URL with fragment
if (m_forceReloadWmlDeck)
// All WML decks are supposed to be reloaded, even within the same URL fragment
if (frameContainsWMLContent(m_frame))
return true;
#endif
......@@ -4429,7 +4433,8 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
bool shouldScroll = !formData && !(m_currentHistoryItem && m_currentHistoryItem->formData()) && urlsMatchItem(item);
#if ENABLE(WML)
if (m_frame->document()->isWMLDocument())
// All WML decks should go through the real load mechanism, not the scroll-to-anchor code
if (frameContainsWMLContent(m_frame))
shouldScroll = false;
#endif
......
/*
* Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -236,10 +236,6 @@ namespace WebCore {
void didFirstVisuallyNonEmptyLayout();
#if ENABLE(WML)
void setForceReloadWmlDeck(bool);
#endif
void loadedResourceFromMemoryCache(const CachedResource*);
void tellClientAboutPastMemoryCacheLoads();
......@@ -625,10 +621,6 @@ namespace WebCore {
#ifndef NDEBUG
bool m_didDispatchDidCommitLoad;
#endif
#if ENABLE(WML)
bool m_forceReloadWmlDeck;
#endif
};
} // namespace WebCore
......
......@@ -28,6 +28,7 @@
#include "HTMLNames.h"
#include "MappedAttribute.h"
#include "NodeList.h"
#include "Page.h"
#include "RenderStyle.h"
#include "WMLDocument.h"
#include "WMLDoElement.h"
......@@ -131,20 +132,21 @@ void WMLCardElement::handleIntrinsicEventIfNeeded()
FrameLoader* loader = frame->loader();
if (!loader)
return;
int currentHistoryLength = loader->getHistoryLength();
int lastHistoryLength = pageState->historyLength();
// Calculate the entry method of current card
WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown;
if (lastHistoryLength > currentHistoryLength)
switch (loader->loadType()) {
case FrameLoadTypeReload:
break;
case FrameLoadTypeBack:
eventType = WMLIntrinsicEventOnEnterBackward;
else if (lastHistoryLength < currentHistoryLength)
break;
default:
eventType = WMLIntrinsicEventOnEnterForward;
break;
}
// Synchronize history length with WMLPageState
pageState->setHistoryLength(currentHistoryLength);
// Figure out target event handler
WMLIntrinsicEventHandler* eventHandler = this->eventHandler();
bool hasIntrinsicEvent = false;
......@@ -241,13 +243,25 @@ void WMLCardElement::parseMappedAttribute(MappedAttribute* attr)
void WMLCardElement::insertedIntoDocument()
{
WMLElement::insertedIntoDocument();
Document* document = this->document();
// The first card inserted into a document, is visible by default.
if (!m_isVisible) {
RefPtr<NodeList> nodeList = document()->getElementsByTagName("card");
RefPtr<NodeList> nodeList = document->getElementsByTagName("card");
if (nodeList && nodeList->length() == 1 && nodeList->item(0) == this)
m_isVisible = true;
}
// For the WML layout tests we embed WML content in a XHTML document. Navigating to different cards
// within the same deck has a different behaviour in HTML than in WML. HTML wants to "scroll to anchor"
// (see FrameLoader) but WML wants a reload. Notify the root document of the layout test that we want
// to mimic WML behaviour. This is rather tricky, but has been tested extensively. Usually it's not possible
// at all to embed WML in HTML, it's not designed that way, we're just "abusing" it for dynamically created layout tests.
if (document->page() && document->page()->mainFrame()) {
Document* rootDocument = document->page()->mainFrame()->document();
if (rootDocument && rootDocument != document)
rootDocument->setContainsWMLContent(true);
}
}
RenderObject* WMLCardElement::createRenderer(RenderArena* arena, RenderStyle* style)
......
/**
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -102,9 +102,6 @@ void WMLGoElement::executeTask(Event*)
// FIXME: 'newcontext' handling not implemented for external cards
bool inSameDeck = doc->url().path() == url.path();
if (inSameDeck && url.hasRef()) {
// Force frame loader to load the URL with fragment identifier
loader->setForceReloadWmlDeck(true);
if (WMLCardElement* card = WMLCardElement::findNamedCardInDocument(doc, url.ref())) {
if (card->isNewContext())
pageState->reset();
......
/*
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2004-2007 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
......@@ -25,6 +24,7 @@
#if ENABLE(WML)
#include "WMLPageState.h"
#include "CString.h"
#include "HistoryItem.h"
#include "KURL.h"
#include "Page.h"
......@@ -33,7 +33,6 @@ namespace WebCore {
WMLPageState::WMLPageState(Page* page)
: m_page(page)
, m_historyLength(0)
, m_activeCard(0)
, m_hasDeckAccess(false)
{
......@@ -44,17 +43,27 @@ WMLPageState::~WMLPageState()
m_variables.clear();
}
#ifndef NDEBUG
// Debugging helper for use within gdb
void WMLPageState::dump()
{
WMLVariableMap::iterator it = m_variables.begin();
WMLVariableMap::iterator end = m_variables.end();
fprintf(stderr, "Dumping WMLPageState (this=%p) associated with Page (page=%p)...\n", this, m_page);
for (; it != end; ++it)
fprintf(stderr, "\t-> name: '%s'\tvalue: '%s'\n", (*it).first.latin1().data(), (*it).second.latin1().data());
}
#endif
void WMLPageState::reset()
{
// remove all the variables in the current browser context
// Remove all the variables
m_variables.clear();
// clear the navigation history state
if (m_page)
m_page->backForwardList()->clearWmlPageHistory();
// reset implementation-specfic state if UA has
m_historyLength = 0;
// Clear the navigation history state
if (BackForwardList* list = m_page ? m_page->backForwardList() : 0)
list->clearWMLPageHistory();
}
bool WMLPageState::setNeedCheckDeckAccess(bool need)
......
......@@ -39,6 +39,10 @@ public:
WMLPageState(Page*);
virtual ~WMLPageState();
#ifndef NDEBUG
void dump();
#endif
// reset the browser context when 'newcontext' attribute
// of card element is performed as part of go task
void reset();
......
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