WebCore:
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Jan 2008 08:48:16 +0000 (08:48 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Jan 2008 08:48:16 +0000 (08:48 +0000)
        Reviewed and tweaked quite a bit by Darin.

        Fix for http://bugs.webkit.org/show_bug.cgi?id=14959
        No back forward entry added for pages created in javascript

        A new HistoryItem is created for calls to Document::open. Calls to
        Document::write save the written data to a SharedBuffer that is also
        stored on the HistoryItem. When the user navigates back to a
        HistoryItem that has a valid buffer, that data is used for the page
        content.

        Tests: http/tests/navigation/document-open-adds-history-item.html
               http/tests/navigation/document-open-delayed-adds-history-item.html
               http/tests/navigation/document-open-new-window-adds-history-item.html
               http/tests/navigation/document-open-replace-no-history-item.html

        * bindings/js/JSHTMLDocumentCustom.cpp:
        (WebCore::JSHTMLDocument::open): Pass a MIME type of either "text/html" or
        "text/plain" and a boolean for "replace" in rather than always setting replace
        to true and the MIME type to "text/html".

        * dom/DOMImplementation.cpp:
        (WebCore::DOMImplementation::createHTMLDocument): Pass in MIME type and
        replace boolean explicitly, since we don't want to rely on Document::open()'s
        default.

        * dom/Document.cpp:
        (WebCore::Document::open): Correctly determine the "replace" boolean.
        Pass along the MIME type, replace boolean, and shared buffer to the
        frame loader's didExplicitOpen function.
        (WebCore::Document::write): Pass MIME type and replace boolean explicitly
        to the open function so we don't do treat it as replace if you write without
        an open. Store text written by the script so it can be used later for history.
        (WebCore::Document::clear): Drop the text written byt he script.

        * dom/Document.h: Added MIME type and replace boolean parameters for open.
        Had to keep the old version for the sake of DOM bindings. Added the shared
        buffer used for text written by script.

        * history/HistoryItem.cpp:
        (WebCore::HistoryItem::HistoryItem): Copy m_substituteData.
        (WebCore::HistoryItem::substituteData): Added.
        (WebCore::HistoryItem::setSubstituteData): Added.
        * history/HistoryItem.h: Added m_substituteData, getter, and setter.

        * loader/FrameLoader.cpp:
        (WebCore::FrameLoader::didExplicitOpen): Added code to create or update the
        history item, including attaching the shared buffer that will contain all
        the data written by script.
        (WebCore::FrameLoader::load): Added a SubstituteData parameter, passed through
        when creating the document loader.
        (WebCore::FrameLoader::reloadAllowingStaleData): Create the document loader
        with the substitute data from the current history item.
        (WebCore::FrameLoader::reload): Ditto.
        (WebCore::FrameLoader::shouldTreatURLAsSameAsCurrent): If the current history
        item has substitute data, then consider the URL from the substitute data
        rather than the one in the history item itself.
        (WebCore::FrameLoader::loadItem): Pass in the history item's substitute data.
        * loader/FrameLoader.h: Added parameters to load and didExplicitOpen.

        * platform/text/CharacterNames.h: Added byteOrderMark, and also added it under
        its other official name, zeroWidthNoBreakSpace.

        * xml/DOMParser.cpp:
        (WebCore::DOMParser::parseFromString): Pass in MIME type and replace boolean
        explicitly, since we don't want to rely on Document::open()'s default.
        * xml/XMLHttpRequest.cpp:
        (WebCore::XMLHttpRequest::getResponseXML): Ditto.
        * xml/XSLTProcessor.cpp:
        (WebCore::XSLTProcessor::createDocumentFromSource): Ditto.

LayoutTests:

        Reviewed by Darin.

        Test cases for fix to http://bugs.webkit.org/show_bug.cgi?id=14959
        No back forward entry added for pages created in javascript.

        * http/tests/navigation/document-open-adds-history-item-expected.txt: Added.
        * http/tests/navigation/document-open-adds-history-item.html: Added.
        * http/tests/navigation/document-open-delayed-adds-history-item-expected.txt: Added.
        * http/tests/navigation/document-open-delayed-adds-history-item.html: Added.
        * http/tests/navigation/document-open-new-window-adds-history-item-expected.txt: Added.
        * http/tests/navigation/document-open-new-window-adds-history-item.html: Added.
        * http/tests/navigation/document-open-replace-no-history-item-expected.txt: Added.
        * http/tests/navigation/document-open-replace-no-history-item.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29816 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/navigation/document-open-adds-history-item-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-adds-history-item.html [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-delayed-adds-history-item-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-delayed-adds-history-item.html [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-new-window-adds-history-item-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-new-window-adds-history-item.html [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-replace-no-history-item-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/navigation/document-open-replace-no-history-item.html [new file with mode: 0644]
LayoutTests/http/tests/navigation/resources/document-open-page-2.html [new file with mode: 0644]
LayoutTests/http/tests/navigation/resources/document-open.js [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/bindings/js/JSHTMLDocumentCustom.cpp
WebCore/dom/DOMImplementation.cpp
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/history/HistoryItem.cpp
WebCore/history/HistoryItem.h
WebCore/loader/FrameLoader.cpp
WebCore/loader/FrameLoader.h
WebCore/platform/text/CharacterNames.h
WebCore/xml/DOMParser.cpp
WebCore/xml/XMLHttpRequest.cpp
WebCore/xml/XSLTProcessor.cpp

index 5998feaa51e619c884783c252a5654b0b1cbd799..b27e53bfc43f132cbc4de4138d50c855de698691 100644 (file)
@@ -1,3 +1,19 @@
+2008-01-27  Matt Perry  <mpComplete@gmail.com>
+
+        Reviewed by Darin.
+
+        Test cases for fix to http://bugs.webkit.org/show_bug.cgi?id=14959
+        No back forward entry added for pages created in javascript.
+
+        * http/tests/navigation/document-open-adds-history-item-expected.txt: Added.
+        * http/tests/navigation/document-open-adds-history-item.html: Added.
+        * http/tests/navigation/document-open-delayed-adds-history-item-expected.txt: Added.
+        * http/tests/navigation/document-open-delayed-adds-history-item.html: Added.
+        * http/tests/navigation/document-open-new-window-adds-history-item-expected.txt: Added.
+        * http/tests/navigation/document-open-new-window-adds-history-item.html: Added.
+        * http/tests/navigation/document-open-replace-no-history-item-expected.txt: Added.
+        * http/tests/navigation/document-open-replace-no-history-item.html: Added.
+
 2008-01-26  Darin Adler  <darin@apple.com>
 
         Reviewed by Oliver.
@@ -3569,6 +3585,7 @@ to skip list since it is still failing on tiger.
         * platform/mac/svg/custom/foreignObject-crash-on-hover-expected.txt: Added.
         * svg/custom/foreignObject-crash-on-hover.xml: Added.
 
+>>>>>>> .r29342
 2007-12-21  Sam Weinig  <sam@webkit.org>
 
         Reviewed by Adele.
diff --git a/LayoutTests/http/tests/navigation/document-open-adds-history-item-expected.txt b/LayoutTests/http/tests/navigation/document-open-adds-history-item-expected.txt
new file mode 100644 (file)
index 0000000..5bfa065
--- /dev/null
@@ -0,0 +1,7 @@
+This generated document and its contents should be in the back/forward list.
+
+============== Back Forward List ==============
+        http://127.0.0.1:8000/navigation/document-open-adds-history-item.html  **nav target**
+curr->  http://127.0.0.1:8000/navigation/document-open-adds-history-item.html  **nav target**
+        http://127.0.0.1:8000/navigation/resources/document-open-page-2.html  **nav target**
+===============================================
diff --git a/LayoutTests/http/tests/navigation/document-open-adds-history-item.html b/LayoutTests/http/tests/navigation/document-open-adds-history-item.html
new file mode 100644 (file)
index 0000000..3619f3d
--- /dev/null
@@ -0,0 +1,20 @@
+<html>
+<head>
+<script src="resources/document-open.js"></script>
+<script>
+    function runTest()
+    {
+        window.firstVisit = true;
+        document.open();
+        document.writeln("<script>" + window.stopTest + "<" + "/script>");
+        document.writeln("<body onload='stopTest();'>");
+        document.writeln("This generated document and its contents should be in the back/forward list.");
+        document.writeln("</body>");
+        document.close();
+    }
+</script>
+</head>
+<body onload="startTest()">
+This tests that document.open creates a back/forward item.
+</body>
+</html>
diff --git a/LayoutTests/http/tests/navigation/document-open-delayed-adds-history-item-expected.txt b/LayoutTests/http/tests/navigation/document-open-delayed-adds-history-item-expected.txt
new file mode 100644 (file)
index 0000000..164e21f
--- /dev/null
@@ -0,0 +1,7 @@
+This generated document and its contents should be in the back/forward list... even with a delayed close.
+
+============== Back Forward List ==============
+        http://127.0.0.1:8000/navigation/document-open-delayed-adds-history-item.html  **nav target**
+curr->  http://127.0.0.1:8000/navigation/document-open-delayed-adds-history-item.html  **nav target**
+        http://127.0.0.1:8000/navigation/resources/document-open-page-2.html  **nav target**
+===============================================
diff --git a/LayoutTests/http/tests/navigation/document-open-delayed-adds-history-item.html b/LayoutTests/http/tests/navigation/document-open-delayed-adds-history-item.html
new file mode 100644 (file)
index 0000000..929820b
--- /dev/null
@@ -0,0 +1,26 @@
+<html>
+<head>
+<script src="resources/document-open.js"></script>
+<script>
+    function runTest()
+    {
+        window.firstVisit = true;
+        document.open();
+        document.writeln("<script>" + window.stopTest + "<" + "/script>");
+        document.writeln("<body onload='stopTest();'>");
+        document.writeln("This generated document and its contents should be in the back/forward list...");
+        setTimeout("runTest2();", 0);
+    }
+    function runTest2()
+    {
+        document.writeln("even with a delayed close.");
+        document.writeln("</body>");
+        document.close();
+    }
+</script>
+</head>
+<body onload="startTest()">
+This tests that document.open creates a back/forward item, and the page loads
+correctly even when writes are split across a timeout.
+</body>
+</html>
diff --git a/LayoutTests/http/tests/navigation/document-open-new-window-adds-history-item-expected.txt b/LayoutTests/http/tests/navigation/document-open-new-window-adds-history-item-expected.txt
new file mode 100644 (file)
index 0000000..660351c
--- /dev/null
@@ -0,0 +1,10 @@
+This tests that document.open in a new window creates a back/forward item.
+
+============== Back Forward List ==============
+curr->  http://127.0.0.1:8000/navigation/document-open-new-window-adds-history-item.html  **nav target**
+===============================================
+
+============== Back Forward List ==============
+curr->  about:blank  **nav target**
+        http://127.0.0.1:8000/navigation/resources/document-open-page-2.html  **nav target**
+===============================================
diff --git a/LayoutTests/http/tests/navigation/document-open-new-window-adds-history-item.html b/LayoutTests/http/tests/navigation/document-open-new-window-adds-history-item.html
new file mode 100644 (file)
index 0000000..d2b2953
--- /dev/null
@@ -0,0 +1,25 @@
+<html>
+<head>
+<script src="resources/document-open.js"></script>
+<script>
+    function runTest()
+    {
+        if (window.layoutTestController) {
+            layoutTestController.setCanOpenWindows();
+        }
+        w = window.open('');
+        w.firstVisit = true;
+        w.focus();
+        w.document.open();
+        w.document.writeln("<script>" + window.stopTest + "<" + "/script>");
+        w.document.writeln("<body onload='stopTest();'>");
+        w.document.writeln("This generated document and its contents should be in the back/forward list.");
+        w.document.writeln("</body>");
+        w.document.close();
+    }
+</script>
+</head>
+<body onload="startTest()">
+This tests that document.open in a new window creates a back/forward item.
+</body>
+</html>
diff --git a/LayoutTests/http/tests/navigation/document-open-replace-no-history-item-expected.txt b/LayoutTests/http/tests/navigation/document-open-replace-no-history-item-expected.txt
new file mode 100644 (file)
index 0000000..2128d62
--- /dev/null
@@ -0,0 +1,6 @@
+This generated document and its contents should be in the back/forward list. This page should have replaced the originating page as well.
+
+============== Back Forward List ==============
+curr->  http://127.0.0.1:8000/navigation/document-open-replace-no-history-item.html  **nav target**
+        http://127.0.0.1:8000/navigation/resources/document-open-page-2.html  **nav target**
+===============================================
diff --git a/LayoutTests/http/tests/navigation/document-open-replace-no-history-item.html b/LayoutTests/http/tests/navigation/document-open-replace-no-history-item.html
new file mode 100644 (file)
index 0000000..749d180
--- /dev/null
@@ -0,0 +1,22 @@
+<html>
+<head>
+<script src="resources/document-open.js"></script>
+<script>
+    function runTest()
+    {
+        window.firstVisit = true;
+        document.open("text/html", "replace");
+        document.writeln("<script>" + window.stopTest + "<" + "/script>");
+        document.writeln("<body onload='stopTest();'>");
+        document.writeln("This generated document and its contents should be in the back/forward list.");
+        document.writeln("This page should have replaced the originating page as well.");
+        document.writeln("</body>");
+        document.close();
+    }
+</script>
+</head>
+<body onload="startTest()">
+This tests that document.open does not create a back/forward item if "replace"
+is specified.
+</body>
+</html>
diff --git a/LayoutTests/http/tests/navigation/resources/document-open-page-2.html b/LayoutTests/http/tests/navigation/resources/document-open-page-2.html
new file mode 100644 (file)
index 0000000..41d0237
--- /dev/null
@@ -0,0 +1,11 @@
+<head>
+<script>
+    function goBack()
+    {
+        window.history.back();
+    }
+</script>
+</head>
+<body onload="goBack()">
+Just navigates back to where it came from.
+</body>
diff --git a/LayoutTests/http/tests/navigation/resources/document-open.js b/LayoutTests/http/tests/navigation/resources/document-open.js
new file mode 100644 (file)
index 0000000..ac8b4de
--- /dev/null
@@ -0,0 +1,28 @@
+// Common testing functions for document-open history tests.
+
+function startTest()
+{
+    if (window.layoutTestController) {
+        layoutTestController.dumpBackForwardList();
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+        setTimeout("runTest()", 0);
+    }
+}
+
+function stopTest()
+{
+    // We expect the test to set window.firstVisit to true before it open
+    // the document.  When we navigate away, this variable will be cleared.
+    if (window.firstVisit) {
+        // This is the first time we loaded this page.
+        // Navigate away and back to ensure the generated contents remain intact. 
+        window.location = "resources/document-open-page-2.html";
+        window.firstVisit = false;  // just to be explicit.
+    } else {
+        // We are now returning from page-2.  End the test.
+        if (window.layoutTestController) {
+            layoutTestController.notifyDone();
+        }
+    }
+}
index fc86dc154d754b08ec4b796ffab74e6831189fe2..81e002480352ec33e6f1ffddb3f4b1056827f5b0 100644 (file)
@@ -1,3 +1,76 @@
+2008-01-27  Matt Perry  <mpComplete@gmail.com>
+
+        Reviewed and tweaked quite a bit by Darin.
+
+        Fix for http://bugs.webkit.org/show_bug.cgi?id=14959
+        No back forward entry added for pages created in javascript
+
+        A new HistoryItem is created for calls to Document::open. Calls to
+        Document::write save the written data to a SharedBuffer that is also
+        stored on the HistoryItem. When the user navigates back to a
+        HistoryItem that has a valid buffer, that data is used for the page
+        content.
+
+        Tests: http/tests/navigation/document-open-adds-history-item.html
+               http/tests/navigation/document-open-delayed-adds-history-item.html
+               http/tests/navigation/document-open-new-window-adds-history-item.html
+               http/tests/navigation/document-open-replace-no-history-item.html
+
+        * bindings/js/JSHTMLDocumentCustom.cpp:
+        (WebCore::JSHTMLDocument::open): Pass a MIME type of either "text/html" or
+        "text/plain" and a boolean for "replace" in rather than always setting replace
+        to true and the MIME type to "text/html".
+
+        * dom/DOMImplementation.cpp:
+        (WebCore::DOMImplementation::createHTMLDocument): Pass in MIME type and
+        replace boolean explicitly, since we don't want to rely on Document::open()'s
+        default.
+
+        * dom/Document.cpp:
+        (WebCore::Document::open): Correctly determine the "replace" boolean.
+        Pass along the MIME type, replace boolean, and shared buffer to the
+        frame loader's didExplicitOpen function.
+        (WebCore::Document::write): Pass MIME type and replace boolean explicitly
+        to the open function so we don't do treat it as replace if you write without
+        an open. Store text written by the script so it can be used later for history.
+        (WebCore::Document::clear): Drop the text written byt he script.
+
+        * dom/Document.h: Added MIME type and replace boolean parameters for open.
+        Had to keep the old version for the sake of DOM bindings. Added the shared
+        buffer used for text written by script.
+
+        * history/HistoryItem.cpp:
+        (WebCore::HistoryItem::HistoryItem): Copy m_substituteData.
+        (WebCore::HistoryItem::substituteData): Added.
+        (WebCore::HistoryItem::setSubstituteData): Added.
+        * history/HistoryItem.h: Added m_substituteData, getter, and setter.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::didExplicitOpen): Added code to create or update the
+        history item, including attaching the shared buffer that will contain all
+        the data written by script.
+        (WebCore::FrameLoader::load): Added a SubstituteData parameter, passed through
+        when creating the document loader.
+        (WebCore::FrameLoader::reloadAllowingStaleData): Create the document loader
+        with the substitute data from the current history item.
+        (WebCore::FrameLoader::reload): Ditto.
+        (WebCore::FrameLoader::shouldTreatURLAsSameAsCurrent): If the current history
+        item has substitute data, then consider the URL from the substitute data
+        rather than the one in the history item itself.
+        (WebCore::FrameLoader::loadItem): Pass in the history item's substitute data.
+        * loader/FrameLoader.h: Added parameters to load and didExplicitOpen.
+
+        * platform/text/CharacterNames.h: Added byteOrderMark, and also added it under
+        its other official name, zeroWidthNoBreakSpace.
+
+        * xml/DOMParser.cpp:
+        (WebCore::DOMParser::parseFromString): Pass in MIME type and replace boolean
+        explicitly, since we don't want to rely on Document::open()'s default.
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::getResponseXML): Ditto.
+        * xml/XSLTProcessor.cpp:
+        (WebCore::XSLTProcessor::createDocumentFromSource): Ditto.
+
 2008-01-25  Eric Seidel  <eric@webkit.org>
 
         Reviewed by Sam and Darin.
index b3d8dd177044736b8da01990a4aff6f8c260b1cf..832e865d1f262153963f974daa12b7afb1fe4cde 100644 (file)
@@ -164,7 +164,6 @@ __ZN7WebCore11FrameLoader4loadEPNS_14DocumentLoaderE
 __ZN7WebCore11FrameLoader4loadEPNS_14DocumentLoaderENS_13FrameLoadTypeEN3WTF10PassRefPtrINS_9FormStateEEE
 __ZN7WebCore11FrameLoader4loadERKNS_15ResourceRequestE
 __ZN7WebCore11FrameLoader4loadERKNS_15ResourceRequestERKNS_14SubstituteDataE
-__ZN7WebCore11FrameLoader4loadERKNS_15ResourceRequestERKNS_16NavigationActionENS_13FrameLoadTypeEN3WTF10PassRefPtrINS_9FormStateEEE
 __ZN7WebCore11FrameLoader4loadERKNS_15ResourceRequestERKNS_6StringE
 __ZN7WebCore11FrameLoader4loadERKNS_4KURLEPNS_5EventE
 __ZN7WebCore11FrameLoader4loadERKNS_4KURLERKNS_6StringENS_13FrameLoadTypeES6_PNS_5EventEN3WTF10PassRefPtrINS_9FormStateEEE
index 545561764252dc22ed934ac1d44146563bf6ce79..f65e22a7fa6173b4af0a440fa43fab3e8ce521ac 100644 (file)
@@ -109,7 +109,21 @@ JSValue* JSHTMLDocument::open(ExecState* exec, const List& args)
     }
 
     // In the case of two parameters or fewer, do a normal document open.
-    static_cast<HTMLDocument*>(impl())->open();
+
+    // Anything other than undefined or text/html is treated as plain text.
+    const char* mimeType;
+    if (args[0]->isUndefined() || equalIgnoringCase(String(args[0]->toString(exec)), "text/html"))
+        mimeType = "text/html";
+    else
+        mimeType = "text/plain";
+    if (exec->hadException())
+        return jsUndefined();
+
+    bool replace = equalIgnoringCase(String(args[1]->toString(exec)), "replace");
+    if (exec->hadException())
+        return jsUndefined();
+
+    static_cast<HTMLDocument*>(impl())->open(mimeType, replace);
     return jsUndefined();
 }
 
index c6904ecbbfa4ebfd86a81e8391f2e728466a6ef6..35f1b236007d451bfa3f66c8bcbba7ab52d0ed13 100644 (file)
@@ -346,7 +346,7 @@ bool DOMImplementation::isTextMIMEType(const String& mimeType)
 PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title)
 {
     RefPtr<HTMLDocument> d = new HTMLDocument(this, 0);
-    d->open();
+    d->open("text/html", false);
     d->write("<html><head><title>" + title + "</title></head><body></body></html>");
     return d.release();
 }
index 5f60949a452932d6c131fa33be7caad5043074bf..01560a3dec8803cf1bb5bac8cbb9b5138f1becdc 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "AXObjectCache.h"
 #include "CDATASection.h"
+#include "CString.h"
 #include "CSSHelper.h"
 #include "CSSStyleSelector.h"
 #include "CSSStyleSheet.h"
@@ -52,6 +53,7 @@
 #include "FrameLoader.h"
 #include "FrameTree.h"
 #include "FrameView.h"
+#include "HistoryItem.h"
 #include "HTMLBodyElement.h"
 #include "HTMLDocument.h"
 #include "HTMLElementFactory.h"
@@ -1065,7 +1067,6 @@ void Document::recalcStyle(StyleChange change)
         _style->ref();
         _style->setDisplay(BLOCK);
         _style->setVisuallyOrdered(visuallyOrdered);
-        // ### make the font stuff _really_ work!!!!
 
         FontDescription fontDescription;
         fontDescription.setUsePrinterFont(printing());
@@ -1312,9 +1313,22 @@ Tokenizer* Document::createTokenizer()
 
 void Document::open()
 {
+    // Parameters here match the description in the DOM Level 2 specification.
+    // Note that this function is currently only used in non-JavaScript DOM
+    // bindings for the HTMLDocument class, and should not be used elsewhere.
+    open("text/html", true);
+}
+
+void Document::open(const String& mimeType, bool replace)
+{
+    // Calling open() during an onload handler is like a redirect, so we should not add a new
+    // history item.
+    if (m_processingLoadEvent)
+        replace = true;
+
     // This is work that we should probably do in clear(), but we can't have it
     // happen when implicitOpen() is called unless we reorganize Frame code.
-    if (Document *parent = parentDocument()) {
+    if (Documentparent = parentDocument()) {
         if (m_url.isEmpty() || m_url == "about:blank")
             setURL(parent->baseURL());
         if (m_baseURL.isEmpty() || m_baseURL == "about:blank")
@@ -1324,15 +1338,16 @@ void Document::open()
     if (m_frame) {
         if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokenizer()->executingScript()))
             return;
-    
         if (m_frame->loader()->state() == FrameStateProvisional)
             m_frame->loader()->stopAllLoaders();
     }
-    
+
     implicitOpen();
 
-    if (m_frame)
-        m_frame->loader()->didExplicitOpen();
+    if (m_frame) {
+        m_textWrittenByScript = new SharedBuffer;
+        m_frame->loader()->didExplicitOpen(mimeType, replace, m_textWrittenByScript.get());
+    }
 }
 
 void Document::cancelParsing()
@@ -1559,16 +1574,21 @@ void Document::write(const String& text)
     if (!ownerElement())
         printf("Beginning a document.write at %d\n", elapsedTime());
 #endif
-    
+
     if (!m_tokenizer) {
-        open();
+        open("text/html", false);
         ASSERT(m_tokenizer);
         if (!m_tokenizer)
             return;
         write("<html>");
     }
+
     m_tokenizer->write(text, false);
-    
+
+    if (m_textWrittenByScript)
+        m_textWrittenByScript->append(reinterpret_cast<const char*>(text.characters()),
+            text.length() * sizeof(UChar));
+
 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
     if (!ownerElement())
         printf("Ending a document.write at %d\n", elapsedTime());
@@ -1602,6 +1622,8 @@ void Document::clear()
     delete m_tokenizer;
     m_tokenizer = 0;
 
+    m_textWrittenByScript.clear(); 
+
     removeChildren();
 
     m_windowEventListeners.clear();
index 4f4f0a523c18365a8d9117647d676d032d7bc14f..1de9e1de11d80059846acbe341aa575dcc905eed 100644 (file)
@@ -82,6 +82,7 @@ namespace WebCore {
     class RegisteredEventListener;
     class RenderArena;
     class Settings;
+    class SharedBuffer;
     class StyleSheet;
     class StyleSheetList;
     class Text;
@@ -348,14 +349,15 @@ public:
     // to get visually ordered hebrew and arabic pages right
     void setVisuallyOrdered();
 
-    void open();
+    void open(const String& mimeType, bool replace);
+    void open(); // Deprecated.
     void implicitOpen();
     void close();
     void implicitClose();
     void cancelParsing();
 
-    void write(const String& text);
-    void writeln(const String& text);
+    void write(const String&);
+    void writeln(const String&);
     void finishParsing();
     void clear();
 
@@ -926,6 +928,9 @@ private:
 
     bool m_isXHTML;
 
+    // Contains the text written to the document by script, eg through document.write().
+    RefPtr<SharedBuffer> m_textWrittenByScript;
+
     unsigned m_numNodeLists;
 
 #if ENABLE(DATABASE)
index 3f900af45e2a9f2a1d6e1525934f1c3e8e913117..806acb67738dbb5e60074ce29ac04da82f7d8697 100644 (file)
@@ -121,6 +121,7 @@ HistoryItem::HistoryItem(const HistoryItem& item)
     , m_formContentType(item.m_formContentType)
     , m_formReferrer(item.m_formReferrer)
     , m_rssFeedReferrer(item.m_rssFeedReferrer)
+    , m_substituteData(item.m_substituteData)
 {
     if (item.m_formData)
         m_formData = item.m_formData->copy();
@@ -365,6 +366,16 @@ void HistoryItem::setRSSFeedReferrer(const String& referrer)
     m_rssFeedReferrer = referrer;
 }
 
+const SubstituteData& HistoryItem::substituteData() const
+{
+    return m_substituteData;
+}
+
+void HistoryItem::setSubstituteData(const SubstituteData& substituteData)
+{
+    m_substituteData = substituteData;
+}
+
 void HistoryItem::setFormInfoFromRequest(const ResourceRequest& request)
 {
     if (equalIgnoringCase(request.httpMethod(), "POST")) {
index 5d9e04f279b8ddf821da2d6e0a2c21eb54de3057..bce0cf8c27480970f6356d0f14b904ee3b9ee911 100644 (file)
@@ -33,6 +33,7 @@
 #include "PlatformString.h"
 #include <wtf/RefCounted.h>
 #include "StringHash.h"
+#include "SubstituteData.h"
 #include <wtf/HashMap.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/RefPtr.h>
@@ -93,6 +94,7 @@ public:
     String formContentType() const;
     String formReferrer() const;
     String rssFeedReferrer() const;
+    const SubstituteData& substituteData() const;
     
     int visitCount() const;
 
@@ -117,6 +119,7 @@ public:
 
     void setRSSFeedReferrer(const String&);
     void setVisitCount(int);
+    void setSubstituteData(const SubstituteData&);
 
     void addChildItem(PassRefPtr<HistoryItem>);
     HistoryItem* childItemWithName(const String&) const;
@@ -175,6 +178,8 @@ private:
     // info used to support RSS feeds
     String m_rssFeedReferrer;
 
+    SubstituteData m_substituteData;
+
     // PageCache controls these fields.
     HistoryItem* m_next;
     HistoryItem* m_prev;
index a2b16aa6db7169eee52fc7337637e0c606fd494e..067c9fcee3b4d685bb372697b00faf3467a1740d 100644 (file)
@@ -33,6 +33,7 @@
 #include "CString.h"
 #include "Cache.h"
 #include "CachedPage.h"
+#include "CharacterNames.h"
 #include "Chrome.h"
 #include "DOMImplementation.h"
 #include "DocLoader.h"
@@ -696,7 +697,7 @@ bool FrameLoader::didOpenURL(const KURL& url)
     return true;
 }
 
-void FrameLoader::didExplicitOpen()
+void FrameLoader::didExplicitOpen(const String& mimeType, bool replace, SharedBuffer* buffer)
 {
     m_isComplete = false;
     m_didCallImplicitClose = false;
@@ -711,6 +712,37 @@ void FrameLoader::didExplicitOpen()
     cancelRedirection(); 
     if (m_frame->document()->url() != "about:blank")
         m_URL = m_frame->document()->url();
+    bool isItemNew = false;
+
+    // Add a HistoryItem for this open.
+    RefPtr<HistoryItem> item;
+    if (replace && m_currentHistoryItem) 
+        item = m_currentHistoryItem;
+    else {
+        isItemNew = true;
+        item = new HistoryItem(m_URL, m_frame->tree()->name(), m_frame->tree()->parent() ? m_frame->tree()->parent()->tree()->name() : "", "");
+        item->setIsTargetItem(true);
+        m_previousHistoryItem = m_currentHistoryItem;
+        m_currentHistoryItem = item;
+    }
+
+    // Create an alternate URL to distinguish this as a generated page.
+    // FIXME: This may need a bit of refinement. If no one can ever detect this URL, then
+    // why does this need to be generated? But if the value or uniqueness of this URL does
+    // matter, then why is it OK to use the same URL for anything generated from a document
+    // with the same URL (since we just prepend a scheme)?
+    KURL generatedURL("webkitgenerated:" + m_frame->document()->url());
+
+    // Write a BOM so that decoding will work on big-endian as well as little-endian systems.
+    ASSERT(buffer->isEmpty());
+    buffer->append(reinterpret_cast<const char*>(&byteOrderMark), sizeof(UChar));
+
+    item->setSubstituteData(SubstituteData(buffer, mimeType, "UTF-16", m_URL, generatedURL));
+
+    if (isItemNew)
+        if (Page* page = m_frame->page())
+            page->backForwardList()->addItem(item.release());
 }
 
 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
@@ -2031,7 +2063,7 @@ void FrameLoader::load(const KURL& newURL, const String& referrer, FrameLoadType
     } else {
         // must grab this now, since this load may stop the previous load and clear this flag
         bool isRedirect = m_quickRedirectComing;
-        load(request, action, newLoadType, formState);
+        load(request, action, newLoadType, formState, SubstituteData());
         if (isRedirect) {
             m_quickRedirectComing = false;
             if (m_provisionalDocumentLoader)
@@ -2075,9 +2107,9 @@ void FrameLoader::load(const ResourceRequest& request, const String& frameName)
     checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
 }
 
-void FrameLoader::load(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState)
+void FrameLoader::load(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState, const SubstituteData& substituteData)
 {
-    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
+    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
 
     loader->setTriggeringAction(action);
     if (m_documentLoader)
@@ -2278,7 +2310,9 @@ void FrameLoader::reloadAllowingStaleData(const String& encoding)
 
     request.setCachePolicy(ReturnCacheDataElseLoad);
 
-    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
+    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, m_currentHistoryItem->substituteData());
+    setProvisionalHistoryItem(m_currentHistoryItem);
+
     setPolicyDocumentLoader(loader.get());
 
     loader->setOverrideEncoding(encoding);
@@ -2303,7 +2337,8 @@ void FrameLoader::reload()
     if (!unreachableURL.isEmpty())
         initialRequest = ResourceRequest(unreachableURL);
     
-    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
+    RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, m_currentHistoryItem->substituteData());
+    setProvisionalHistoryItem(m_currentHistoryItem);
 
     ResourceRequest& request = loader->request();
 
@@ -3251,11 +3286,11 @@ void FrameLoader::post(const KURL& url, const String& referrer, const String& fr
 
     if (!frameName.isEmpty()) {
         if (Frame* targetFrame = findFrameForNavigation(frameName))
-            targetFrame->loader()->load(request, action, FrameLoadTypeStandard, formState.release());
+            targetFrame->loader()->load(request, action, FrameLoadTypeStandard, formState.release(), SubstituteData());
         else
             checkNewWindowPolicy(action, request, formState.release(), frameName);
     } else
-        load(request, action, FrameLoadTypeStandard, formState.release());
+        load(request, action, FrameLoadTypeStandard, formState.release(), SubstituteData());
 }
 
 bool FrameLoader::isReloading() const
@@ -3645,7 +3680,7 @@ void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques
     mainFrame->loader()->setOpenedByDOM();
     mainFrame->loader()->m_client->dispatchShow();
     mainFrame->loader()->setOpener(frame.get());
-    mainFrame->loader()->load(request, NavigationAction(), FrameLoadTypeStandard, formState);
+    mainFrame->loader()->load(request, NavigationAction(), FrameLoadTypeStandard, formState, SubstituteData());
 }
 
 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
@@ -3789,6 +3824,8 @@ bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
 {
     if (!m_currentHistoryItem)
         return false;
+    if (m_currentHistoryItem->substituteData().isValid())
+        return url == m_currentHistoryItem->substituteData().responseURL();
     return url == m_currentHistoryItem->url() || url == m_currentHistoryItem->originalURL();
 }
 
@@ -4098,7 +4135,7 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
                 action = NavigationAction(itemOriginalURL, loadType, false);
             }
 
-            load(request, action, loadType, 0);
+            load(request, action, loadType, 0, item->substituteData());
         }
     }
 }
index 725e5f32a26d57fafcb2bb6acd12e462688c9bed..00cf84e2ec2f63438daffdfa7b659dca62e44b85 100644 (file)
@@ -153,7 +153,7 @@ namespace WebCore {
         void load(const ResourceRequest&);
         void load(const ResourceRequest&, const SubstituteData&);
         void load(const ResourceRequest&, const String& frameName);
-        void load(const ResourceRequest&, const NavigationAction&, FrameLoadType, PassRefPtr<FormState>);
+        void load(const ResourceRequest&, const NavigationAction&, FrameLoadType, PassRefPtr<FormState>, const SubstituteData&);
         
         void load(DocumentLoader*);
         void load(DocumentLoader*, FrameLoadType, PassRefPtr<FormState>);
@@ -288,7 +288,7 @@ namespace WebCore {
         void stopLoading(bool sendUnload);
         bool closeURL();
 
-        void didExplicitOpen();
+        void didExplicitOpen(const String& mimeType, bool replace, SharedBuffer*);
 
         KURL iconURL();
         void commitIconURLToIconDatabase(const KURL&);
index 5b524790e210ded076304acc93e2dc6d181cdaf4..125da3a82ba5fcd045f2bfb30881e9b4f584c213 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,6 +37,7 @@ namespace WebCore {
 
     const UChar blackSquare = 0x25A0;
     const UChar bullet = 0x2022;
+    const UChar byteOrderMark = 0xFEFF;
     const UChar horizontalEllipsis = 0x2026;
     const UChar ideographicSpace = 0x3000;
     const UChar leftToRightMark = 0x200E;
@@ -51,6 +52,7 @@ namespace WebCore {
     const UChar rightToLeftOverride = 0x202E;
     const UChar softHyphen = 0x00AD;
     const UChar whiteBullet = 0x25E6;
+    const UChar zeroWidthNoBreakSpace = 0xFEFF;
     const UChar zeroWidthSpace = 0x200B;
 
 }
index 8be4d149fb56319f5f0d709592edf3f21a0b5990..346b895ae15c0f62afb3160a447b6cb37461e6f0 100644 (file)
@@ -1,6 +1,5 @@
 /*
- *  This file is part of the KDE libraries
- *  Copyright (C) 2003, 2006 Apple Computer, Inc.
+ *  Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -32,7 +31,7 @@ PassRefPtr<Document> DOMParser::parseFromString(const String& str, const String&
 
     RefPtr<Document> doc = DOMImplementation::instance()->createDocument(contentType, 0, false);
 
-    doc->open();
+    doc->open(contentType, false);
     doc->write(str);
     doc->finishParsing();
     doc->close();
index 51c52ec6a671526befd0fa507740e20124ae980d..577cfe642d39c6abb7b9284cf53a4bc0bbe51d28 100644 (file)
@@ -172,10 +172,10 @@ Document* XMLHttpRequest::getResponseXML(ExceptionCode& ec) const
             m_responseXML = 0;
         } else {
             m_responseXML = m_doc->implementation()->createDocument(0);
-            m_responseXML->open();
+            m_responseXML->open(responseMIMEType(), false);
             m_responseXML->setURL(m_url.deprecatedString());
-            // FIXME: set Last-Modified and cookies (currently, those are only available for HTMLDocuments).
-            m_responseXML->write(String(m_responseText));
+            // FIXME: Set Last-Modified and cookies (currently, those are only available for HTMLDocument).
+            m_responseXML->write(m_responseText);
             m_responseXML->finishParsing();
             m_responseXML->close();
             
index 07efe75da7fbbb6caffdbce9b65e7db423667474..0c102bfcdfc62c367422d040ec008cacbe16afcf 100644 (file)
@@ -238,11 +238,15 @@ RefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceStr
     String documentSource = sourceString;
 
     RefPtr<Document> result;
+    String resultMIMEType;
     if (sourceMIMEType == "text/plain") {
         result = ownerDocument->implementation()->createDocument(frame);
         transformTextStringToXHTMLDocumentString(documentSource);
-    } else
+        resultMIMEType = "application/xhtml+xml";
+    } else {
         result = ownerDocument->implementation()->createDocument(sourceMIMEType, frame, false);
+        resultMIMEType = sourceMIMEType;
+    }
     
     // Before parsing, we need to save & detach the old document and get the new document
     // in place. We have to do this only if we're rendering the result document.
@@ -253,7 +257,7 @@ RefPtr<Document> XSLTProcessor::createDocumentFromSource(const String& sourceStr
         frame->setDocument(result);
     }
     
-    result->open();
+    result->open(resultMIMEType, false);
     if (sourceIsDocument) {
         result->setURL(ownerDocument->url());
         result->setBaseURL(ownerDocument->baseURL());