mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge last green changeset from inbound to mozilla-central
This commit is contained in:
commit
c51963cc5b
@ -66,7 +66,6 @@ nsIScriptElement.h \
|
||||
nsIStyleSheetLinkingElement.h \
|
||||
nsIContentSerializer.h \
|
||||
nsIXPathEvaluatorInternal.h \
|
||||
mozISanitizingSerializer.h \
|
||||
nsCaseTreatment.h \
|
||||
nsContentCID.h \
|
||||
nsCopySupport.h \
|
||||
|
@ -1,128 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 mozilla.org HTML Sanitizer code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ben Bucksch <mozilla@bucksch.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Netscape
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
/* Cleans up HTML source from unwanted tags/attributes
|
||||
|
||||
This class implements a content sink, which takes a parsed HTML document
|
||||
and removes all tags and attributes that are not explicitly allowed.
|
||||
|
||||
This may improve the viewing experience of the user and/or the
|
||||
security/privacy.
|
||||
|
||||
What is allowed is defined by a string (format described before the
|
||||
implementation of |mozHTMLSanitizer::ParsePrefs()|). The sytnax of the
|
||||
definition is not very rich - you can only (dis)allow certain tags and
|
||||
attributes, but not where they may appear. (This makes the implementation
|
||||
much more simple.) E.g. it is impossible to disallow ordinary text as a
|
||||
direct child of the <head> node or to disallow multiple <head> nodes.
|
||||
|
||||
We also remove some known bad attribute values like javascript: URLs.
|
||||
Draconian attitude.
|
||||
|
||||
Currently, the output of this class is unparsed (!) HTML source, which
|
||||
means that each document has to go through the parser twice. Of course,
|
||||
that is a performance killer. There are some reasons for for me doing it
|
||||
that way:
|
||||
* There is, to my knowledge, no interface to hook up such modifiers
|
||||
in the document display data flow. We have a nice interface for doing
|
||||
the modifications (the DOM), but no place to get the DOM and to invoke
|
||||
this code. As I don't want to hack this directly into the html sink,
|
||||
I'd have to create a generic interface first, which is too much work for
|
||||
me at the moment.
|
||||
* It is quite easy to hook up modifiers for the (unparsed) data stream,
|
||||
both in netwerk (for the browser) and esp. in libmime (for Mailnews).
|
||||
* It seems like the safest method - it is easier to debug (you have the
|
||||
HTML source output to check) and is less prone to security-relevant bugs
|
||||
and regressions, because in the case of a bug, it will probably fall back
|
||||
to not outputting, which is safer than erring on the side of letting
|
||||
something slip through (most of the alternative approaches listed below
|
||||
are probably vulnerable to the latter).
|
||||
* It should be possible to later change this class to output a parsed HTML
|
||||
document.
|
||||
So, in other words, I had the choice between better design and better
|
||||
performance. I choose design. Bad performance has an effect on the users
|
||||
of this class only, while bad design has an effect on all users and
|
||||
programmers.
|
||||
|
||||
That being said, I have some ideas, how do make it much more efficient, but
|
||||
they involve hacking core code.
|
||||
* At some point when we have DOM, but didn't do anything with it yet
|
||||
(in particular, didn't load any external objects or ran any javascript),
|
||||
walk the DOM and delete everything the user doesn't explicitly like.
|
||||
* There's this nice GetPref() in the HTMLContentSink. It isn't used exactly
|
||||
as I would like to, but that should be doable. Bascially, before
|
||||
processing any tag (e.g. in OpenContainer or AddLeaf), ask that
|
||||
function, if the tag is allowed. If not, just return.
|
||||
In any case, there's the problem, how the users of the renderer
|
||||
(e.g. Mailnews) can tell it to use the sanitizer and which tags are
|
||||
allowed (the browser may want to allow more tags than Mailnews).
|
||||
That probably means that I have to hack into the docshell (incl. its
|
||||
interface) or similar, which I would really like to avoid.
|
||||
Any ideas appreciated.
|
||||
*/
|
||||
#ifndef _mozISanitizingSerializer_h__
|
||||
#define _mozISanitizingSerializer_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsAString;
|
||||
|
||||
#define MOZ_SANITIZINGHTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/htmlsanitizer;1"
|
||||
|
||||
/* starting interface: nsIContentSerializer */
|
||||
#define MOZ_ISANITIZINGHTMLSERIALIZER_IID_STR "feca3c34-205e-4ae5-bd1c-03c686ff012b"
|
||||
|
||||
#define MOZ_ISANITIZINGHTMLSERIALIZER_IID \
|
||||
{0xfeca3c34, 0x205e, 0x4ae5, \
|
||||
{ 0xbd, 0x1c, 0x03, 0xc6, 0x86, 0xff, 0x01, 0x2b }}
|
||||
|
||||
class mozISanitizingHTMLSerializer : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(MOZ_ISANITIZINGHTMLSERIALIZER_IID)
|
||||
|
||||
NS_IMETHOD Initialize(nsAString* aOutString,
|
||||
PRUint32 aFlags,
|
||||
const nsAString& allowedTags) = 0;
|
||||
// This function violates string ownership rules, see impl.
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(mozISanitizingHTMLSerializer,
|
||||
MOZ_ISANITIZINGHTMLSERIALIZER_IID)
|
||||
|
||||
#endif
|
@ -77,7 +77,6 @@ EXPORTS_mozilla/dom = \
|
||||
LOCAL_INCLUDES = -I$(srcdir)/js/xpconnect/src
|
||||
|
||||
CPPSRCS = \
|
||||
mozSanitizingSerializer.cpp \
|
||||
nsAtomListUtils.cpp \
|
||||
nsAttrAndChildArray.cpp \
|
||||
nsAttrValue.cpp \
|
||||
|
@ -1,684 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* ***** 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 mozilla.org HTML Sanitizer code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ben Bucksch <mozilla@bucksch.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Netscape
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
/*
|
||||
* A serializer and content sink that removes potentially insecure or
|
||||
* otherwise dangerous or offending HTML (eg for display of HTML
|
||||
* e-mail attachments or something).
|
||||
*/
|
||||
|
||||
/* I used nsPlaintextSerializer as base for this class. I don't understand
|
||||
all of the functions in the beginning. Possible that I fail to do
|
||||
something or do something useless.
|
||||
I am not proud about the implementation here at all.
|
||||
Feel free to fix it :-).
|
||||
*/
|
||||
|
||||
#include "mozSanitizingSerializer.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "plstr.h"
|
||||
#include "nsIProperties.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEscape.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static inline PRUnichar* escape(const nsString& source)
|
||||
{
|
||||
return nsEscapeHTML2(source.get(), source.Length());
|
||||
}
|
||||
|
||||
/* XXX: |printf|s in some error conditions. They are intended as information
|
||||
for the user, because they complain about malformed pref values.
|
||||
Not sure, if popping up dialog boxes is the right thing for such code
|
||||
(and if so, how to do it).
|
||||
*/
|
||||
|
||||
#define TEXT_REMOVED "<Text removed>"
|
||||
#define TEXT_BREAKER "|"
|
||||
|
||||
nsresult NS_NewSanitizingHTMLSerializer(nsIContentSerializer** aSerializer)
|
||||
{
|
||||
mozSanitizingHTMLSerializer* it = new mozSanitizingHTMLSerializer();
|
||||
NS_ADDREF(it);
|
||||
*aSerializer = it;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozSanitizingHTMLSerializer::mozSanitizingHTMLSerializer()
|
||||
: mSkipLevel(0),
|
||||
mAllowedTags(30) // Just some initial buffer size
|
||||
{
|
||||
mOutputString = nsnull;
|
||||
}
|
||||
|
||||
mozSanitizingHTMLSerializer::~mozSanitizingHTMLSerializer()
|
||||
{
|
||||
#ifdef DEBUG_BenB
|
||||
printf("Output:\n%s\n", NS_LossyConvertUTF16toASCII(*mOutputString).get());
|
||||
#endif
|
||||
mAllowedTags.Enumerate(ReleaseProperties);
|
||||
}
|
||||
|
||||
//<copy from="xpcom/ds/nsProperties.cpp">
|
||||
bool
|
||||
mozSanitizingHTMLSerializer::ReleaseProperties(nsHashKey* key, void* data,
|
||||
void* closure)
|
||||
{
|
||||
nsIProperties* prop = (nsIProperties*)data;
|
||||
NS_IF_RELEASE(prop);
|
||||
return true;
|
||||
}
|
||||
//</copy>
|
||||
|
||||
NS_IMPL_ISUPPORTS4(mozSanitizingHTMLSerializer,
|
||||
nsIContentSerializer,
|
||||
nsIContentSink,
|
||||
nsIHTMLContentSink,
|
||||
mozISanitizingHTMLSerializer)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::Init(PRUint32 aFlags, PRUint32 dummy,
|
||||
const char* aCharSet, bool aIsCopying,
|
||||
bool aIsWholeDocument)
|
||||
{
|
||||
NS_ENSURE_TRUE(nsContentUtils::GetParserService(), NS_ERROR_UNEXPECTED);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::Initialize(nsAString* aOutString,
|
||||
PRUint32 aFlags,
|
||||
const nsAString& allowedTags)
|
||||
{
|
||||
nsresult rv = Init(aFlags, 0, nsnull, false, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXX This is wrong. It violates XPCOM string ownership rules.
|
||||
// We're only getting away with this because instances of this
|
||||
// class are restricted to single function scope.
|
||||
// (Comment copied from nsPlaintextSerializer)
|
||||
mOutputString = aOutString;
|
||||
|
||||
ParsePrefs(allowedTags);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is not used within the class, but maybe called from somewhere else?
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::Flush(nsAString& aStr)
|
||||
{
|
||||
#ifdef DEBUG_BenB
|
||||
printf("Flush: -%s-", NS_LossyConvertUTF16toASCII(aStr).get());
|
||||
#endif
|
||||
Write(aStr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::AppendDocumentStart(nsIDocument *aDocument,
|
||||
nsAString& aStr)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
mozSanitizingHTMLSerializer::Write(const nsAString& aString)
|
||||
{
|
||||
mOutputString->Append(aString);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::IsEnabled(PRInt32 aTag, bool* aReturn)
|
||||
{
|
||||
*aReturn = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true, if the id represents a container
|
||||
*/
|
||||
bool
|
||||
mozSanitizingHTMLSerializer::IsContainer(PRInt32 aId)
|
||||
{
|
||||
bool isContainer = false;
|
||||
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (parserService) {
|
||||
parserService->IsContainer(aId, isContainer);
|
||||
}
|
||||
|
||||
return isContainer;
|
||||
}
|
||||
|
||||
|
||||
/* XXX I don't really know, what these functions do, but they seem to be
|
||||
needed ;-). Mostly copied from nsPlaintextSerializer. */
|
||||
/* akk says:
|
||||
"I wonder if the sanitizing class could inherit from nsHTMLSerializer,
|
||||
so that at least these methods that none of us understand only have to be
|
||||
written once?" */
|
||||
|
||||
// static
|
||||
PRInt32
|
||||
mozSanitizingHTMLSerializer::GetIdForContent(nsIContent* aContent)
|
||||
{
|
||||
if (!aContent->IsHTML()) {
|
||||
return eHTMLTag_unknown;
|
||||
}
|
||||
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
|
||||
return parserService ? parserService->HTMLAtomTagToId(aContent->Tag()) :
|
||||
eHTMLTag_unknown;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::AppendText(nsIContent* aText,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsAString& aStr)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mOutputString = &aStr;
|
||||
|
||||
nsAutoString linebuffer;
|
||||
rv = DoAddLeaf(eHTMLTag_text, linebuffer);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::AppendElementStart(Element* aElement,
|
||||
Element* aOriginalElement,
|
||||
nsAString& aStr)
|
||||
{
|
||||
NS_ENSURE_ARG(aElement);
|
||||
|
||||
mElement = aElement;
|
||||
|
||||
mOutputString = &aStr;
|
||||
|
||||
PRInt32 id = GetIdForContent(mElement);
|
||||
|
||||
bool isContainer = IsContainer(id);
|
||||
|
||||
nsresult rv;
|
||||
if (isContainer) {
|
||||
rv = DoOpenContainer(id);
|
||||
}
|
||||
else {
|
||||
rv = DoAddLeaf(id, EmptyString());
|
||||
}
|
||||
|
||||
mElement = nsnull;
|
||||
mOutputString = nsnull;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::AppendElementEnd(Element* aElement,
|
||||
nsAString& aStr)
|
||||
{
|
||||
NS_ENSURE_ARG(aElement);
|
||||
|
||||
mElement = aElement;
|
||||
|
||||
mOutputString = &aStr;
|
||||
|
||||
PRInt32 id = GetIdForContent(mElement);
|
||||
|
||||
bool isContainer = IsContainer(id);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (isContainer) {
|
||||
rv = DoCloseContainer(id);
|
||||
}
|
||||
|
||||
mElement = nsnull;
|
||||
mOutputString = nsnull;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::OpenContainer(const nsIParserNode& aNode)
|
||||
{
|
||||
PRInt32 type = aNode.GetNodeType();
|
||||
|
||||
mParserNode = const_cast<nsIParserNode *>(&aNode);
|
||||
return DoOpenContainer(type);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::CloseContainer(const nsHTMLTag aTag)
|
||||
{
|
||||
return DoCloseContainer(aTag);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::AddLeaf(const nsIParserNode& aNode)
|
||||
{
|
||||
eHTMLTags type = (eHTMLTags)aNode.GetNodeType();
|
||||
const nsAString& text = aNode.GetText();
|
||||
|
||||
mParserNode = const_cast<nsIParserNode*>(&aNode);
|
||||
return DoAddLeaf(type, text);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::SetDocumentCharset(nsACString& aCharset)
|
||||
{
|
||||
// No idea, if this works - it isn't invoked by |TestOutput|.
|
||||
Write(NS_LITERAL_STRING("\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=")
|
||||
/* Danger: breaking the line within the string literal, like
|
||||
"foo"\n"bar", breaks win32! */
|
||||
+ nsAdoptingString(escape(NS_ConvertASCIItoUTF16(aCharset)))
|
||||
+ NS_LITERAL_STRING("\">\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozSanitizingHTMLSerializer::OpenHead()
|
||||
{
|
||||
// XXX We don't have a parser node here, is it okay to ignore this?
|
||||
// return OpenContainer(aNode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Here comes the actual code...
|
||||
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::DoOpenContainer(PRInt32 aTag)
|
||||
{
|
||||
eHTMLTags type = (eHTMLTags)aTag;
|
||||
|
||||
if (mSkipLevel == 0 && IsAllowedTag(type))
|
||||
{
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (!parserService)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
const PRUnichar* tag_name = parserService->HTMLIdToStringTag(aTag);
|
||||
NS_ENSURE_TRUE(tag_name, NS_ERROR_INVALID_POINTER);
|
||||
|
||||
Write(NS_LITERAL_STRING("<") + nsDependentString(tag_name));
|
||||
|
||||
// Attributes
|
||||
if (mParserNode)
|
||||
{
|
||||
PRInt32 count = mParserNode->GetAttributeCount();
|
||||
for (PRInt32 i = 0; i < count; i++)
|
||||
{
|
||||
const nsAString& key = mParserNode->GetKeyAt(i);
|
||||
if(IsAllowedAttribute(type, key))
|
||||
{
|
||||
// Ensure basic sanity of value
|
||||
nsAutoString value(mParserNode->GetValueAt(i));
|
||||
// SanitizeAttrValue() modifies |value|
|
||||
if (NS_SUCCEEDED(SanitizeAttrValue(type, key, value)))
|
||||
{
|
||||
// Write out
|
||||
Write(NS_LITERAL_STRING(" "));
|
||||
Write(key); // I get an infinive loop with | + key + | !!!
|
||||
Write(NS_LITERAL_STRING("=\"") + value + NS_LITERAL_STRING("\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write(NS_LITERAL_STRING(">"));
|
||||
}
|
||||
else if (mSkipLevel != 0 || type == eHTMLTag_script || type == eHTMLTag_style)
|
||||
++mSkipLevel;
|
||||
else
|
||||
Write(NS_LITERAL_STRING(" "));
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::DoCloseContainer(PRInt32 aTag)
|
||||
{
|
||||
eHTMLTags type = (eHTMLTags)aTag;
|
||||
|
||||
if (mSkipLevel == 0 && IsAllowedTag(type)) {
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (!parserService)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
const PRUnichar* tag_name = parserService->HTMLIdToStringTag(aTag);
|
||||
NS_ENSURE_TRUE(tag_name, NS_ERROR_INVALID_POINTER);
|
||||
|
||||
Write(NS_LITERAL_STRING("</") + nsDependentString(tag_name)
|
||||
+ NS_LITERAL_STRING(">"));
|
||||
}
|
||||
else if (mSkipLevel == 0)
|
||||
Write(NS_LITERAL_STRING(" "));
|
||||
else
|
||||
--mSkipLevel;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::DoAddLeaf(PRInt32 aTag,
|
||||
const nsAString& aText)
|
||||
{
|
||||
if (mSkipLevel != 0)
|
||||
return NS_OK;
|
||||
|
||||
eHTMLTags type = (eHTMLTags)aTag;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (type == eHTMLTag_whitespace ||
|
||||
type == eHTMLTag_newline)
|
||||
{
|
||||
Write(aText); // sure to be safe?
|
||||
}
|
||||
else if (type == eHTMLTag_text)
|
||||
{
|
||||
nsAutoString text(aText);
|
||||
if(NS_SUCCEEDED(SanitizeTextNode(text)))
|
||||
Write(text);
|
||||
else
|
||||
Write(NS_LITERAL_STRING(TEXT_REMOVED)); // Does not happen (yet)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else if (type == eHTMLTag_entity)
|
||||
{
|
||||
Write(NS_LITERAL_STRING("&"));
|
||||
Write(aText); // sure to be safe?
|
||||
// using + operator here might give an infinitive loop, see above.
|
||||
// not adding ";", because Gecko delivers that as part of |aText| (freaky)
|
||||
}
|
||||
else
|
||||
{
|
||||
DoOpenContainer(type);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Similar to SanitizeAttrValue.
|
||||
*/
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::SanitizeTextNode(nsString& aText /*inout*/)
|
||||
{
|
||||
aText.Adopt(escape(aText));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Ensures basic sanity of attribute value.
|
||||
This function also (tries to :-( ) makes sure, that no
|
||||
unwanted / dangerous URLs appear in the document
|
||||
(like javascript: and data:).
|
||||
|
||||
Pass the value as |aValue| arg. It will be modified in-place.
|
||||
|
||||
If the value is not allowed at all, we return with NS_ERROR_ILLEGAL_VALUE.
|
||||
In that case, do not use the |aValue|, but output nothing.
|
||||
*/
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::SanitizeAttrValue(nsHTMLTag aTag,
|
||||
const nsAString& anAttrName,
|
||||
nsString& aValue /*inout*/)
|
||||
{
|
||||
/* First, cut the attribute to 1000 chars.
|
||||
Attributes with values longer than 1000 chars seem bogus,
|
||||
considering that we don't support any JS. The longest attributes
|
||||
I can think of are URLs, and URLs with 1000 chars are likely to be
|
||||
bogus, too. */
|
||||
aValue = Substring(aValue, 0, 1000);
|
||||
//aValue.Truncate(1000); //-- this cuts half of the document !!?!!
|
||||
|
||||
aValue.Adopt(escape(aValue));
|
||||
|
||||
/* Check some known bad stuff. Add more!
|
||||
I don't care too much, if it happens to trigger in some innocent cases
|
||||
(like <img alt="Statistical data: Mortage rates and newspapers">) -
|
||||
security first. */
|
||||
if (aValue.Find("javascript:") != kNotFound ||
|
||||
aValue.Find("data:") != kNotFound ||
|
||||
aValue.Find("base64") != kNotFound)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
// Check img src scheme
|
||||
if (aTag == eHTMLTag_img &&
|
||||
anAttrName.LowerCaseEqualsLiteral("src"))
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCAutoString scheme;
|
||||
rv = ioService->ExtractScheme(NS_LossyConvertUTF16toASCII(aValue), scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!scheme.Equals("cid", nsCaseInsensitiveCStringComparator()))
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BenB
|
||||
printf("attribute value for %s: -%s-\n",
|
||||
NS_LossyConvertUTF16toASCII(anAttrName).get(),
|
||||
NS_LossyConvertUTF16toASCII(aValue).get());
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
bool
|
||||
mozSanitizingHTMLSerializer::IsAllowedTag(nsHTMLTag aTag)
|
||||
{
|
||||
|
||||
nsPRUint32Key tag_key(aTag);
|
||||
#ifdef DEBUG_BenB
|
||||
printf("IsAllowedTag %d: %s\n",
|
||||
aTag,
|
||||
mAllowedTags.Exists(&tag_key)?"yes":"no");
|
||||
#endif
|
||||
return mAllowedTags.Exists(&tag_key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
bool
|
||||
mozSanitizingHTMLSerializer::IsAllowedAttribute(nsHTMLTag aTag,
|
||||
const nsAString& anAttributeName)
|
||||
{
|
||||
#ifdef DEBUG_BenB
|
||||
printf("IsAllowedAttribute %d, -%s-\n",
|
||||
aTag,
|
||||
NS_LossyConvertUTF16toASCII(anAttributeName).get());
|
||||
#endif
|
||||
nsresult rv;
|
||||
|
||||
nsPRUint32Key tag_key(aTag);
|
||||
nsIProperties* attr_bag = (nsIProperties*)mAllowedTags.Get(&tag_key);
|
||||
NS_ENSURE_TRUE(attr_bag, false);
|
||||
|
||||
bool allowed;
|
||||
nsCAutoString attr;
|
||||
ToLowerCase(NS_ConvertUTF16toUTF8(anAttributeName), attr);
|
||||
rv = attr_bag->Has(attr.get(), &allowed);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG_BenB
|
||||
printf(" Allowed: %s\n", allowed?"yes":"no");
|
||||
#endif
|
||||
return allowed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
aPref is a long string, which holds an exhaustive list of allowed tags
|
||||
and attributes. All other tags and attributes will be removed.
|
||||
|
||||
aPref has the format
|
||||
"html head body ul ol li a(href,name,title) img(src,alt,title) #text"
|
||||
i.e.
|
||||
- tags are separated by whitespace
|
||||
- the attribute list follows the tag directly in brackets
|
||||
- the attributes are separated by commas.
|
||||
|
||||
There is no way to express further restrictions, like "no text inside the
|
||||
<head> element". This is so to considerably reduce the complexity of the
|
||||
pref and this implementation.
|
||||
|
||||
Update: Akk told me that I might be able to use DTD classes. Later(TM)...
|
||||
*/
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::ParsePrefs(const nsAString& aPref)
|
||||
{
|
||||
char* pref = ToNewCString(aPref);
|
||||
char* tags_lasts;
|
||||
for (char* iTag = PL_strtok_r(pref, " ", &tags_lasts);
|
||||
iTag;
|
||||
iTag = PL_strtok_r(NULL, " ", &tags_lasts))
|
||||
{
|
||||
ParseTagPref(nsCAutoString(iTag));
|
||||
}
|
||||
delete[] pref;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parses e.g. "a(href,title)" (but not several tags at once).
|
||||
*/
|
||||
nsresult
|
||||
mozSanitizingHTMLSerializer::ParseTagPref(const nsCAutoString& tagpref)
|
||||
{
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (!parserService)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Parsing tag
|
||||
PRInt32 bracket = tagpref.FindChar('(');
|
||||
if (bracket == 0)
|
||||
{
|
||||
printf(" malformed pref: %s\n", tagpref.get());
|
||||
return NS_ERROR_CANNOT_CONVERT_DATA;
|
||||
}
|
||||
|
||||
nsAutoString tag;
|
||||
CopyUTF8toUTF16(StringHead(tagpref, bracket), tag);
|
||||
|
||||
// Create key
|
||||
PRInt32 tag_id = parserService->HTMLStringTagToId(tag);
|
||||
if (tag_id == eHTMLTag_userdefined)
|
||||
{
|
||||
printf(" unknown tag <%s>, won't add.\n",
|
||||
NS_ConvertUTF16toUTF8(tag).get());
|
||||
return NS_ERROR_CANNOT_CONVERT_DATA;
|
||||
}
|
||||
nsPRUint32Key tag_key(tag_id);
|
||||
|
||||
if (mAllowedTags.Exists(&tag_key))
|
||||
{
|
||||
printf(" duplicate tag: %s\n", NS_ConvertUTF16toUTF8(tag).get());
|
||||
return NS_ERROR_CANNOT_CONVERT_DATA;
|
||||
}
|
||||
if (bracket == kNotFound)
|
||||
/* There are no attributes in the pref. So, allow none; only the tag
|
||||
itself */
|
||||
{
|
||||
mAllowedTags.Put(&tag_key, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attributes
|
||||
|
||||
// where is the macro for non-fatal errors in opt builds?
|
||||
if(tagpref[tagpref.Length() - 1] != ')' ||
|
||||
tagpref.Length() < PRUint32(bracket) + 3)
|
||||
{
|
||||
printf(" malformed pref: %s\n", tagpref.get());
|
||||
return NS_ERROR_CANNOT_CONVERT_DATA;
|
||||
}
|
||||
nsCOMPtr<nsIProperties> attr_bag =
|
||||
do_CreateInstance(NS_PROPERTIES_CONTRACTID);
|
||||
NS_ENSURE_TRUE(attr_bag, NS_ERROR_INVALID_POINTER);
|
||||
nsCAutoString attrList;
|
||||
attrList.Append(Substring(tagpref,
|
||||
bracket + 1,
|
||||
tagpref.Length() - 2 - bracket));
|
||||
char* attrs_lasts;
|
||||
for (char* iAttr = PL_strtok_r(attrList.BeginWriting(),
|
||||
",", &attrs_lasts);
|
||||
iAttr;
|
||||
iAttr = PL_strtok_r(NULL, ",", &attrs_lasts))
|
||||
{
|
||||
attr_bag->Set(iAttr, 0);
|
||||
}
|
||||
|
||||
nsIProperties* attr_bag_raw = attr_bag;
|
||||
NS_ADDREF(attr_bag_raw);
|
||||
mAllowedTags.Put(&tag_key, attr_bag_raw);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
might be useful:
|
||||
htmlparser/public/nsHTMLTokens.h for tag categories
|
||||
*/
|
@ -1,158 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* ***** 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 mozilla.org HTML Sanitizer code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ben Bucksch <mozilla@bucksch.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Netscape
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
/*
|
||||
* A serializer and content sink that removes potentially insecure or
|
||||
* otherwise dangerous or offending HTML (eg for display of HTML
|
||||
* e-mail attachments or something).
|
||||
*/
|
||||
|
||||
#ifndef mozSanitizingSerializer_h__
|
||||
#define mozSanitizingSerializer_h__
|
||||
|
||||
#include "mozISanitizingSerializer.h"
|
||||
#include "nsIContentSerializer.h"
|
||||
#include "nsIHTMLContentSink.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
class mozSanitizingHTMLSerializer : public nsIContentSerializer,
|
||||
public nsIHTMLContentSink,
|
||||
public mozISanitizingHTMLSerializer
|
||||
{
|
||||
public:
|
||||
mozSanitizingHTMLSerializer();
|
||||
virtual ~mozSanitizingHTMLSerializer();
|
||||
static bool ReleaseProperties(nsHashKey* key, void* data, void* closure);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIContentSerializer
|
||||
NS_IMETHOD Init(PRUint32 flags, PRUint32 dummy, const char* aCharSet,
|
||||
bool aIsCopying, bool aIsWholeDocument);
|
||||
|
||||
NS_IMETHOD AppendText(nsIContent* aText, PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset, nsAString& aStr);
|
||||
NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
|
||||
PRInt32 aStartOffset, PRInt32 aEndOffset,
|
||||
nsAString& aStr)
|
||||
{ return NS_OK; }
|
||||
NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
|
||||
PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset,
|
||||
nsAString& aStr)
|
||||
{ return NS_OK; }
|
||||
NS_IMETHOD AppendComment(nsIContent* aComment, PRInt32 aStartOffset,
|
||||
PRInt32 aEndOffset, nsAString& aStr)
|
||||
{ return NS_OK; }
|
||||
NS_IMETHOD AppendDoctype(nsIContent *aDoctype, nsAString& aStr)
|
||||
{ return NS_OK; }
|
||||
NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
|
||||
mozilla::dom::Element* aOriginalElement,
|
||||
nsAString& aStr);
|
||||
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
||||
nsAString& aStr);
|
||||
NS_IMETHOD Flush(nsAString& aStr);
|
||||
|
||||
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
|
||||
nsAString& aStr);
|
||||
|
||||
// nsIContentSink
|
||||
NS_IMETHOD WillParse(void) { return NS_OK; }
|
||||
NS_IMETHOD WillInterrupt(void) { return NS_OK; }
|
||||
NS_IMETHOD WillResume(void) { return NS_OK; }
|
||||
NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
|
||||
NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
|
||||
NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
|
||||
NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
|
||||
virtual void FlushPendingNotifications(mozFlushType aType) { }
|
||||
NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
|
||||
virtual nsISupports *GetTarget() { return nsnull; }
|
||||
|
||||
// nsIHTMLContentSink
|
||||
NS_IMETHOD OpenHead();
|
||||
NS_IMETHOD IsEnabled(PRInt32 aTag, bool* aReturn);
|
||||
NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition) { return NS_OK; }
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
// nsISanitizingHTMLSerializer
|
||||
NS_IMETHOD Initialize(nsAString* aOutString,
|
||||
PRUint32 aFlags, const nsAString& allowedTags);
|
||||
|
||||
protected:
|
||||
nsresult ParsePrefs(const nsAString& aPref);
|
||||
nsresult ParseTagPref(const nsCAutoString& tagpref);
|
||||
bool IsAllowedTag(nsHTMLTag aTag);
|
||||
bool IsAllowedAttribute(nsHTMLTag aTag, const nsAString& anAttributeName);
|
||||
nsresult SanitizeAttrValue(nsHTMLTag aTag, const nsAString& attr_name,
|
||||
nsString& value /*inout*/);
|
||||
nsresult SanitizeTextNode(nsString& value /*inout*/);
|
||||
bool IsContainer(PRInt32 aId);
|
||||
static PRInt32 GetIdForContent(nsIContent* aContent);
|
||||
nsresult GetParserService(nsIParserService** aParserService);
|
||||
nsresult DoOpenContainer(PRInt32 aTag);
|
||||
nsresult DoCloseContainer(PRInt32 aTag);
|
||||
nsresult DoAddLeaf(PRInt32 aTag, const nsAString& aText);
|
||||
void Write(const nsAString& aString);
|
||||
|
||||
protected:
|
||||
PRInt32 mFlags;
|
||||
PRUint32 mSkipLevel;
|
||||
nsHashtable mAllowedTags;
|
||||
|
||||
nsRefPtr<mozilla::dom::Element> mElement;
|
||||
nsAString* mOutputString;
|
||||
nsIParserNode* mParserNode;
|
||||
nsCOMPtr<nsIParserService> mParserService;
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewSanitizingHTMLSerializer(nsIContentSerializer** aSerializer);
|
||||
|
||||
#endif
|
6
js/src/jit-test/tests/basic/testBug737575.js
Normal file
6
js/src/jit-test/tests/basic/testBug737575.js
Normal file
@ -0,0 +1,6 @@
|
||||
function f(s) {
|
||||
return arguments[s];
|
||||
}
|
||||
|
||||
for (var i = 0; i < 10; ++i)
|
||||
assertEq(f(String(i+1), 0,1,2,3,4,5,6,7,8,9), i);
|
6
js/src/jit-test/tests/basic/testWeirdGetterInvocation.js
Normal file
6
js/src/jit-test/tests/basic/testWeirdGetterInvocation.js
Normal file
@ -0,0 +1,6 @@
|
||||
function getArgs() { return arguments; }
|
||||
var a1 = getArgs(1);
|
||||
var a2 = getArgs(1);
|
||||
a1.__proto__ = a2;
|
||||
delete a1[0];
|
||||
a1[0];
|
@ -678,14 +678,17 @@ TypeSet::addCall(JSContext *cx, TypeCallsite *site)
|
||||
class TypeConstraintArith : public TypeConstraint
|
||||
{
|
||||
public:
|
||||
JSScript *script;
|
||||
jsbytecode *pc;
|
||||
|
||||
/* Type set receiving the result of the arithmetic. */
|
||||
TypeSet *target;
|
||||
|
||||
/* For addition operations, the other operand. */
|
||||
TypeSet *other;
|
||||
|
||||
TypeConstraintArith(TypeSet *target, TypeSet *other)
|
||||
: TypeConstraint("arith"), target(target), other(other)
|
||||
TypeConstraintArith(JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
|
||||
: TypeConstraint("arith"), script(script), pc(pc), target(target), other(other)
|
||||
{
|
||||
JS_ASSERT(target);
|
||||
}
|
||||
@ -694,9 +697,9 @@ public:
|
||||
};
|
||||
|
||||
void
|
||||
TypeSet::addArith(JSContext *cx, TypeSet *target, TypeSet *other)
|
||||
TypeSet::addArith(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
|
||||
{
|
||||
add(cx, cx->typeLifoAlloc().new_<TypeConstraintArith>(target, other));
|
||||
add(cx, cx->typeLifoAlloc().new_<TypeConstraintArith>(script, pc, target, other));
|
||||
}
|
||||
|
||||
/* Subset constraint which transforms primitive values into appropriate objects. */
|
||||
@ -1299,27 +1302,29 @@ TypeConstraintArith::newType(JSContext *cx, TypeSet *source, Type type)
|
||||
} else if (type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
|
||||
if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
|
||||
TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_BOOLEAN |
|
||||
TYPE_FLAG_ANYOBJECT) ||
|
||||
other->getObjectCount() != 0) {
|
||||
TYPE_FLAG_ANYOBJECT)) {
|
||||
target->addType(cx, Type::DoubleType());
|
||||
} else if (other->getObjectCount() != 0) {
|
||||
TypeDynamicResult(cx, script, pc, Type::DoubleType());
|
||||
}
|
||||
} else if (type.isPrimitive(JSVAL_TYPE_STRING)) {
|
||||
target->addType(cx, Type::StringType());
|
||||
} else {
|
||||
if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
|
||||
TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN |
|
||||
TYPE_FLAG_ANYOBJECT) ||
|
||||
other->getObjectCount() != 0) {
|
||||
target->addType(cx, Type::Int32Type());
|
||||
}
|
||||
if (other->hasAnyFlag(TYPE_FLAG_DOUBLE))
|
||||
target->addType(cx, Type::DoubleType());
|
||||
} else if (other->hasAnyFlag(TYPE_FLAG_DOUBLE)) {
|
||||
target->addType(cx, Type::DoubleType());
|
||||
} else if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
|
||||
TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN |
|
||||
TYPE_FLAG_ANYOBJECT)) {
|
||||
target->addType(cx, Type::Int32Type());
|
||||
} else if (other->getObjectCount() != 0) {
|
||||
TypeDynamicResult(cx, script, pc, Type::Int32Type());
|
||||
}
|
||||
} else {
|
||||
if (type.isUnknown())
|
||||
target->addType(cx, Type::UnknownType());
|
||||
else if (type.isPrimitive(JSVAL_TYPE_DOUBLE))
|
||||
target->addType(cx, Type::DoubleType());
|
||||
else if (!type.isAnyObject() && type.isObject())
|
||||
TypeDynamicResult(cx, script, pc, Type::Int32Type());
|
||||
else
|
||||
target->addType(cx, Type::Int32Type());
|
||||
}
|
||||
@ -3616,10 +3621,10 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
case JSOP_LOCALDEC: {
|
||||
uint32_t slot = GetBytecodeSlot(script, pc);
|
||||
if (trackSlot(slot)) {
|
||||
poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
|
||||
poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
|
||||
} else if (slot < TotalSlots(script)) {
|
||||
TypeSet *types = TypeScript::SlotTypes(script, slot);
|
||||
types->addArith(cx, types);
|
||||
types->addArith(cx, script, pc, types);
|
||||
types->addSubset(cx, &pushed[0]);
|
||||
} else {
|
||||
pushed[0].addType(cx, Type::UnknownType());
|
||||
@ -3702,21 +3707,21 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
break;
|
||||
|
||||
case JSOP_ADD:
|
||||
poppedTypes(pc, 0)->addArith(cx, &pushed[0], poppedTypes(pc, 1));
|
||||
poppedTypes(pc, 1)->addArith(cx, &pushed[0], poppedTypes(pc, 0));
|
||||
poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 1));
|
||||
poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 0));
|
||||
break;
|
||||
|
||||
case JSOP_SUB:
|
||||
case JSOP_MUL:
|
||||
case JSOP_MOD:
|
||||
case JSOP_DIV:
|
||||
poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
|
||||
poppedTypes(pc, 1)->addArith(cx, &pushed[0]);
|
||||
poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
|
||||
poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0]);
|
||||
break;
|
||||
|
||||
case JSOP_NEG:
|
||||
case JSOP_POS:
|
||||
poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
|
||||
poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
|
||||
break;
|
||||
|
||||
case JSOP_LAMBDA:
|
||||
|
@ -441,7 +441,8 @@ class TypeSet
|
||||
void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
TypeSet *objectTypes, TypeSet *valueTypes);
|
||||
void addCall(JSContext *cx, TypeCallsite *site);
|
||||
void addArith(JSContext *cx, TypeSet *target, TypeSet *other = NULL);
|
||||
void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
TypeSet *target, TypeSet *other = NULL);
|
||||
void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
|
||||
void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
Type type, TypeSet *types = NULL);
|
||||
|
@ -6247,7 +6247,6 @@ dumpValue(const Value &v)
|
||||
#ifdef DEBUG
|
||||
switch (v.whyMagic()) {
|
||||
case JS_ARRAY_HOLE: fprintf(stderr, " array hole"); break;
|
||||
case JS_ARGS_HOLE: fprintf(stderr, " args hole"); break;
|
||||
case JS_NATIVE_ENUMERATE: fprintf(stderr, " native enumeration"); break;
|
||||
case JS_NO_ITER_VALUE: fprintf(stderr, " no iter value"); break;
|
||||
case JS_GENERATOR_CLOSING: fprintf(stderr, " generator closing"); break;
|
||||
|
@ -297,6 +297,66 @@ UnsignedPtrDiff(const void *bigger, const void *smaller)
|
||||
*/
|
||||
enum MaybeReportError { REPORT_ERROR = true, DONT_REPORT_ERROR = false };
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* A bit array is an array of bits represented by an array of words (size_t). */
|
||||
|
||||
static inline unsigned
|
||||
NumWordsForBitArrayOfLength(size_t length)
|
||||
{
|
||||
return (length + (JS_BITS_PER_WORD - 1)) / JS_BITS_PER_WORD;
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
BitArrayIndexToWordIndex(size_t length, size_t bitIndex)
|
||||
{
|
||||
unsigned wordIndex = bitIndex / JS_BITS_PER_WORD;
|
||||
JS_ASSERT(wordIndex < length);
|
||||
return wordIndex;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
BitArrayIndexToWordMask(size_t i)
|
||||
{
|
||||
return size_t(1) << (i % JS_BITS_PER_WORD);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsBitArrayElementSet(size_t *array, size_t length, size_t i)
|
||||
{
|
||||
return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsAnyBitArrayElementSet(size_t *array, size_t length)
|
||||
{
|
||||
unsigned numWords = NumWordsForBitArrayOfLength(length);
|
||||
for (unsigned i = 0; i < numWords; ++i) {
|
||||
if (array[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SetBitArrayElement(size_t *array, size_t length, size_t i)
|
||||
{
|
||||
array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ClearBitArrayElement(size_t *array, size_t length, size_t i)
|
||||
{
|
||||
array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ClearAllBitArrayElements(size_t *array, size_t length)
|
||||
{
|
||||
for (unsigned i = 0; i < length; ++i)
|
||||
array[i] = 0;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
@ -275,7 +275,6 @@ typedef uint64_t JSValueShiftedTag;
|
||||
typedef enum JSWhyMagic
|
||||
{
|
||||
JS_ARRAY_HOLE, /* a hole in a dense array */
|
||||
JS_ARGS_HOLE, /* a hole in the args object's array */
|
||||
JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded
|
||||
* to JS_EnumerateState, which really means the object can be
|
||||
* enumerated like a native object. */
|
||||
@ -289,6 +288,7 @@ typedef enum JSWhyMagic
|
||||
JS_UNASSIGNED_ARGUMENTS, /* the initial value of callobj.arguments */
|
||||
JS_OPTIMIZED_ARGUMENTS, /* optimized-away 'arguments' value */
|
||||
JS_IS_CONSTRUCTING, /* magic value passed to natives to indicate construction */
|
||||
JS_OVERWRITTEN_CALLEE, /* arguments.callee has been overwritten */
|
||||
JS_GENERIC_MAGIC /* for local use */
|
||||
} JSWhyMagic;
|
||||
|
||||
|
@ -864,47 +864,6 @@ class GetPropCompiler : public PICStubCompiler
|
||||
repatcher.relink(pic.slowPathCall, target);
|
||||
}
|
||||
|
||||
LookupStatus generateArgsLengthStub()
|
||||
{
|
||||
Assembler masm;
|
||||
|
||||
Jump notArgs = masm.guardShape(pic.objReg, obj);
|
||||
|
||||
masm.load32(Address(pic.objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), pic.objReg);
|
||||
masm.move(pic.objReg, pic.shapeReg);
|
||||
Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg,
|
||||
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
|
||||
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), pic.objReg);
|
||||
|
||||
masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
|
||||
Jump done = masm.jump();
|
||||
|
||||
pic.updatePCCounters(f, masm);
|
||||
|
||||
PICLinker buffer(masm, pic);
|
||||
if (!buffer.init(cx))
|
||||
return error();
|
||||
|
||||
if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
|
||||
!buffer.verifyRange(f.chunk())) {
|
||||
return disable("code memory is out of range");
|
||||
}
|
||||
|
||||
buffer.link(notArgs, pic.slowPathStart);
|
||||
buffer.link(overridden, pic.slowPathStart);
|
||||
buffer.link(done, pic.fastPathRejoin);
|
||||
|
||||
CodeLocationLabel start = buffer.finalize(f);
|
||||
JaegerSpew(JSpew_PICs, "generate args length stub at %p\n",
|
||||
start.executableAddress());
|
||||
|
||||
patchPreviousToHere(start);
|
||||
|
||||
disable("args length done");
|
||||
|
||||
return Lookup_Cacheable;
|
||||
}
|
||||
|
||||
LookupStatus generateArrayLengthStub()
|
||||
{
|
||||
Assembler masm;
|
||||
@ -1883,21 +1842,14 @@ GetPropMaybeCached(VMFrame &f, ic::PICInfo *pic, bool cached)
|
||||
}
|
||||
if (!f.regs.sp[-1].isPrimitive()) {
|
||||
JSObject *obj = &f.regs.sp[-1].toObject();
|
||||
if (obj->isArray() ||
|
||||
(obj->isArguments() && !obj->asArguments().hasOverriddenLength()) ||
|
||||
obj->isString()) {
|
||||
if (obj->isArray() || obj->isString()) {
|
||||
GetPropCompiler cc(f, script, obj, *pic, NULL, stub);
|
||||
if (obj->isArray()) {
|
||||
LookupStatus status = cc.generateArrayLengthStub();
|
||||
if (status == Lookup_Error)
|
||||
THROW();
|
||||
f.regs.sp[-1].setNumber(obj->getArrayLength());
|
||||
} else if (obj->isArguments()) {
|
||||
LookupStatus status = cc.generateArgsLengthStub();
|
||||
if (status == Lookup_Error)
|
||||
THROW();
|
||||
f.regs.sp[-1].setInt32(int32_t(obj->asArguments().initialLength()));
|
||||
} else if (obj->isString()) {
|
||||
} else {
|
||||
LookupStatus status = cc.generateStringObjLengthStub();
|
||||
if (status == Lookup_Error)
|
||||
THROW();
|
||||
@ -2368,158 +2320,6 @@ GetElementIC::attachGetProp(VMFrame &f, JSObject *obj, const Value &v, PropertyN
|
||||
return Lookup_Cacheable;
|
||||
}
|
||||
|
||||
LookupStatus
|
||||
GetElementIC::attachArguments(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
|
||||
if (!v.isInt32())
|
||||
return disable(f, "arguments object with non-integer key");
|
||||
|
||||
if (op == JSOP_CALLELEM)
|
||||
return disable(f, "arguments object with call");
|
||||
|
||||
JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
|
||||
|
||||
Assembler masm;
|
||||
|
||||
Jump shapeGuard = masm.testObjClass(Assembler::NotEqual, objReg, typeReg, obj->getClass());
|
||||
|
||||
masm.move(objReg, typeReg);
|
||||
masm.load32(Address(objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)),
|
||||
objReg);
|
||||
Jump overridden = masm.branchTest32(Assembler::NonZero, objReg,
|
||||
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
|
||||
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), objReg);
|
||||
|
||||
Jump outOfBounds;
|
||||
if (idRemat.isConstant()) {
|
||||
outOfBounds = masm.branch32(Assembler::BelowOrEqual, objReg, Imm32(v.toInt32()));
|
||||
} else {
|
||||
outOfBounds = masm.branch32(Assembler::BelowOrEqual, objReg, idRemat.dataReg());
|
||||
}
|
||||
|
||||
masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);
|
||||
if (idRemat.isConstant()) {
|
||||
Address slot(objReg, offsetof(ArgumentsData, slots) + v.toInt32() * sizeof(Value));
|
||||
masm.loadTypeTag(slot, objReg);
|
||||
} else {
|
||||
BaseIndex slot(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE,
|
||||
offsetof(ArgumentsData, slots));
|
||||
masm.loadTypeTag(slot, objReg);
|
||||
}
|
||||
Jump holeCheck = masm.branchPtr(Assembler::Equal, objReg, ImmType(JSVAL_TYPE_MAGIC));
|
||||
|
||||
masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::STACK_FRAME_SLOT)), objReg);
|
||||
Jump liveArguments = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(0));
|
||||
|
||||
masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);
|
||||
|
||||
if (idRemat.isConstant()) {
|
||||
Address slot(objReg, offsetof(ArgumentsData, slots) + v.toInt32() * sizeof(Value));
|
||||
masm.loadValueAsComponents(slot, typeReg, objReg);
|
||||
} else {
|
||||
BaseIndex slot(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE,
|
||||
offsetof(ArgumentsData, slots));
|
||||
masm.loadValueAsComponents(slot, typeReg, objReg);
|
||||
}
|
||||
|
||||
Jump done = masm.jump();
|
||||
|
||||
liveArguments.linkTo(masm.label(), &masm);
|
||||
|
||||
masm.move(objReg, typeReg);
|
||||
|
||||
Address fun(typeReg, StackFrame::offsetOfExec());
|
||||
masm.loadPtr(fun, objReg);
|
||||
|
||||
Address nargs(objReg, offsetof(JSFunction, nargs));
|
||||
masm.load16(nargs, objReg);
|
||||
|
||||
Jump notFormalArg;
|
||||
if (idRemat.isConstant())
|
||||
notFormalArg = masm.branch32(Assembler::BelowOrEqual, objReg, Imm32(v.toInt32()));
|
||||
else
|
||||
notFormalArg = masm.branch32(Assembler::BelowOrEqual, objReg, idRemat.dataReg());
|
||||
|
||||
masm.lshift32(Imm32(3), objReg); /* nargs << 3 == nargs * sizeof(Value) */
|
||||
masm.subPtr(objReg, typeReg); /* fp - numFormalArgs => start of formal args */
|
||||
|
||||
Label loadFromStack = masm.label();
|
||||
masm.move(typeReg, objReg);
|
||||
|
||||
if (idRemat.isConstant()) {
|
||||
Address frameEntry(objReg, v.toInt32() * sizeof(Value));
|
||||
masm.loadValueAsComponents(frameEntry, typeReg, objReg);
|
||||
} else {
|
||||
BaseIndex frameEntry(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE);
|
||||
masm.loadValueAsComponents(frameEntry, typeReg, objReg);
|
||||
}
|
||||
Jump done2 = masm.jump();
|
||||
|
||||
notFormalArg.linkTo(masm.label(), &masm);
|
||||
|
||||
masm.push(typeReg);
|
||||
|
||||
Address argsObject(typeReg, StackFrame::offsetOfArgsObj());
|
||||
masm.loadPtr(argsObject, typeReg);
|
||||
|
||||
masm.load32(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)),
|
||||
typeReg);
|
||||
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), typeReg);
|
||||
|
||||
/* This basically does fp - (numFormalArgs + numActualArgs + 2) */
|
||||
|
||||
masm.addPtr(typeReg, objReg);
|
||||
masm.addPtr(Imm32(2), objReg);
|
||||
masm.lshiftPtr(Imm32(3), objReg);
|
||||
|
||||
masm.pop(typeReg);
|
||||
masm.subPtr(objReg, typeReg);
|
||||
|
||||
masm.jump(loadFromStack);
|
||||
|
||||
updatePCCounters(f, masm);
|
||||
|
||||
PICLinker buffer(masm, *this);
|
||||
|
||||
if (!buffer.init(cx))
|
||||
return error(cx);
|
||||
|
||||
if (!buffer.verifyRange(f.chunk()))
|
||||
return disable(f, "code memory is out of range");
|
||||
|
||||
buffer.link(shapeGuard, slowPathStart);
|
||||
buffer.link(overridden, slowPathStart);
|
||||
buffer.link(outOfBounds, slowPathStart);
|
||||
buffer.link(holeCheck, slowPathStart);
|
||||
buffer.link(done, fastPathRejoin);
|
||||
buffer.link(done2, fastPathRejoin);
|
||||
|
||||
CodeLocationLabel cs = buffer.finalizeCodeAddendum();
|
||||
|
||||
JaegerSpew(JSpew_PICs, "generated getelem arguments stub at %p\n", cs.executableAddress());
|
||||
|
||||
Repatcher repatcher(f.chunk());
|
||||
repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
|
||||
|
||||
JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
|
||||
JS_ASSERT(!inlineShapeGuardPatched);
|
||||
|
||||
inlineShapeGuardPatched = true;
|
||||
stubsGenerated++;
|
||||
|
||||
if (stubsGenerated == MAX_GETELEM_IC_STUBS)
|
||||
disable(f, "max stubs reached");
|
||||
|
||||
disable(f, "generated arguments stub");
|
||||
|
||||
if (!obj->getGeneric(cx, id, vp))
|
||||
return Lookup_Error;
|
||||
|
||||
return Lookup_Cacheable;
|
||||
}
|
||||
|
||||
#if defined JS_METHODJIT_TYPED_ARRAY
|
||||
LookupStatus
|
||||
GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
|
||||
@ -2627,9 +2427,6 @@ GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *
|
||||
if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
|
||||
return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
|
||||
|
||||
if (obj->isArguments())
|
||||
return attachArguments(f, obj, v, id, vp);
|
||||
|
||||
#if defined JS_METHODJIT_TYPED_ARRAY
|
||||
/*
|
||||
* Typed array ICs can make stub calls, and need to know which registers
|
||||
|
@ -301,7 +301,6 @@ struct GetElementIC : public BasePolyIC {
|
||||
LookupStatus update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
|
||||
LookupStatus attachGetProp(VMFrame &f, JSObject *obj, const Value &v, PropertyName *name,
|
||||
Value *vp);
|
||||
LookupStatus attachArguments(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
|
||||
LookupStatus attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
|
||||
LookupStatus disable(VMFrame &f, const char *reason);
|
||||
LookupStatus error(JSContext *cx);
|
||||
|
@ -89,39 +89,42 @@ ArgumentsObject::data() const
|
||||
return reinterpret_cast<js::ArgumentsData *>(getFixedSlot(DATA_SLOT).toPrivate());
|
||||
}
|
||||
|
||||
inline bool
|
||||
ArgumentsObject::isElementDeleted(uint32_t i) const
|
||||
{
|
||||
return IsBitArrayElementSet(data()->deletedBits, initialLength(), i);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ArgumentsObject::isAnyElementDeleted() const
|
||||
{
|
||||
return IsAnyBitArrayElementSet(data()->deletedBits, initialLength());
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::markElementDeleted(uint32_t i)
|
||||
{
|
||||
SetBitArrayElement(data()->deletedBits, initialLength(), i);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
ArgumentsObject::element(uint32_t i) const
|
||||
{
|
||||
JS_ASSERT(i < initialLength());
|
||||
JS_ASSERT(!isElementDeleted(i));
|
||||
return data()->slots[i];
|
||||
}
|
||||
|
||||
inline const js::Value *
|
||||
ArgumentsObject::elements() const
|
||||
{
|
||||
return Valueify(data()->slots);
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setElement(uint32_t i, const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(i < initialLength());
|
||||
JS_ASSERT(!isElementDeleted(i));
|
||||
data()->slots[i] = v;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ArgumentsObject::getElement(uint32_t i, Value *vp)
|
||||
{
|
||||
if (i >= initialLength())
|
||||
return false;
|
||||
|
||||
*vp = element(i);
|
||||
|
||||
/*
|
||||
* If the argument was overwritten, it could be in any object slot, so we
|
||||
* can't optimize.
|
||||
*/
|
||||
if (vp->isMagic(JS_ARGS_HOLE))
|
||||
if (i >= initialLength() || isElementDeleted(i))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -133,6 +136,8 @@ ArgumentsObject::getElement(uint32_t i, Value *vp)
|
||||
JS_ASSERT_IF(isStrictArguments(), !fp);
|
||||
if (fp)
|
||||
*vp = fp->canonicalActualArg(i);
|
||||
else
|
||||
*vp = element(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -144,8 +149,6 @@ struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo
|
||||
ArgumentsObject &argsobj;
|
||||
Value *dst;
|
||||
bool operator()(uint32_t argi, Value *src) {
|
||||
if (argsobj.element(argi).isMagic(JS_ARGS_HOLE))
|
||||
return false;
|
||||
*dst++ = *src;
|
||||
return true;
|
||||
}
|
||||
@ -159,21 +162,18 @@ ArgumentsObject::getElements(uint32_t start, uint32_t count, Value *vp)
|
||||
JS_ASSERT(start + count >= start);
|
||||
|
||||
uint32_t length = initialLength();
|
||||
if (start > length || start + count > length)
|
||||
if (start > length || start + count > length || isAnyElementDeleted())
|
||||
return false;
|
||||
|
||||
StackFrame *fp = maybeStackFrame();
|
||||
|
||||
/* If there's no stack frame for this, argument values are in elements(). */
|
||||
if (!fp) {
|
||||
const Value *srcbeg = elements() + start;
|
||||
const Value *srcbeg = Valueify(data()->slots) + start;
|
||||
const Value *srcend = srcbeg + count;
|
||||
const Value *src = srcbeg;
|
||||
for (Value *dst = vp; src < srcend; ++dst, ++src) {
|
||||
if (src->isMagic(JS_ARGS_HOLE))
|
||||
return false;
|
||||
for (Value *dst = vp; src < srcend; ++dst, ++src)
|
||||
*dst = *src;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ NormalArgumentsObject::callee() const
|
||||
inline void
|
||||
NormalArgumentsObject::clearCallee()
|
||||
{
|
||||
data()->callee.set(compartment(), MagicValue(JS_ARGS_HOLE));
|
||||
data()->callee.set(compartment(), MagicValue(JS_OVERWRITTEN_CALLEE));
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
@ -56,12 +56,14 @@ using namespace js::gc;
|
||||
|
||||
struct PutArg
|
||||
{
|
||||
PutArg(JSCompartment *comp, HeapValue *dst) : dst(dst), compartment(comp) {}
|
||||
HeapValue *dst;
|
||||
PutArg(JSCompartment *comp, ArgumentsObject &argsobj)
|
||||
: compartment(comp), argsobj(argsobj), dst(argsobj.data()->slots) {}
|
||||
JSCompartment *compartment;
|
||||
bool operator()(unsigned, Value *src) {
|
||||
JS_ASSERT(dst->isMagic(JS_ARGS_HOLE) || dst->isUndefined());
|
||||
if (!dst->isMagic(JS_ARGS_HOLE))
|
||||
ArgumentsObject &argsobj;
|
||||
HeapValue *dst;
|
||||
bool operator()(unsigned i, Value *src) {
|
||||
JS_ASSERT(dst->isUndefined());
|
||||
if (!argsobj.isElementDeleted(i))
|
||||
dst->set(compartment, *src);
|
||||
++dst;
|
||||
return true;
|
||||
@ -75,7 +77,7 @@ js_PutArgsObject(StackFrame *fp)
|
||||
if (argsobj.isNormalArguments()) {
|
||||
JS_ASSERT(argsobj.maybeStackFrame() == fp);
|
||||
JSCompartment *comp = fp->scopeChain().compartment();
|
||||
fp->forEachCanonicalActualArg(PutArg(comp, argsobj.data()->slots));
|
||||
fp->forEachCanonicalActualArg(PutArg(comp, argsobj));
|
||||
argsobj.setStackFrame(NULL);
|
||||
} else {
|
||||
JS_ASSERT(!argsobj.maybeStackFrame());
|
||||
@ -108,14 +110,20 @@ ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
|
||||
if (!emptyArgumentsShape)
|
||||
return NULL;
|
||||
|
||||
ArgumentsData *data = (ArgumentsData *)
|
||||
cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
|
||||
unsigned numDeletedWords = NumWordsForBitArrayOfLength(argc);
|
||||
unsigned numBytes = offsetof(ArgumentsData, slots) +
|
||||
numDeletedWords * sizeof(size_t) +
|
||||
argc * sizeof(Value);
|
||||
|
||||
ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
data->callee.init(ObjectValue(callee));
|
||||
for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++)
|
||||
vp->init(UndefinedValue());
|
||||
data->deletedBits = (size_t *)(data->slots + argc);
|
||||
ClearAllBitArrayElements(data->deletedBits, numDeletedWords);
|
||||
|
||||
/* We have everything needed to fill in the object, so make the object. */
|
||||
JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
|
||||
@ -151,7 +159,7 @@ ArgumentsObject::create(JSContext *cx, StackFrame *fp)
|
||||
* to retrieve up-to-date parameter values.
|
||||
*/
|
||||
if (argsobj->isStrictArguments())
|
||||
fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
|
||||
fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
|
||||
else
|
||||
argsobj->setStackFrame(fp);
|
||||
|
||||
@ -166,7 +174,7 @@ ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp)
|
||||
if (!argsobj)
|
||||
return NULL;
|
||||
|
||||
fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
|
||||
fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
|
||||
return argsobj;
|
||||
}
|
||||
|
||||
@ -176,8 +184,10 @@ args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
ArgumentsObject &argsobj = obj->asArguments();
|
||||
if (JSID_IS_INT(id)) {
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
if (arg < argsobj.initialLength())
|
||||
argsobj.setElement(arg, MagicValue(JS_ARGS_HOLE));
|
||||
if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
|
||||
argsobj.setElement(arg, UndefinedValue());
|
||||
argsobj.markElementDeleted(arg);
|
||||
}
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
|
||||
argsobj.markLengthOverridden();
|
||||
} else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
|
||||
@ -199,8 +209,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
* prototype to point to another Arguments object with a bigger argc.
|
||||
*/
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
if (arg < argsobj.initialLength()) {
|
||||
JS_ASSERT(!argsobj.element(arg).isMagic(JS_ARGS_HOLE));
|
||||
if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
|
||||
if (StackFrame *fp = argsobj.maybeStackFrame())
|
||||
*vp = fp->canonicalActualArg(arg);
|
||||
else
|
||||
@ -212,7 +221,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
|
||||
const Value &v = argsobj.callee();
|
||||
if (!v.isMagic(JS_ARGS_HOLE))
|
||||
if (!v.isMagic(JS_OVERWRITTEN_CALLEE))
|
||||
*vp = v;
|
||||
}
|
||||
return true;
|
||||
@ -267,7 +276,7 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
|
||||
unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32_t arg = uint32_t(JSID_TO_INT(id));
|
||||
if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
|
||||
if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
|
||||
return true;
|
||||
|
||||
attrs |= JSPROP_ENUMERATE;
|
||||
@ -278,7 +287,7 @@ args_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
|
||||
if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
|
||||
return true;
|
||||
|
||||
if (argsobj.callee().isMagic(JS_ARGS_HOLE))
|
||||
if (argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE))
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -295,17 +304,29 @@ NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Val
|
||||
{
|
||||
JS_ASSERT(!fp->hasArgsObj());
|
||||
|
||||
/* Fast path: no need to convert to id when elem is already an int in range. */
|
||||
if (elem.isInt32()) {
|
||||
int32_t i = elem.toInt32();
|
||||
if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
|
||||
*vp = fp->canonicalActualArg(elem.toInt32());
|
||||
*vp = fp->canonicalActualArg(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Slow path: create and canonicalize an id, then emulate args_resolve. */
|
||||
|
||||
jsid id;
|
||||
if (!ValueToId(cx, elem, &id))
|
||||
return false;
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
int32_t i = JSID_TO_INT(id);
|
||||
if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
|
||||
*vp = fp->canonicalActualArg(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
|
||||
*vp = Int32Value(fp->numActualArgs());
|
||||
@ -363,11 +384,8 @@ StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
* prototype to point to another Arguments object with a bigger argc.
|
||||
*/
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
if (arg < argsobj.initialLength()) {
|
||||
const Value &v = argsobj.element(arg);
|
||||
if (!v.isMagic(JS_ARGS_HOLE))
|
||||
*vp = v;
|
||||
}
|
||||
if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
|
||||
*vp = argsobj.element(arg);
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
|
||||
if (!argsobj.hasOverriddenLength())
|
||||
@ -418,7 +436,7 @@ strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObje
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
uint32_t arg = uint32_t(JSID_TO_INT(id));
|
||||
if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
|
||||
if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
|
||||
return true;
|
||||
|
||||
attrs |= JSPROP_ENUMERATE;
|
||||
|
@ -23,6 +23,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeff Walden <jwalden+code@mit.edu> (original author)
|
||||
* Luke Wagner <luke@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
@ -43,30 +44,8 @@
|
||||
|
||||
#include "jsfun.h"
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
class GetPropCompiler;
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
struct VMFrame;
|
||||
namespace mjit {
|
||||
namespace ic {
|
||||
struct PICInfo;
|
||||
struct GetElementIC;
|
||||
|
||||
/* Aargh, Windows. */
|
||||
#ifdef GetProp
|
||||
#undef GetProp
|
||||
#endif
|
||||
void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *pic);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct EmptyShape;
|
||||
|
||||
/*
|
||||
* ArgumentsData stores the initial indexed arguments provided to the
|
||||
* corresponding and that function itself. It is used to store arguments[i]
|
||||
@ -82,6 +61,12 @@ struct ArgumentsData
|
||||
*/
|
||||
HeapValue callee;
|
||||
|
||||
/*
|
||||
* Pointer to an array of bits indicating, for every argument in 'slots',
|
||||
* whether the element has been deleted. See isElementDeleted comment.
|
||||
*/
|
||||
size_t *deletedBits;
|
||||
|
||||
/*
|
||||
* Values of the arguments for this object, or MagicValue(JS_ARGS_HOLE) if
|
||||
* the indexed argument has been modified.
|
||||
@ -147,29 +132,18 @@ class ArgumentsObject : public JSObject
|
||||
static const uint32_t DATA_SLOT = 1;
|
||||
static const uint32_t STACK_FRAME_SLOT = 2;
|
||||
|
||||
public:
|
||||
static const uint32_t RESERVED_SLOTS = 3;
|
||||
static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4;
|
||||
|
||||
private:
|
||||
/* Lower-order bit stolen from the length slot. */
|
||||
static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
|
||||
static const uint32_t PACKED_BITS_COUNT = 1;
|
||||
|
||||
/*
|
||||
* Need access to DATA_SLOT, INITIAL_LENGTH_SLOT, LENGTH_OVERRIDDEN_BIT, and
|
||||
* PACKED_BIT_COUNT.
|
||||
*/
|
||||
#ifdef JS_POLYIC
|
||||
friend class ::GetPropCompiler;
|
||||
friend struct mjit::ic::GetElementIC;
|
||||
#endif
|
||||
|
||||
void initInitialLength(uint32_t length);
|
||||
void initData(ArgumentsData *data);
|
||||
static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee);
|
||||
|
||||
public:
|
||||
static const uint32_t RESERVED_SLOTS = 3;
|
||||
static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4;
|
||||
|
||||
/* Create an arguments object for a frame that is expecting them. */
|
||||
static bool create(JSContext *cx, StackFrame *fp);
|
||||
|
||||
@ -214,8 +188,25 @@ class ArgumentsObject : public JSObject
|
||||
|
||||
inline js::ArgumentsData *data() const;
|
||||
|
||||
/*
|
||||
* Because the arguments object is a real object, its elements may be
|
||||
* deleted. This is implemented by setting a 'deleted' flag for the arg
|
||||
* which is read by argument object resolve and getter/setter hooks.
|
||||
*
|
||||
* NB: an element, once deleted, stays deleted. Thus:
|
||||
*
|
||||
* function f(x) { delete arguments[0]; arguments[0] = 42; return x }
|
||||
* assertEq(f(1), 1);
|
||||
*
|
||||
* This works because, once a property is deleted from an arguments object,
|
||||
* it gets regular properties with regular getters/setters that don't alias
|
||||
* ArgumentsData::slots.
|
||||
*/
|
||||
inline bool isElementDeleted(uint32_t i) const;
|
||||
inline bool isAnyElementDeleted() const;
|
||||
inline void markElementDeleted(uint32_t i);
|
||||
|
||||
inline const js::Value &element(uint32_t i) const;
|
||||
inline const js::Value *elements() const;
|
||||
inline void setElement(uint32_t i, const js::Value &v);
|
||||
|
||||
/* The stack frame for this ArgumentsObject, if the frame is still active. */
|
||||
|
@ -73,7 +73,6 @@
|
||||
#include "nsIXBLService.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsPlainTextSerializer.h"
|
||||
#include "mozSanitizingSerializer.h"
|
||||
#include "nsXMLContentSerializer.h"
|
||||
#include "nsXHTMLContentSerializer.h"
|
||||
#include "nsRuleNode.h"
|
||||
@ -514,7 +513,6 @@ MAKE_CTOR(CreateXMLContentSerializer, nsIContentSerializer, NS_NewXML
|
||||
MAKE_CTOR(CreateHTMLContentSerializer, nsIContentSerializer, NS_NewHTMLContentSerializer)
|
||||
MAKE_CTOR(CreateXHTMLContentSerializer, nsIContentSerializer, NS_NewXHTMLContentSerializer)
|
||||
MAKE_CTOR(CreatePlainTextSerializer, nsIContentSerializer, NS_NewPlainTextSerializer)
|
||||
MAKE_CTOR(CreateSanitizingHTMLSerializer, nsIContentSerializer, NS_NewSanitizingHTMLSerializer)
|
||||
MAKE_CTOR(CreateXBLService, nsIXBLService, NS_NewXBLService)
|
||||
MAKE_CTOR(CreateContentPolicy, nsIContentPolicy, NS_NewContentPolicy)
|
||||
#ifdef MOZ_XUL
|
||||
@ -711,7 +709,6 @@ NS_DEFINE_NAMED_CID(NS_XMLCONTENTSERIALIZER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_XHTMLCONTENTSERIALIZER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_HTMLCONTENTSERIALIZER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_PLAINTEXTSERIALIZER_CID);
|
||||
NS_DEFINE_NAMED_CID(MOZ_SANITIZINGHTMLSERIALIZER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_PARSERUTILS_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_SCRIPTABLEUNESCAPEHTML_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_XBLSERVICE_CID);
|
||||
@ -987,7 +984,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
||||
{ &kNS_HTMLCONTENTSERIALIZER_CID, false, NULL, CreateHTMLContentSerializer },
|
||||
{ &kNS_XHTMLCONTENTSERIALIZER_CID, false, NULL, CreateXHTMLContentSerializer },
|
||||
{ &kNS_PLAINTEXTSERIALIZER_CID, false, NULL, CreatePlainTextSerializer },
|
||||
{ &kMOZ_SANITIZINGHTMLSERIALIZER_CID, false, NULL, CreateSanitizingHTMLSerializer },
|
||||
{ &kNS_PARSERUTILS_CID, false, NULL, nsParserUtilsConstructor },
|
||||
{ &kNS_SCRIPTABLEUNESCAPEHTML_CID, false, NULL, nsParserUtilsConstructor },
|
||||
{ &kNS_XBLSERVICE_CID, false, NULL, CreateXBLService },
|
||||
@ -1135,7 +1131,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
||||
{ NS_CONTENTSERIALIZER_CONTRACTID_PREFIX "text/html", &kNS_HTMLCONTENTSERIALIZER_CID },
|
||||
{ NS_CONTENTSERIALIZER_CONTRACTID_PREFIX "application/vnd.mozilla.xul+xml", &kNS_XMLCONTENTSERIALIZER_CID },
|
||||
{ NS_CONTENTSERIALIZER_CONTRACTID_PREFIX "text/plain", &kNS_PLAINTEXTSERIALIZER_CID },
|
||||
{ MOZ_SANITIZINGHTMLSERIALIZER_CONTRACTID, &kMOZ_SANITIZINGHTMLSERIALIZER_CID },
|
||||
{ NS_PARSERUTILS_CONTRACTID, &kNS_PARSERUTILS_CID },
|
||||
{ NS_SCRIPTABLEUNESCAPEHTML_CONTRACTID, &kNS_SCRIPTABLEUNESCAPEHTML_CID },
|
||||
{ "@mozilla.org/xbl;1", &kNS_XBLSERVICE_CID },
|
||||
|
@ -64,8 +64,9 @@ import android.widget.TextView;
|
||||
import android.widget.TextSwitcher;
|
||||
import android.widget.ViewSwitcher.ViewFactory;
|
||||
|
||||
public class BrowserToolbar extends LinearLayout {
|
||||
private static final String LOGTAG = "GeckoToolbar";
|
||||
public class BrowserToolbar {
|
||||
private static final String LOGTAG = "GeckoToolbar";
|
||||
private LinearLayout mLayout;
|
||||
private Button mAwesomeBar;
|
||||
private ImageButton mTabs;
|
||||
public ImageButton mFavicon;
|
||||
@ -90,16 +91,19 @@ public class BrowserToolbar extends LinearLayout {
|
||||
|
||||
private int mCount;
|
||||
|
||||
public BrowserToolbar(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
public BrowserToolbar(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void from(LinearLayout layout) {
|
||||
mLayout = layout;
|
||||
mTitleCanExpand = true;
|
||||
|
||||
// Get the device's highlight color
|
||||
TypedArray typedArray;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
typedArray = context.obtainStyledAttributes(new int[] { android.R.attr.textColorHighlight });
|
||||
typedArray = mContext.obtainStyledAttributes(new int[] { android.R.attr.textColorHighlight });
|
||||
} else {
|
||||
ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext, android.R.style.TextAppearance);
|
||||
typedArray = wrapper.getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorHighlight });
|
||||
@ -107,17 +111,14 @@ public class BrowserToolbar extends LinearLayout {
|
||||
|
||||
mColor = typedArray.getColor(typedArray.getIndex(0), 0);
|
||||
typedArray.recycle();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mAwesomeBar = (Button) findViewById(R.id.awesome_bar);
|
||||
mAwesomeBar = (Button) mLayout.findViewById(R.id.awesome_bar);
|
||||
mAwesomeBar.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
onAwesomeBarSearch();
|
||||
}
|
||||
});
|
||||
|
||||
Resources resources = getResources();
|
||||
Resources resources = mContext.getResources();
|
||||
|
||||
mPadding = new int[] { mAwesomeBar.getPaddingLeft(),
|
||||
mAwesomeBar.getPaddingTop(),
|
||||
@ -132,7 +133,7 @@ public class BrowserToolbar extends LinearLayout {
|
||||
|
||||
mAwesomeBar.setPadding(mPadding[0], mPadding[1], mPadding[2], mPadding[3]);
|
||||
|
||||
mTabs = (ImageButton) findViewById(R.id.tabs);
|
||||
mTabs = (ImageButton) mLayout.findViewById(R.id.tabs);
|
||||
mTabs.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
if (Tabs.getInstance().getCount() > 1)
|
||||
@ -145,7 +146,7 @@ public class BrowserToolbar extends LinearLayout {
|
||||
|
||||
mCounterColor = 0xFFC7D1DB;
|
||||
|
||||
mTabsCount = (TextSwitcher) findViewById(R.id.tabs_count);
|
||||
mTabsCount = (TextSwitcher) mLayout.findViewById(R.id.tabs_count);
|
||||
mTabsCount.removeAllViews();
|
||||
mTabsCount.setFactory(new ViewFactory() {
|
||||
public View makeView() {
|
||||
@ -169,18 +170,18 @@ public class BrowserToolbar extends LinearLayout {
|
||||
mTabsCount.setText("0");
|
||||
mCount = 0;
|
||||
|
||||
mFavicon = (ImageButton) findViewById(R.id.favicon);
|
||||
mSiteSecurity = (ImageButton) findViewById(R.id.site_security);
|
||||
mFavicon = (ImageButton) mLayout.findViewById(R.id.favicon);
|
||||
mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security);
|
||||
mProgressSpinner = (AnimationDrawable) resources.getDrawable(R.drawable.progress_spinner);
|
||||
|
||||
mStop = (ImageButton) findViewById(R.id.stop);
|
||||
mStop = (ImageButton) mLayout.findViewById(R.id.stop);
|
||||
mStop.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
doStop();
|
||||
}
|
||||
});
|
||||
|
||||
mShadow = (ImageView) findViewById(R.id.shadow);
|
||||
mShadow = (ImageView) mLayout.findViewById(R.id.shadow);
|
||||
|
||||
mHandler = new Handler();
|
||||
mSlideUpIn = new TranslateAnimation(0, 0, 40, 0);
|
||||
@ -329,18 +330,26 @@ public class BrowserToolbar extends LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibility(int visibility) {
|
||||
mLayout.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public void requestFocusFromTouch() {
|
||||
mLayout.requestFocusFromTouch();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (Build.VERSION.SDK_INT >= 11)
|
||||
GeckoActionBar.show(GeckoApp.mAppContext);
|
||||
else
|
||||
setVisibility(View.VISIBLE);
|
||||
mLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
if (Build.VERSION.SDK_INT >= 11)
|
||||
GeckoActionBar.hide(GeckoApp.mAppContext);
|
||||
else
|
||||
setVisibility(View.GONE);
|
||||
mLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
|
@ -1592,15 +1592,11 @@ abstract public class GeckoApp
|
||||
// The ActionBar needs to be refreshed on rotation as different orientation uses different resources
|
||||
public void refreshActionBar() {
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
|
||||
mBrowserToolbar.init();
|
||||
LinearLayout actionBar = (LinearLayout) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
|
||||
mBrowserToolbar.from(actionBar);
|
||||
mBrowserToolbar.refresh();
|
||||
GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
|
||||
GeckoActionBar.setDisplayOptions(this, ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM |
|
||||
ActionBar.DISPLAY_SHOW_HOME |
|
||||
ActionBar.DISPLAY_SHOW_TITLE |
|
||||
ActionBar.DISPLAY_USE_LOGO);
|
||||
GeckoActionBar.setCustomView(this, mBrowserToolbar);
|
||||
GeckoActionBar.setCustomView(this, actionBar);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1633,12 +1629,16 @@ abstract public class GeckoApp
|
||||
|
||||
setContentView(R.layout.gecko_app);
|
||||
|
||||
LinearLayout actionBar;
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
mBrowserToolbar = (BrowserToolbar) GeckoActionBar.getCustomView(this);
|
||||
actionBar = (LinearLayout) GeckoActionBar.getCustomView(this);
|
||||
} else {
|
||||
mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar);
|
||||
actionBar = (LinearLayout) findViewById(R.id.browser_toolbar);
|
||||
}
|
||||
|
||||
mBrowserToolbar = new BrowserToolbar(mAppContext);
|
||||
mBrowserToolbar.from(actionBar);
|
||||
|
||||
// setup gecko layout
|
||||
mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout);
|
||||
mMainLayout = (LinearLayout) findViewById(R.id.main_layout);
|
||||
@ -1670,7 +1670,6 @@ abstract public class GeckoApp
|
||||
checkAndLaunchUpdate();
|
||||
}
|
||||
|
||||
mBrowserToolbar.init();
|
||||
mBrowserToolbar.setTitle(mLastTitle);
|
||||
|
||||
String passedUri = null;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.mozilla.gecko.BrowserToolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/browser_toolbar"
|
||||
style="@style/BrowserToolbar">
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/browser_toolbar"
|
||||
style="@style/BrowserToolbar">
|
||||
|
||||
<RelativeLayout android:id="@+id/address_bar"
|
||||
style="@style/AddressBar"
|
||||
@ -81,4 +81,4 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</org.mozilla.gecko.BrowserToolbar>
|
||||
</LinearLayout>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.mozilla.gecko.BrowserToolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/browser_toolbar"
|
||||
style="@style/BrowserToolbar">
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/browser_toolbar"
|
||||
style="@style/BrowserToolbar">
|
||||
|
||||
<RelativeLayout android:id="@+id/address_bar"
|
||||
style="@style/AddressBar"
|
||||
@ -82,4 +82,4 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</org.mozilla.gecko.BrowserToolbar>
|
||||
</LinearLayout>
|
||||
|
@ -29,6 +29,7 @@
|
||||
</style>
|
||||
|
||||
<style name="Gecko.App">
|
||||
<item name="android:windowBackground">@drawable/abouthome_bg_repeat</item>
|
||||
<item name="android:actionBarStyle">@style/ActionBar.GeckoApp</item>
|
||||
</style>
|
||||
|
||||
|
@ -27,7 +27,9 @@
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Gecko.App"/>
|
||||
<style name="Gecko.App">
|
||||
<item name="android:windowBackground">@drawable/abouthome_bg_repeat</item>
|
||||
</style>
|
||||
|
||||
<style name="Gecko.Light.AwesomeBar"/>
|
||||
|
||||
|
@ -245,12 +245,12 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
|
||||
bool aLastCall,
|
||||
nsDTDMode aMode) // ignored
|
||||
{
|
||||
if (mExecutor->IsBroken()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsresult rv;
|
||||
if (NS_FAILED(rv = mExecutor->IsBroken())) {
|
||||
return rv;
|
||||
}
|
||||
if (aSourceBuffer.Length() > PR_INT32_MAX) {
|
||||
mExecutor->MarkAsBroken();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
// Maintain a reference to ourselves so we don't go away
|
||||
@ -446,8 +446,7 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
|
||||
heapBuffer = stackBuffer.FalliblyCopyAsOwningBuffer();
|
||||
if (!heapBuffer) {
|
||||
// Allocation failed. The parser is now broken.
|
||||
mExecutor->MarkAsBroken();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -947,10 +947,10 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
nsHtml5OwningUTF16Buffer::FalliblyCreate(
|
||||
NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE);
|
||||
if (!newBuf) {
|
||||
mExecutor->MarkAsBroken(); // marks this stream parser as terminated,
|
||||
// which prevents entry to code paths that
|
||||
// would use mFirstBuffer or mLastBuffer.
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// marks this stream parser as terminated,
|
||||
// which prevents entry to code paths that
|
||||
// would use mFirstBuffer or mLastBuffer.
|
||||
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
NS_ASSERTION(!mFirstBuffer, "How come we have the first buffer set?");
|
||||
NS_ASSERTION(!mLastBuffer, "How come we have the last buffer set?");
|
||||
@ -1143,8 +1143,9 @@ nsHtml5StreamParser::OnDataAvailable(nsIRequest* aRequest,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
if (mExecutor->IsBroken()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsresult rv;
|
||||
if (NS_FAILED(rv = mExecutor->IsBroken())) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mRequest == aRequest, "Got data on wrong stream.");
|
||||
@ -1152,10 +1153,9 @@ nsHtml5StreamParser::OnDataAvailable(nsIRequest* aRequest,
|
||||
const mozilla::fallible_t fallible = mozilla::fallible_t();
|
||||
nsAutoArrayPtr<PRUint8> data(new (fallible) PRUint8[aLength]);
|
||||
if (!data) {
|
||||
mExecutor->MarkAsBroken();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
nsresult rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
|
||||
rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
|
||||
aLength, &totalRead);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(totalRead <= aLength, "Read more bytes than were available?");
|
||||
|
@ -117,6 +117,20 @@ nsHtml5TreeOpExecutor::WillParse()
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHtml5TreeOpExecutor::WillBuildModel(nsDTDMode aDTDMode)
|
||||
{
|
||||
if (mDocShell && !GetDocument()->GetScriptGlobalObject()) {
|
||||
// Not loading as data but script global object not ready
|
||||
return MarkAsBroken(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
mDocument->AddObserver(this);
|
||||
WillBuildModelImpl();
|
||||
GetDocument()->BeginLoad();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// This is called when the tree construction has ended
|
||||
NS_IMETHODIMP
|
||||
nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated)
|
||||
@ -143,7 +157,9 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated)
|
||||
GetParser()->DropStreamParser();
|
||||
|
||||
// This comes from nsXMLContentSink and nsHTMLContentSink
|
||||
DidBuildModelImpl(aTerminated);
|
||||
// If this parser has been marked as broken, treat the end of parse as
|
||||
// forced termination.
|
||||
DidBuildModelImpl(aTerminated || IsBroken());
|
||||
|
||||
if (!mLayoutStarted) {
|
||||
// We never saw the body, and layout never got started. Force
|
||||
@ -274,12 +290,12 @@ nsHtml5TreeOpExecutor::UpdateChildCounts()
|
||||
// No-op
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5TreeOpExecutor::MarkAsBroken()
|
||||
nsresult
|
||||
nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!mRunsToCompletion, "Fragment parsers can't be broken!");
|
||||
mBroken = true;
|
||||
mBroken = aReason;
|
||||
if (mStreamParser) {
|
||||
mStreamParser->Terminate();
|
||||
}
|
||||
@ -293,6 +309,7 @@ nsHtml5TreeOpExecutor::MarkAsBroken()
|
||||
NS_WARNING("failed to dispatch executor flush event");
|
||||
}
|
||||
}
|
||||
return aReason;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -129,14 +129,17 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
|
||||
bool mCallContinueInterruptedParsingIfEnabled;
|
||||
|
||||
/**
|
||||
* True if this parser should refuse to process any more input.
|
||||
* Currently, the only way a parser can break is if it drops some input
|
||||
* due to a memory allocation failure. In such a case, the whole parser
|
||||
* needs to be marked as broken, because some input has been lost and
|
||||
* parsing more input could lead to a DOM where pieces of HTML source
|
||||
* Non-NS_OK if this parser should refuse to process any more input.
|
||||
* For example, the parser needs to be marked as broken if it drops some
|
||||
* input due to a memory allocation failure. In such a case, the whole
|
||||
* parser needs to be marked as broken, because some input has been lost
|
||||
* and parsing more input could lead to a DOM where pieces of HTML source
|
||||
* that weren't supposed to become scripts become scripts.
|
||||
*
|
||||
* Since NS_OK is actually 0, zeroing operator new takes care of
|
||||
* initializing this.
|
||||
*/
|
||||
bool mBroken;
|
||||
nsresult mBroken;
|
||||
|
||||
public:
|
||||
|
||||
@ -153,14 +156,7 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
|
||||
/**
|
||||
*
|
||||
*/
|
||||
NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) {
|
||||
NS_ASSERTION(!mDocShell || GetDocument()->GetScriptGlobalObject(),
|
||||
"Script global object not ready");
|
||||
mDocument->AddObserver(this);
|
||||
WillBuildModelImpl();
|
||||
GetDocument()->BeginLoad();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
|
||||
|
||||
/**
|
||||
* Emits EOF.
|
||||
@ -263,13 +259,16 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
|
||||
/**
|
||||
* Marks this parser as broken and tells the stream parser (if any) to
|
||||
* terminate.
|
||||
*
|
||||
* @return aReason for convenience
|
||||
*/
|
||||
void MarkAsBroken();
|
||||
nsresult MarkAsBroken(nsresult aReason);
|
||||
|
||||
/**
|
||||
* Checks if this parser is broken.
|
||||
* Checks if this parser is broken. Returns a non-NS_OK (i.e. non-0)
|
||||
* value if broken.
|
||||
*/
|
||||
inline bool IsBroken() {
|
||||
inline nsresult IsBroken() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
return mBroken;
|
||||
}
|
||||
|
@ -588,7 +588,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
|
||||
return AppendToDocument(asContent, aBuilder);
|
||||
}
|
||||
case eTreeOpMarkAsBroken: {
|
||||
aBuilder->MarkAsBroken();
|
||||
aBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
|
||||
return rv;
|
||||
}
|
||||
case eTreeOpRunScript: {
|
||||
|
@ -4,12 +4,16 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMElement;
|
||||
interface nsIDOMDocumentFragment;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* Non-Web HTML parser functionality to Firefox extensions and XULRunner apps.
|
||||
* Don't use this from within Gecko--use nsContentUtils, nsTreeSanitizer, etc.
|
||||
* directly instead.
|
||||
*/
|
||||
[scriptable, uuid(290f49bb-0619-4bda-8006-ab31bec7231a)]
|
||||
[scriptable, uuid(a1101145-0025-411e-8873-fdf57bf28128)]
|
||||
interface nsIParserUtils : nsISupports
|
||||
{
|
||||
|
||||
@ -100,6 +104,22 @@ interface nsIParserUtils : nsISupports
|
||||
AString convertToPlainText(in AString src,
|
||||
in unsigned long flags,
|
||||
in unsigned long wrapCol);
|
||||
|
||||
/**
|
||||
* Parses markup into a sanitized document fragment.
|
||||
*
|
||||
* @param fragment the input markup
|
||||
* @param flags sanitization option flags defined above
|
||||
* @param isXML true if |fragment| is XML and false if HTML
|
||||
* @param baseURI the base URL for this fragment
|
||||
* @param element the context node for the fragment parsing algorithm
|
||||
*/
|
||||
nsIDOMDocumentFragment parseFragment(in AString fragment,
|
||||
in unsigned long flags,
|
||||
in boolean isXML,
|
||||
in nsIURI baseURI,
|
||||
in nsIDOMElement element);
|
||||
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
@ -41,7 +41,7 @@ interface nsIDOMDocumentFragment;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* A utility class for HTML parsing in the feed processor.
|
||||
* This interface is OBSOLETE and exists solely for legacy extensions.
|
||||
*/
|
||||
[scriptable, uuid(3ab244a9-f09d-44da-9e3f-ee4d67367f2d)]
|
||||
interface nsIScriptableUnescapeHTML : nsISupports
|
||||
@ -52,16 +52,20 @@ interface nsIScriptableUnescapeHTML : nsISupports
|
||||
* nsIDocumentEncoder::OutputSelectionOnly |
|
||||
* nsIDocumentEncoder::OutputAbsoluteLinks, 0).
|
||||
*
|
||||
* You should most likely call nsIParserUtils::convertToPlainText()
|
||||
* instead of calling this method.
|
||||
* You should call nsIParserUtils::convertToPlainText() instead of calling
|
||||
* this method.
|
||||
*
|
||||
* @param src The HTML string to convert to plain text.
|
||||
*/
|
||||
AString unescape(in AString src);
|
||||
|
||||
/**
|
||||
* Parses markup into a sanitized document fragment.
|
||||
* Parses markup into a sanitized document fragment. This is equivalent to
|
||||
* calling nsIParserUtils::parseFragment(fragment, 0, isXML, baseURI,
|
||||
* element).
|
||||
*
|
||||
* You should call nsIParserUtils::parseFragment() instead of calling this
|
||||
* method.
|
||||
* @param fragment the input markup
|
||||
* @param isXML true if |fragment| is XML and false if HTML
|
||||
* @param baseURI the base URL for this fragment
|
||||
|
@ -79,9 +79,9 @@ static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserUtils::ConvertToPlainText(const nsAString& aFromStr,
|
||||
PRUint32 aFlags,
|
||||
PRUint32 aWrapCol,
|
||||
nsAString& aToStr)
|
||||
PRUint32 aFlags,
|
||||
PRUint32 aWrapCol,
|
||||
nsAString& aToStr)
|
||||
{
|
||||
return nsContentUtils::ConvertToPlainText(aFromStr,
|
||||
aToStr,
|
||||
@ -142,15 +142,28 @@ nsParserUtils::Sanitize(const nsAString& aFromStr,
|
||||
return encoder->EncodeToString(aToStr);
|
||||
}
|
||||
|
||||
// The feed version of nsContentUtils::CreateContextualFragment It
|
||||
// creates a fragment, but doesn't go to all the effort to preserve
|
||||
// context like innerHTML does, because feed DOMs shouldn't have that.
|
||||
NS_IMETHODIMP
|
||||
nsParserUtils::ParseFragment(const nsAString& aFragment,
|
||||
bool aIsXML,
|
||||
nsIURI* aBaseURI,
|
||||
nsIDOMElement* aContextElement,
|
||||
nsIDOMDocumentFragment** aReturn)
|
||||
bool aIsXML,
|
||||
nsIURI* aBaseURI,
|
||||
nsIDOMElement* aContextElement,
|
||||
nsIDOMDocumentFragment** aReturn)
|
||||
{
|
||||
return nsParserUtils::ParseFragment(aFragment,
|
||||
0,
|
||||
aIsXML,
|
||||
aBaseURI,
|
||||
aContextElement,
|
||||
aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserUtils::ParseFragment(const nsAString& aFragment,
|
||||
PRUint32 aFlags,
|
||||
bool aIsXML,
|
||||
nsIURI* aBaseURI,
|
||||
nsIDOMElement* aContextElement,
|
||||
nsIDOMDocumentFragment** aReturn)
|
||||
{
|
||||
NS_ENSURE_ARG(aContextElement);
|
||||
*aReturn = nsnull;
|
||||
@ -239,7 +252,7 @@ nsParserUtils::ParseFragment(const nsAString& aFragment,
|
||||
}
|
||||
}
|
||||
if (fragment) {
|
||||
nsTreeSanitizer sanitizer;
|
||||
nsTreeSanitizer sanitizer(aFlags);
|
||||
sanitizer.Sanitize(fragment);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include "nsIParserUtils.h"
|
||||
|
||||
class nsParserUtils : public nsIScriptableUnescapeHTML,
|
||||
public nsIParserUtils
|
||||
public nsIParserUtils
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -149,12 +149,11 @@ var qaTools = {
|
||||
return newArray;
|
||||
},
|
||||
writeSafeHTML : function(elementID, htmlstr) {
|
||||
document.getElementById(elementID).innerHTML = ""; //clear it.
|
||||
var gUnescapeHTML = Components.classes["@mozilla.org/feed-unescapehtml;1"].getService(Components.interfaces.nsIScriptableUnescapeHTML);
|
||||
document.getElementById(elementID).textContent = ""; //clear it.
|
||||
var utils = Components.classes["@mozilla.org/parserutils;1"].getService(Components.interfaces.nsIParserUtils);
|
||||
var context = document.getElementById(elementID);
|
||||
var fragment = gUnescapeHTML.parseFragment(htmlstr, false, null, context);
|
||||
var fragment = utils.parseFragment(htmlstr, 0, false, null, context);
|
||||
context.appendChild(fragment);
|
||||
|
||||
},
|
||||
|
||||
assignLinkHandlers : function(node) {
|
||||
|
@ -75,7 +75,7 @@ const IO_CONTRACTID = "@mozilla.org/network/io-service;1"
|
||||
const BAG_CONTRACTID = "@mozilla.org/hash-property-bag;1"
|
||||
const ARRAY_CONTRACTID = "@mozilla.org/array;1";
|
||||
const SAX_CONTRACTID = "@mozilla.org/saxparser/xmlreader;1";
|
||||
const UNESCAPE_CONTRACTID = "@mozilla.org/feed-unescapehtml;1";
|
||||
const PARSERUTILS_CONTRACTID = "@mozilla.org/parserutils;1";
|
||||
|
||||
|
||||
var gIoService = null;
|
||||
@ -644,14 +644,16 @@ function TextConstruct() {
|
||||
this.base = null;
|
||||
this.type = "text";
|
||||
this.text = null;
|
||||
this.unescapeHTML = Cc[UNESCAPE_CONTRACTID].
|
||||
getService(Ci.nsIScriptableUnescapeHTML);
|
||||
this.parserUtils = Cc[PARSERUTILS_CONTRACTID].getService(Ci.nsIParserUtils);
|
||||
}
|
||||
|
||||
TextConstruct.prototype = {
|
||||
plainText: function TC_plainText() {
|
||||
if (this.type != "text") {
|
||||
return this.unescapeHTML.unescape(stripTags(this.text));
|
||||
return this.parserUtils.convertToPlainText(stripTags(this.text),
|
||||
Ci.nsIDocumentEncoder.OutputSelectionOnly |
|
||||
Ci.nsIDocumentEncoder.OutputAbsoluteLinks,
|
||||
0);
|
||||
}
|
||||
return this.text;
|
||||
},
|
||||
@ -672,8 +674,8 @@ TextConstruct.prototype = {
|
||||
else
|
||||
return null;
|
||||
|
||||
return this.unescapeHTML.parseFragment(this.text, isXML,
|
||||
this.base, element);
|
||||
return this.parserUtils.parseFragment(this.text, 0, isXML,
|
||||
this.base, element);
|
||||
},
|
||||
|
||||
// XPCOM stuff
|
||||
|
@ -22,9 +22,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=675492
|
||||
/** Test for Bug 675492 **/
|
||||
|
||||
Components
|
||||
.classes["@mozilla.org/feed-unescapehtml;1"]
|
||||
.getService(Components.interfaces.nsIScriptableUnescapeHTML)
|
||||
.parseFragment("<p>test</p>", false, null, document.createElementNS("http://www.w3.org/1999/xhtml", "body"));
|
||||
.classes["@mozilla.org/parserutils;1"]
|
||||
.getService(Components.interfaces.nsIParserUtils)
|
||||
.parseFragment("<p>test</p>", 0, false, null, document.createElementNS("http://www.w3.org/1999/xhtml", "body"));
|
||||
ok(true, "No crash!");
|
||||
]]>
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user