mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to f-t
This commit is contained in:
commit
d96c7fc639
@ -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/
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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", "" },
|
||||
|
@ -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]
|
||||
|
34
content/base/test/test_bug864595.html
Normal file
34
content/base/test/test_bug864595.html
Normal 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>
|
@ -13,7 +13,9 @@
|
||||
#include "MFTDecoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class mp4_demuxer::MP4Sample;
|
||||
namespace mp4_demuxer {
|
||||
class MP4Sample;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -46,7 +46,6 @@ DOMCI_CLASS(CSSSupportsRule)
|
||||
DOMCI_CLASS(XSLTProcessor)
|
||||
|
||||
// DOM Level 3 XPath objects
|
||||
DOMCI_CLASS(XPathExpression)
|
||||
DOMCI_CLASS(XPathNSResolver)
|
||||
|
||||
// WhatWG WebApps Objects
|
||||
|
@ -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')
|
||||
|
@ -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',
|
||||
]
|
||||
|
@ -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);
|
||||
};
|
@ -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,
|
||||
|
@ -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);
|
||||
};
|
@ -4,7 +4,6 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
interface XPathExpression;
|
||||
interface XPathNSResolver;
|
||||
|
||||
[Constructor]
|
||||
|
22
dom/webidl/XPathExpression.webidl
Normal file
22
dom/webidl/XPathExpression.webidl
Normal 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);
|
||||
};
|
@ -481,6 +481,7 @@ WEBIDL_FILES = [
|
||||
'XMLSerializer.webidl',
|
||||
'XMLStylesheetProcessingInstruction.webidl',
|
||||
'XPathEvaluator.webidl',
|
||||
'XPathExpression.webidl',
|
||||
'XPathResult.webidl',
|
||||
'XULCommandEvent.webidl',
|
||||
'XULDocument.webidl',
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
247
dom/xslt/xpath/XPathExpression.cpp
Normal file
247
dom/xslt/xpath/XPathExpression.cpp
Normal 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
|
75
dom/xslt/xpath/XPathExpression.h
Normal file
75
dom/xslt/xpath/XPathExpression.h
Normal 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 */
|
@ -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',
|
||||
]
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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']);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
75
js/src/jit/AsmJSFrameIterator.cpp
Normal file
75
js/src/jit/AsmJSFrameIterator.cpp
Normal 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();
|
||||
}
|
||||
|
46
js/src/jit/AsmJSFrameIterator.h
Normal file
46
js/src/jit/AsmJSFrameIterator.h
Normal 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
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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_))
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user