Bug 599588 addendum - Revert change to nsIParser and introduce a new abstract class instead to avoid changing the interface during an interface freeze. r=jonas, a=blocking2.0-final.

--HG--
extra : rebase_source : 3272dc97668c262945b91809a918ac5c013d8569
This commit is contained in:
Henri Sivonen 2010-11-16 09:47:10 +02:00
parent f9289aaa14
commit 037d45c4a7
10 changed files with 146 additions and 320 deletions

View File

@ -183,6 +183,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsTextEditorState.h"
#include "nsIPluginHost.h"
#include "nsICategoryManager.h"
#include "nsAHtml5FragmentParser.h"
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
@ -3898,23 +3899,27 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
}
}
nsAHtml5FragmentParser* asFragmentParser =
static_cast<nsAHtml5FragmentParser*> (parser.get());
nsCOMPtr<nsIContent> fragment = do_QueryInterface(frag);
if (contextAsContent &&
!(nsGkAtoms::html == contextAsContent->Tag() &&
contextAsContent->IsHTML())) {
parser->ParseFragment(aFragment,
fragment,
contextAsContent->Tag(),
contextAsContent->GetNameSpaceID(),
(document->GetCompatibilityMode() == eCompatibility_NavQuirks),
PR_FALSE);
asFragmentParser->ParseHtml5Fragment(aFragment,
fragment,
contextAsContent->Tag(),
contextAsContent->GetNameSpaceID(),
(document->GetCompatibilityMode() ==
eCompatibility_NavQuirks),
PR_FALSE);
} else {
parser->ParseFragment(aFragment,
fragment,
nsGkAtoms::body,
kNameSpaceID_XHTML,
(document->GetCompatibilityMode() == eCompatibility_NavQuirks),
PR_FALSE);
asFragmentParser->ParseHtml5Fragment(aFragment,
fragment,
nsGkAtoms::body,
kNameSpaceID_XHTML,
(document->GetCompatibilityMode() ==
eCompatibility_NavQuirks),
PR_FALSE);
}
frag.swap(*aReturn);

View File

@ -77,6 +77,7 @@
#include "nsDOMError.h"
#include "nsScriptLoader.h"
#include "nsRuleData.h"
#include "nsAHtml5FragmentParser.h"
#include "nsPresState.h"
#include "nsILayoutHistoryState.h"
@ -745,9 +746,15 @@ nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
}
PRInt32 oldChildCount = GetChildCount();
parser->ParseFragment(aInnerHTML, this, Tag(), GetNameSpaceID(),
doc->GetCompatibilityMode() == eCompatibility_NavQuirks,
PR_TRUE);
nsAHtml5FragmentParser* asFragmentParser =
static_cast<nsAHtml5FragmentParser*> (parser.get());
asFragmentParser->ParseHtml5Fragment(aInnerHTML,
this,
Tag(),
GetNameSpaceID(),
doc->GetCompatibilityMode() ==
eCompatibility_NavQuirks,
PR_TRUE);
doc->SetFragmentParser(parser);
// HTML5 parser has notified, but not fired mutation events.

View File

@ -48,6 +48,7 @@ LIBXUL_LIBRARY = 1
EXPORTS = \
nsHtml5Module.h \
nsAHtml5FragmentParser.h \
$(NULL)
ifdef MOZ_SVG

View File

@ -0,0 +1,72 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is HTML Parser C++ Translator code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Henri Sivonen <hsivonen@iki.fi>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsAHtml5FragmentParser_h_
#define nsAHtml5FragmentParser_h_
#include "nsIParser.h"
/**
* The purpose of this class is to avoid changing the signatures in nsIParser.h
* after the Firefox 4.0 interface freeze. In later releases this can be folded
* into nsIParser.h.
*/
class nsAHtml5FragmentParser : public nsIParser {
public:
/**
* Invoke the fragment parsing algorithm (innerHTML).
*
* @param aSourceBuffer the string being set as innerHTML
* @param aTargetNode the target container
* @param aContextLocalName local name of context node
* @param aContextNamespace namespace of context node
* @param aQuirks true to make <table> not close <p>
* @param aPreventScriptExecution true to prevent scripts from executing;
* don't set to false when parsing into a target node that has been bound
* to tree.
*/
NS_IMETHOD ParseHtml5Fragment(const nsAString& aSourceBuffer,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution) = 0;
};
#endif // nsAHtml5FragmentParser_h_

View File

@ -428,11 +428,21 @@ nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
NS_IMETHODIMP
nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution)
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsHtml5Parser::ParseHtml5Fragment(const nsAString& aSourceBuffer,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution)
{
nsIDocument* doc = aTargetNode->GetOwnerDoc();
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_AVAILABLE);

View File

@ -62,8 +62,9 @@
#include "nsHtml5StreamParser.h"
#include "nsHtml5AtomTable.h"
#include "nsWeakReference.h"
#include "nsAHtml5FragmentParser.h"
class nsHtml5Parser : public nsIParser,
class nsHtml5Parser : public nsAHtml5FragmentParser, // inherits nsIParser
public nsSupportsWeakReference
{
public:
@ -214,23 +215,13 @@ class nsHtml5Parser : public nsIParser,
nsDTDMode aMode = eDTDMode_autodetect);
/**
* Invoke the fragment parsing algorithm (innerHTML).
*
* @param aSourceBuffer the string being set as innerHTML
* @param aTargetNode the target container
* @param aContextLocalName local name of context node
* @param aContextNamespace namespace of context node
* @param aQuirks true to make <table> not close <p>
* @param aPreventScriptExecution true to prevent scripts from executing;
* don't set to false when parsing into a target node that has been bound
* to tree.
* Don't call. For interface backwards compat only.
*/
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution);
PRBool aQuirks);
/**
* Don't call. For interface compat only.
@ -280,6 +271,30 @@ class nsHtml5Parser : public nsIParser,
/* End nsIParser */
/* Start nsAHtml5FragmentParser */
/**
* Invoke the fragment parsing algorithm (innerHTML).
*
* @param aSourceBuffer the string being set as innerHTML
* @param aTargetNode the target container
* @param aContextLocalName local name of context node
* @param aContextNamespace namespace of context node
* @param aQuirks true to make <table> not close <p>
* @param aPreventScriptExecution true to prevent scripts from executing;
* don't set to false when parsing into a target node that has been bound
* to tree.
*/
NS_IMETHOD ParseHtml5Fragment(const nsAString& aSourceBuffer,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution);
/* End nsAHtml5FragmentParser */
// Not from an external interface
// Non-inherited methods

View File

@ -266,8 +266,7 @@ class nsIParser : public nsISupports {
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution) = 0;
PRBool aQuirks) = 0;
/**
* This method gets called when the tokens have been consumed, and it's time

View File

@ -2126,8 +2126,7 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution)
PRBool aQuirks)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -219,8 +219,7 @@ class nsParser : public nsIParser,
nsIContent* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace,
PRBool aQuirks,
PRBool aPreventScriptExecution);
PRBool aQuirks);
/**
* This method gets called when the tokens have been consumed, and it's time

View File

@ -1,281 +0,0 @@
do_get_profile();
do_load_httpd_js();
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
// Dynamically generates a classID for our component, registers it to mask
// the existing component, and stored the masked components classID to be
// restored later, when we unregister.
function registerTemporaryComponent(comp)
{
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
if (!comp.prototype.classID) {
let uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
comp.prototype.classID = uuidgen.generateUUID();
}
comp.prototype.maskedClassID = Components.ID(Cc[comp.prototype.contractID].number);
if (!comp.prototype.factory)
comp.prototype.factory = getFactory(comp);
registrar.registerFactory(comp.prototype.classID, "", comp.prototype.contractID, comp.prototype.factory);
}
function unregisterTemporaryComponent(comp)
{
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(comp.prototype.classID, comp.prototype.factory);
registrar.registerFactory(comp.prototype.maskedClassID, "", comp.prototype.contractID, null);
}
let DownloadListener = {
init: function () {
let obs = Services.obs;
obs.addObserver(this, "dl-done", true);
},
observe: function (subject, topic, data) {
this.onFinished(subject, topic, data);
},
QueryInterface: function (iid) {
if (iid.equals(Ci.nsIObserver) ||
iid.equals(Ci.nsISupportsWeakReference) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
DownloadListener.init();
function HelperAppDlg() { }
HelperAppDlg.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
contractID: "@mozilla.org/helperapplauncherdialog;1",
show: function (launcher, ctx, reason) {
launcher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToFile;
launcher.launchWithApplication(null, false);
},
promptForSaveToFile: function (launcher, ctx, defaultFile, suggestedExtension, forcePrompt) { }
}
// Stolen from XPCOMUtils, since this handy function is not public there
function getFactory(comp)
{
return {
createInstance: function (outer, iid) {
if (outer)
throw Cr.NS_ERROR_NO_AGGREGATION;
return (new comp()).QueryInterface(iid);
}
}
}
// Override the download-manager-ui to prevent anyone from trying to open
// a window.
function DownloadMgrUI() { }
DownloadMgrUI.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI]),
contractID: "@mozilla.org/download-manager-ui;1",
show: function (ir, aID, reason) { },
visible: false,
getAttention: function () { }
}
function AlertsSVC() { }
AlertsSVC.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
contractID: "@mozilla.org/alerts-service;1",
showAlertNotification: function (url, title, text, clickable, cookie, listener, name) { },
}
registerTemporaryComponent(HelperAppDlg);
registerTemporaryComponent(DownloadMgrUI);
registerTemporaryComponent(AlertsSVC);
function initChildTestEnv()
{
sendCommand(' \
const Cc = Components.classes; \
const Ci = Components.interfaces; \
const Cr = Components.results; \
function WindowContext() { } \
\
WindowContext.prototype = { \
getInterface: function (iid) { \
if (iid.equals(Ci.nsIInterfaceRequestor) || \
iid.equals(Ci.nsIURIContentListener) || \
iid.equals(Ci.nsILoadGroup) || \
iid.equals(Ci.nsIDocumentLoader) || \
iid.equals(Ci.nsIDOMWindow)) \
return this; \
\
throw Cr.NS_ERROR_NO_INTERFACE; \
}, \
\
/* nsIURIContentListener */ \
onStartURIOpen: function (uri) { }, \
isPreferred: function (type, desiredtype) { return false; }, \
\
/* nsILoadGroup */ \
addRequest: function (request, context) { }, \
removeRequest: function (request, context, status) { } \
}; \
\
var ioservice = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);\
var uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);\
');
}
function testFinisher(endFunc) {
let ef = endFunc;
return function (file) {
ef(file);
runNextTest();
}
}
function runChildTestSet(set)
{
DownloadListener.onFinished = testFinisher(set[2]);
sendCommand('\
let uri = ioservice.newURI("http://localhost:4444' + set[0] + '", null, null);\
let channel = ioservice.newChannelFromURI(uri); \
uriloader.openURI(channel, true, new WindowContext()); \
');
}
var httpserver = null;
let currentTest = 0;
function runNextTest()
{
if (currentTest == tests.length) {
httpserver.stop(do_test_finished);
return;
}
let set = tests[currentTest++];
runChildTestSet(set);
}
const responseBody = [0x1f, 0x8b, 0x08, 0x00, 0x16, 0x5a, 0x8a, 0x48, 0x02,
0x03, 0x2b, 0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6,
0x35, 0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00];
/*
* First test: a file with Content-Type application/x-gzip and Content-Encoding gzip
* should not be decoded in a round-trip
*/
function testResponse1(metadata, response) {
response.setHeader("Content-Type", "application/x-gzip", false);
response.setHeader("Content-Encoding", "gzip", false);
response.setHeader("Content-Disposition", "attachment", false);
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
bos.setOutputStream(response.bodyOutputStream);
bos.writeByteArray(responseBody, responseBody.length);
}
function finishTest1(subject, topic, data) {
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
do_check_true(file.path.search("test1.gz") != 0);
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
fis.init(file, -1, -1, 0);
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
bis.setInputStream(fis);
let str = bis.readByteArray(bis.available());
do_check_true(str.length == responseBody.length);
let cmp = 0;
for (i = 0; i < str.length; i++) {
cmp += str[i] - responseBody[i];
if (cmp != 0) break;
}
do_check_true(cmp == 0);
}
/*
* Second test: a file with Content-Type text/html and Content-Encoding gzip
* should not be decoded in a round-trip, if its filename ends in ".gz".
* We specify a Content-disposition header to force it to be saved as a file.
*/
function testResponse2(metadata, response) {
response.setHeader("Content-Type", "text/html", false);
response.setHeader("Content-Encoding", "gzip", false);
response.setHeader("Content-Disposition", "attachment", false);
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
bos.setOutputStream(response.bodyOutputStream);
bos.writeByteArray(responseBody, responseBody.length);
}
function finishTest2(subject, topic, data) {
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
do_check_true(file.path.search("test2.gz") != 0);
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
fis.init(file, -1, -1, 0);
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
bis.setInputStream(fis);
let str = bis.readByteArray(bis.available());
do_check_true(str.length == responseBody.length);
let cmp = 0;
for (i = 0; i < str.length; i++) {
cmp += str[i] - responseBody[i];
if (cmp != 0) break;
}
do_check_true(cmp == 0);
}
function testResponse3(metadata, response) {
response.setHeader("Content-Type", "text/html", false);
response.setHeader("Content-Encoding", "gzip", false);
response.setHeader("Content-Disposition", "attachment", false);
var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
bos.setOutputStream(response.bodyOutputStream);
bos.writeByteArray(responseBody, responseBody.length);
}
function finishTest3(subject, topic, data) {
let file = subject.QueryInterface(Ci.nsIDownload).targetFile;
do_check_true(file.path.search("test3.txt") != 0);
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
fis.init(file, -1, -1, 0);
let bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
bis.setInputStream(fis);
let str = bis.readByteArray(bis.available());
let decodedBody = [ 116, 101, 115, 116, 10 ]; // 't','e','s','t','\n'
do_check_true(str.length == decodedBody.length);
let cmp = 0;
for (i = 0; i < str.length; i++) {
cmp += str[i] - decodedBody[i];
if (cmp != 0) break;
}
do_check_true(cmp == 0);
}
let tests = [
[ "/test1.gz", testResponse1, finishTest1 ],
[ "/test2.gz", testResponse2, finishTest2 ],
[ "/test3.txt", testResponse3, finishTest3 ],
];
function run_test() {
// do_load_child_test_harness();
httpserver = new nsHttpServer();
httpserver.start(4444);
do_test_pending();
initChildTestEnv();
for each (set in tests)
httpserver.registerPathHandler(set[0], set[1]);
runNextTest();
}