Merge m-c to f-t

This commit is contained in:
Phil Ringnalda 2014-06-28 20:53:05 -07:00
commit d96c7fc639
181 changed files with 4210 additions and 5932 deletions

View File

@ -71,3 +71,7 @@ GTAGS
GRTAGS
GSYMS
GPATH
# Unit tests for Loop
^browser/components/loop/standalone/content/config\.js$
^browser/components/loop/standalone/node_modules/

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1403216209000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1403823002000">
<emItems>
<emItem blockID="i454" id="sqlmoz@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -192,6 +192,12 @@
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
@ -244,10 +250,12 @@
<prefs>
</prefs>
</emItem>
<emItem blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
<versionRange minVersion="0" maxVersion="*">
<emItem blockID="i630" id="webbooster@iminent.com">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
<prefs>
<pref>browser.startup.homepage</pref>
<pref>browser.search.defaultenginename</pref>
</prefs>
</emItem>
<emItem blockID="i174" id="info@thebflix.com">
@ -570,6 +578,14 @@
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i628" id="ffxtlbr@iminent.com">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
<prefs>
<pref>browser.startup.homepage</pref>
<pref>browser.search.defaultenginename</pref>
</prefs>
</emItem>
<emItem blockID="i228" id="crossriderapp5060@crossrider.com">
<versionRange minVersion="0" maxVersion="*" severity="1">

View File

@ -51,7 +51,6 @@ class nsIDOMDocumentType;
class nsIDOMElement;
class nsIDOMNodeFilter;
class nsIDOMNodeList;
class nsIDOMXPathExpression;
class nsIDOMXPathNSResolver;
class nsIHTMLCollection;
class nsILayoutHistoryState;
@ -122,6 +121,7 @@ class TouchList;
class TreeWalker;
class UndoManager;
class XPathEvaluator;
class XPathExpression;
class XPathResult;
template<typename> class OwningNonNull;
template<typename> class Sequence;
@ -2269,7 +2269,7 @@ public:
const nsAString& aAttrValue);
Element* GetBindingParent(nsINode& aNode);
void LoadBindingDocument(const nsAString& aURI, mozilla::ErrorResult& rv);
already_AddRefed<nsIDOMXPathExpression>
mozilla::dom::XPathExpression*
CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
mozilla::ErrorResult& rv);

View File

@ -330,7 +330,7 @@ nsCSPParser::subHost()
/* consume */
++charCounter;
}
if (accept(DOT) && !accept(isCharacterToken)) {
if (accept(DOT) && !hostChar()) {
return false;
}
if (charCounter > kSubHostPathCharacterCutoff) {
@ -366,8 +366,8 @@ nsCSPParser::host()
}
}
// Expecting at least one Character
if (!accept(isCharacterToken)) {
// Expecting at least one host-char
if (!hostChar()) {
const char16_t* params[] = { mCurToken.get() };
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
params, ArrayLength(params));
@ -684,6 +684,7 @@ nsCSPParser::sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs)
// mCurToken is only set here and remains the current token
// to be processed, which avoid passing arguments between functions.
mCurToken = mCurDir[i];
resetCurValue();
CSPPARSERLOG(("nsCSPParser::sourceList, mCurToken: %s, mCurValue: %s",
NS_ConvertUTF16toUTF8(mCurToken).get(),

View File

@ -771,8 +771,9 @@ nsCSPPolicy::permits(nsContentPolicyType aContentType,
return true;
}
// Didn't find a directive, load is not allowed.
return false;
// unspecified default-src should default to no restrictions
// see bug 764937
return true;
}
bool

View File

@ -51,7 +51,7 @@ nsDOMCaretPosition::GetClientRect() const
NS_ASSERTION(domRange, "unable to retrieve valid dom range from CaretPosition");
rect = domRange->GetBoundingClientRect();
rect = domRange->GetBoundingClientRect(false);
return rect.forget();
}

View File

@ -102,7 +102,6 @@
#include "nsBidiUtils.h"
#include "nsIDOMUserDataHandler.h"
#include "nsIDOMXPathExpression.h"
#include "nsIDOMXPathNSResolver.h"
#include "nsIParserService.h"
#include "nsContentCreatorFunctions.h"
@ -12041,7 +12040,7 @@ nsIDocument::Constructor(const GlobalObject& aGlobal,
return doc.forget();
}
already_AddRefed<nsIDOMXPathExpression>
XPathExpression*
nsIDocument::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv)
@ -12066,14 +12065,6 @@ nsIDocument::Evaluate(JSContext* aCx, const nsAString& aExpression,
aType, aResult, rv);
}
NS_IMETHODIMP
nsDocument::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
nsIDOMXPathExpression** aResult)
{
return XPathEvaluator()->CreateExpression(aExpression, aResolver, aResult);
}
NS_IMETHODIMP
nsDocument::CreateNSResolver(nsIDOMNode* aNodeResolver,
nsIDOMXPathNSResolver** aResult)

View File

@ -2725,17 +2725,23 @@ nsRange::CreateContextualFragment(const nsAString& aFragment, ErrorResult& aRv)
static void ExtractRectFromOffset(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
const int32_t aOffset, nsRect* aR, bool aKeepLeft)
const int32_t aOffset, nsRect* aR, bool aKeepLeft,
bool aClampToEdge)
{
nsPoint point;
aFrame->GetPointFromOffset(aOffset, &point);
point += aFrame->GetOffsetTo(aRelativeTo);
//given a point.x, extract left or right portion of rect aR
//point.x has to be within this rect
NS_ASSERTION(aR->x <= point.x && point.x <= aR->XMost(),
"point.x should not be outside of rect r");
if (!aClampToEdge && !aR->Contains(point)) {
aR->width = 0;
aR->x = point.x;
return;
}
if (aClampToEdge) {
point = aR->ClampPoint(point);
}
if (aKeepLeft) {
aR->width = point.x - aR->x;
@ -2762,7 +2768,8 @@ GetTextFrameForContent(nsIContent* aContent)
}
static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
nsIContent* aContent, int32_t aStartOffset, int32_t aEndOffset)
nsIContent* aContent, int32_t aStartOffset,
int32_t aEndOffset, bool aClampToEdge)
{
nsTextFrame* textFrame = GetTextFrameForContent(aContent);
if (textFrame) {
@ -2779,11 +2786,11 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
nsRect r(f->GetOffsetTo(relativeTo), f->GetSize());
if (fstart < aStartOffset) {
// aStartOffset is within this frame
ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl);
ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl, aClampToEdge);
}
if (fend > aEndOffset) {
// aEndOffset is in the middle of this frame
ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl);
ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl, aClampToEdge);
}
aCallback->AddRect(r);
}
@ -2795,7 +2802,8 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
nsRange* aRange,
nsINode* aStartParent, int32_t aStartOffset,
nsINode* aEndParent, int32_t aEndOffset)
nsINode* aEndParent, int32_t aEndOffset,
bool aClampToEdge)
{
// Hold strong pointers across the flush
nsCOMPtr<nsINode> startContainer = aStartParent;
@ -2832,7 +2840,7 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
nsIFrame* relativeTo =
nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
nsRect r(outFrame->GetOffsetTo(relativeTo), outFrame->GetSize());
ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false);
ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false, aClampToEdge);
r.width = 0;
aCollector->AddRect(r);
}
@ -2851,10 +2859,10 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
if (node == startContainer) {
int32_t offset = startContainer == endContainer ?
aEndOffset : content->GetText()->GetLength();
GetPartialTextRect(aCollector, content, aStartOffset, offset);
GetPartialTextRect(aCollector, content, aStartOffset, offset, aClampToEdge);
continue;
} else if (node == endContainer) {
GetPartialTextRect(aCollector, content, 0, aEndOffset);
GetPartialTextRect(aCollector, content, 0, aEndOffset, aClampToEdge);
continue;
}
}
@ -2870,12 +2878,12 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
NS_IMETHODIMP
nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult)
{
*aResult = GetBoundingClientRect().take();
*aResult = GetBoundingClientRect(true).take();
return NS_OK;
}
already_AddRefed<DOMRect>
nsRange::GetBoundingClientRect()
nsRange::GetBoundingClientRect(bool aClampToEdge)
{
nsRefPtr<DOMRect> rect = new DOMRect(ToSupports(this));
if (!mStartParent) {
@ -2884,7 +2892,7 @@ nsRange::GetBoundingClientRect()
nsLayoutUtils::RectAccumulator accumulator;
CollectClientRects(&accumulator, this, mStartParent, mStartOffset,
mEndParent, mEndOffset);
mEndParent, mEndOffset, aClampToEdge);
nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect :
accumulator.mResultRect;
@ -2895,12 +2903,12 @@ nsRange::GetBoundingClientRect()
NS_IMETHODIMP
nsRange::GetClientRects(nsIDOMClientRectList** aResult)
{
*aResult = GetClientRects().take();
*aResult = GetClientRects(true).take();
return NS_OK;
}
already_AddRefed<DOMRectList>
nsRange::GetClientRects()
nsRange::GetClientRects(bool aClampToEdge)
{
if (!mStartParent) {
return nullptr;
@ -2912,7 +2920,7 @@ nsRange::GetClientRects()
nsLayoutUtils::RectListBuilder builder(rectList);
CollectClientRects(&builder, this, mStartParent, mStartOffset,
mEndParent, mEndOffset);
mEndParent, mEndOffset, aClampToEdge);
return rectList.forget();
}

View File

@ -217,8 +217,8 @@ public:
void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
void SurroundContents(nsINode& aNode, ErrorResult& aErr);
already_AddRefed<DOMRect> GetBoundingClientRect();
already_AddRefed<DOMRectList> GetClientRects();
already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true);
already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true);
nsINode* GetParentObject() const { return mOwner; }
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE MOZ_FINAL;
@ -259,7 +259,8 @@ public:
static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
nsRange* aRange,
nsINode* aStartParent, int32_t aStartOffset,
nsINode* aEndParent, int32_t aEndOffset);
nsINode* aEndParent, int32_t aEndOffset,
bool aClampToEdge);
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
protected:

View File

@ -395,6 +395,14 @@ nsresult TestSimplePolicies() {
"script-src http://www.example.com" },
{ "script-src http://www.example.com/path-1//path_2",
"script-src http://www.example.com" },
{ "default-src 127.0.0.1",
"default-src http://127.0.0.1" },
{ "default-src 127.0.0.1:*",
"default-src http://127.0.0.1:*" },
{ "default-src -; ",
"default-src http://-" },
{ "script-src 1",
"script-src http://1" }
};
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
@ -432,8 +440,6 @@ nsresult TestBadPolicies() {
{ "", "" },
{ "; ; ; ; ; ; ;", "" },
{ "defaut-src asdf", "" },
{ "default-src -; ", "" },
{ "script-src 1", "" },
{ "default-src: aaa", "" },
{ "default-src 'unsafe-inlin' ", "" },
{ "default-src :88", "" },

View File

@ -538,6 +538,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #bug 901343, specialpowers.wr
[test_bug827160.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #needs plugin support # b2g(needs plugin support) b2g-debug(debug-only failure) b2g-desktop(needs plugin support)
[test_bug840098.html]
[test_bug864595.html]
[test_bug868999.html]
[test_bug869000.html]
[test_bug869002.html]

View File

@ -0,0 +1,34 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=864595
-->
<head>
<title>Test for Bug 864595</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=864595">Mozilla Bug 864595</a>
<div id='editable' style='display:inline-block;'>abcd </div>
<script type="application/javascript">
/** Test for Bug 864595 **/
var range = document.createRange();
var elt = document.getElementById('editable');
var eltRect = elt.getBoundingClientRect();
var txtNode = elt.childNodes[0];
range.setStart(txtNode, 0);
range.setEnd(txtNode, 5);
var rect = range.getBoundingClientRect();
ok(rect.left >= eltRect.left && rect.right <= eltRect.right, "rect.left >= eltRect.left && rect.right <= eltRect.right");
/* Put caret in the space */
var caretPosX = rect.right + 10;
var caretPosY = (rect.top + rect.bottom ) / 2;
var caretRect = document.caretPositionFromPoint(caretPosX, caretPosY).getClientRect();
ok(caretRect.right >= rect.right, "caretRect.right >= rect.right");
</script>
</body>
</html>

View File

@ -13,7 +13,9 @@
#include "MFTDecoder.h"
#include "mozilla/RefPtr.h"
class mp4_demuxer::MP4Sample;
namespace mp4_demuxer {
class MP4Sample;
}
namespace mozilla {

View File

@ -12,39 +12,13 @@
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsXMLBindingSet)
NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(nsXMLBindingSet)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLBindingSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLBindingSet)
nsXMLBinding* binding = tmp->mFirst;
while (binding) {
binding->mExpr = nullptr;
binding = binding->mNext;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLBindingSet)
nsXMLBinding* binding = tmp->mFirst;
while (binding) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsXMLBinding::mExpr");
cb.NoteXPCOMChild(binding->mExpr);
binding = binding->mNext;
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXMLBindingSet, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXMLBindingSet, Release)
nsXMLBindingSet::~nsXMLBindingSet()
{}
nsresult
nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
void
nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsAutoPtr<XPathExpression>&& aExpr)
{
nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, aExpr));
NS_ENSURE_TRUE(newbinding, NS_ERROR_OUT_OF_MEMORY);
nsAutoPtr<nsXMLBinding> newbinding(new nsXMLBinding(aVar, Move(aExpr)));
if (mFirst) {
nsXMLBinding* binding = mFirst;
@ -53,12 +27,12 @@ nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
// if the target variable is already used in a binding, ignore it
// since it won't be useful for anything
if (binding->mVar == aVar)
return NS_OK;
return;
// add the binding at the end of the list
if (!binding->mNext) {
binding->mNext = newbinding;
break;
return;
}
binding = binding->mNext;
@ -67,8 +41,6 @@ nsXMLBindingSet::AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
else {
mFirst = newbinding;
}
return NS_OK;
}
int32_t
@ -102,39 +74,30 @@ nsXMLBindingValues::GetAssignmentFor(nsXULTemplateResultXML* aResult,
return value;
}
nsCOMPtr<nsIDOMNode> contextNode;
aResult->GetNode(getter_AddRefs(contextNode));
nsINode* contextNode = aResult->Node();
if (!contextNode) {
return nullptr;
}
mValues.EnsureLengthAtLeast(aIndex + 1);
nsCOMPtr<nsISupports> resultsupports;
aBinding->mExpr->Evaluate(contextNode, aType,
nullptr, getter_AddRefs(resultsupports));
mValues.ReplaceElementAt(aIndex, XPathResult::FromSupports(resultsupports));
ErrorResult ignored;
mValues[aIndex] = aBinding->mExpr->Evaluate(*contextNode, aType, nullptr,
ignored);
return mValues[aIndex];
}
void
nsINode*
nsXMLBindingValues::GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t aIndex,
nsIDOMNode** aNode)
int32_t aIndex)
{
XPathResult* result = GetAssignmentFor(aResult, aBinding, aIndex,
XPathResult::FIRST_ORDERED_NODE_TYPE);
nsINode* node;
ErrorResult rv;
if (result && (node = result->GetSingleNodeValue(rv))) {
CallQueryInterface(node, aNode);
} else {
*aNode = nullptr;
}
return result ? result->GetSingleNodeValue(rv) : nullptr;
}
void

View File

@ -8,9 +8,10 @@
#include "nsAutoPtr.h"
#include "nsIAtom.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/XPathExpression.h"
class nsINode;
class nsXULTemplateResultXML;
class nsXMLBindingValues;
namespace mozilla {
@ -28,11 +29,11 @@ class XPathResult;
*/
struct nsXMLBinding {
nsCOMPtr<nsIAtom> mVar;
nsCOMPtr<nsIDOMXPathExpression> mExpr;
nsAutoPtr<mozilla::dom::XPathExpression> mExpr;
nsAutoPtr<nsXMLBinding> mNext;
nsXMLBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
nsXMLBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr)
: mVar(aVar), mExpr(aExpr), mNext(nullptr)
{
MOZ_COUNT_CTOR(nsXMLBinding);
@ -53,26 +54,16 @@ class nsXMLBindingSet MOZ_FINAL
~nsXMLBindingSet();
public:
// results hold a reference to a binding set in their
// nsXMLBindingValues fields
nsCycleCollectingAutoRefCnt mRefCnt;
// pointer to the first binding in a linked list
nsAutoPtr<nsXMLBinding> mFirst;
public:
NS_METHOD_(MozExternalRefCountType) AddRef();
NS_METHOD_(MozExternalRefCountType) Release();
NS_DECL_OWNINGTHREAD
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXMLBindingSet)
NS_INLINE_DECL_REFCOUNTING(nsXMLBindingSet);
/**
* Add a binding to the set
*/
nsresult
AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr);
void
AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr);
/**
* The nsXMLBindingValues class stores an array of values, one for each
@ -131,11 +122,10 @@ public:
int32_t idx,
uint16_t type);
void
nsINode*
GetNodeAssignmentFor(nsXULTemplateResultXML* aResult,
nsXMLBinding* aBinding,
int32_t idx,
nsIDOMNode** aValue);
int32_t idx);
void
GetStringAssignmentFor(nsXULTemplateResultXML* aResult,

View File

@ -21,10 +21,11 @@
#include "nsPIDOMWindow.h"
#include "nsXULContentUtils.h"
#include "nsXMLHttpRequest.h"
#include "mozilla/dom/XPathEvaluator.h"
#include "nsXULTemplateQueryProcessorXML.h"
#include "nsXULTemplateResultXML.h"
#include "nsXULSortService.h"
#include "mozilla/dom/Element.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -53,15 +54,13 @@ NS_IMETHODIMP
nsXULTemplateResultSetXML::GetNext(nsISupports **aResult)
{
ErrorResult rv;
nsCOMPtr<nsIDOMNode> node =
do_QueryInterface(mResults->SnapshotItem(mPosition, rv));
nsINode* node = mResults->SnapshotItem(mPosition, rv);
if (rv.Failed()) {
return rv.ErrorCode();
}
nsXULTemplateResultXML* result =
new nsXULTemplateResultXML(mQuery, node, mBindingSet);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
new nsXULTemplateResultXML(mQuery, node->AsContent(), mBindingSet);
++mPosition;
*aResult = result;
@ -82,8 +81,6 @@ TraverseRuleToBindingsMap(nsISupports* aKey, nsXMLBindingSet* aMatch, void* aCon
static_cast<nsCycleCollectionTraversalCallback*>(aContext);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mRuleToBindingsMap key");
cb->NoteXPCOMChild(aKey);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mRuleToBindingsMap value");
cb->NoteNativeChild(aMatch, NS_CYCLE_COLLECTION_PARTICIPANT(nsXMLBindingSet));
return PL_DHASH_NEXT;
}
@ -210,15 +207,14 @@ nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource,
return NS_ERROR_UNEXPECTED;
// the datasource is either a document or a DOM element
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
if (doc)
doc->GetDocumentElement(getter_AddRefs(mRoot));
mRoot = doc->GetDocumentElement();
else
mRoot = do_QueryInterface(aDatasource);
NS_ENSURE_STATE(mRoot);
mEvaluator = do_CreateInstance("@mozilla.org/dom/xpath-evaluator;1");
NS_ENSURE_TRUE(mEvaluator, NS_ERROR_OUT_OF_MEMORY);
mEvaluator = new XPathEvaluator();
return NS_OK;
}
@ -240,8 +236,6 @@ nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
nsIAtom* aMemberVariable,
nsISupports** _retval)
{
nsresult rv = NS_OK;
*_retval = nullptr;
nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
@ -254,16 +248,16 @@ nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
if (expr.IsEmpty())
expr.Assign('*');
nsCOMPtr<nsIDOMXPathExpression> compiledexpr;
rv = CreateExpression(expr, aQueryNode, getter_AddRefs(compiledexpr));
if (NS_FAILED(rv)) {
ErrorResult rv;
nsAutoPtr<XPathExpression> compiledexpr;
compiledexpr = CreateExpression(expr, content, rv);
if (rv.Failed()) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_XPATH);
return rv;
return rv.ErrorCode();
}
nsRefPtr<nsXMLQuery> query =
new nsXMLQuery(this, aMemberVariable, compiledexpr);
NS_ENSURE_TRUE(query, NS_ERROR_OUT_OF_MEMORY);
new nsXMLQuery(this, aMemberVariable, Move(compiledexpr));
for (nsIContent* condition = content->GetFirstChild();
condition;
@ -279,19 +273,15 @@ nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
// ignore assignments without a variable or an expression
if (!var.IsEmpty() && !expr.IsEmpty()) {
nsCOMPtr<nsIDOMNode> conditionNode =
do_QueryInterface(condition);
rv = CreateExpression(expr, conditionNode,
getter_AddRefs(compiledexpr));
if (NS_FAILED(rv)) {
compiledexpr = CreateExpression(expr, condition, rv);
if (rv.Failed()) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_ASSIGN_XPATH);
return rv;
return rv.ErrorCode();
}
nsCOMPtr<nsIAtom> varatom = do_GetAtom(var);
rv = query->AddBinding(varatom, compiledexpr);
NS_ENSURE_SUCCESS(rv, rv);
query->AddBinding(varatom, Move(compiledexpr));
}
}
}
@ -299,7 +289,7 @@ nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
*_retval = query;
NS_ADDREF(*_retval);
return rv;
return NS_OK;
}
NS_IMETHODIMP
@ -318,7 +308,7 @@ nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource,
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIDOMNode> context;
nsCOMPtr<nsINode> context;
if (aRef)
aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(),
getter_AddRefs(supports));
@ -326,21 +316,21 @@ nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource,
if (!context)
context = mRoot;
nsIDOMXPathExpression* expr = xmlquery->GetResultsExpression();
XPathExpression* expr = xmlquery->GetResultsExpression();
if (!expr)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISupports> exprsupportsresults;
nsresult rv = expr->Evaluate(context,
XPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
nullptr, getter_AddRefs(exprsupportsresults));
NS_ENSURE_SUCCESS(rv, rv);
ErrorResult rv;
nsRefPtr<XPathResult> exprresults =
expr->Evaluate(*context, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
nullptr, rv);
if (rv.Failed()) {
return rv.ErrorCode();
}
XPathResult* exprresults = XPathResult::FromSupports(exprsupportsresults);
nsXULTemplateResultSetXML* results =
new nsXULTemplateResultSetXML(xmlquery, exprresults,
new nsXULTemplateResultSetXML(xmlquery, exprresults.forget(),
xmlquery->GetBindingSet());
NS_ENSURE_TRUE(results, NS_ERROR_OUT_OF_MEMORY);
*aResults = results;
NS_ADDREF(*aResults);
@ -363,16 +353,19 @@ nsXULTemplateQueryProcessorXML::AddBinding(nsIDOMNode* aRuleNode,
mRuleToBindingsMap.Put(aRuleNode, bindings);
}
nsCOMPtr<nsIDOMXPathExpression> compiledexpr;
nsresult rv =
CreateExpression(aExpr, aRuleNode, getter_AddRefs(compiledexpr));
if (NS_FAILED(rv)) {
nsCOMPtr<nsINode> ruleNode = do_QueryInterface(aRuleNode);
ErrorResult rv;
nsAutoPtr<XPathExpression> compiledexpr;
compiledexpr = CreateExpression(aExpr, ruleNode, rv);
if (rv.Failed()) {
nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_BINDING_XPATH);
return NS_OK;
}
// aRef isn't currently used for XML query processors
return bindings->AddBinding(aVar, compiledexpr);
bindings->AddBinding(aVar, Move(compiledexpr));
return NS_OK;
}
NS_IMETHODIMP
@ -383,10 +376,10 @@ nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource,
*aRef = nullptr;
// the datasource is either a document or a DOM element
nsCOMPtr<nsIDOMElement> rootElement;
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDatasource);
nsCOMPtr<Element> rootElement;
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
if (doc)
doc->GetDocumentElement(getter_AddRefs(rootElement));
rootElement = doc->GetRootElement();
else
rootElement = do_QueryInterface(aDatasource);
@ -394,11 +387,7 @@ nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource,
if (!rootElement)
return NS_OK;
nsXULTemplateResultXML* result =
new nsXULTemplateResultXML(nullptr, rootElement, nullptr);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
*aRef = result;
*aRef = new nsXULTemplateResultXML(nullptr, rootElement, nullptr);
NS_ADDREF(*aRef);
return NS_OK;
@ -434,24 +423,18 @@ nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode
return mRuleToBindingsMap.GetWeak(aRuleNode);
}
nsresult
XPathExpression*
nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr,
nsIDOMNode* aNode,
nsIDOMXPathExpression** aCompiledExpr)
nsINode* aNode,
ErrorResult& aRv)
{
nsCOMPtr<nsIDOMXPathNSResolver> nsResolver;
nsCOMPtr<nsIDOMDocument> doc;
aNode->GetOwnerDocument(getter_AddRefs(doc));
nsCOMPtr<nsIDOMXPathEvaluator> eval = do_QueryInterface(doc);
if (eval) {
nsresult rv =
eval->CreateNSResolver(aNode, getter_AddRefs(nsResolver));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMXPathNSResolver> nsResolver =
aNode->OwnerDoc()->CreateNSResolver(aNode, aRv);
if (aRv.Failed()) {
return nullptr;
}
return mEvaluator->CreateExpression(aExpr, nsResolver, aCompiledExpr);
return mEvaluator->CreateExpression(aExpr, nsResolver, aRv);
}
NS_IMETHODIMP

View File

@ -13,14 +13,14 @@
#include "nsString.h"
#include "nsCOMArray.h"
#include "nsRefPtrHashtable.h"
#include "nsIDOMElement.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMXPathExpression.h"
#include "nsIDOMXPathEvaluator.h"
#include "nsXMLBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIXMLHttpRequest.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/XPathEvaluator.h"
#include "mozilla/dom/XPathResult.h"
class nsXULTemplateQueryProcessorXML;
@ -43,26 +43,26 @@ class nsXMLQuery MOZ_FINAL : public nsISupports
nsIAtom* GetMemberVariable() { return mMemberVariable; }
// return a weak reference to the expression used to generate results
nsIDOMXPathExpression* GetResultsExpression() { return mResultsExpr; }
mozilla::dom::XPathExpression* GetResultsExpression()
{ return mResultsExpr; }
// return a weak reference to the additional required bindings
nsXMLBindingSet* GetBindingSet() { return mRequiredBindings; }
// add a required binding for the query
nsresult
AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr)
void
AddBinding(nsIAtom* aVar, nsAutoPtr<mozilla::dom::XPathExpression>&& aExpr)
{
if (!mRequiredBindings) {
mRequiredBindings = new nsXMLBindingSet();
NS_ENSURE_TRUE(mRequiredBindings, NS_ERROR_OUT_OF_MEMORY);
}
return mRequiredBindings->AddBinding(aVar, aExpr);
mRequiredBindings->AddBinding(aVar, mozilla::Move(aExpr));
}
nsXMLQuery(nsXULTemplateQueryProcessorXML* aProcessor,
nsIAtom* aMemberVariable,
nsIDOMXPathExpression* aResultsExpr)
nsIAtom* aMemberVariable,
nsAutoPtr<mozilla::dom::XPathExpression>&& aResultsExpr)
: mProcessor(aProcessor),
mMemberVariable(aMemberVariable),
mResultsExpr(aResultsExpr)
@ -75,7 +75,7 @@ class nsXMLQuery MOZ_FINAL : public nsISupports
nsCOMPtr<nsIAtom> mMemberVariable;
nsCOMPtr<nsIDOMXPathExpression> mResultsExpr;
nsAutoPtr<mozilla::dom::XPathExpression> mResultsExpr;
nsRefPtr<nsXMLBindingSet> mRequiredBindings;
};
@ -109,7 +109,7 @@ public:
NS_DECL_NSISIMPLEENUMERATOR
nsXULTemplateResultSetXML(nsXMLQuery* aQuery,
mozilla::dom::XPathResult* aResults,
already_AddRefed<mozilla::dom::XPathResult> aResults,
nsXMLBindingSet* aBindingSet)
: mQuery(aQuery),
mBindingSet(aBindingSet),
@ -143,10 +143,10 @@ public:
// create an XPath expression from aExpr, using aNode for
// resolving namespaces
nsresult
mozilla::dom::XPathExpression*
CreateExpression(const nsAString& aExpr,
nsIDOMNode* aNode,
nsIDOMXPathExpression** aCompiledExpr);
nsINode* aNode,
mozilla::ErrorResult& aRv);
private:
@ -156,9 +156,9 @@ private:
nsRefPtrHashtable<nsISupportsHashKey, nsXMLBindingSet> mRuleToBindingsMap;
nsCOMPtr<nsIDOMElement> mRoot;
nsCOMPtr<mozilla::dom::Element> mRoot;
nsCOMPtr<nsIDOMXPathEvaluator> mEvaluator;
nsRefPtr<mozilla::dom::XPathEvaluator> mEvaluator;
nsCOMPtr<nsIXULTemplateBuilder> mTemplateBuilder;

View File

@ -18,17 +18,15 @@ static uint32_t sTemplateId = 0;
NS_IMPL_ISUPPORTS(nsXULTemplateResultXML, nsIXULTemplateResult)
nsXULTemplateResultXML::nsXULTemplateResultXML(nsXMLQuery* aQuery,
nsIDOMNode* aNode,
nsIContent* aNode,
nsXMLBindingSet* aBindings)
: mQuery(aQuery), mNode(aNode)
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mNode);
// If the node has an id, create the uri from it. Otherwise, there isn't
// anything to identify the node with so just use a somewhat random number.
nsCOMPtr<nsIAtom> id = content->GetID();
nsCOMPtr<nsIAtom> id = mNode->GetID();
if (id) {
nsCOMPtr<nsIURI> uri = content->GetBaseURI();
nsCOMPtr<nsIURI> uri = mNode->GetBaseURI();
nsAutoCString spec;
uri->GetSpec(spec);
@ -52,10 +50,7 @@ NS_IMETHODIMP
nsXULTemplateResultXML::GetIsContainer(bool* aIsContainer)
{
// a node is considered a container if it has children
if (mNode)
mNode->HasChildNodes(aIsContainer);
else
*aIsContainer = false;
*aIsContainer = mNode && mNode->HasChildNodes();
return NS_OK;
}
@ -148,7 +143,7 @@ nsXULTemplateResultXML::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue)
NS_ENSURE_ARG_POINTER(aVar);
nsXMLBinding* binding;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsISupports> node;
if (mQuery && aVar == mQuery->GetMemberVariable()) {
node = mNode;
@ -156,20 +151,17 @@ nsXULTemplateResultXML::GetBindingObjectFor(nsIAtom* aVar, nsISupports** aValue)
else {
int32_t idx = mRequiredValues.LookupTargetIndex(aVar, &binding);
if (idx > 0) {
mRequiredValues.GetNodeAssignmentFor(this, binding, idx,
getter_AddRefs(node));
node = mRequiredValues.GetNodeAssignmentFor(this, binding, idx);
}
else {
idx = mOptionalValues.LookupTargetIndex(aVar, &binding);
if (idx > 0) {
mOptionalValues.GetNodeAssignmentFor(this, binding, idx,
getter_AddRefs(node));
node = mOptionalValues.GetNodeAssignmentFor(this, binding, idx);
}
}
}
*aValue = node;
NS_IF_ADDREF(*aValue);
node.forget(aValue);
return NS_OK;
}
@ -195,10 +187,3 @@ nsXULTemplateResultXML::HasBeenRemoved()
{
return NS_OK;
}
void
nsXULTemplateResultXML::GetNode(nsIDOMNode** aNode)
{
*aNode = mNode;
NS_IF_ADDREF(*aNode);
}

View File

@ -7,6 +7,7 @@
#define nsXULTemplateResultXML_h__
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsIURI.h"
#include "nsIRDFResource.h"
#include "nsXULTemplateQueryProcessorXML.h"
@ -24,10 +25,13 @@ public:
NS_DECL_NSIXULTEMPLATERESULT
nsXULTemplateResultXML(nsXMLQuery* aQuery,
nsIDOMNode* aNode,
nsIContent* aNode,
nsXMLBindingSet* aBindings);
void GetNode(nsIDOMNode** aNode);
nsIContent* Node()
{
return mNode;
}
protected:
@ -43,7 +47,7 @@ protected:
nsCOMPtr<nsXMLQuery> mQuery;
// context node in datasource
nsCOMPtr<nsIDOMNode> mNode;
nsCOMPtr<nsIContent> mNode;
// assignments in query
nsXMLBindingValues mRequiredValues;

View File

@ -111,8 +111,6 @@
#include "nsIXULTemplateBuilder.h"
#include "nsITreeColumns.h"
#endif
#include "nsIDOMXPathExpression.h"
#include "nsIDOMNSXPathExpression.h"
#include "nsIDOMXPathNSResolver.h"
// Storage includes
@ -344,8 +342,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XPathExpression, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -942,11 +938,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(XPathExpression, nsIDOMXPathExpression)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathExpression)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSXPathExpression)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(XPathNSResolver, nsIDOMXPathNSResolver)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver)
DOM_CLASSINFO_MAP_END

View File

@ -46,7 +46,6 @@ DOMCI_CLASS(CSSSupportsRule)
DOMCI_CLASS(XSLTProcessor)
// DOM Level 3 XPath objects
DOMCI_CLASS(XPathExpression)
DOMCI_CLASS(XPathNSResolver)
// WhatWG WebApps Objects

View File

@ -1672,6 +1672,11 @@ DOMInterfaces = {
'resultNotAddRefed': ['singleNodeValue', 'iterateNext', 'snapshotItem']
},
'XPathExpression': {
'wrapperCache': False,
'nativeOwnership': 'owned',
},
'XULDocument': {
'headerFile': 'XULDocument.h'
},
@ -2011,6 +2016,5 @@ addExternalIface('StackFrame', nativeType='nsIStackFrame',
addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
notflattened=True)
addExternalIface('UserDataHandler')
addExternalIface('XPathExpression')
addExternalIface('XPathNSResolver')
addExternalIface('XULCommandDispatcher')

View File

@ -5,9 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIDOMNSXPathExpression.idl',
'nsIDOMXPathEvaluator.idl',
'nsIDOMXPathExpression.idl',
'nsIDOMXPathNSResolver.idl',
'nsIDOMXPathResult.idl',
]

View File

@ -1,34 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
interface XPathException;
/**
* Interface for Mozilla specific XPathExpression functions.
*/
[scriptable, uuid(ce600ca8-e98a-4419-ad61-2f6d0cb0ecc8)]
interface nsIDOMNSXPathExpression : nsISupports
{
/**
* Evaluate the expression with the given context. Similar to
* nsIDOMXPathExpression::evaluate(), except that this takes the context
* position and size too.
*
* @param contextNode The context node
* @param contextPosition The context position
* @param contextSize The context size
* @param type The needed result type
* @param result The result
*/
nsISupports evaluateWithContext(in nsIDOMNode contextNode,
in unsigned long contextPosition,
in unsigned long contextSize,
in unsigned short type,
in nsISupports result)
raises(XPathException,
DOMException);
};

View File

@ -10,16 +10,11 @@
#include "domstubs.idl"
interface nsIDOMXPathNSResolver;
interface nsIDOMXPathExpression;
interface XPathException;
[uuid(75506f8a-b504-11d5-a7f2-ca108ab8b6fc)]
[uuid(89a0fe71-c1d9-46bd-b76b-47f51fd935ff)]
interface nsIDOMXPathEvaluator : nsISupports
{
nsIDOMXPathExpression createExpression(in DOMString expression,
in nsIDOMXPathNSResolver resolver)
raises(XPathException,
DOMException);
nsIDOMXPathNSResolver createNSResolver(in nsIDOMNode nodeResolver);
nsISupports evaluate(in DOMString expression,
in nsIDOMNode contextNode,

View File

@ -1,22 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Corresponds to http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020208
*/
#include "domstubs.idl"
interface XPathException;
[scriptable, uuid(75506f82-b504-11d5-a7f2-ca108ab8b6fc)]
interface nsIDOMXPathExpression : nsISupports
{
nsISupports evaluate(in nsIDOMNode contextNode,
in unsigned short type,
in nsISupports result)
raises(XPathException,
DOMException);
};

View File

@ -4,7 +4,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
interface XPathExpression;
interface XPathNSResolver;
[Constructor]

View File

@ -0,0 +1,22 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
interface XPathExpression {
// The result specifies a specific result object which may be reused and
// returned by this method. If this is specified as null or it's not an
// XPathResult object, a new result object will be constructed and returned.
[Throws]
XPathResult evaluate(Node contextNode, unsigned short type, object? result);
// The result specifies a specific result object which may be reused and
// returned by this method. If this is specified as null or it's not an
// XPathResult object, a new result object will be constructed and returned.
[Throws, ChromeOnly]
XPathResult evaluateWithContext(Node contextNode,
unsigned long contextPosition,
unsigned long contextSize,
unsigned short type, object? result);
};

View File

@ -481,6 +481,7 @@ WEBIDL_FILES = [
'XMLSerializer.webidl',
'XMLStylesheetProcessingInstruction.webidl',
'XPathEvaluator.webidl',
'XPathExpression.webidl',
'XPathResult.webidl',
'XULCommandEvent.webidl',
'XULDocument.webidl',

View File

@ -21,6 +21,7 @@
#include "nsPIDOMWindow.h"
#include <algorithm>
#include "BackgroundChild.h"
#include "GeckoProfiler.h"
#include "js/OldDebugAPI.h"
#include "jsfriendapi.h"
@ -39,6 +40,7 @@
#include "nsContentUtils.h"
#include "nsCycleCollector.h"
#include "nsDOMJSUtils.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsISupportsImpl.h"
#include "nsLayoutStatics.h"
#include "nsNetUtil.h"
@ -63,6 +65,12 @@
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#ifdef ENABLE_TESTS
#include "BackgroundChildImpl.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "prrng.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
@ -160,6 +168,10 @@ RuntimeService* gRuntimeService = nullptr;
// Only non-null during the call to Init.
RuntimeService* gRuntimeServiceDuringInit = nullptr;
#ifdef ENABLE_TESTS
bool gTestPBackground = false;
#endif // ENABLE_TESTS
enum {
ID_Worker = 0,
ID_ChromeWorker,
@ -904,6 +916,37 @@ private:
WorkerPrivate* mWorkerPrivate;
};
class WorkerBackgroundChildCallback MOZ_FINAL :
public nsIIPCBackgroundChildCreateCallback
{
bool* mDone;
public:
WorkerBackgroundChildCallback(bool* aDone)
: mDone(aDone)
{
MOZ_ASSERT(mDone);
}
NS_DECL_ISUPPORTS
private:
~WorkerBackgroundChildCallback()
{ }
virtual void
ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
{
*mDone = true;
}
virtual void
ActorFailed() MOZ_OVERRIDE
{
*mDone = true;
}
};
class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
{
WorkerPrivate* mWorkerPrivate;
@ -946,6 +989,9 @@ private:
~WorkerThreadPrimaryRunnable()
{ }
nsresult
SynchronouslyCreatePBackground();
NS_DECL_NSIRUNNABLE
};
@ -1045,6 +1091,28 @@ public:
}
#endif
#ifdef ENABLE_TESTS
void
TestPBackground()
{
using namespace mozilla::ipc;
if (gTestPBackground) {
// Randomize value to validate workers are not cross-posting messages.
uint32_t testValue;
PRSize randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
nsCString testStr;
testStr.AppendInt(testValue);
testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
PBackgroundChild* existingBackgroundChild =
BackgroundChild::GetForCurrentThread();
MOZ_RELEASE_ASSERT(existingBackgroundChild);
bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
MOZ_RELEASE_ASSERT(ok);
}
}
#endif // #ENABLE_TESTS
private:
WorkerThread()
: nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
@ -1248,6 +1316,10 @@ RuntimeService::GetOrCreateService()
return nullptr;
}
#ifdef ENABLE_TESTS
gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false);
#endif // ENABLE_TESTS
// The observer service now owns us until shutdown.
gRuntimeService = service;
}
@ -1537,10 +1609,6 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
return false;
}
#ifdef DEBUG
thread->SetAcceptingNonWorkerRunnables(false);
#endif
return true;
}
@ -2492,8 +2560,20 @@ RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
bool aMayWait,
uint32_t aRecursionDepth)
{
using mozilla::ipc::BackgroundChild;
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!aMayWait);
// If the PBackground child is not created yet, then we must permit
// blocking event processing to support SynchronouslyCreatePBackground().
// If this occurs then we are spinning on the event queue at the start of
// PrimaryWorkerRunnable::Run() and don't want to process the event in
// mWorkerPrivate yet.
if (aMayWait) {
MOZ_ASSERT(aRecursionDepth == 2);
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
return NS_OK;
}
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
return NS_OK;
@ -2537,11 +2617,15 @@ LogViolationDetailsRunnable::Run()
return NS_OK;
}
NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
NS_IMETHODIMP
WorkerThreadPrimaryRunnable::Run()
{
using mozilla::ipc::BackgroundChild;
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
@ -2560,6 +2644,19 @@ WorkerThreadPrimaryRunnable::Run()
profiler_register_thread(threadName.get(), &stackBaseGuess);
// Note: SynchronouslyCreatePBackground() must be called prior to
// mThread->SetWorker() in order to avoid accidentally consuming
// worker messages here.
nsresult rv = SynchronouslyCreatePBackground();
if (NS_WARN_IF(NS_FAILED(rv))) {
// XXX need to fire an error at parent.
return rv;
}
#ifdef ENABLE_TESTS
mThread->TestPBackground();
#endif
mThread->SetWorker(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
@ -2593,6 +2690,12 @@ WorkerThreadPrimaryRunnable::Run()
JS_ReportPendingException(cx);
}
#ifdef ENABLE_TESTS
mThread->TestPBackground();
#endif
BackgroundChild::CloseForCurrentThread();
#ifdef MOZ_ENABLE_PROFILER_SPS
if (stack) {
stack->sampleRuntime(nullptr);
@ -2631,6 +2734,38 @@ WorkerThreadPrimaryRunnable::Run()
return NS_OK;
}
nsresult
WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground()
{
using mozilla::ipc::BackgroundChild;
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
bool done = false;
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
new WorkerBackgroundChildCallback(&done);
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
return NS_ERROR_FAILURE;
}
while (!done) {
if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWay */))) {
return NS_ERROR_FAILURE;
}
}
if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
return NS_ERROR_FAILURE;
}
#ifdef DEBUG
mThread->SetAcceptingNonWorkerRunnables(false);
#endif
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
nsRunnable)

View File

@ -7,7 +7,7 @@
#include "mozilla/Move.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsXPathExpression.h"
#include "mozilla/dom/XPathExpression.h"
#include "nsXPathNSResolver.h"
#include "XPathResult.h"
#include "nsContentCID.h"
@ -20,6 +20,7 @@
#include "nsDOMString.h"
#include "nsNameSpaceManager.h"
#include "nsContentUtils.h"
#include "txIXPathContext.h"
#include "mozilla/dom/XPathEvaluatorBinding.h"
#include "mozilla/dom/BindingUtils.h"
@ -94,54 +95,56 @@ XPathEvaluator::Evaluate(const nsAString & aExpression,
nsISupports *aInResult,
nsISupports **aResult)
{
nsCOMPtr<nsIDOMXPathExpression> expression;
nsresult rv = CreateExpression(aExpression, aResolver,
getter_AddRefs(expression));
NS_ENSURE_SUCCESS(rv, rv);
ErrorResult rv;
nsAutoPtr<XPathExpression> expression(CreateExpression(aExpression,
aResolver, rv));
if (rv.Failed()) {
return rv.ErrorCode();
}
return expression->Evaluate(aContextNode, aType, aInResult, aResult);
nsCOMPtr<nsINode> node = do_QueryInterface(aContextNode);
if (!node) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIXPathResult> inResult = do_QueryInterface(aInResult);
nsRefPtr<XPathResult> result =
expression->Evaluate(*node, aType,
static_cast<XPathResult*>(inResult.get()), rv);
if (rv.Failed()) {
return rv.ErrorCode();
}
*aResult = ToSupports(result.forget().take());
return NS_OK;
}
NS_IMETHODIMP
XPathExpression*
XPathEvaluator::CreateExpression(const nsAString & aExpression,
nsIDOMXPathNSResolver *aResolver,
nsIDOMXPathExpression **aResult)
ErrorResult& aRv)
{
nsresult rv;
if (!mRecycler) {
nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
rv = recycler->init();
NS_ENSURE_SUCCESS(rv, rv);
mRecycler = recycler;
mRecycler = new txResultRecycler;
}
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTML()));
nsAutoPtr<Expr> expression;
rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
getter_Transfers(expression));
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_NAMESPACE_ERR) {
return NS_ERROR_DOM_NAMESPACE_ERR;
aRv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
getter_Transfers(expression));
if (aRv.Failed()) {
if (aRv.ErrorCode() != NS_ERROR_DOM_NAMESPACE_ERR) {
aRv.Throw(NS_ERROR_DOM_INVALID_EXPRESSION_ERR);
}
return NS_ERROR_DOM_INVALID_EXPRESSION_ERR;
return nullptr;
}
nsCOMPtr<nsIDOMDocument> document = do_QueryReferent(mDocument);
*aResult = new nsXPathExpression(Move(expression), mRecycler, document);
if (!*aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aResult);
return NS_OK;
return new XPathExpression(Move(expression), mRecycler, doc);
}
JSObject*
@ -159,16 +162,6 @@ XPathEvaluator::Constructor(const GlobalObject& aGlobal,
return newObj.forget();
}
already_AddRefed<nsIDOMXPathExpression>
XPathEvaluator::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv)
{
nsCOMPtr<nsIDOMXPathExpression> expr;
rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expr));
return expr.forget();
}
already_AddRefed<nsIDOMXPathNSResolver>
XPathEvaluator::CreateNSResolver(nsINode* aNodeResolver,
ErrorResult& rv)

View File

@ -21,6 +21,7 @@ namespace mozilla {
namespace dom {
class GlobalObject;
class XPathExpression;
class XPathResult;
/**
@ -47,7 +48,7 @@ public:
}
static already_AddRefed<XPathEvaluator>
Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
already_AddRefed<nsIDOMXPathExpression>
XPathExpression*
CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv);

View File

@ -0,0 +1,247 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Move.h"
#include "XPathExpression.h"
#include "txExpr.h"
#include "txExprResult.h"
#include "txIXPathContext.h"
#include "nsError.h"
#include "nsIDOMCharacterData.h"
#include "nsDOMClassInfoID.h"
#include "nsIDOMDocument.h"
#include "XPathResult.h"
#include "txURIUtils.h"
#include "txXPathTreeWalker.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/XPathResultBinding.h"
using mozilla::Move;
namespace mozilla {
namespace dom {
class EvalContextImpl : public txIEvalContext
{
public:
EvalContextImpl(const txXPathNode& aContextNode,
uint32_t aContextPosition, uint32_t aContextSize,
txResultRecycler* aRecycler)
: mContextNode(aContextNode),
mContextPosition(aContextPosition),
mContextSize(aContextSize),
mLastError(NS_OK),
mRecycler(aRecycler)
{
}
nsresult getError()
{
return mLastError;
}
TX_DECL_EVAL_CONTEXT;
private:
const txXPathNode& mContextNode;
uint32_t mContextPosition;
uint32_t mContextSize;
nsresult mLastError;
nsRefPtr<txResultRecycler> mRecycler;
};
XPathExpression::XPathExpression(nsAutoPtr<Expr>&& aExpression,
txResultRecycler* aRecycler,
nsIDocument *aDocument)
: mExpression(Move(aExpression)),
mRecycler(aRecycler),
mDocument(do_GetWeakReference(aDocument)),
mCheckDocument(aDocument != nullptr)
{
}
XPathExpression::~XPathExpression()
{
}
already_AddRefed<XPathResult>
XPathExpression::EvaluateWithContext(JSContext* aCx,
nsINode& aContextNode,
uint32_t aContextPosition,
uint32_t aContextSize,
uint16_t aType,
JS::Handle<JSObject*> aInResult,
ErrorResult& aRv)
{
XPathResult* inResult = nullptr;
if (aInResult) {
nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult);
if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) {
aRv.Throw(rv);
return nullptr;
}
}
return EvaluateWithContext(aContextNode, aContextPosition, aContextSize,
aType, inResult, aRv);
}
already_AddRefed<XPathResult>
XPathExpression::EvaluateWithContext(nsINode& aContextNode,
uint32_t aContextPosition,
uint32_t aContextSize,
uint16_t aType,
XPathResult* aInResult,
ErrorResult& aRv)
{
if (aContextPosition > aContextSize) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
if (!nsContentUtils::CanCallerAccess(&aContextNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
if (mCheckDocument) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
if (doc != aContextNode.OwnerDoc()) {
aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
return nullptr;
}
}
uint16_t nodeType = aContextNode.NodeType();
if (nodeType == nsIDOMNode::TEXT_NODE ||
nodeType == nsIDOMNode::CDATA_SECTION_NODE) {
nsCOMPtr<nsIDOMCharacterData> textNode =
do_QueryInterface(&aContextNode);
if (!textNode) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
uint32_t textLength;
textNode->GetLength(&textLength);
if (textLength == 0) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
// XXX Need to get logical XPath text node for CDATASection
// and Text nodes.
}
else if (nodeType != nsIDOMNode::DOCUMENT_NODE &&
nodeType != nsIDOMNode::ELEMENT_NODE &&
nodeType != nsIDOMNode::ATTRIBUTE_NODE &&
nodeType != nsIDOMNode::COMMENT_NODE &&
nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(&aContextNode));
EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize,
mRecycler);
nsRefPtr<txAExprResult> exprResult;
aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
if (aRv.Failed()) {
return nullptr;
}
uint16_t resultType = aType;
if (aType == XPathResult::ANY_TYPE) {
short exprResultType = exprResult->getResultType();
switch (exprResultType) {
case txAExprResult::NUMBER:
resultType = XPathResult::NUMBER_TYPE;
break;
case txAExprResult::STRING:
resultType = XPathResult::STRING_TYPE;
break;
case txAExprResult::BOOLEAN:
resultType = XPathResult::BOOLEAN_TYPE;
break;
case txAExprResult::NODESET:
resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE;
break;
case txAExprResult::RESULT_TREE_FRAGMENT:
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
}
nsRefPtr<XPathResult> xpathResult = aInResult;
if (!xpathResult) {
xpathResult = new XPathResult(&aContextNode);
}
aRv = xpathResult->SetExprResult(exprResult, resultType, &aContextNode);
return xpathResult.forget();
}
/*
* Implementation of the txIEvalContext private to XPathExpression
* EvalContextImpl bases on only one context node and no variables
*/
nsresult
EvalContextImpl::getVariable(int32_t aNamespace,
nsIAtom* aLName,
txAExprResult*& aResult)
{
aResult = 0;
return NS_ERROR_INVALID_ARG;
}
bool
EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
{
return false;
}
void*
EvalContextImpl::getPrivateContext()
{
// we don't have a private context here.
return nullptr;
}
txResultRecycler*
EvalContextImpl::recycler()
{
return mRecycler;
}
void
EvalContextImpl::receiveError(const nsAString& aMsg, nsresult aRes)
{
mLastError = aRes;
// forward aMsg to console service?
}
const txXPathNode&
EvalContextImpl::getContextNode()
{
return mContextNode;
}
uint32_t
EvalContextImpl::size()
{
return mContextSize;
}
uint32_t
EvalContextImpl::position()
{
return mContextPosition;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_XPathExpression_h
#define mozilla_dom_XPathExpression_h
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIWeakReferenceUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "mozilla/dom/XPathExpressionBinding.h"
class Expr;
class nsIDocument;
class nsINode;
class txResultRecycler;
class txXPathNode;
namespace mozilla {
namespace dom {
class XPathResult;
/**
* A class for evaluating an XPath expression string
*/
class XPathExpression MOZ_FINAL : public NonRefcountedDOMObject
{
public:
XPathExpression(nsAutoPtr<Expr>&& aExpression, txResultRecycler* aRecycler,
nsIDocument *aDocument);
~XPathExpression();
JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
{
return XPathExpressionBinding::Wrap(aCx, this, aTookOwnership);
}
already_AddRefed<XPathResult>
Evaluate(JSContext* aCx, nsINode& aContextNode, uint16_t aType,
JS::Handle<JSObject*> aInResult, ErrorResult& aRv)
{
return EvaluateWithContext(aCx, aContextNode, 1, 1, aType, aInResult,
aRv);
}
already_AddRefed<XPathResult>
EvaluateWithContext(JSContext* aCx, nsINode& aContextNode,
uint32_t aContextPosition, uint32_t aContextSize,
uint16_t aType, JS::Handle<JSObject*> aInResult,
ErrorResult& aRv);
already_AddRefed<XPathResult>
Evaluate(nsINode& aContextNode, uint16_t aType, XPathResult* aInResult,
ErrorResult& aRv)
{
return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aRv);
}
already_AddRefed<XPathResult>
EvaluateWithContext(nsINode& aContextNode, uint32_t aContextPosition,
uint32_t aContextSize, uint16_t aType,
XPathResult* aInResult, ErrorResult& aRv);
private:
nsAutoPtr<Expr> mExpression;
nsRefPtr<txResultRecycler> mRecycler;
nsWeakPtr mDocument;
bool mCheckDocument;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_XPathExpression_h */

View File

@ -6,11 +6,11 @@
EXPORTS.mozilla.dom += [
'XPathEvaluator.h',
'XPathExpression.h',
'XPathResult.h',
]
UNIFIED_SOURCES += [
'nsXPathExpression.cpp',
'nsXPathNSResolver.cpp',
'txBooleanExpr.cpp',
'txBooleanResult.cpp',
@ -47,6 +47,7 @@ UNIFIED_SOURCES += [
'txXPathOptimizer.cpp',
'txXPCOMExtensionFunction.cpp',
'XPathEvaluator.cpp',
'XPathExpression.cpp',
'XPathResult.cpp',
]

View File

@ -1,202 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Move.h"
#include "nsXPathExpression.h"
#include "txExpr.h"
#include "txExprResult.h"
#include "nsError.h"
#include "nsIDOMCharacterData.h"
#include "nsDOMClassInfoID.h"
#include "nsIDOMDocument.h"
#include "XPathResult.h"
#include "txURIUtils.h"
#include "txXPathTreeWalker.h"
using namespace mozilla::dom;
using mozilla::Move;
NS_IMPL_CYCLE_COLLECTION(nsXPathExpression, mDocument)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathExpression)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathExpression)
DOMCI_DATA(XPathExpression, nsXPathExpression)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPathExpression)
NS_INTERFACE_MAP_ENTRY(nsIDOMXPathExpression)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSXPathExpression)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXPathExpression)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathExpression)
NS_INTERFACE_MAP_END
nsXPathExpression::nsXPathExpression(nsAutoPtr<Expr>&& aExpression,
txResultRecycler* aRecycler,
nsIDOMDocument *aDocument)
: mExpression(Move(aExpression)),
mRecycler(aRecycler),
mDocument(aDocument)
{
}
NS_IMETHODIMP
nsXPathExpression::Evaluate(nsIDOMNode *aContextNode,
uint16_t aType,
nsISupports *aInResult,
nsISupports **aResult)
{
return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aResult);
}
NS_IMETHODIMP
nsXPathExpression::EvaluateWithContext(nsIDOMNode *aContextNode,
uint32_t aContextPosition,
uint32_t aContextSize,
uint16_t aType,
nsISupports *aInResult,
nsISupports **aResult)
{
nsCOMPtr<nsINode> context = do_QueryInterface(aContextNode);
NS_ENSURE_ARG(context);
if (aContextPosition > aContextSize)
return NS_ERROR_FAILURE;
if (!nsContentUtils::CanCallerAccess(aContextNode))
return NS_ERROR_DOM_SECURITY_ERR;
if (mDocument && mDocument != aContextNode) {
nsCOMPtr<nsIDOMDocument> contextDocument;
aContextNode->GetOwnerDocument(getter_AddRefs(contextDocument));
if (mDocument != contextDocument) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
}
uint16_t nodeType = context->NodeType();
if (nodeType == nsIDOMNode::TEXT_NODE ||
nodeType == nsIDOMNode::CDATA_SECTION_NODE) {
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aContextNode);
NS_ENSURE_TRUE(textNode, NS_ERROR_FAILURE);
if (textNode) {
uint32_t textLength;
textNode->GetLength(&textLength);
if (textLength == 0)
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
// XXX Need to get logical XPath text node for CDATASection
// and Text nodes.
}
else if (nodeType != nsIDOMNode::DOCUMENT_NODE &&
nodeType != nsIDOMNode::ELEMENT_NODE &&
nodeType != nsIDOMNode::ATTRIBUTE_NODE &&
nodeType != nsIDOMNode::COMMENT_NODE &&
nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
NS_ENSURE_ARG(aResult);
*aResult = nullptr;
nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode));
if (!contextNode) {
return NS_ERROR_OUT_OF_MEMORY;
}
EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize,
mRecycler);
nsRefPtr<txAExprResult> exprResult;
nsresult rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
NS_ENSURE_SUCCESS(rv, rv);
uint16_t resultType = aType;
if (aType == XPathResult::ANY_TYPE) {
short exprResultType = exprResult->getResultType();
switch (exprResultType) {
case txAExprResult::NUMBER:
resultType = XPathResult::NUMBER_TYPE;
break;
case txAExprResult::STRING:
resultType = XPathResult::STRING_TYPE;
break;
case txAExprResult::BOOLEAN:
resultType = XPathResult::BOOLEAN_TYPE;
break;
case txAExprResult::NODESET:
resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE;
break;
case txAExprResult::RESULT_TREE_FRAGMENT:
NS_ERROR("Can't return a tree fragment!");
return NS_ERROR_FAILURE;
}
}
// We need a result object and it must be our implementation.
nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(aInResult);
if (!xpathResult) {
// Either no aInResult or not one of ours.
xpathResult = new XPathResult(context);
}
rv = xpathResult->SetExprResult(exprResult, resultType, context);
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(xpathResult, aResult);
}
/*
* Implementation of the txIEvalContext private to nsXPathExpression
* EvalContextImpl bases on only one context node and no variables
*/
nsresult
nsXPathExpression::EvalContextImpl::getVariable(int32_t aNamespace,
nsIAtom* aLName,
txAExprResult*& aResult)
{
aResult = 0;
return NS_ERROR_INVALID_ARG;
}
bool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
{
return false;
}
void* nsXPathExpression::EvalContextImpl::getPrivateContext()
{
// we don't have a private context here.
return nullptr;
}
txResultRecycler* nsXPathExpression::EvalContextImpl::recycler()
{
return mRecycler;
}
void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg,
nsresult aRes)
{
mLastError = aRes;
// forward aMsg to console service?
}
const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode()
{
return mContextNode;
}
uint32_t nsXPathExpression::EvalContextImpl::size()
{
return mContextSize;
}
uint32_t nsXPathExpression::EvalContextImpl::position()
{
return mContextPosition;
}

View File

@ -1,78 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsXPathExpression_h__
#define nsXPathExpression_h__
#include "nsIDOMXPathExpression.h"
#include "nsIDOMNSXPathExpression.h"
#include "txIXPathContext.h"
#include "txResultRecycler.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
class Expr;
class txXPathNode;
/**
* A class for evaluating an XPath expression string
*/
class nsXPathExpression MOZ_FINAL : public nsIDOMXPathExpression,
public nsIDOMNSXPathExpression
{
public:
nsXPathExpression(nsAutoPtr<Expr>&& aExpression, txResultRecycler* aRecycler,
nsIDOMDocument *aDocument);
// nsISupports interface
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXPathExpression,
nsIDOMXPathExpression)
// nsIDOMXPathExpression interface
NS_DECL_NSIDOMXPATHEXPRESSION
// nsIDOMNSXPathExpression interface
NS_DECL_NSIDOMNSXPATHEXPRESSION
private:
~nsXPathExpression() {}
nsAutoPtr<Expr> mExpression;
nsRefPtr<txResultRecycler> mRecycler;
nsCOMPtr<nsIDOMDocument> mDocument;
class EvalContextImpl : public txIEvalContext
{
public:
EvalContextImpl(const txXPathNode& aContextNode,
uint32_t aContextPosition, uint32_t aContextSize,
txResultRecycler* aRecycler)
: mContextNode(aContextNode),
mContextPosition(aContextPosition),
mContextSize(aContextSize),
mLastError(NS_OK),
mRecycler(aRecycler)
{
}
nsresult getError()
{
return mLastError;
}
TX_DECL_EVAL_CONTEXT;
private:
const txXPathNode& mContextNode;
uint32_t mContextPosition;
uint32_t mContextSize;
nsresult mLastError;
nsRefPtr<txResultRecycler> mRecycler;
};
};
#endif

View File

@ -8,9 +8,9 @@
#include "txNodeSet.h"
txResultRecycler::txResultRecycler()
: mEmptyStringResult(nullptr),
mTrueResult(nullptr),
mFalseResult(nullptr)
: mEmptyStringResult(new StringResult(nullptr)),
mTrueResult(new BooleanResult(true)),
mFalseResult(new BooleanResult(false))
{
}
@ -28,34 +28,6 @@ txResultRecycler::~txResultRecycler()
while (numberIter.hasNext()) {
delete static_cast<NumberResult*>(numberIter.next());
}
NS_IF_RELEASE(mEmptyStringResult);
NS_IF_RELEASE(mTrueResult);
NS_IF_RELEASE(mFalseResult);
}
nsresult
txResultRecycler::init()
{
NS_ASSERTION(!mEmptyStringResult && !mTrueResult && !mFalseResult,
"Already inited");
mEmptyStringResult = new StringResult(nullptr);
NS_ENSURE_TRUE(mEmptyStringResult, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mEmptyStringResult);
mTrueResult = new BooleanResult(true);
NS_ENSURE_TRUE(mTrueResult, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mTrueResult);
mFalseResult = new BooleanResult(false);
NS_ENSURE_TRUE(mFalseResult, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mFalseResult);
return NS_OK;
}

View File

@ -7,6 +7,7 @@
#define txResultRecycler_h__
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "txStack.h"
class txAExprResult;
@ -21,7 +22,6 @@ class txResultRecycler
public:
txResultRecycler();
~txResultRecycler();
nsresult init();
void AddRef()
{
@ -72,9 +72,9 @@ private:
txStack mStringResults;
txStack mNodeSetResults;
txStack mNumberResults;
StringResult* mEmptyStringResult;
BooleanResult* mTrueResult;
BooleanResult* mFalseResult;
nsRefPtr<StringResult> mEmptyStringResult;
nsRefPtr<BooleanResult> mTrueResult;
nsRefPtr<BooleanResult> mFalseResult;
};
#endif //txResultRecycler_h__

View File

@ -80,11 +80,6 @@ txXPathOptimizer::optimize(Expr* aInExpr, Expr** aOutExpr)
if (exprType != Expr::LITERAL_EXPR &&
!aInExpr->isSensitiveTo(Expr::ANY_CONTEXT)) {
nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
rv = recycler->init();
NS_ENSURE_SUCCESS(rv, rv);
txEarlyEvalContext context(recycler);
nsRefPtr<txAExprResult> exprRes;

View File

@ -125,10 +125,6 @@ txExecutionState::init(const txXPathNode& aNode,
NS_ENSURE_SUCCESS(rv, rv);
mRecycler = new txResultRecycler;
NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY);
rv = mRecycler->init();
NS_ENSURE_SUCCESS(rv, rv);
// The actual value here doesn't really matter since noone should use this
// value. But lets put something errorlike in just in case

View File

@ -470,10 +470,6 @@ txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName,
if (!mRecycler) {
mRecycler = new txResultRecycler;
NS_ENSURE_TRUE(mRecycler, NS_ERROR_OUT_OF_MEMORY);
rv = mRecycler->init();
NS_ENSURE_SUCCESS(rv, rv);
}
txXSLTParamContext paramContext(&mParamNamespaceMap, *contextNode,

View File

@ -178,7 +178,10 @@ ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface)
// XXX - We should actually figure out the minimum shmem allocation size on
// a certain platform and use that.
const uint32_t sShmemPageSize = 4096;
#ifdef DEBUG
const uint32_t sSupportedBlockSize = 4;
#endif
enum AllocationStatus
{
@ -324,5 +327,5 @@ ISurfaceAllocator::DeallocGrallocBuffer(MaybeMagicGrallocBufferHandle* aHandle)
SharedBufferManagerChild::GetSingleton()->DeallocGrallocBuffer(*aHandle);
}
} // namespace
} // namespace
} // namespace layers
} // namespace mozilla

View File

@ -59,8 +59,6 @@
#include <ui/Fence.h>
#endif
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
namespace mozilla {
using namespace std;
@ -406,11 +404,13 @@ SetRects(int n,
aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
}
#ifdef DEBUG
static inline bool
FuzzyEqual(float a, float b)
{
return fabs(a - b) < 0.0001f;
}
#endif
static int
DecomposeIntoNoRepeatRects(const Rect& aRect,

View File

@ -162,13 +162,15 @@ nsFontMetrics::XHeight()
nscoord
nsFontMetrics::SuperscriptOffset()
{
return ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
return ROUND_TO_TWIPS(GetMetrics().emHeight *
NS_FONT_SUPERSCRIPT_OFFSET_RATIO);
}
nscoord
nsFontMetrics::SubscriptOffset()
{
return ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
return ROUND_TO_TWIPS(GetMetrics().emHeight *
NS_FONT_SUBSCRIPT_OFFSET_RATIO);
}
void

View File

@ -13,6 +13,7 @@
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/Preferences.h"
#include "base/task.h"
#include "Layers.h"
#include "TestLayers.h"
@ -58,6 +59,24 @@ public:
MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
};
class TestScopedBoolPref {
public:
TestScopedBoolPref(const char* aPref, bool aVal)
: mPref(aPref)
{
mOldVal = Preferences::GetBool(aPref);
Preferences::SetBool(aPref, aVal);
}
~TestScopedBoolPref() {
Preferences::SetBool(mPref, mOldVal);
}
private:
const char* mPref;
bool mOldVal;
};
class MockContentControllerDelayed : public MockContentController {
public:
MockContentControllerDelayed()
@ -884,6 +903,8 @@ TEST_F(AsyncPanZoomControllerTester, FlingStopTap) {
}
TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
TestScopedBoolPref overscrollEnabledPref("apz.overscroll.enabled", true);
TimeStamp testStartTime = TimeStamp::Now();
AsyncPanZoomController::SetFrameTime(testStartTime);
@ -894,20 +915,78 @@ TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
apzc->SetFrameMetrics(TestFrameMetrics());
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
// Pan sufficiently to hit overscroll behavior
int time = 0;
int touchStart = 500;
int touchEnd = 10;
ApzcPan(apzc, tm, time, touchStart, touchEnd);
EXPECT_TRUE(apzc->IsOverscrolled());
// Note that in the calls to SampleContentTransformForFrame below, the time
// increment used is sufficiently large for the animation to have completed. However,
// any single call to SampleContentTransformForFrame will not finish an animation
// *and* also proceed through the following animation, if there is one.
// Therefore the minimum number of calls to go from an overscroll-inducing pan
// to a reset state is 3; these are documented further below.
ScreenPoint pointOut;
ViewTransform viewTransformOut;
// This sample will run to the end of the non-overscrolling fling animation
// and will schedule the overscrolling fling animation.
apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut);
EXPECT_EQ(ScreenPoint(0, 90), pointOut);
EXPECT_TRUE(apzc->IsOverscrolled());
// This sample will run to the end of the overscrolling fling animation and
// will schedule the snapback animation.
apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(20000), &viewTransformOut, pointOut);
EXPECT_EQ(ScreenPoint(0, 90), pointOut);
EXPECT_TRUE(apzc->IsOverscrolled());
// This sample will run to the end of the snapback animation and reset the state.
apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(30000), &viewTransformOut, pointOut);
EXPECT_EQ(ScreenPoint(0, 90), pointOut);
EXPECT_FALSE(apzc->IsOverscrolled());
apzc->AssertStateIsReset();
apzc->Destroy();
}
TEST_F(AsyncPanZoomControllerTester, OverScrollAbort) {
TestScopedBoolPref overscrollEnabledPref("apz.overscroll.enabled", true);
TimeStamp testStartTime = TimeStamp::Now();
AsyncPanZoomController::SetFrameTime(testStartTime);
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc, tm);
apzc->SetFrameMetrics(TestFrameMetrics());
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
// Pan sufficiently to hit overscroll behavior
int time = 0;
int touchStart = 500;
int touchEnd = 10;
ApzcPan(apzc, tm, time, touchStart, touchEnd);
EXPECT_TRUE(apzc->IsOverscrolled());
ScreenPoint pointOut;
ViewTransform viewTransformOut;
// Pan down
ApzcPan(apzc, tm, time, touchStart, touchEnd);
apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
EXPECT_EQ(ScreenPoint(0, 90), pointOut);
// This sample call will run to the end of the non-overscrolling fling animation
// and will schedule the overscrolling fling animation (see comment in OverScrollPanning
// above for more explanation).
apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut);
EXPECT_TRUE(apzc->IsOverscrolled());
// At this point, we have an active overscrolling fling animation.
// Check that cancelling the animation clears the overscroll.
apzc->CancelAnimation();
EXPECT_FALSE(apzc->IsOverscrolled());
apzc->AssertStateIsReset();
apzc->Destroy();
}

View File

@ -7,9 +7,7 @@
#include "mozilla/MemoryReporting.h"
#include "gfxHarfBuzzShaper.h"
#include <algorithm>
#include "gfxGraphiteShaper.h"
#include "gfxDWriteFontList.h"
#include "gfxContext.h"
#include <dwrite.h>
@ -106,14 +104,6 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
}
ComputeMetrics(anAAOption);
if (FontCanSupportGraphite()) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
if (FontCanSupportHarfBuzz()) {
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
}
gfxDWriteFont::~gfxDWriteFont()
@ -134,32 +124,6 @@ gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
&mStyle, mNeedsBold, anAAOption);
}
bool
gfxDWriteFont::ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
{
bool ok = false;
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
if (!ok && mHarfBuzzShaper) {
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
return ok;
}
const gfxFont::Metrics&
gfxDWriteFont::GetMetrics()
{
@ -316,8 +280,6 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
fontMetrics.strikethroughPosition * mFUnitsConvFactor;
mMetrics->strikeoutSize =
fontMetrics.strikethroughThickness * mFUnitsConvFactor;
mMetrics->superscriptOffset = 0;
mMetrics->subscriptOffset = 0;
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
@ -329,9 +291,8 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n",
mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight);
printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
mMetrics->superscriptOffset, mMetrics->subscriptOffset);
printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n",
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
#endif
}

View File

@ -71,14 +71,6 @@ public:
virtual cairo_scaled_font_t *GetCairoScaledFont();
protected:
virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping = false);
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
void ComputeMetrics(AntialiasOption anAAOption);

View File

@ -133,7 +133,7 @@ gfxFT2FontBase::GetMetrics()
fprintf (stderr, " maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
#endif
mHasMetrics = true;

View File

@ -24,8 +24,6 @@
#include "gfxFT2Utils.h"
#include "gfxFT2FontList.h"
#include <locale.h>
#include "gfxHarfBuzzShaper.h"
#include "gfxGraphiteShaper.h"
#include "nsGkAtoms.h"
#include "nsTArray.h"
#include "nsUnicodeRange.h"
@ -44,42 +42,20 @@
*/
bool
gfxFT2Font::ShapeText(gfxContext *aContext,
gfxFT2Font::ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText)
{
bool ok = false;
if (FontCanSupportGraphite()) {
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
if (!mGraphiteShaper) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
ok = mGraphiteShaper->ShapeText(aContext, aText,
aOffset, aLength,
aScript, aShapedText);
}
}
if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
if (!mHarfBuzzShaper) {
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
ok = mHarfBuzzShaper->ShapeText(aContext, aText,
aOffset, aLength,
aScript, aShapedText);
}
if (!ok) {
if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
aShapedText)) {
// harfbuzz must have failed(?!), just render raw glyphs
AddRange(aText, aOffset, aLength, aShapedText);
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
}
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
return true;
}

View File

@ -77,8 +77,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping);
gfxShapedText *aShapedText);
void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd);

View File

@ -67,8 +67,6 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
aMetrics->zeroOrAveCharWidth = spaceWidth;
const gfxFloat xHeight = 0.5 * emHeight;
aMetrics->xHeight = xHeight;
aMetrics->superscriptOffset = xHeight;
aMetrics->subscriptOffset = xHeight;
const gfxFloat underlineSize = emHeight / 14.0;
aMetrics->underlineSize = underlineSize;
aMetrics->underlineOffset = -underlineSize;
@ -243,24 +241,6 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
}
SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
if (os2 && os2->ySuperscriptYOffset) {
gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
ftMetrics.y_scale);
aMetrics->superscriptOffset = std::max(1.0, val);
} else {
aMetrics->superscriptOffset = aMetrics->xHeight;
}
if (os2 && os2->ySubscriptYOffset) {
gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset,
ftMetrics.y_scale);
// some fonts have the incorrect sign.
val = fabs(val);
aMetrics->subscriptOffset = std::max(1.0, val);
} else {
aMetrics->subscriptOffset = aMetrics->xHeight;
}
aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
// Make the line height an integer number of pixels so that lines will be

View File

@ -23,6 +23,7 @@
#include "gfxTypes.h"
#include "gfxContext.h"
#include "gfxFontMissingGlyphs.h"
#include "gfxGraphiteShaper.h"
#include "gfxHarfBuzzShaper.h"
#include "gfxUserFontSet.h"
#include "gfxPlatformFontList.h"
@ -4074,8 +4075,7 @@ gfxFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
gfxShapedText *aShapedText)
{
nsDependentCSubstring ascii((const char*)aText, aLength);
nsAutoString utf16;
@ -4084,7 +4084,7 @@ gfxFont::ShapeText(gfxContext *aContext,
return false;
}
return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength,
aScript, aShapedText, aPreferPlatformShaping);
aScript, aShapedText);
}
bool
@ -4093,33 +4093,30 @@ gfxFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
gfxShapedText *aShapedText)
{
bool ok = false;
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
if (!ok && mHarfBuzzShaper && !aPreferPlatformShaping) {
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) {
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
if (FontCanSupportGraphite()) {
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
if (!mGraphiteShaper) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
}
if (!ok) {
if (!mPlatformShaper) {
CreatePlatformShaper();
}
if (mPlatformShaper) {
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
if (!mHarfBuzzShaper) {
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
return ok;
@ -4597,8 +4594,6 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
// this should always be present in any valid OS/2 of any version
if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
SET_SIGNED(aveCharWidth, os2->xAvgCharWidth);
SET_SIGNED(subscriptOffset, os2->ySubscriptYOffset);
SET_SIGNED(superscriptOffset, os2->ySuperscriptYOffset);
SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
SET_SIGNED(strikeoutOffset, os2->yStrikeoutPosition);
@ -4660,13 +4655,6 @@ void gfxFont::CalculateDerivedMetrics(Metrics& aMetrics)
aMetrics.maxAdvance = aMetrics.aveCharWidth;
}
if (!aMetrics.subscriptOffset) {
aMetrics.subscriptOffset = aMetrics.xHeight;
}
if (!aMetrics.superscriptOffset) {
aMetrics.superscriptOffset = aMetrics.xHeight;
}
if (!aMetrics.strikeoutOffset) {
aMetrics.strikeoutOffset = aMetrics.xHeight * 0.5;
}
@ -4685,19 +4673,6 @@ gfxFont::SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont)
return;
}
// MS (P)Gothic and MS (P)Mincho are not having suitable values in their super script offset.
// If the values are not suitable, we should use x-height instead of them.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=353632
if (aMetrics->superscriptOffset <= 0 ||
aMetrics->superscriptOffset >= aMetrics->maxAscent) {
aMetrics->superscriptOffset = aMetrics->xHeight;
}
// And also checking the case of sub script offset. The old gfx for win has checked this too.
if (aMetrics->subscriptOffset <= 0 ||
aMetrics->subscriptOffset >= aMetrics->maxAscent) {
aMetrics->subscriptOffset = aMetrics->xHeight;
}
aMetrics->underlineSize = std::max(1.0, aMetrics->underlineSize);
aMetrics->strikeoutSize = std::max(1.0, aMetrics->strikeoutSize);

View File

@ -1479,12 +1479,12 @@ public:
// Shape a piece of text and store the resulting glyph data into
// aShapedText. Parameters aOffset/aLength indicate the range of
// aShapedText to be updated; aLength is also the length of aText.
virtual bool ShapeText(gfxContext *aContext,
virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText) = 0;
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText) = 0;
gfxFont *GetFont() const { return mFont; }
@ -1658,8 +1658,6 @@ public:
// Font metrics
struct Metrics {
gfxFloat xHeight;
gfxFloat superscriptOffset;
gfxFloat subscriptOffset;
gfxFloat strikeoutSize;
gfxFloat strikeoutOffset;
gfxFloat underlineSize;
@ -1998,8 +1996,7 @@ protected:
uint32_t aOffset, // dest offset in gfxShapedText
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText, // where to store the result
bool aPreferPlatformShaping = false);
gfxShapedText *aShapedText); // where to store the result
// Call the appropriate shaper to generate glyphs for aText and store
// them into aShapedText.
@ -2008,8 +2005,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping = false);
gfxShapedText *aShapedText);
// Helper to adjust for synthetic bold and set character-type flags
// in the shaped text; implementations of ShapeText should call this
@ -2168,19 +2164,14 @@ protected:
// measurement by mathml code
nsAutoPtr<gfxFont> mNonAAFont;
// we may switch between these shapers on the fly, based on the script
// of the text run being shaped
nsAutoPtr<gfxFontShaper> mPlatformShaper;
// we create either or both of these shapers when needed, depending
// whether the font has graphite tables, and whether graphite shaping
// is actually enabled
nsAutoPtr<gfxFontShaper> mHarfBuzzShaper;
nsAutoPtr<gfxFontShaper> mGraphiteShaper;
mozilla::RefPtr<mozilla::gfx::ScaledFont> mAzureScaledFont;
// Create a default platform text shaper for this font.
// (TODO: This should become pure virtual once all font backends have
// been updated.)
virtual void CreatePlatformShaper() { }
// Helper for subclasses that want to initialize standard metrics from the
// tables of sfnt (TrueType/OpenType) fonts.
// This will use mFUnitsConvFactor if it is already set, else compute it

View File

@ -196,4 +196,8 @@ enum {
#define NS_FONT_VARIANT_POSITION_SUPER 1
#define NS_FONT_VARIANT_POSITION_SUB 2
// based on fixed offset values used within WebKit
#define NS_FONT_SUBSCRIPT_OFFSET_RATIO (0.20)
#define NS_FONT_SUPERSCRIPT_OFFSET_RATIO (0.34)
#endif

View File

@ -8,9 +8,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/WindowsVersion.h"
#include "gfxHarfBuzzShaper.h"
#include <algorithm>
#include "gfxGraphiteShaper.h"
#include "gfxWindowsPlatform.h"
#include "gfxContext.h"
#include "mozilla/Preferences.h"
@ -52,10 +50,6 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
mNeedsBold(aNeedsBold),
mScriptCache(nullptr)
{
if (FontCanSupportGraphite()) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
gfxGDIFont::~gfxGDIFont()
@ -83,13 +77,12 @@ gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
}
bool
gfxGDIFont::ShapeText(gfxContext *aContext,
gfxGDIFont::ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText)
{
if (!mMetrics) {
Initialize();
@ -108,7 +101,7 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
}
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
aShapedText, aPreferPlatformShaping);
aShapedText);
}
const gfxFont::Metrics&
@ -247,9 +240,6 @@ gfxGDIFont::Initialize()
TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) {
mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y;
// Some fonts have wrong sign on their subscript offset, bug 410917.
mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y);
mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize;
mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition;
mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize;
@ -288,8 +278,6 @@ gfxGDIFont::Initialize()
mMetrics->xHeight =
ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
mMetrics->superscriptOffset = mMetrics->xHeight;
mMetrics->subscriptOffset = mMetrics->xHeight;
mMetrics->strikeoutSize = 1;
mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight
mMetrics->underlineSize = 1;
@ -394,9 +382,8 @@ gfxGDIFont::Initialize()
printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight);
printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
mMetrics->superscriptOffset, mMetrics->subscriptOffset);
printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n",
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
#endif
}

View File

@ -72,13 +72,12 @@ public:
protected:
/* override to ensure the cairo font is set up properly */
virtual bool ShapeText(gfxContext *aContext,
virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping);
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText);
void Initialize(); // creates metrics and Cairo fonts

View File

@ -8,9 +8,7 @@
#include "mozilla/MemoryReporting.h"
#include "gfxCoreTextShaper.h"
#include "gfxHarfBuzzShaper.h"
#include <algorithm>
#include "gfxGraphiteShaper.h"
#include "gfxPlatformMac.h"
#include "gfxContext.h"
#include "gfxFontUtils.h"
@ -107,13 +105,6 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl
NS_WARNING(warnBuf);
#endif
}
if (FontCanSupportGraphite()) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
if (FontCanSupportHarfBuzz()) {
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
}
gfxMacFont::~gfxMacFont()
@ -127,29 +118,31 @@ gfxMacFont::~gfxMacFont()
}
bool
gfxMacFont::ShapeText(gfxContext *aContext,
gfxMacFont::ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText)
{
if (!mIsValid) {
NS_WARNING("invalid font! expect incorrect text rendering");
return false;
}
bool requiresAAT =
static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout();
return gfxFont::ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText, requiresAAT);
}
if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout()) {
if (!mCoreTextShaper) {
mCoreTextShaper = new gfxCoreTextShaper(this);
}
if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText)) {
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
return true;
}
}
void
gfxMacFont::CreatePlatformShaper()
{
mPlatformShaper = new gfxCoreTextShaper(this);
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
aShapedText);
}
bool
@ -332,7 +325,7 @@ gfxMacFont::InitMetrics()
fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
#endif
}

View File

@ -51,16 +51,13 @@ public:
virtual FontType GetType() const { return FONT_TYPE_MAC; }
protected:
virtual void CreatePlatformShaper();
// override to prefer CoreText shaping with fonts that depend on AAT
virtual bool ShapeText(gfxContext *aContext,
virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping = false);
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText);
void InitMetrics();
void InitMetricsFromPlatform();
@ -76,6 +73,8 @@ protected:
cairo_font_face_t *mFontFace;
nsAutoPtr<gfxFontShaper> mCoreTextShaper;
Metrics mMetrics;
uint32_t mSpaceGlyph;
};

View File

@ -20,8 +20,6 @@
#include "gfxFT2Utils.h"
#include "harfbuzz/hb.h"
#include "harfbuzz/hb-ot.h"
#include "gfxHarfBuzzShaper.h"
#include "gfxGraphiteShaper.h"
#include "nsUnicodeProperties.h"
#include "nsUnicodeScriptCodes.h"
#include "gfxFontconfigUtils.h"
@ -663,14 +661,6 @@ public:
protected:
virtual already_AddRefed<gfxFont> GetSmallCapsFont();
virtual bool ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping);
private:
gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle);
@ -1564,42 +1554,6 @@ gfxFcFont::GetSmallCapsFont()
return font.forget();
}
bool
gfxFcFont::ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
gfxShapedText *aShapedText,
bool aPreferPlatformShaping)
{
bool ok = false;
if (FontCanSupportGraphite()) {
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
if (!mGraphiteShaper) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
}
if (!ok) {
if (!mHarfBuzzShaper) {
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
}
NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
return ok;
}
/* static */ void
gfxPangoFontGroup::Shutdown()
{

View File

@ -145,8 +145,6 @@ NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
#define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
#define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT
#define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
#define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
@ -266,7 +264,6 @@ gfxPlatform::gfxPlatform()
: mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
&gfxPlatform::GetAzureBackendInfo)
{
mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
mFallbackUsesCmaps = UNINITIALIZED_VALUE;
@ -1134,18 +1131,6 @@ gfxPlatform::UseGraphiteShaping()
return mGraphiteShapingEnabled;
}
bool
gfxPlatform::UseHarfBuzzForScript(int32_t aScriptCode)
{
if (mUseHarfBuzzScripts == UNINITIALIZED_VALUE) {
mUseHarfBuzzScripts = Preferences::GetInt(GFX_PREF_HARFBUZZ_SCRIPTS, HARFBUZZ_SCRIPTS_DEFAULT);
}
int32_t shapingType = mozilla::unicode::ScriptShapingType(aScriptCode);
return (mUseHarfBuzzScripts & shapingType) != 0;
}
gfxFontEntry*
gfxPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const uint8_t *aFontData,
@ -1880,9 +1865,6 @@ gfxPlatform::FontsPrefsChanged(const char *aPref)
} else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
FlushFontAndWordCaches();
} else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
FlushFontAndWordCaches();
} else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
mBidiNumeralOption = UNINITIALIZED_VALUE;
} else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {

View File

@ -389,13 +389,6 @@ public:
*/
bool UseGraphiteShaping();
/**
* Whether to use the harfbuzz shaper (depending on script complexity).
*
* This allows harfbuzz to be enabled selectively via the preferences.
*/
bool UseHarfBuzzForScript(int32_t aScriptCode);
// check whether format is supported on a platform or not (if unclear, returns true)
virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) { return false; }
@ -610,9 +603,6 @@ protected:
// when doing system font fallback
int8_t mFallbackUsesCmaps;
// which scripts should be shaped with harfbuzz
int32_t mUseHarfBuzzScripts;
// max character limit for words in word cache
int32_t mWordCacheCharLimit;

View File

@ -44,6 +44,7 @@ struct Orientation;
[ref] native gfxRect(gfxRect);
native gfxGraphicsFilter(GraphicsFilter);
[ref] native nsIntRect(nsIntRect);
native nsIntRectByVal(nsIntRect);
[ref] native nsIntSize(nsIntSize);
native nsSize(nsSize);
[ptr] native nsIFrame(nsIFrame);
@ -53,6 +54,7 @@ native Orientation(mozilla::image::Orientation);
[ref] native TimeStamp(mozilla::TimeStamp);
[ptr] native SVGImageContext(mozilla::SVGImageContext);
native TempRefSourceSurface(mozilla::TemporaryRef<mozilla::gfx::SourceSurface>);
native TempRefImgIContainer(already_AddRefed<imgIContainer>);
/**
@ -62,7 +64,7 @@ native TempRefSourceSurface(mozilla::TemporaryRef<mozilla::gfx::SourceSurface>);
*
* Internally, imgIContainer also manages animation of images.
*/
[scriptable, builtinclass, uuid(503a830c-734d-4362-91f6-73f83ac59646)]
[scriptable, builtinclass, uuid(c9bd1257-45fb-4ea6-a669-6da212479191)]
interface imgIContainer : nsISupports
{
/**
@ -348,4 +350,19 @@ interface imgIContainer : nsISupports
* resetAnimation(), or requestRefresh() is called for the first time.
*/
[notxpcom] void setAnimationStartTime([const] in TimeStamp aTime);
/*
* Given an invalidation rect in the coordinate system used by the decoder,
* returns an invalidation rect in image space.
*
* This is the identity transformation in most cases, but the result can
* differ if the image is wrapped by an ImageWrapper that changes its size
* or orientation.
*/
[notxpcom] nsIntRectByVal getImageSpaceInvalidationRect([const] in nsIntRect aRect);
/*
* Removes any ImageWrappers and returns the unwrapped base image.
*/
[notxpcom, nostdcall] TempRefImgIContainer unwrap();
};

View File

@ -424,5 +424,18 @@ ClippedImage::GetOrientation()
return InnerImage()->GetOrientation();
}
NS_IMETHODIMP_(nsIntRect)
ClippedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
{
if (!ShouldClip()) {
return InnerImage()->GetImageSpaceInvalidationRect(aRect);
}
nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect));
rect = rect.Intersect(mClip);
rect.MoveBy(-mClip.x, -mClip.y);
return rect;
}
} // namespace image
} // namespace mozilla

View File

@ -52,6 +52,7 @@ public:
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD RequestDiscard() MOZ_OVERRIDE;
NS_IMETHOD_(Orientation) GetOrientation() MOZ_OVERRIDE;
NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE;
protected:
ClippedImage(Image* aImage, nsIntRect aClip);

View File

@ -317,5 +317,17 @@ ImageWrapper::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
mInnerImage->SetAnimationStartTime(aTime);
}
NS_IMETHODIMP_(nsIntRect)
ImageWrapper::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
{
return mInnerImage->GetImageSpaceInvalidationRect(aRect);
}
already_AddRefed<imgIContainer>
ImageWrapper::Unwrap()
{
return mInnerImage->Unwrap();
}
} // namespace image
} // namespace mozilla

View File

@ -250,5 +250,32 @@ OrientedImage::Draw(gfxContext* aContext,
aWhichFrame, aFlags);
}
NS_IMETHODIMP_(nsIntRect)
OrientedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
{
nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect));
if (mOrientation.IsIdentity()) {
return rect;
}
int32_t width, height;
nsresult rv = InnerImage()->GetWidth(&width);
rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&height);
if (NS_FAILED(rv)) {
// Fall back to identity if the width and height aren't available.
return rect;
}
// Transform the invalidation rect into the correct orientation.
gfxMatrix matrix(OrientationMatrix(nsIntSize(width, height)).Invert());
gfxRect invalidRect(matrix.TransformBounds(gfxRect(rect.x, rect.y,
rect.width, rect.height)));
invalidRect.RoundOut();
return nsIntRect(invalidRect.x, invalidRect.y,
invalidRect.width, invalidRect.height);
}
} // namespace image
} // namespace mozilla

View File

@ -47,6 +47,7 @@ public:
const SVGImageContext* aSVGContext,
uint32_t aWhichFrame,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE;
protected:
OrientedImage(Image* aImage, Orientation aOrientation)

View File

@ -1601,6 +1601,12 @@ RasterImage::SetLoopCount(int32_t aLoopCount)
}
}
NS_IMETHODIMP_(nsIntRect)
RasterImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
{
return aRect;
}
nsresult
RasterImage::AddSourceData(const char *aBuffer, uint32_t aCount)
{
@ -3160,6 +3166,13 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
return RequestDecodeIfNeeded(rv, aIntent, done, wasSize);
}
already_AddRefed<imgIContainer>
RasterImage::Unwrap()
{
nsCOMPtr<imgIContainer> self(this);
return self.forget();
}
NS_IMPL_ISUPPORTS(RasterImage::DecodePool,
nsIObserver)

View File

@ -570,6 +570,12 @@ VectorImage::SendInvalidationNotifications()
}
}
NS_IMETHODIMP_(nsIntRect)
VectorImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
{
return aRect;
}
//******************************************************************************
/* readonly attribute int32_t height; */
NS_IMETHODIMP
@ -1208,5 +1214,12 @@ VectorImage::InvalidateObserversOnNextRefreshDriverTick()
}
}
already_AddRefed<imgIContainer>
VectorImage::Unwrap()
{
nsCOMPtr<imgIContainer> self(this);
return self.forget();
}
} // namespace image
} // namespace mozilla

View File

@ -599,6 +599,7 @@ static nsresult NewImageChannel(nsIChannel **aResult,
// If all of the proxy requests are canceled then this request should be
// canceled too.
//
aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
rv = NS_NewChannel(aResult,
aURI, // URI
nullptr, // Cached IOService

View File

@ -16,6 +16,9 @@ const FRAME_COMPLETE = 0x04;
const LOAD_COMPLETE = 0x08;
const DECODE_COMPLETE = 0x10;
// Safebrowsing requires that the profile dir is set.
do_get_profile();
// An implementation of imgIScriptedNotificationObserver with the ability to
// call specified functions on onStartRequest and onStopRequest.
function ImageListener(start_callback, stop_callback)

View File

@ -249,64 +249,6 @@ IsClusterExtender(uint32_t aCh, uint8_t aCategory)
(aCh >= 0xff9e && aCh <= 0xff9f)); // katakana sound marks
}
// TODO: replace this with a properties file or similar;
// expect this to evolve as harfbuzz shaping support matures.
//
// The "shaping type" of each script run, as returned by this
// function, is compared to the bits set in the
// gfx.font_rendering.harfbuzz.scripts
// preference to decide whether to use the harfbuzz shaper.
//
int32_t
ScriptShapingType(int32_t aScriptCode)
{
switch (aScriptCode) {
default:
return SHAPING_DEFAULT; // scripts not explicitly listed here are
// assumed to just use default shaping
case MOZ_SCRIPT_ARABIC:
case MOZ_SCRIPT_SYRIAC:
case MOZ_SCRIPT_NKO:
case MOZ_SCRIPT_MANDAIC:
return SHAPING_ARABIC; // bidi scripts with Arabic-style shaping
case MOZ_SCRIPT_HEBREW:
return SHAPING_HEBREW;
case MOZ_SCRIPT_HANGUL:
return SHAPING_HANGUL;
case MOZ_SCRIPT_MONGOLIAN: // to be supported by the Arabic shaper?
return SHAPING_MONGOLIAN;
case MOZ_SCRIPT_THAI: // no complex OT features, but MS engines like to do
// sequence checking
return SHAPING_THAI;
case MOZ_SCRIPT_BENGALI:
case MOZ_SCRIPT_DEVANAGARI:
case MOZ_SCRIPT_GUJARATI:
case MOZ_SCRIPT_GURMUKHI:
case MOZ_SCRIPT_KANNADA:
case MOZ_SCRIPT_MALAYALAM:
case MOZ_SCRIPT_ORIYA:
case MOZ_SCRIPT_SINHALA:
case MOZ_SCRIPT_TAMIL:
case MOZ_SCRIPT_TELUGU:
case MOZ_SCRIPT_KHMER:
case MOZ_SCRIPT_LAO:
case MOZ_SCRIPT_TIBETAN:
case MOZ_SCRIPT_NEW_TAI_LUE:
case MOZ_SCRIPT_TAI_LE:
case MOZ_SCRIPT_MYANMAR:
case MOZ_SCRIPT_PHAGS_PA:
case MOZ_SCRIPT_BATAK:
case MOZ_SCRIPT_BRAHMI:
return SHAPING_INDIC; // scripts that require Indic or other "special" shaping
}
}
void
ClusterIterator::Next()
{

View File

@ -119,18 +119,6 @@ uint32_t GetLowercase(uint32_t aCh);
uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged
uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase
enum ShapingType {
SHAPING_DEFAULT = 0x0001,
SHAPING_ARABIC = 0x0002,
SHAPING_HEBREW = 0x0004,
SHAPING_HANGUL = 0x0008,
SHAPING_MONGOLIAN = 0x0010,
SHAPING_INDIC = 0x0020,
SHAPING_THAI = 0x0040
};
int32_t ScriptShapingType(int32_t aScriptCode);
// A simple iterator for a string of char16_t codepoints that advances
// by Unicode grapheme clusters
class ClusterIterator

View File

@ -37,6 +37,11 @@ class PBackgroundChild;
// (assuming success) GetForCurrentThread() will return the same actor every
// time.
//
// CloseForCurrentThread() will close the current PBackground actor. Subsequent
// calls to GetForCurrentThread will return null. CloseForCurrentThread() may
// only be called exactly once per thread. Currently it is illegal to call this
// before the PBackground actor has been created.
//
// The PBackgroundChild actor and all its sub-protocol actors will be
// automatically destroyed when its designated thread completes.
class BackgroundChild MOZ_FINAL
@ -56,6 +61,10 @@ public:
static bool
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
// See above.
static void
CloseForCurrentThread();
private:
// Only called by ContentChild or ContentParent.
static void

View File

@ -350,6 +350,8 @@ class ChildImpl MOZ_FINAL : public BackgroundChildImpl
nsIThread* mBoundThread;
#endif
DebugOnly<bool> mActorDestroyed;
public:
static bool
OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
@ -372,8 +374,15 @@ public:
THREADSAFETY_ASSERT(current);
}
void
AssertActorDestroyed()
{
MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
}
ChildImpl()
: mBoundThread(nullptr)
, mActorDestroyed(false)
{
AssertIsOnMainThread();
}
@ -397,6 +406,10 @@ private:
static bool
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
// Forwarded from BackgroundChild.
static void
CloseForCurrentThread();
// Forwarded from BackgroundChildImpl.
static BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread();
@ -409,6 +422,17 @@ private:
if (threadLocalInfo) {
if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->Close();
threadLocalInfo->mActor->AssertActorDestroyed();
// Since the actor is created on the main thread it must only
// be released on the main thread as well.
if (!NS_IsMainThread()) {
ChildImpl* actor;
threadLocalInfo->mActor.forget(&actor);
nsCOMPtr<nsIRunnable> releaser =
NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser)));
}
}
delete threadLocalInfo;
}
@ -419,7 +443,9 @@ private:
// This class is reference counted.
~ChildImpl()
{ }
{
AssertActorDestroyed();
}
void
SetBoundThread()
@ -835,6 +861,13 @@ BackgroundChild::GetOrCreateForCurrentThread(
return ChildImpl::GetOrCreateForCurrentThread(aCallback);
}
// static
void
BackgroundChild::CloseForCurrentThread()
{
ChildImpl::CloseForCurrentThread();
}
// -----------------------------------------------------------------------------
// BackgroundChildImpl Public Methods
// -----------------------------------------------------------------------------
@ -1578,7 +1611,11 @@ ChildImpl::GetForCurrentThread()
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
if (!threadLocalInfo) {
return nullptr;
}
return threadLocalInfo->mActor;
}
// static
@ -1642,6 +1679,31 @@ ChildImpl::GetOrCreateForCurrentThread(
return true;
}
// static
void
ChildImpl::CloseForCurrentThread()
{
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
// If we don't have a thread local we are in one of these conditions:
// 1) Startup has not completed and we are racing
// 2) We were called again after a previous close or shutdown
// For now, these should not happen, so crash. We can add extra complexity
// in the future if it turns out we need to support these cases.
if (!threadLocalInfo) {
MOZ_CRASH("Attempting to close a non-existent PBackground actor!");
}
if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->FlushPendingInterruptQueue();
}
DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
MOZ_ASSERT(status == PR_SUCCESS);
}
// static
BackgroundChildImpl::ThreadLocal*
ChildImpl::GetThreadLocalForCurrentThread()
@ -1946,6 +2008,7 @@ ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBoundThread();
mActorDestroyed = true;
BackgroundChildImpl::ActorDestroy(aWhy);
}

View File

@ -7,11 +7,13 @@
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsITimer.h"
#include "nsICancelableRunnable.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/scoped_nsautorelease_pool.h"
#include "mozilla/Assertions.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/DebugOnly.h"
#include "nsComponentManagerUtils.h"
#include "nsDebug.h"
@ -40,12 +42,14 @@ static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate;
namespace mozilla {
namespace ipc {
class DoWorkRunnable MOZ_FINAL : public nsIRunnable,
class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable,
public nsITimerCallback
{
public:
DoWorkRunnable(MessagePump* aPump)
: mPump(aPump)
, mCanceled(false)
, mCallingRunWhileCanceled(false)
{
MOZ_ASSERT(aPump);
}
@ -53,12 +57,15 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSICANCELABLERUNNABLE
private:
~DoWorkRunnable()
{ }
MessagePump* mPump;
bool mCanceled;
bool mCallingRunWhileCanceled;
};
} /* namespace ipc */
@ -211,11 +218,17 @@ MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
}
}
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback)
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback,
nsICancelableRunnable)
NS_IMETHODIMP
DoWorkRunnable::Run()
{
MOZ_ASSERT(!mCanceled || mCallingRunWhileCanceled);
if (mCanceled && !mCallingRunWhileCanceled) {
return NS_OK;
}
MessageLoop* loop = MessageLoop::current();
MOZ_ASSERT(loop);
@ -242,6 +255,23 @@ DoWorkRunnable::Notify(nsITimer* aTimer)
return NS_OK;
}
NS_IMETHODIMP
DoWorkRunnable::Cancel()
{
MOZ_ASSERT(!mCanceled);
MOZ_ASSERT(!mCallingRunWhileCanceled);
// Workers require cancelable runnables, but we can't really cancel cleanly
// here. If we don't process all of these then we will leave something
// unprocessed in the chromium queue. Therefore, eagerly complete our work
// instead by immediately calling Run().
mCanceled = true;
mozilla::AutoRestore<bool> guard(mCallingRunWhileCanceled);
mCallingRunWhileCanceled = true;
Run();
return NS_OK;
}
void
MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate)
{

View File

@ -2717,11 +2717,19 @@ Parser<ParseHandler>::matchLabel(MutableHandle<PropertyName*> label)
template <typename ParseHandler>
bool
Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, JSAtom *atom)
Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, HandlePropertyName name)
{
JSAutoByteString name;
if (AtomToPrintableString(context, atom, &name))
report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable", name.ptr());
JSAutoByteString printable;
if (!AtomToPrintableString(context, name, &printable))
return false;
StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr);
if (stmt && stmt->type == STMT_CATCH) {
report(ParseError, false, pn, JSMSG_REDECLARED_CATCH_IDENTIFIER, printable.ptr());
} else {
report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable",
printable.ptr());
}
return false;
}
@ -3000,20 +3008,26 @@ Parser<ParseHandler>::bindVarOrConst(BindData<ParseHandler> *data,
if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
return false;
} else {
bool inCatchBody = (stmt && stmt->type == STMT_CATCH);
bool error = (isConstDecl ||
dn_kind == Definition::CONST ||
(dn_kind == Definition::LET &&
(stmt->type != STMT_CATCH || OuterLet(pc, stmt, name))));
(!inCatchBody || OuterLet(pc, stmt, name))));
if (parser->options().extraWarningsOption
? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
: error)
{
JSAutoByteString bytes;
if (!AtomToPrintableString(cx, name, &bytes))
return false;
ParseReportKind reporter = error ? ParseError : ParseExtraWarning;
if (!AtomToPrintableString(cx, name, &bytes) ||
!parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR,
Definition::kindString(dn_kind), bytes.ptr()))
if (!(inCatchBody
? parser->report(reporter, false, pn,
JSMSG_REDECLARED_CATCH_IDENTIFIER, bytes.ptr())
: parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR,
Definition::kindString(dn_kind), bytes.ptr())))
{
return false;
}
@ -3608,6 +3622,25 @@ Parser<FullParseHandler>::letDeclaration()
JS_ASSERT(pc->staticScope == stmt->staticScope);
} else {
if (pc->atBodyLevel()) {
/*
* When bug 589199 is fixed, let variables will be stored in
* the slots of a new scope chain object, encountered just
* before the global object in the overall chain. This extra
* object is present in the scope chain for all code in that
* global, including self-hosted code. But self-hosted code
* must be usable against *any* global object, including ones
* with other let variables -- variables possibly placed in
* conflicting slots. Forbid top-level let declarations to
* prevent such conflicts from ever occurring.
*/
if (options().selfHostingMode &&
!pc->sc->isFunctionBox() &&
stmt == pc->topScopeStmt)
{
report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET);
return null();
}
/*
* ES4 specifies that let at top level and at body-block scope
* does not shadow var, so convert back to var.

View File

@ -642,7 +642,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
static Node null() { return ParseHandler::null(); }
bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom);
bool reportRedeclaration(Node pn, bool isConst, HandlePropertyName name);
bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
bool checkFinalReturn(Node pn);
DefinitionNode getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom);

View File

@ -98,7 +98,9 @@ assertThrowsValue(function() { f(8,2.4) }, 2.4+36);
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var identity=imp.identity; function g(x) { x=+x; return +identity(x) } return g'), null, imp)(13.37), 13.37);
// Test asm.js => ion paths
setJitCompilerOption("ion.usecount.trigger", 20);
setJitCompilerOption("ion.usecount.trigger", 10);
setJitCompilerOption("baseline.usecount.trigger", 0);
setJitCompilerOption("offthread-compilation.enable", 0);
// In registers on x64 and ARM, on the stack for x86
function ffiIntFew(a,b,c,d) { return d+1 }
@ -109,32 +111,32 @@ for (var i = 0; i < 40; i++)
// Stack and registers for x64 and ARM, stack for x86
function ffiIntMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiIntMany});
for (var i = 0; i < 40; i++)
for (var i = 0; i < 15; i++)
assertEq(f(i), i+10);
// In registers on x64 and ARM, on the stack for x86
function ffiDoubleFew(a,b,c,d) { return d+1 }
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0) } return f'), null, {ffi:ffiDoubleFew});
for (var i = 0; i < 40; i++)
for (var i = 0; i < 15; i++)
assertEq(f(i), i+4);
// Stack and registers for x64 and ARM, stack for x86
function ffiDoubleMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDoubleMany});
for (var i = 0; i < 40; i++)
for (var i = 0; i < 15; i++)
assertEq(f(i), i+10);
// Test the throw path
function ffiThrow(n) { if (n == 38) throw 'yolo'; }
function ffiThrow(n) { if (n == 14) throw 'yolo'; }
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; ffi(i >> 0); } return f'), null, {ffi:ffiThrow});
var i = 0;
try {
for (; i < 40; i++)
for (; i < 15; i++)
f(i);
throw 'assume unreachable';
} catch (e) {
assertEq(e, 'yolo');
assertEq(i, 38);
assertEq(i, 14);
}
// OOL conversion paths

View File

@ -17,10 +17,14 @@ function dumpStack()
stack = new Error().stack
}
setJitCompilerOption("ion.usecount.trigger", 10);
setJitCompilerOption("baseline.usecount.trigger", 0);
setJitCompilerOption("offthread-compilation.enable", 0);
var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
var f = asmLink(callFFI, null, {ffi:dumpStack});
for (var i = 0; i < 5000; i++) {
for (var i = 0; i < 15; i++) {
stack = null;
f();
matchStack(stack, ['dumpStack', 'f']);
@ -42,7 +46,7 @@ matchStack(stack, ["dumpStack", "f", "middle", "f"]);
function returnStackDumper() { return { valueOf:function() { stack = new Error().stack } } }
var f = asmLink(callFFI, null, {ffi:returnStackDumper});
for (var i = 0; i < 5000; i++) {
for (var i = 0; i < 15; i++) {
stack = null;
f();
matchStack(stack, ['valueOf', 'f']);

View File

@ -16,7 +16,6 @@
#include "jsprf.h"
#include "prmjtime.h"
#include "assembler/assembler/MacroAssembler.h"
#include "frontend/Parser.h"
#include "jit/AsmJSLink.h"
#include "jit/AsmJSModule.h"
@ -1409,9 +1408,6 @@ class MOZ_STACK_CLASS ModuleCompiler
return false;
return exits_.add(p, Move(exitDescriptor), *exitIndex);
}
bool addFunctionName(PropertyName *name, uint32_t *index) {
return module_->addFunctionName(name, index);
}
// Note a constraint on the minimum size of the heap. The heap size is
// constrained when linking to be at least the maximum of all such constraints.
@ -1443,6 +1439,11 @@ class MOZ_STACK_CLASS ModuleCompiler
bool finishGeneratingFunction(Func &func, MIRGenerator &mir, CodeGenerator &codegen) {
JS_ASSERT(func.defined() && func.code()->bound());
uint32_t beginOffset = func.code()->offset();
uint32_t endOffset = masm_.currentOffset();
if (!module_->addFunctionCodeRange(func.name(), beginOffset, endOffset))
return false;
jit::IonScriptCounts *counts = codegen.extractScriptCounts();
if (counts && !module_->addFunctionCounts(counts)) {
js_delete(counts);
@ -1480,15 +1481,19 @@ class MOZ_STACK_CLASS ModuleCompiler
module_->finishFunctionBodies(masm_.currentOffset());
}
void startGeneratingEntry(unsigned exportIndex) {
module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
}
bool finishGeneratingEntry(unsigned exportIndex) {
return module_->addEntryCodeRange(exportIndex, masm_.currentOffset());
}
void setInterpExitOffset(unsigned exitIndex) {
module_->exit(exitIndex).initInterpOffset(masm_.currentOffset());
}
void setIonExitOffset(unsigned exitIndex) {
module_->exit(exitIndex).initIonOffset(masm_.currentOffset());
}
void setEntryOffset(unsigned exportIndex) {
module_->exportedFunction(exportIndex).initCodeOffset(masm_.currentOffset());
}
void buildCompilationTimeReport(bool storedInCache, ScopedJSFreePtr<char> *out) {
ScopedJSFreePtr<char> slowFuns;
@ -1808,7 +1813,6 @@ class FunctionCompiler
ModuleCompiler & m_;
LifoAlloc & lifo_;
ParseNode * fn_;
uint32_t functionNameIndex_;
LocalMap locals_;
VarInitializerVector varInitializers_;
@ -1829,15 +1833,11 @@ class FunctionCompiler
LabeledBlockMap labeledBreaks_;
LabeledBlockMap labeledContinues_;
static const uint32_t NO_FUNCTION_NAME_INDEX = UINT32_MAX;
JS_STATIC_ASSERT(NO_FUNCTION_NAME_INDEX > CallSiteDesc::FUNCTION_NAME_INDEX_MAX);
public:
FunctionCompiler(ModuleCompiler &m, ParseNode *fn, LifoAlloc &lifo)
: m_(m),
lifo_(lifo),
fn_(fn),
functionNameIndex_(NO_FUNCTION_NAME_INDEX),
locals_(m.cx()),
varInitializers_(m.cx()),
alloc_(nullptr),
@ -2279,12 +2279,7 @@ class FunctionCompiler
uint32_t line, column;
m_.tokenStream().srcCoords.lineNumAndColumnIndex(call.node_->pn_pos.begin, &line, &column);
if (functionNameIndex_ == NO_FUNCTION_NAME_INDEX) {
if (!m_.addFunctionName(FunctionName(fn_), &functionNameIndex_))
return false;
}
CallSiteDesc desc(line, column, functionNameIndex_);
CallSiteDesc desc(line, column);
MAsmJSCall *ins = MAsmJSCall::New(alloc(), desc, callee, call.regArgs_, returnType,
call.spIncrement_);
if (!ins)
@ -5955,7 +5950,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
// PushRegsInMask(NonVolatileRegs).
masm.setFramePushed(0);
// See AsmJSFrameSize comment in Assembler-*.h.
// See AsmJSFrameSize comment in Assembler-shared.h.
#if defined(JS_CODEGEN_ARM)
masm.push(lr);
#endif // JS_CODEGEN_ARM
@ -6030,7 +6025,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
// Call into the real function.
AssertStackAlignment(masm);
masm.call(CallSiteDesc::Entry(), func.code());
masm.call(func.code());
// Pop the stack and recover the original 'argv' argument passed to the
// trampoline (which was pushed on the stack).
@ -6214,14 +6209,18 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
m.setInterpExitOffset(exitIndex);
masm.setFramePushed(0);
// See AsmJSFrameSize comment in Assembler-*.h.
// See AsmJSFrameSize comment in Assembler-shared.h.
#if defined(JS_CODEGEN_ARM)
masm.push(lr);
#endif
#if defined(JS_CODEGEN_MIPS)
#elif defined(JS_CODEGEN_MIPS)
masm.push(ra);
#endif
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
LoadAsmJSActivationIntoRegister(masm, activation);
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
MIRType typeArray[] = { MIRType_Pointer, // cx
MIRType_Pointer, // exitDatum
MIRType_Int32, // argc
@ -6240,16 +6239,11 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
// Fill the argument array.
unsigned offsetToCallerStackArgs = AsmJSFrameSize + masm.framePushed();
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
// Prepare the arguments for the call to InvokeFromAsmJS_*.
ABIArgMIRTypeIter i(invokeArgTypes);
Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
LoadAsmJSActivationIntoRegister(masm, activation);
// Record sp in the AsmJSActivation for stack-walking.
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
// argument 0: cx
if (i->kind() == ABIArg::GPR) {
@ -6290,16 +6284,16 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
AssertStackAlignment(masm);
switch (exit.sig().retType().which()) {
case RetType::Void:
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore), i.stackBytesConsumedSoFar());
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_Ignore));
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
break;
case RetType::Signed:
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32), i.stackBytesConsumedSoFar());
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToInt32));
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
masm.unboxInt32(argv, ReturnReg);
break;
case RetType::Double:
masm.callExit(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber), i.stackBytesConsumedSoFar());
masm.call(AsmJSImmPtr(AsmJSImm_InvokeFromAsmJS_ToNumber));
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
masm.loadDouble(argv, ReturnDoubleReg);
break;
@ -6311,6 +6305,11 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
// Note: the caller is IonMonkey code which means there are no non-volatile
// registers to restore.
masm.freeStack(stackDec);
// Clear exitFP before the frame is destroyed.
LoadAsmJSActivationIntoRegister(masm, activation);
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
masm.ret();
}
@ -6335,9 +6334,6 @@ GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
LoadAsmJSActivationIntoRegister(masm, activation);
// Record sp in the AsmJSActivation for stack-walking.
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
// Store real arguments
ABIArgMIRTypeIter i(callArgTypes);
@ -6365,12 +6361,12 @@ GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
AssertStackAlignment(masm);
switch (retType.which()) {
case RetType::Signed:
masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32), i.stackBytesConsumedSoFar());
masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToInt32));
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
break;
case RetType::Double:
masm.callExit(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber), i.stackBytesConsumedSoFar());
masm.call(AsmJSImmPtr(AsmJSImm_CoerceInPlace_ToNumber));
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnDoubleReg);
break;
@ -6388,19 +6384,22 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
m.setIonExitOffset(exitIndex);
masm.setFramePushed(0);
// See AsmJSFrameSize comment in Assembler-*.h.
#if defined(JS_CODEGEN_X64)
masm.Push(HeapReg);
#elif defined(JS_CODEGEN_ARM)
// See AsmJSFrameSize comment in Assembler-shared.h.
#if defined(JS_CODEGEN_ARM)
masm.push(lr);
// The GlobalReg (r10) and HeapReg (r11) also need to be restored before
// returning to asm.js code.
// The NANReg also needs to be restored, but is a constant and is reloaded before
// returning to asm.js code.
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
#elif defined(JS_CODEGEN_MIPS)
masm.push(ra);
#endif
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
LoadAsmJSActivationIntoRegister(masm, activation);
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
// Ion does not preserve nonvolatile registers, so we have to preserve them.
#if defined(JS_CODEGEN_X64)
masm.Push(HeapReg);
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
#endif
@ -6498,19 +6497,6 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
Register reg2 = AsmJSIonExitRegE2;
Register reg3 = AsmJSIonExitRegE3;
LoadAsmJSActivationIntoRegister(masm, reg0);
// Record sp in the AsmJSActivation for stack-walking.
#if defined(JS_CODEGEN_MIPS)
// Add a flag to indicate to AsmJSFrameIterator that we are calling
// into Ion, since the offset from SP to the return address is
// different when calling Ion vs. the native ABI.
masm.ma_or(reg1, StackPointer, Imm32(0x1));
masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP()));
#else
masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
#endif
// The following is inlined:
// JSContext *cx = activation->cx();
// Activation *act = cx->mainThread().activation();
@ -6524,6 +6510,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
offsetof(PerThreadData, jitJSContext);
LoadAsmJSActivationIntoRegister(masm, reg0);
masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
@ -6595,13 +6582,19 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
masm.bind(&done);
masm.freeStack(stackDec);
// Restore non-volatile registers saved in the prologue.
#if defined(JS_CODEGEN_X64)
masm.Pop(HeapReg);
#endif
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
masm.loadConstantDouble(GenericNaN(), NANReg);
masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
#endif
// Clear exitFP before the frame is destroyed.
LoadAsmJSActivationIntoRegister(masm, activation);
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
masm.ret();
JS_ASSERT(masm.framePushed() == 0);
@ -6642,18 +6635,20 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
masm.align(CodeAlignment);
masm.bind(&m.stackOverflowLabel());
// The stack-overflow is checked before bumping the stack.
masm.setFramePushed(0);
// Store the frame pointer in AsmJSActivation::exitFP for stack unwinding.
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
LoadAsmJSActivationIntoRegister(masm, activation);
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitFP()));
MIRTypeVector argTypes(m.cx());
argTypes.infallibleAppend(MIRType_Pointer); // cx
unsigned stackDec = StackDecrementForCall(masm, argTypes, MaybeRetAddr);
masm.reserveStack(stackDec);
Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
LoadAsmJSActivationIntoRegister(masm, activation);
// Record sp in the AsmJSActivation for stack-walking.
masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
ABIArgMIRTypeIter i(argTypes);
// argument 0: cx
@ -6668,7 +6663,11 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
JS_ASSERT(i.done());
AssertStackAlignment(masm);
masm.callExit(AsmJSImmPtr(AsmJSImm_ReportOverRecursed), i.stackBytesConsumedSoFar());
masm.call(AsmJSImmPtr(AsmJSImm_ReportOverRecursed));
// Clear exitFP before the frame is destroyed.
LoadAsmJSActivationIntoRegister(masm, activation);
masm.storePtr(ImmWord(0), Address(activation, AsmJSActivation::offsetOfExitFP()));
// Don't worry about restoring the stack; throwLabel will pop everything.
masm.jump(throwLabel);
@ -6867,10 +6866,10 @@ static bool
GenerateStubs(ModuleCompiler &m)
{
for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) {
m.setEntryOffset(i);
m.startGeneratingEntry(i);
if (!GenerateEntry(m, m.module().exportedFunction(i)))
return false;
if (m.masm().oom())
if (m.masm().oom() || !m.finishGeneratingEntry(i))
return false;
}

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/AsmJSFrameIterator.h"
#include "jit/AsmJS.h"
#include "jit/AsmJSModule.h"
using namespace js;
using namespace js::jit;
static void *
ReturnAddressFromFP(uint8_t *fp)
{
// In asm.js code, the "frame" consists of a single word: the saved
// return address of the caller.
static_assert(AsmJSFrameSize == sizeof(void*), "Frame size mismatch");
return *(uint8_t**)fp;
}
AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation &activation)
: module_(&activation.module()),
fp_(activation.exitFP())
{
if (!fp_)
return;
settle(ReturnAddressFromFP(fp_));
}
void
AsmJSFrameIterator::operator++()
{
JS_ASSERT(!done());
fp_ += callsite_->stackDepth();
settle(ReturnAddressFromFP(fp_));
}
void
AsmJSFrameIterator::settle(void *returnAddress)
{
const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(ReturnAddressFromFP(fp_));
JS_ASSERT(codeRange);
codeRange_ = codeRange;
switch (codeRange->kind()) {
case AsmJSModule::CodeRange::Entry:
fp_ = nullptr;
JS_ASSERT(done());
return;
case AsmJSModule::CodeRange::Function:
callsite_ = module_->lookupCallSite(returnAddress);
JS_ASSERT(callsite_);
break;
}
}
JSAtom *
AsmJSFrameIterator::functionDisplayAtom() const
{
JS_ASSERT(!done());
return reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_)->functionName(*module_);
}
unsigned
AsmJSFrameIterator::computeLine(uint32_t *column) const
{
JS_ASSERT(!done());
if (column)
*column = callsite_->column();
return callsite_->line();
}

View File

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_AsmJSFrameIterator_h
#define jit_AsmJSFrameIterator_h
#include "mozilla/NullPtr.h"
#include <stdint.h>
class JSAtom;
namespace js {
class AsmJSActivation;
class AsmJSModule;
namespace jit { struct CallSite; }
// Iterates over the frames of a single AsmJSActivation.
class AsmJSFrameIterator
{
const AsmJSModule *module_;
const jit::CallSite *callsite_;
uint8_t *fp_;
// Really, a const AsmJSModule::CodeRange*, but no forward declarations of
// nested classes, so use void* to avoid pulling in all of AsmJSModule.h.
const void *codeRange_;
void settle(void *returnAddress);
public:
explicit AsmJSFrameIterator() : module_(nullptr) {}
explicit AsmJSFrameIterator(const AsmJSActivation &activation);
void operator++();
bool done() const { return !fp_; }
JSAtom *functionDisplayAtom() const;
unsigned computeLine(uint32_t *column) const;
};
} // namespace js
#endif // jit_AsmJSFrameIterator_h

View File

@ -34,101 +34,6 @@ using namespace js::jit;
using mozilla::IsNaN;
using mozilla::PodZero;
static uint8_t *
ReturnAddressForExitCall(uint8_t **psp)
{
uint8_t *sp = *psp;
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
// For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
// to C++. Since the call instruction pushes the return address, we know
// that the return address is 1 word below exitSP.
return *(uint8_t**)(sp - sizeof(void*));
#elif defined(JS_CODEGEN_ARM)
// For calls to Ion/C++ on ARM, the *caller* pushes the return address on
// the stack. For Ion, this is just part of the ABI. For C++, the return
// address is explicitly pushed before the call since we cannot expect the
// callee to immediately push lr. This means that exitSP points to the
// return address.
return *(uint8_t**)sp;
#elif defined(JS_CODEGEN_MIPS)
// On MIPS we have two cases: an exit to C++ will store the return address
// at ShadowStackSpace above sp; an exit to Ion will store the return
// address at sp. To distinguish the two cases, the low bit of sp (which is
// aligned and therefore zero) is set for Ion exits.
if (uintptr_t(sp) & 0x1) {
sp = *psp -= 0x1; // Clear the low bit
return *(uint8_t**)sp;
}
return *(uint8_t**)(sp + ShadowStackSpace);
#else
# error "Unknown architecture!"
#endif
}
static uint8_t *
ReturnAddressForJitCall(uint8_t *sp)
{
// Once inside JIT code, sp always points to the word before the return
// address.
return *(uint8_t**)(sp - sizeof(void*));
}
AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation)
: module_(nullptr)
{
if (!activation || activation->isInterruptedSP())
return;
module_ = &activation->module();
sp_ = activation->exitSP();
settle(ReturnAddressForExitCall(&sp_));
}
void
AsmJSFrameIterator::operator++()
{
settle(ReturnAddressForJitCall(sp_));
}
void
AsmJSFrameIterator::settle(uint8_t *returnAddress)
{
callsite_ = module_->lookupCallSite(returnAddress);
if (!callsite_ || callsite_->isEntry()) {
module_ = nullptr;
return;
}
if (callsite_->isEntry()) {
module_ = nullptr;
return;
}
sp_ += callsite_->stackDepth();
if (callsite_->isExit())
return settle(ReturnAddressForJitCall(sp_));
JS_ASSERT(callsite_->isNormal());
}
JSAtom *
AsmJSFrameIterator::functionDisplayAtom() const
{
JS_ASSERT(!done());
return module_->functionName(callsite_->functionNameIndex());
}
unsigned
AsmJSFrameIterator::computeLine(uint32_t *column) const
{
JS_ASSERT(!done());
if (column)
*column = callsite_->column();
return callsite_->line();
}
static bool
CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj)
{

View File

@ -9,31 +9,8 @@
#include "NamespaceImports.h"
class JSAtom;
namespace js {
class AsmJSActivation;
class AsmJSModule;
namespace jit { struct CallSite; }
// Iterates over the frames of a single AsmJSActivation.
class AsmJSFrameIterator
{
const AsmJSModule *module_;
const jit::CallSite *callsite_;
uint8_t *sp_;
void settle(uint8_t *returnAddress);
public:
explicit AsmJSFrameIterator(const AsmJSActivation *activation);
void operator++();
bool done() const { return !module_; }
JSAtom *functionDisplayAtom() const;
unsigned computeLine(uint32_t *column) const;
};
#ifdef JS_ION
// Create a new JSFunction to replace originalFun as the representation of the

View File

@ -167,6 +167,7 @@ AsmJSModule::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModu
exits_.sizeOfExcludingThis(mallocSizeOf) +
exports_.sizeOfExcludingThis(mallocSizeOf) +
callSites_.sizeOfExcludingThis(mallocSizeOf) +
codeRanges_.sizeOfExcludingThis(mallocSizeOf) +
functionNames_.sizeOfExcludingThis(mallocSizeOf) +
heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
@ -189,11 +190,11 @@ struct CallSiteRetAddrOffset
};
const CallSite *
AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
AsmJSModule::lookupCallSite(void *returnAddress) const
{
JS_ASSERT(isFinished());
uint32_t target = returnAddress - code_;
uint32_t target = ((uint8_t*)returnAddress) - code_;
size_t lowerBound = 0;
size_t upperBound = callSites_.length();
@ -204,6 +205,45 @@ AsmJSModule::lookupCallSite(uint8_t *returnAddress) const
return &callSites_[match];
}
namespace js {
// Create an ordering on CodeRange and pc offsets suitable for BinarySearch.
// Stick these in the same namespace as AsmJSModule so that argument-dependent
// lookup will find it.
bool
operator==(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
{
return pcOffset >= rhs.beginOffset() && pcOffset < rhs.endOffset();
}
bool
operator<=(const AsmJSModule::CodeRange &lhs, const AsmJSModule::CodeRange &rhs)
{
return lhs.beginOffset() <= rhs.beginOffset();
}
bool
operator<(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
{
return pcOffset < rhs.beginOffset();
}
} // namespace js
const AsmJSModule::CodeRange *
AsmJSModule::lookupCodeRange(void *pc) const
{
JS_ASSERT(isFinished());
uint32_t target = ((uint8_t*)pc) - code_;
size_t lowerBound = 0;
size_t upperBound = codeRanges_.length();
size_t match;
if (!BinarySearch(codeRanges_, lowerBound, upperBound, target, &match))
return nullptr;
return &codeRanges_[match];
}
struct HeapAccessOffset
{
const AsmJSHeapAccessVector &accesses;
@ -214,12 +254,12 @@ struct HeapAccessOffset
};
const AsmJSHeapAccess *
AsmJSModule::lookupHeapAccess(uint8_t *pc) const
AsmJSModule::lookupHeapAccess(void *pc) const
{
JS_ASSERT(isFinished());
JS_ASSERT(containsPC(pc));
uint32_t target = pc - code_;
uint32_t target = ((uint8_t*)pc) - code_;
size_t lowerBound = 0;
size_t upperBound = heapAccesses_.length();
@ -293,6 +333,11 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl
CallSite &c = callSites_[i];
c.setReturnAddressOffset(masm.actualOffset(c.returnAddressOffset()));
}
for (size_t i = 0; i < codeRanges_.length(); i++) {
CodeRange &c = codeRanges_[i];
c.beginOffset_ = masm.actualOffset(c.beginOffset_);
c.endOffset_ = masm.actualOffset(c.endOffset_);
}
#endif
JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
@ -1084,6 +1129,7 @@ AsmJSModule::serializedSize() const
SerializedVectorSize(exits_) +
SerializedVectorSize(exports_) +
SerializedPodVectorSize(callSites_) +
SerializedPodVectorSize(codeRanges_) +
SerializedVectorSize(functionNames_) +
SerializedPodVectorSize(heapAccesses_) +
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
@ -1104,6 +1150,7 @@ AsmJSModule::serialize(uint8_t *cursor) const
cursor = SerializeVector(cursor, exits_);
cursor = SerializeVector(cursor, exports_);
cursor = SerializePodVector(cursor, callSites_);
cursor = SerializePodVector(cursor, codeRanges_);
cursor = SerializeVector(cursor, functionNames_);
cursor = SerializePodVector(cursor, heapAccesses_);
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
@ -1130,6 +1177,7 @@ AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
(cursor = DeserializeVector(cx, cursor, &exits_)) &&
(cursor = DeserializeVector(cx, cursor, &exports_)) &&
(cursor = DeserializePodVector(cx, cursor, &callSites_)) &&
(cursor = DeserializePodVector(cx, cursor, &codeRanges_)) &&
(cursor = DeserializeVector(cx, cursor, &functionNames_)) &&
(cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) &&
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
@ -1200,6 +1248,7 @@ AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) con
!CloneVector(cx, exits_, &out.exits_) ||
!CloneVector(cx, exports_, &out.exports_) ||
!ClonePodVector(cx, callSites_, &out.callSites_) ||
!ClonePodVector(cx, codeRanges_, &out.codeRanges_) ||
!CloneVector(cx, functionNames_, &out.functionNames_) ||
!ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) ||
!staticLinkData_.clone(cx, &out.staticLinkData_))

View File

@ -313,6 +313,33 @@ class AsmJSModule
bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
};
class CodeRange
{
public:
enum Kind { Entry, Function };
private:
Kind kind_;
uint32_t beginOffset_;
uint32_t endOffset_;
uint32_t functionNameIndex_;
friend class AsmJSModule;
CodeRange(Kind kind, uint32_t beginOffset, uint32_t endOffset)
: kind_(kind), beginOffset_(beginOffset), endOffset_(endOffset)
{}
public:
CodeRange() {}
Kind kind() const { return kind_; }
uint32_t beginOffset() const { return beginOffset_; }
uint32_t endOffset() const { return endOffset_; }
PropertyName *functionName(const AsmJSModule &module) const {
JS_ASSERT(kind_ == Function);
return module.functionNames_[functionNameIndex_].name();
}
};
class Name
{
PropertyName *name_;
@ -479,6 +506,7 @@ class AsmJSModule
Vector<Exit, 0, SystemAllocPolicy> exits_;
Vector<ExportedFunction, 0, SystemAllocPolicy> exports_;
Vector<jit::CallSite, 0, SystemAllocPolicy> callSites_;
Vector<CodeRange, 0, SystemAllocPolicy> codeRanges_;
Vector<Name, 0, SystemAllocPolicy> functionNames_;
Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> heapAccesses_;
Vector<jit::IonScriptCounts*, 0, SystemAllocPolicy> functionCounts_;
@ -666,17 +694,21 @@ class AsmJSModule
if (len > pod.minHeapLength_)
pod.minHeapLength_ = len;
}
bool addFunctionName(PropertyName *name, uint32_t *nameIndex) {
bool addFunctionCodeRange(PropertyName *name, uint32_t beginOffset, uint32_t endOffset) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
JS_ASSERT(name->isTenured());
if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX)
JS_ASSERT(beginOffset <= endOffset);
JS_ASSERT_IF(!codeRanges_.empty(), codeRanges_.back().endOffset() <= beginOffset);
if (functionNames_.length() >= UINT32_MAX)
return false;
*nameIndex = functionNames_.length();
return functionNames_.append(name);
CodeRange codeRange(CodeRange::Function, beginOffset, endOffset);
codeRange.functionNameIndex_ = functionNames_.length();
return functionNames_.append(name) && codeRanges_.append(codeRange);
}
PropertyName *functionName(uint32_t i) const {
JS_ASSERT(isFinished());
return functionNames_[i].name();
bool addEntryCodeRange(unsigned exportIndex, uint32_t endOffset) {
uint32_t beginOffset = exports_[exportIndex].pod.codeOffset_;
CodeRange codeRange(CodeRange::Entry, beginOffset, endOffset);
return codeRanges_.append(codeRange);
}
bool addExit(unsigned ffiIndex, unsigned *exitIndex) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
@ -852,11 +884,15 @@ class AsmJSModule
// Lookup a callsite by the return pc (from the callee to the caller).
// Return null if no callsite was found.
const jit::CallSite *lookupCallSite(uint8_t *returnAddress) const;
const jit::CallSite *lookupCallSite(void *returnAddress) const;
// Lookup the name the code range containing the given pc. Return null if no
// code range was found.
const CodeRange *lookupCodeRange(void *pc) const;
// Lookup a heap access site by the pc which performs the access. Return
// null if no heap access was found.
const jit::AsmJSHeapAccess *lookupHeapAccess(uint8_t *pc) const;
const jit::AsmJSHeapAccess *lookupHeapAccess(void *pc) const;
// The global data section is placed after the executable code (i.e., at
// offset codeBytes_) in the module's linear allocation. The global data

View File

@ -356,7 +356,7 @@ HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *fault
if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
module.containsPC(faultingAddress))
{
activation->setInterrupted(nullptr);
activation->setResumePC(nullptr);
int32_t nextpc = int32_t(module.interruptExit());
rt->mainThread.simulator()->set_resume_pc(nextpc);
return true;
@ -465,7 +465,7 @@ HandleException(PEXCEPTION_POINTERS exception)
// The trampoline will jump to activation->resumePC if execution isn't
// interrupted.
if (module.containsPC(faultingAddress)) {
activation->setInterrupted(pc);
activation->setResumePC(pc);
*ppc = module.interruptExit();
JSRuntime::AutoLockForInterrupt lock(rt);
@ -668,7 +668,7 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request)
// The trampoline will jump to activation->resumePC if execution isn't
// interrupted.
if (module.containsPC(faultingAddress)) {
activation->setInterrupted(pc);
activation->setResumePC(pc);
*ppc = module.interruptExit();
JSRuntime::AutoLockForInterrupt lock(rt);
@ -918,7 +918,7 @@ HandleSignal(int signum, siginfo_t *info, void *ctx)
// The trampoline will jump to activation->resumePC if execution isn't
// interrupted.
if (module.containsPC(faultingAddress)) {
activation->setInterrupted(pc);
activation->setResumePC(pc);
*ppc = module.interruptExit();
JSRuntime::AutoLockForInterrupt lock(rt);

View File

@ -22,6 +22,8 @@
using namespace js;
using namespace js::jit;
using mozilla::IsInRange;
// These constructor are exactly the same except for the type of the iterator
// which is given to the SnapshotIterator constructor. Doing so avoid the
// creation of virtual functions for the IonIterator but may introduce some
@ -76,8 +78,8 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
JS_ASSERT(bailoutInfo);
// We don't have an exit frame.
MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 &&
size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0,
MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
"Fake jitTop pointer should be within the first page.");
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
gc::AutoSuppressGC suppress(cx);

View File

@ -8573,7 +8573,7 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
break;
case MAsmJSCall::Callee::Builtin:
masm.call(mir->desc(), AsmJSImmPtr(callee.builtin()));
masm.call(AsmJSImmPtr(callee.builtin()));
break;
}

View File

@ -18,6 +18,8 @@
using namespace js;
using namespace jit;
using mozilla::IsInRange;
using JS::AutoCheckCannotGC;
using parallel::Spew;
@ -524,8 +526,8 @@ jit::BailoutPar(BailoutStack *sp, uint8_t **entryFramePointer)
ForkJoinContext *cx = ForkJoinContext::current();
// We don't have an exit frame.
MOZ_ASSERT(size_t(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout)) < 0x1000 &&
size_t(FAKE_JIT_TOP_FOR_BAILOUT) >= 0,
MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
"Fake jitTop pointer should be within the first page.");
cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;

View File

@ -437,12 +437,17 @@ bool HasIDIV();
// Arm/D32 has double registers that can NOT be treated as float32
// and this requires some dances in lowering.
inline bool hasUnaliasedDouble() {
inline bool
hasUnaliasedDouble()
{
return Has32DP();
}
// On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
// to a double as a temporary, you need a temporary double register.
inline bool hasMultiAlias() {
inline bool
hasMultiAlias()
{
return true;
}

View File

@ -141,12 +141,6 @@ static const uint32_t StackAlignment = 8;
static const uint32_t CodeAlignment = 8;
static const bool StackKeptAligned = true;
// As an invariant across architectures, within asm.js code:
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
// To achieve this on ARM, the first instruction of the asm.js prologue pushes
// lr without incrementing masm.framePushed.
static const uint32_t AsmJSFrameSize = sizeof(void*);
static const Scale ScalePointer = TimesFour;
class Instruction;

View File

@ -53,7 +53,7 @@ CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
{
JS_ASSERT(gen->compilingAsmJS());
// See comment in Assembler-arm.h about AsmJSFrameSize.
// See comment in Assembler-shared.h about AsmJSFrameSize.
masm.push(lr);
// The asm.js over-recursed handler wants to be able to assume that SP

View File

@ -1789,6 +1789,17 @@ MacroAssemblerARMCompat::callIon(Register callee)
}
}
void
MacroAssemblerARMCompat::callIonFromAsmJS(Register callee)
{
ma_callIonNoPush(callee);
// The Ion ABI has the callee pop the return address off the stack.
// The asm.js caller assumes that the call leaves sp unchanged, so bump
// the stack.
subPtr(Imm32(sizeof(void*)), sp);
}
void
MacroAssemblerARMCompat::reserveStack(uint32_t amount)
{
@ -3624,19 +3635,6 @@ MacroAssemblerARM::ma_call(ImmPtr dest)
as_blx(CallReg);
}
void
MacroAssemblerARM::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
{
// Note: this function stores the return address to sp[0]. The caller must
// anticipate this by pushing additional space on the stack. The ABI does
// not provide space for a return address so this function may only be
// called if no argument are passed.
JS_ASSERT(stackArgBytes == 0);
AutoForbidPools afp(this);
as_dtr(IsStore, 32, Offset, pc, DTRAddr(sp, DtrOffImm(0)));
as_blx(r);
}
void
MacroAssemblerARMCompat::breakpoint()
{

View File

@ -397,9 +397,6 @@ class MacroAssemblerARM : public Assembler
void ma_call(ImmPtr dest);
// calls reg, storing the return address into sp[0]
void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
// Float registers can only be loaded/stored in continuous runs
// when using vstm/vldm.
// This function breaks set into continuous runs and loads/stores
@ -566,38 +563,13 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
ma_callIonHalfPush(ScratchRegister);
}
void appendCallSite(const CallSiteDesc &desc) {
// Add an extra sizeof(void*) to include the return address that was
// pushed by the call instruction (see CallSite::stackDepth).
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + AsmJSFrameSize));
}
void call(const CallSiteDesc &desc, const Register reg) {
call(reg);
appendCallSite(desc);
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
}
void call(const CallSiteDesc &desc, Label *label) {
call(label);
appendCallSite(desc);
}
void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
call(imm);
appendCallSite(desc);
}
void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
movePtr(imm, CallReg);
ma_callAndStoreRet(CallReg, stackArgBytes);
appendCallSite(CallSiteDesc::Exit());
}
void callIonFromAsmJS(const Register reg) {
ma_callIonNoPush(reg);
appendCallSite(CallSiteDesc::Exit());
// The Ion ABI has the callee pop the return address off the stack.
// The asm.js caller assumes that the call leaves sp unchanged, so bump
// the stack.
subPtr(Imm32(sizeof(void*)), sp);
enoughMemory_ &= append(desc, currentOffset(), framePushed_);
}
void branch(JitCode *c) {
@ -1287,6 +1259,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
// Makes an Ion call using the only two methods that it is sane for
// indep code to make a call
void callIon(Register callee);
void callIonFromAsmJS(Register callee);
void reserveStack(uint32_t amount);
void freeStack(uint32_t amount);

View File

@ -4070,7 +4070,7 @@ Simulator::execute()
int32_t rpc = resume_pc_;
if (MOZ_UNLIKELY(rpc != 0)) {
// AsmJS signal handler ran and we have to adjust the pc.
activation->setInterrupted((void *)get_pc());
activation->setResumePC((void *)get_pc());
set_pc(rpc);
resume_pc_ = 0;
}

View File

@ -152,12 +152,6 @@ static const uint32_t StackAlignment = 8;
static const uint32_t CodeAlignment = 4;
static const bool StackKeptAligned = true;
// As an invariant across architectures, within asm.js code:
// $sp % StackAlignment = (AsmJSFrameSize + masm.framePushed) % StackAlignment
// To achieve this on MIPS, the first instruction of the asm.js prologue pushes
// ra without incrementing masm.framePushed.
static const uint32_t AsmJSFrameSize = sizeof(void*);
static const Scale ScalePointer = TimesFour;
// MIPS instruction types

View File

@ -52,7 +52,7 @@ CodeGeneratorMIPS::generateAsmJSPrologue(Label *stackOverflowLabel)
{
JS_ASSERT(gen->compilingAsmJS());
// See comment in Assembler-mips.h about AsmJSFrameSize.
// See comment in Assembler-shared.h about AsmJSFrameSize.
masm.push(ra);
// The asm.js over-recursed handler wants to be able to assume that SP

Some files were not shown because too many files have changed in this diff Show More