This commit is contained in:
Kyle Huey 2011-10-09 10:18:23 -04:00
Родитель ee5000bf9d 8e039fda6d
Коммит 9ea644607b
85 изменённых файлов: 1248 добавлений и 511 удалений

Просмотреть файл

@ -335,6 +335,21 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
nsRefPtr<AccEvent> focusEvent =
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, fromUserInputFlag);
nsEventShell::FireEvent(focusEvent);
// Fire scrolling_start event when the document receives the focus if it has
// an anchor jump. If an accessible within the document receive the focus
// then null out the anchor jump because it no longer applies.
nsDocAccessible* targetDocument = target->GetDocAccessible();
nsAccessible* anchorJump = targetDocument->AnchorJump();
if (anchorJump) {
if (target == targetDocument) {
// XXX: bug 625699, note in some cases the node could go away before we
// we receive focus event, for example if the node is removed from DOM.
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
anchorJump, fromUserInputFlag);
}
targetDocument->SetAnchorJump(nsnull);
}
}
nsIContent*

Просмотреть файл

@ -162,7 +162,7 @@ nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
if (documentNode) {
nsDocAccessible* document = GetDocAccessible(documentNode);
if (document)
document->HandleAnchorJump(aTargetNode);
document->SetAnchorJump(aTargetNode);
}
}

Просмотреть файл

@ -1769,22 +1769,6 @@ nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
}
}
void
nsDocAccessible::ProcessAnchorJump(nsIContent* aTargetNode)
{
// If the jump target is not accessible then fire an event for nearest
// accessible in parent chain.
nsAccessible* target = GetAccessibleOrContainer(aTargetNode);
if (!target)
return;
// XXX: bug 625699, note in some cases the node could go away before we flush
// the queue, for example if the node becomes inaccessible, or is removed from
// the DOM.
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
target->GetNode());
}
void
nsDocAccessible::ProcessContentInserted(nsAccessible* aContainer,
const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent)

Просмотреть файл

@ -205,13 +205,13 @@ public:
nsresult FireDelayedAccessibleEvent(AccEvent* aEvent);
/**
* Handle anchor jump when page is loaded.
* Get/set the anchor jump.
*/
inline void HandleAnchorJump(nsIContent* aTargetNode)
{
HandleNotification<nsDocAccessible, nsIContent>
(this, &nsDocAccessible::ProcessAnchorJump, aTargetNode);
}
inline nsAccessible* AnchorJump()
{ return GetAccessibleOrContainer(mAnchorJumpElm); }
inline void SetAnchorJump(nsIContent* aTargetNode)
{ mAnchorJumpElm = aTargetNode; }
/**
* Bind the child document to the tree.
@ -467,11 +467,6 @@ protected:
*/
void ProcessPendingEvent(AccEvent* aEvent);
/**
* Process anchor jump notification and fire scrolling end event.
*/
void ProcessAnchorJump(nsIContent* aTargetNode);
/**
* Update the accessible tree for inserted content.
*/
@ -572,6 +567,11 @@ protected:
*/
PRUint32 mLoadEventType;
/**
* Reference to anchor jump element.
*/
nsCOMPtr<nsIContent> mAnchorJumpElm;
/**
* Keep the ARIA attribute old value that is initialized by
* AttributeWillChange and used by AttributeChanged notifications.

Просмотреть файл

@ -35,6 +35,7 @@
// Test
// gA11yEventDumpID = "debug"; // debug stuff
//gA11yEventDumpToConsole = true; // debug stuff
function doTest()
{

Просмотреть файл

@ -16,11 +16,12 @@
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochitests/content/a11y/accessible/treeview.js" />
<script type="application/javascript"
src="../common.js" />
<script type="application/javascript"
src="../role.js" />
<script type="application/javascript"
src="../states.js" />
<script type="application/javascript"
src="../events.js" />
@ -34,6 +35,7 @@
// Hack to make xul:tabbrowser work
const Ci = Components.interfaces;
const CC = Components.classes;
Components.utils.import("resource://gre/modules/Services.jsm");
@ -45,23 +47,78 @@
}
};
var gURLBar = {
focused: false
};
var gFindBarInitialized = false;
////////////////////////////////////////////////////////////////////////////
// Tests
var gScrollHandler = {
handleEvent: function gScrollHandler_handleEvent(aEvent) {
if (aEvent.DOMNode.getAttribute("name") == "link1") {
ok(true, "scrolling start event was handled on link1");
unregisterA11yEventListener(EVENT_SCROLLING_START, this);
SimpleTest.finish();
function getTabDocument()
{
return getNode("tabBrowser").selectedBrowser.contentDocument;
}
function getAnchorJumpInTabDocument()
{
return getTabDocument().querySelector("a[name='link1']");
}
function loadTab(aTabBrowserID, aURL)
{
function loadTabChecker()
{
this.type = EVENT_REORDER;
this.match = function loadTabChecker_match(aEvent)
{
var target = aEvent.accessible;
if (target.role == ROLE_INTERNAL_FRAME &&
target.parent.parent == getAccessible(getNode(aTabBrowserID).mTabBox.tabpanels)) {
return true;
}
return false;
}
}
};
this.eventSeq = [ new loadTabChecker() ];
this.invoke = function loadTab_invoke()
{
getNode(aTabBrowserID).loadURI(aURL);
}
this.getID = function loadTab_getID()
{
return "load tab " + aURL + " for " + prettyName(aTabBrowserID);
}
}
function advanceFocusIntoTab(aTabBrowserID)
{
this.eventSeq = [
new focusChecker(getTabDocument),
new invokerChecker(EVENT_SCROLLING_START, getAnchorJumpInTabDocument)
];
this.invoke = function advanceFocusIntoTab_invoke()
{
var tabDoc = getAccessible(getTabDocument());
tabDoc.takeFocus();
}
this.getID = function advanceFocusIntoTab_getID()
{
return "advance focus into loaded tab";
}
}
//gA11yEventDumpToConsole = true; // debug stuff
var gQueue = null;
function doTest()
{
registerA11yEventListener(EVENT_SCROLLING_START, gScrollHandler);
var rootDir = getRootDirectory(window.location.href);
/*
@ -74,10 +131,12 @@
var tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
var url = rootDir + "scroll.html#link1";
var tabBrowser = document.getElementById("tabBrowser");
tabBrowser.loadURI(url);
gQueue = new eventQueue();
gQueue.push(new loadTab("tabBrowser", url));
gQueue.push(new advanceFocusIntoTab("tabBrowser"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
@ -97,6 +156,11 @@
title="Same page links to targets with content fires scrolling start accessible event on leaf text node">
Mozilla Bug 519303
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=691734"
title="Make sure scrolling start event is fired when document receive focus">
Mozilla Bug 691734
</a>
<p id="display"></p>
<div id="content" style="display: none">
@ -115,13 +179,17 @@
</menupopup>
</menu>
</menubar>
<keyset>
<key id="key_close"/>
</keyset>
<hbox>
<tabs id="tabbrowser-tabs" class="tabbrowser-tabs"
tabbrowser="tabBrowser"
flex="1"
setfocus="false">
<tab class="tabbrowser-tab" selected="true"/>
flex="1">
<tab class="tabbrowser-tab" selected="true" label="tab"/>
</tabs>
</hbox>
<tabbrowser id="tabBrowser"
type="content-primary"
tabcontainer="tabbrowser-tabs"

Просмотреть файл

@ -357,9 +357,14 @@ pref("browser.search.suggest.enabled", true);
pref("browser.sessionhistory.max_entries", 50);
// handle links targeting new windows
// 0=default window, 1=current window/tab, 2=new window, 3=new tab in most recent window
// 1=current window/tab, 2=new window, 3=new tab in most recent window
pref("browser.link.open_newwindow", 3);
// handle external links (i.e. links opened from a different application)
// default: use browser.link.open_newwindow
// 1-3: see browser.link.open_newwindow for interpretation
pref("browser.link.open_newwindow.override.external", -1);
// 0: no restrictions - divert everything
// 1: don't divert window.open at all
// 2: don't divert window.open with features

Просмотреть файл

@ -4925,8 +4925,13 @@ nsBrowserAccess.prototype = {
return null;
}
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW)
aWhere = gPrefService.getIntPref("browser.link.open_newwindow");
if (aWhere == Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
if (isExternal &&
gPrefService.prefHasUserValue("browser.link.open_newwindow.override.external"))
aWhere = gPrefService.getIntPref("browser.link.open_newwindow.override.external");
else
aWhere = gPrefService.getIntPref("browser.link.open_newwindow");
}
switch (aWhere) {
case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
// FIXME: Bug 408379. So how come this doesn't send the
@ -8524,7 +8529,7 @@ function switchToTabHavingURI(aURI, aOpenNew) {
if (isBrowserWindow && isTabEmpty(gBrowser.selectedTab))
gBrowser.selectedBrowser.loadURI(aURI.spec);
else
openUILinkIn(aURI.spec, "tab");
openUILinkIn(aURI.spec, "tab", { inBackground: false });
}
return false;

Просмотреть файл

@ -566,10 +566,10 @@
if (this.mTab.hasAttribute("busy")) {
this.mTab.removeAttribute("busy");
this.mTabBrowser._tabAttrModified(this.mTab);
if (!this.mTab.selected)
this.mTab.setAttribute("unread", "true");
}
this.mTab.removeAttribute("progress");
if (!this.mTab.selected)
this.mTab.setAttribute("unread", "true");
var location = aRequest.QueryInterface(nsIChannel).URI;
@ -876,7 +876,6 @@
(window.windowState != window.STATE_MINIMIZED);
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.selectedTab;
this.mCurrentTab.removeAttribute("unread");
this.showTab(this.mCurrentTab);
if (updatePageReport)
@ -909,8 +908,9 @@
true, false);
}
// Don't switch the fast find or update the titlebar (bug 540248) - this tab switch is temporary
if (!this._previewMode) {
this.mCurrentTab.removeAttribute("unread");
#ifdef MOZ_E10S_COMPAT
// Bug 666816 - TypeAheadFind support for e10s
#else

Просмотреть файл

@ -73,7 +73,6 @@ let gTests = [
check: function(aTab) {
// Right click should do nothing (context menu will be shown)
is(gURLBar.value, TEST_VALUE, "Urlbar still has the value we entered");
ok(gURLBar.focused, "Urlbar is still focused after click");
}
},

Просмотреть файл

@ -62,6 +62,8 @@ function test() {
testVal("<https://>mozilla.org</sub/file.ext?foo&bar#top>");
testVal("<https://sub.>mozilla.org<:666/file.ext>");
testVal("<sub.>mozilla.org<:666/file.ext>");
testVal("localhost<:666/file.ext>");
let IPs = ["192.168.1.1",
"[::]",
@ -87,6 +89,7 @@ function test() {
IPs.forEach(function (IP) {
testVal(IP);
testVal(IP + "</file.ext>");
testVal(IP + "<:666/file.ext>");
testVal("<https://>" + IP);
testVal("<https://>" + IP + "</file.ext>");
testVal("<https://user:pass@>" + IP + "<:666/file.ext>");

Просмотреть файл

@ -204,7 +204,7 @@
let textNode = this.editor.rootElement.firstChild;
let value = textNode.textContent;
let protocol = value.match(/^[a-z\d.+\-]+:/);
let protocol = value.match(/^[a-z\d.+\-]+:(?=[^\d])/);
if (protocol &&
["http:", "https:", "ftp:"].indexOf(protocol[0]) == -1)
return;

Просмотреть файл

@ -44,7 +44,6 @@ var gTabsPane = {
*
* browser.link.open_newwindow
* - determines where pages which would open in a new window are opened:
* 0 opens such links in the default window,
* 1 opens such links in the most recent window or tab,
* 2 opens such links in a new window,
* 3 opens such links in a new tab

Просмотреть файл

@ -324,7 +324,6 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
if (aAttribute == *lengthListInfo.mLengthListInfo[i].mName) {
rv = lengthListInfo.mLengthLists[i].SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
lengthListInfo.Reset(i);
}
foundMatch = PR_TRUE;
@ -340,7 +339,6 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
if (aAttribute == *numberListInfo.mNumberListInfo[i].mName) {
rv = numberListInfo.mNumberLists[i].SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
numberListInfo.Reset(i);
}
foundMatch = PR_TRUE;
@ -356,7 +354,6 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
if (pointList) {
rv = pointList->SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
// The spec says we parse everything up to the failure, so we don't
// call pointList->ClearBaseValue()
}
@ -372,7 +369,6 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
if (segList) {
rv = segList->SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
// The spec says we parse everything up to the failure, so we don't
// call segList->ClearBaseValue()
}
@ -556,13 +552,12 @@ nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
aResult);
}
nsresult
nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
bool aNotify)
void
nsSVGElement::UnsetAttrInternal(PRInt32 aNamespaceID, nsIAtom* aName,
bool aNotify)
{
// XXXbz there's a bunch of redundancy here with AfterSetAttr.
// Maybe consolidate?
nsresult rv = nsSVGElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
if (aNamespaceID == kNameSpaceID_None) {
// If this is an svg presentation attribute, remove rule to force an update
@ -575,7 +570,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
nsIAtom* eventName = GetEventNameForAttr(aName);
manager->RemoveScriptEventListener(eventName);
}
return rv;
return;
}
// Check if this is a length attribute going away
@ -585,7 +580,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *lenInfo.mLengthInfo[i].mName) {
lenInfo.Reset(i);
DidChangeLength(i, PR_FALSE);
return rv;
return;
}
}
@ -596,7 +591,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *lengthListInfo.mLengthListInfo[i].mName) {
lengthListInfo.Reset(i);
DidChangeLengthList(i, PR_FALSE);
return rv;
return;
}
}
@ -607,7 +602,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *numberListInfo.mNumberListInfo[i].mName) {
numberListInfo.Reset(i);
DidChangeNumberList(i, PR_FALSE);
return rv;
return;
}
}
@ -616,7 +611,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
SVGAnimatedPointList *pointList = GetAnimatedPointList();
if (pointList) {
pointList->ClearBaseValue();
return rv;
return;
}
}
@ -626,7 +621,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (segList) {
segList->ClearBaseValue();
DidChangePathSegList(PR_FALSE);
return rv;
return;
}
}
@ -637,7 +632,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *numInfo.mNumberInfo[i].mName) {
numInfo.Reset(i);
DidChangeNumber(i, PR_FALSE);
return rv;
return;
}
}
@ -648,7 +643,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *numPairInfo.mNumberPairInfo[i].mName) {
numPairInfo.Reset(i);
DidChangeNumberPair(i, PR_FALSE);
return rv;
return;
}
}
@ -659,7 +654,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *intInfo.mIntegerInfo[i].mName) {
intInfo.Reset(i);
DidChangeInteger(i, PR_FALSE);
return rv;
return;
}
}
@ -670,7 +665,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *intPairInfo.mIntegerPairInfo[i].mName) {
intPairInfo.Reset(i);
DidChangeIntegerPair(i, PR_FALSE);
return rv;
return;
}
}
@ -681,7 +676,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *angleInfo.mAngleInfo[i].mName) {
angleInfo.Reset(i);
DidChangeAngle(i, PR_FALSE);
return rv;
return;
}
}
@ -692,7 +687,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *boolInfo.mBooleanInfo[i].mName) {
boolInfo.Reset(i);
DidChangeBoolean(i, PR_FALSE);
return rv;
return;
}
}
@ -703,7 +698,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (aName == *enumInfo.mEnumInfo[i].mName) {
enumInfo.Reset(i);
DidChangeEnum(i, PR_FALSE);
return rv;
return;
}
}
@ -713,9 +708,10 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (viewBox) {
viewBox->Init();
DidChangeViewBox(PR_FALSE);
return rv;
return;
}
}
// Check if this is a preserveAspectRatio attribute going away
if (aName == nsGkAtoms::preserveAspectRatio) {
SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
@ -724,7 +720,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (preserveAspectRatio) {
preserveAspectRatio->Init();
DidChangePreserveAspectRatio(PR_FALSE);
return rv;
return;
}
}
@ -734,7 +730,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (transformList) {
transformList->ClearBaseValue();
DidChangeTransformList(PR_FALSE);
return rv;
return;
}
}
@ -744,7 +740,7 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
if (svgClass) {
svgClass->Init();
return rv;
return;
}
}
}
@ -757,11 +753,17 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
aName == *stringInfo.mStringInfo[i].mName) {
stringInfo.Reset(i);
DidChangeString(i);
return rv;
return;
}
}
}
return rv;
nsresult
nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
bool aNotify)
{
UnsetAttrInternal(aNamespaceID, aName, aNotify);
return nsSVGElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
}
nsChangeHint
@ -1304,7 +1306,7 @@ nsSVGElement::SetLength(nsIAtom* aName, const nsSVGLength2 &aLength)
for (PRUint32 i = 0; i < lengthInfo.mLengthCount; i++) {
if (aName == *lengthInfo.mLengthInfo[i].mName) {
lengthInfo.mLengths[i] = aLength;
DidChangeLength(i, PR_TRUE);
DidAnimateLength(i);
return;
}
}

Просмотреть файл

@ -519,6 +519,9 @@ protected:
static nsSVGEnumMapping sSVGUnitTypesMap[];
private:
void UnsetAttrInternal(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
bool aNotify);
nsRefPtr<mozilla::css::StyleRule> mContentStyleRule;
};

Просмотреть файл

@ -417,24 +417,25 @@ bool nsSVGUseElement::HasValidDimensions()
}
void
nsSVGUseElement::SyncWidthHeight(PRUint8 aAttrEnum)
nsSVGUseElement::SyncWidthHeight(nsIAtom* aName)
{
NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
"The clue is in the function name");
if (HasValidDimensions() == !mClone) {
TriggerReclone();
return;
}
if (mClone && (aAttrEnum == WIDTH || aAttrEnum == HEIGHT)) {
if (mClone) {
nsCOMPtr<nsIDOMSVGSymbolElement> symbol = do_QueryInterface(mClone);
nsCOMPtr<nsIDOMSVGSVGElement> svg = do_QueryInterface(mClone);
if (symbol || svg) {
nsIAtom* aAttrName = aAttrEnum == WIDTH ?
nsGkAtoms::width : nsGkAtoms::height;
if (mLengthAttributes[aAttrEnum].IsExplicitlySet()) {
PRUint32 index = *sLengthInfo[WIDTH].mName == aName ? WIDTH : HEIGHT;
if (mLengthAttributes[index].IsExplicitlySet()) {
static_cast<nsSVGElement*>(mClone.get())->
SetLength(aAttrName, mLengthAttributes[aAttrEnum]);
SetLength(aName, mLengthAttributes[index]);
} else {
// Our width/height attribute is now no longer explicitly set, so we
// need to revert the clone's width/height to the width/height of the
@ -497,22 +498,6 @@ nsSVGUseElement::PrependLocalTransformTo(const gfxMatrix &aMatrix) const
return matrix.PreMultiply(gfxMatrix().Translate(gfxPoint(x, y)));
}
void
nsSVGUseElement::DidChangeLength(PRUint8 aAttrEnum, bool aDoSetAttr)
{
nsSVGUseElementBase::DidChangeLength(aAttrEnum, aDoSetAttr);
SyncWidthHeight(aAttrEnum);
}
void
nsSVGUseElement::DidAnimateLength(PRUint8 aAttrEnum)
{
nsSVGUseElementBase::DidAnimateLength(aAttrEnum);
SyncWidthHeight(aAttrEnum);
}
nsSVGElement::LengthAttributesInfo
nsSVGUseElement::GetLengthInfo()
{
@ -520,33 +505,6 @@ nsSVGUseElement::GetLengthInfo()
NS_ARRAY_LENGTH(sLengthInfo));
}
void
nsSVGUseElement::DidChangeString(PRUint8 aAttrEnum)
{
nsSVGUseElementBase::DidChangeString(aAttrEnum);
if (aAttrEnum == HREF) {
// we're changing our nature, clear out the clone information
mOriginal = nsnull;
UnlinkSource();
TriggerReclone();
}
}
void
nsSVGUseElement::DidAnimateString(PRUint8 aAttrEnum)
{
if (aAttrEnum == HREF) {
// we're changing our nature, clear out the clone information
mOriginal = nsnull;
UnlinkSource();
TriggerReclone();
return;
}
nsSVGUseElementBase::DidAnimateString(aAttrEnum);
}
nsSVGElement::StringAttributesInfo
nsSVGUseElement::GetStringInfo()
{

Просмотреть файл

@ -103,10 +103,6 @@ public:
// nsSVGElement specializations:
virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix) const;
virtual void DidChangeLength(PRUint8 aAttrEnum, bool aDoSetAttr);
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidChangeString(PRUint8 aAttrEnum);
virtual void DidAnimateString(PRUint8 aAttrEnum);
// nsIContent interface
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
@ -133,7 +129,7 @@ protected:
virtual StringAttributesInfo GetStringInfo();
bool HasValidDimensions();
void SyncWidthHeight(PRUint8 aAttrEnum);
void SyncWidthHeight(nsIAtom *aName);
void LookupHref();
void TriggerReclone();
void UnlinkSource();

Просмотреть файл

@ -141,7 +141,9 @@ EventTarget::AddEventListener(JSContext* aCx, uintN aArgc, jsval* aVp)
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
EventTarget* self = GetPrivate(aCx, obj);
JS_ASSERT(self);
if (!self) {
return true;
}
JSString* type;
JSObject* listener;
@ -167,7 +169,9 @@ EventTarget::RemoveEventListener(JSContext* aCx, uintN aArgc, jsval* aVp)
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
EventTarget* self = GetPrivate(aCx, obj);
JS_ASSERT(self);
if (!self) {
return true;
}
JSString* type;
JSObject* listener;
@ -193,7 +197,9 @@ EventTarget::DispatchEvent(JSContext* aCx, uintN aArgc, jsval* aVp)
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
EventTarget* self = GetPrivate(aCx, obj);
JS_ASSERT(self);
if (!self) {
return true;
}
JSObject* event;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &event)) {

Просмотреть файл

@ -112,6 +112,29 @@ public:
return proto;
}
static void
ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
{
JS_ASSERT(!JS_IsExceptionPending(aCx));
WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
JS_ASSERT(worker);
if (aSaveEventHandlers) {
for (int index = 0; index < STRING_COUNT; index++) {
const char* name = sEventStrings[index];
jsval listener;
if (!worker->GetEventListenerOnEventTarget(aCx, name + 2, &listener) ||
!JS_DefineProperty(aCx, aObj, name, listener, NULL, NULL,
(PROPERTY_FLAGS & ~JSPROP_SHARED))) {
JS_ClearPendingException(aCx);
}
}
}
SetJSPrivateSafeish(aCx, aObj, NULL);
}
protected:
static WorkerPrivate*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName);
@ -225,7 +248,7 @@ private:
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
if (worker) {
worker->FinalizeInstance(aCx);
worker->FinalizeInstance(aCx, true);
}
}
@ -337,6 +360,12 @@ public:
return proto;
}
static void
ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
{
Worker::ClearPrivateSlot(aCx, aObj, aSaveEventHandlers);
}
private:
// No instance of this class should ever be created so these are explicitly
// left without an implementation to prevent linking in case someone tries to
@ -369,7 +398,7 @@ private:
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
if (worker) {
worker->FinalizeInstance(aCx);
worker->FinalizeInstance(aCx, true);
}
}
@ -425,6 +454,20 @@ InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
return Worker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
}
void
ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
{
JSClass* clasp = JS_GET_CLASS(aCx, aObj);
JS_ASSERT(clasp == Worker::Class() || clasp == ChromeWorker::Class());
if (clasp == ChromeWorker::Class()) {
ChromeWorker::ClearPrivateSlot(aCx, aObj, aSaveEventHandlers);
}
else {
Worker::ClearPrivateSlot(aCx, aObj, aSaveEventHandlers);
}
}
} // namespace worker
namespace chromeworker {

Просмотреть файл

@ -51,6 +51,9 @@ JSObject*
InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
bool aMainRuntime);
void
ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers);
} // namespace worker
namespace chromeworker {

Просмотреть файл

@ -76,6 +76,7 @@
#include "Principal.h"
#include "RuntimeService.h"
#include "ScriptLoader.h"
#include "Worker.h"
#include "WorkerFeature.h"
#include "WorkerScope.h"
@ -646,7 +647,7 @@ public:
NS_WARNING("Failed to dispatch, going to leak!");
}
mFinishedWorker->FinalizeInstance(aCx);
mFinishedWorker->FinalizeInstance(aCx, false);
RuntimeService* runtime = RuntimeService::GetService();
NS_ASSERTION(runtime, "This should never be null!");
@ -678,7 +679,7 @@ public:
RuntimeService::AutoSafeJSContext cx;
mFinishedWorker->FinalizeInstance(cx);
mFinishedWorker->FinalizeInstance(cx, false);
RuntimeService* runtime = RuntimeService::GetService();
NS_ASSERTION(runtime, "This should never be null!");
@ -1772,7 +1773,7 @@ WorkerPrivateParent<Derived>::Notify(JSContext* aCx, Status aStatus)
mParentStatus = aStatus;
}
FinalizeInstance(aCx);
FinalizeInstance(aCx, false);
if (pending) {
WorkerPrivate* self = ParentAsWorkerPrivate();
@ -1867,13 +1868,21 @@ WorkerPrivateParent<Derived>::Resume(JSContext* aCx)
template <class Derived>
void
WorkerPrivateParent<Derived>::FinalizeInstance(JSContext* aCx)
WorkerPrivateParent<Derived>::FinalizeInstance(JSContext* aCx,
bool aFromJSFinalizer)
{
AssertIsOnParentThread();
if (mJSObject) {
// Make sure we're in the right compartment.
JSAutoEnterCompartment ac;
if (!ac.enter(aCx, mJSObject)) {
NS_ERROR("How can this fail?!");
return;
}
// Decouple the object from the private now.
SetJSPrivateSafeish(aCx, mJSObject, nsnull);
worker::ClearPrivateSlot(aCx, mJSObject, !aFromJSFinalizer);
// Clear the JS object.
mJSObject = nsnull;

Просмотреть файл

@ -276,7 +276,7 @@ public:
}
void
FinalizeInstance(JSContext* aCx);
FinalizeInstance(JSContext* aCx, bool aFromJSFinalizer);
bool
Terminate(JSContext* aCx)

Просмотреть файл

@ -26,6 +26,61 @@ Tests of DOM Worker terminate feature
var interval;
var worker;
function messageListener(event) {
is(event.data, "Still alive!", "Correct message!");
if (messageCount++ == 20) {
ok(worker.onmessage === messageListener,
"Correct listener before terminate");
worker.terminate();
var exception = false;
try {
worker.addEventListener("message", messageListener, false);
}
catch (e) {
exception = true;
}
is(exception, false, "addEventListener didn't throw after terminate");
exception = false;
try {
worker.removeEventListener("message", messageListener, false);
}
catch (e) {
exception = true;
}
is(exception, false, "removeEventListener didn't throw after terminate");
exception = false;
try {
worker.postMessage("foo");
}
catch (e) {
exception = true;
}
is(exception, false, "postMessage didn't throw after terminate");
exception = false;
try {
worker.terminate();
}
catch (e) {
exception = true;
}
is(exception, false, "terminate didn't throw after terminate");
ok(worker.onmessage === messageListener,
"Correct listener after terminate");
worker.onmessage = function(event) { }
interval = setInterval(testCount, 1000);
}
}
function testCount() {
is(messageCount, 21, "Received another message after terminated!");
if (intervalCount++ == 5) {
@ -34,19 +89,8 @@ Tests of DOM Worker terminate feature
}
}
var worker = new Worker("terminate_worker.js");
worker.onmessage = function(event) {
is(event.data, "Still alive!", "Bad message!");
if (messageCount++ == 20) {
worker.terminate();
interval = setInterval(testCount, 1000);
}
};
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
}
worker = new Worker("terminate_worker.js");
worker.onmessage = messageListener;
SimpleTest.waitForExplicitFinish();

Просмотреть файл

@ -179,6 +179,8 @@ CanvasLayerD3D10::UpdateSurface()
destination = (PRUint8*)map.pData;
}
mGLContext->MakeCurrent();
// We have to flush to ensure that any buffered GL operations are
// in the framebuffer before we read.
mGLContext->fFlush();

Просмотреть файл

@ -113,6 +113,8 @@ CanvasLayerD3D9::UpdateSurface()
destination = (PRUint8*)r.pBits;
}
mGLContext->MakeCurrent();
// We have to flush to ensure that any buffered GL operations are
// in the framebuffer before we read.
mGLContext->fFlush();

Просмотреть файл

@ -247,14 +247,14 @@ protected:
log.SetLength(len);
if (!success) {
fprintf (stderr, "=== SHADER COMPILATION FAILED ===\n");
printf_stderr("=== SHADER COMPILATION FAILED ===\n");
} else {
fprintf (stderr, "=== SHADER COMPILATION WARNINGS ===\n");
printf_stderr("=== SHADER COMPILATION WARNINGS ===\n");
}
fprintf (stderr, "=== Source:\n%s\n", aShaderSource);
fprintf (stderr, "=== Log:\n%s\n", log.get());
fprintf (stderr, "============\n");
printf_stderr("=== Source:\n%s\n", aShaderSource);
printf_stderr("=== Log:\n%s\n", log.get());
printf_stderr("============\n");
if (!success) {
mGL->fDeleteShader(sh);
@ -303,12 +303,12 @@ protected:
log.SetLength(len);
if (!success) {
fprintf (stderr, "=== PROGRAM LINKING FAILED ===\n");
printf_stderr("=== PROGRAM LINKING FAILED ===\n");
} else {
fprintf (stderr, "=== PROGRAM LINKING WARNINGS ===\n");
printf_stderr("=== PROGRAM LINKING WARNINGS ===\n");
}
fprintf (stderr, "=== Log:\n%s\n", log.get());
fprintf (stderr, "============\n");
printf_stderr("=== Log:\n%s\n", log.get());
printf_stderr("============\n");
}
// We can mark the shaders for deletion; they're attached to the program

Просмотреть файл

@ -891,15 +891,13 @@ gfxHarfBuzzShaper::InitTextRun(gfxContext *aContext,
hb_buffer_reverse(buffer);
}
#ifdef DEBUG
nsresult rv =
#endif
SetGlyphsFromRun(aContext, aTextRun, buffer, aRunStart, aRunLength);
SetGlyphsFromRun(aContext, aTextRun, buffer, aRunStart, aRunLength);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into textrun");
hb_buffer_destroy(buffer);
hb_font_destroy(font);
return PR_TRUE;
return NS_SUCCEEDED(rv);
}
/**

Просмотреть файл

@ -144,7 +144,7 @@ namespace StructType {
namespace FunctionType {
static JSBool Create(JSContext* cx, uintN argc, jsval* vp);
static JSBool ConstructData(JSContext* cx, JSObject* typeObj,
JSObject* dataObj, JSObject* fnObj, JSObject* thisObj);
JSObject* dataObj, JSObject* fnObj, JSObject* thisObj, jsval errVal);
static JSBool Call(JSContext* cx, uintN argc, jsval* vp);
@ -3286,8 +3286,8 @@ PointerType::ConstructData(JSContext* cx,
return JS_FALSE;
}
if (argc > 2) {
JS_ReportError(cx, "constructor takes 0, 1, or 2 arguments");
if (argc > 3) {
JS_ReportError(cx, "constructor takes 0, 1, 2, or 3 arguments");
return JS_FALSE;
}
@ -3298,40 +3298,63 @@ PointerType::ConstructData(JSContext* cx,
// Set return value early, must not observe *vp after
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
if (argc == 0) {
// Construct a null pointer.
// There are 3 things that we might be creating here:
// 1 - A null pointer (no arguments)
// 2 - An initialized pointer (1 argument)
// 3 - A closure (1-3 arguments)
//
// The API doesn't give us a perfect way to distinguish 2 and 3, but the
// heuristics we use should be fine.
//
// Case 1 - Null pointer
//
if (argc == 0)
return JS_TRUE;
// Analyze the arguments a bit to decide what to do next.
jsval* argv = JS_ARGV(cx, vp);
JSObject* baseObj = PointerType::GetBaseType(cx, obj);
bool looksLikeClosure = CType::GetTypeCode(cx, baseObj) == TYPE_function &&
JSVAL_IS_OBJECT(argv[0]) &&
JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(argv[0]));
//
// Case 2 - Initialized pointer
//
if (!looksLikeClosure) {
if (argc != 1) {
JS_ReportError(cx, "first argument must be a function");
return JS_FALSE;
}
return ExplicitConvert(cx, argv[0], obj, CData::GetData(cx, result));
}
jsval* argv = JS_ARGV(cx, vp);
if (argc >= 1) {
JSObject* baseObj = PointerType::GetBaseType(cx, obj);
if (CType::GetTypeCode(cx, baseObj) == TYPE_function &&
JSVAL_IS_OBJECT(argv[0]) &&
JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(argv[0]))) {
// Construct a FunctionType.ptr from a JS function, and allow an
// optional 'this' argument.
JSObject* thisObj = NULL;
if (argc == 2) {
if (JSVAL_IS_OBJECT(argv[1])) {
thisObj = JSVAL_TO_OBJECT(argv[1]);
} else if (!JS_ValueToObject(cx, argv[1], &thisObj)) {
return JS_FALSE;
}
}
//
// Case 3 - Closure
//
JSObject* fnObj = JSVAL_TO_OBJECT(argv[0]);
return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj);
}
if (argc == 2) {
JS_ReportError(cx, "first argument must be a function");
// The second argument is an optional 'this' parameter with which to invoke
// the given js function. Callers may leave this blank, or pass null if they
// wish to pass the third argument.
JSObject* thisObj = NULL;
if (argc >= 2) {
if (JSVAL_IS_OBJECT(argv[1])) {
thisObj = JSVAL_TO_OBJECT(argv[1]);
} else if (!JS_ValueToObject(cx, argv[1], &thisObj)) {
return JS_FALSE;
}
}
// Construct from a raw pointer value.
return ExplicitConvert(cx, argv[0], obj, CData::GetData(cx, result));
// The third argument is an optional error sentinel that js-ctypes will return
// if an exception is raised while executing the closure. The type must match
// the return type of the callback.
jsval errVal = JSVAL_VOID;
if (argc == 3)
errVal = argv[2];
JSObject* fnObj = JSVAL_TO_OBJECT(argv[0]);
return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj, errVal);
}
JSObject*
@ -4922,7 +4945,8 @@ FunctionType::ConstructData(JSContext* cx,
JSObject* typeObj,
JSObject* dataObj,
JSObject* fnObj,
JSObject* thisObj)
JSObject* thisObj,
jsval errVal)
{
JS_ASSERT(CType::GetTypeCode(cx, typeObj) == TYPE_function);
@ -4939,7 +4963,7 @@ FunctionType::ConstructData(JSContext* cx,
return JS_FALSE;
}
JSObject* closureObj = CClosure::Create(cx, typeObj, fnObj, thisObj, data);
JSObject* closureObj = CClosure::Create(cx, typeObj, fnObj, thisObj, errVal, data);
if (!closureObj)
return JS_FALSE;
js::AutoObjectRooter root(cx, closureObj);
@ -5220,6 +5244,7 @@ CClosure::Create(JSContext* cx,
JSObject* typeObj,
JSObject* fnObj,
JSObject* thisObj,
jsval errVal,
PRFuncPtr* fnptr)
{
JS_ASSERT(fnObj);
@ -5234,7 +5259,7 @@ CClosure::Create(JSContext* cx,
JS_ASSERT(!fninfo->mIsVariadic);
JS_ASSERT(GetABICode(cx, fninfo->mABI) != ABI_WINAPI);
AutoPtr<ClosureInfo> cinfo(cx->new_<ClosureInfo>());
AutoPtr<ClosureInfo> cinfo(cx->new_<ClosureInfo>(JS_GetRuntime(cx)));
if (!cinfo) {
JS_ReportOutOfMemory(cx);
return NULL;
@ -5277,6 +5302,37 @@ CClosure::Create(JSContext* cx,
cinfo->cxThread = JS_GetContextThread(cx);
#endif
// Prepare the error sentinel value. It's important to do this now, because
// we might be unable to convert the value to the proper type. If so, we want
// the caller to know about it _now_, rather than some uncertain time in the
// future when the error sentinel is actually needed.
if (!JSVAL_IS_VOID(errVal)) {
// Make sure the callback returns something.
if (CType::GetTypeCode(cx, fninfo->mReturnType) == TYPE_void_t) {
JS_ReportError(cx, "A void callback can't pass an error sentinel");
return NULL;
}
// With the exception of void, the FunctionType constructor ensures that
// the return type has a defined size.
JS_ASSERT(CType::IsSizeDefined(cx, fninfo->mReturnType));
// Allocate a buffer for the return value.
size_t rvSize = CType::GetSize(cx, fninfo->mReturnType);
cinfo->errResult = cx->malloc_(rvSize);
if (!cinfo->errResult)
return NULL;
// Do the value conversion. This might fail, in which case we throw.
if (!ImplicitConvert(cx, errVal, fninfo->mReturnType, cinfo->errResult,
false, NULL))
return NULL;
} else {
cinfo->errResult = NULL;
}
// Copy the important bits of context into cinfo.
cinfo->closureObj = result;
cinfo->typeObj = typeObj;
cinfo->thisObj = thisObj;
@ -5294,17 +5350,14 @@ CClosure::Create(JSContext* cx,
ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF,
CClosure::ClosureStub, cinfo.get(), code);
if (status != FFI_OK) {
ffi_closure_free(cinfo->closure);
JS_ReportError(cx, "couldn't create closure - libffi error");
return NULL;
}
// Stash the ClosureInfo struct on our new object.
if (!JS_SetReservedSlot(cx, result, SLOT_CLOSUREINFO,
PRIVATE_TO_JSVAL(cinfo.get()))) {
ffi_closure_free(cinfo->closure);
PRIVATE_TO_JSVAL(cinfo.get())))
return NULL;
}
cinfo.forget();
// Casting between void* and a function pointer is forbidden in C and C++.
@ -5344,9 +5397,6 @@ CClosure::Finalize(JSContext* cx, JSObject* obj)
return;
ClosureInfo* cinfo = static_cast<ClosureInfo*>(JSVAL_TO_PRIVATE(slot));
if (cinfo->closure)
ffi_closure_free(cinfo->closure);
cx->delete_(cinfo);
}
@ -5385,8 +5435,9 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
// Initialize the result to zero, in case something fails. Small integer types
// are promoted to a word-sized ffi_arg, so we must be careful to zero the
// whole word.
size_t rvSize = 0;
if (cif->rtype != &ffi_type_void) {
size_t size = cif->rtype->size;
rvSize = cif->rtype->size;
switch (typeCode) {
#define DEFINE_INT_TYPE(name, type, ffiType) \
case TYPE_##name:
@ -5395,12 +5446,12 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z)
#include "typedefs.h"
size = Align(size, sizeof(ffi_arg));
rvSize = Align(rvSize, sizeof(ffi_arg));
break;
default:
break;
}
memset(result, 0, size);
memset(result, 0, rvSize);
}
// Get a death grip on 'closureObj'.
@ -5425,17 +5476,51 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
// Call the JS function. 'thisObj' may be NULL, in which case the JS engine
// will find an appropriate object to use.
jsval rval;
if (!JS_CallFunctionValue(cx, thisObj, OBJECT_TO_JSVAL(jsfnObj), cif->nargs,
argv.begin(), &rval))
return;
JSBool success = JS_CallFunctionValue(cx, thisObj, OBJECT_TO_JSVAL(jsfnObj),
cif->nargs, argv.begin(), &rval);
// Convert the result. Note that we pass 'isArgument = false', such that
// ImplicitConvert will *not* autoconvert a JS string into a pointer-to-char
// type, which would require an allocation that we can't track. The JS
// function must perform this conversion itself and return a PointerType
// CData; thusly, the burden of freeing the data is left to the user.
if (!ImplicitConvert(cx, rval, fninfo->mReturnType, result, false, NULL))
return;
if (success && cif->rtype != &ffi_type_void)
success = ImplicitConvert(cx, rval, fninfo->mReturnType, result, false,
NULL);
if (!success) {
// Something failed. The callee may have thrown, or it may not have
// returned a value that ImplicitConvert() was happy with. Depending on how
// prudent the consumer has been, we may or may not have a recovery plan.
// In any case, a JS exception cannot be passed to C code, so report the
// exception if any and clear it from the cx.
if (JS_IsExceptionPending(cx))
JS_ReportPendingException(cx);
if (cinfo->errResult) {
// Good case: we have a sentinel that we can return. Copy it in place of
// the actual return value, and then proceed.
// The buffer we're returning might be larger than the size of the return
// type, due to libffi alignment issues (see above). But it should never
// be smaller.
size_t copySize = CType::GetSize(cx, fninfo->mReturnType);
JS_ASSERT(copySize <= rvSize);
memcpy(result, cinfo->errResult, copySize);
} else {
// Bad case: not much we can do here. The rv is already zeroed out, so we
// just report (another) error and hope for the best. JS_ReportError will
// actually throw an exception here, so then we have to report it. Again.
// Ugh.
JS_ReportError(cx, "JavaScript callback failed, and an error sentinel "
"was not specified.");
if (JS_IsExceptionPending(cx))
JS_ReportPendingException(cx);
return;
}
}
// Small integer types must be returned as a word-sized ffi_arg. Coerce it
// back into the size libffi expects.

Просмотреть файл

@ -322,14 +322,32 @@ struct FunctionInfo
struct ClosureInfo
{
JSContext* cx; // JSContext to use
JSRuntime* rt; // Used in the destructor, where cx might have already
// been GCed.
JSObject* closureObj; // CClosure object
JSObject* typeObj; // FunctionType describing the C function
JSObject* thisObj; // 'this' object to use for the JS function call
JSObject* jsfnObj; // JS function
void* errResult; // Result that will be returned if the closure throws
ffi_closure* closure; // The C closure itself
#ifdef DEBUG
jsword cxThread; // The thread on which the context may be used
#endif
// Anything conditionally freed in the destructor should be initialized to
// NULL here.
ClosureInfo(JSRuntime* runtime)
: rt(runtime)
, errResult(NULL)
, closure(NULL)
{}
~ClosureInfo() {
if (closure)
ffi_closure_free(closure);
if (errResult)
rt->free_(errResult);
};
};
bool IsCTypesGlobal(JSContext* cx, JSObject* obj);
@ -491,7 +509,7 @@ namespace FunctionType {
namespace CClosure {
JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* fnObj,
JSObject* thisObj, PRFuncPtr* fnptr);
JSObject* thisObj, jsval errVal, PRFuncPtr* fnptr);
}
namespace CData {

2
js/src/ctypes/libffi/configure поставляемый
Просмотреть файл

@ -12362,7 +12362,7 @@ $as_echo "#define HAVE_AS_STRING_PSEUDO_OP 1" >>confdefs.h
fi
case "$target" in
*-apple-darwin10* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
*-apple-darwin1* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
$as_echo "#define FFI_MMAP_EXEC_WRIT 1" >>confdefs.h

Просмотреть файл

@ -316,7 +316,8 @@ if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64
fi
case "$target" in
*-apple-darwin10* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
# Darwin 10 (OSX 10.6) and beyond allocate non-executable pages
*-apple-darwin1* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
AC_DEFINE(FFI_MMAP_EXEC_WRIT, 1,
[Cannot use malloc on this target, so, we revert to
alternative means])

Просмотреть файл

Просмотреть файл

@ -0,0 +1,28 @@
# HG changeset patch
# Parent e357f3f732a0f3e98f8bd4661de03c9042c5c330
# User Landry Breuil <landry@openbsd.org>
treat powerpc-*-openbsd* as powerpc-*-freebsd*
diff --git a/js/src/ctypes/libffi/configure b/js/src/ctypes/libffi/configure
--- a/js/src/ctypes/libffi/configure
+++ b/js/src/ctypes/libffi/configure
@@ -11272,17 +11272,17 @@ case "$host" in
TARGET=POWERPC; TARGETDIR=powerpc
;;
powerpc-*-darwin*)
TARGET=POWERPC_DARWIN; TARGETDIR=powerpc
;;
powerpc-*-aix* | rs6000-*-aix*)
TARGET=POWERPC_AIX; TARGETDIR=powerpc
;;
- powerpc-*-freebsd*)
+ powerpc-*-freebsd* | powerpc-*-openbsd*)
TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
;;
powerpc*-*-rtems*)
TARGET=POWERPC; TARGETDIR=powerpc
;;
s390-*-* | s390x-*-*)
TARGET=S390; TARGETDIR=s390

Просмотреть файл

@ -0,0 +1,27 @@
diff --git a/js/src/ctypes/libffi/configure b/js/src/ctypes/libffi/configure
index 2c08e1b..37e3055 100755
--- a/js/src/ctypes/libffi/configure
+++ b/js/src/ctypes/libffi/configure
@@ -12362,7 +12362,7 @@ $as_echo "#define HAVE_AS_STRING_PSEUDO_OP 1" >>confdefs.h
fi
case "$target" in
- *-apple-darwin10* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
+ *-apple-darwin1* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
$as_echo "#define FFI_MMAP_EXEC_WRIT 1" >>confdefs.h
diff --git a/js/src/ctypes/libffi/configure.ac b/js/src/ctypes/libffi/configure.ac
index e85cff1..1db02ce 100644
--- a/js/src/ctypes/libffi/configure.ac
+++ b/js/src/ctypes/libffi/configure.ac
@@ -316,7 +316,8 @@ if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64
fi
case "$target" in
- *-apple-darwin10* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
+ # Darwin 10 (OSX 10.6) and beyond allocate non-executable pages
+ *-apple-darwin1* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*)
AC_DEFINE(FFI_MMAP_EXEC_WRIT, 1,
[Cannot use malloc on this target, so, we revert to
alternative means])

Просмотреть файл

@ -0,0 +1,3 @@
var rg = /(X(?:.(?!X))*?Y)|(Y(?:.(?!Y))*?Z)/g;
var str = "Y aaa X Match1 Y aaa Y Match2 Z";
assertEq(str.match(rg) + "", "X Match1 Y,Y Match2 Z");

Просмотреть файл

@ -555,7 +555,7 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, InternBehavior ib, F
{
CHECK_REQUEST(cx);
if (!CheckStringLength(cx, length))
if (!JSString::validateLength(cx, length))
return NULL;
/*
@ -597,7 +597,7 @@ js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, InternBehavio
{
CHECK_REQUEST(cx);
if (!CheckStringLength(cx, length))
if (!JSString::validateLength(cx, length))
return NULL;
return AtomizeInline(cx, &chars, length, ib);

Просмотреть файл

@ -254,6 +254,15 @@ types::TypeObjectString(TypeObject *type)
return TypeString(Type::ObjectType(type));
}
unsigned JSScript::id() {
if (!id_) {
id_ = ++compartment()->types.scriptCount;
InferSpew(ISpewOps, "script #%u: %p %s:%d",
id_, this, filename ? filename : "<null>", lineno);
}
return id_;
}
void
types::InferSpew(SpewChannel channel, const char *fmt, ...)
{
@ -874,12 +883,8 @@ public:
void newType(JSContext *cx, TypeSet *source, Type type)
{
if (!target->hasType(type)) {
if (!target->hasType(type))
script->analysis()->addTypeBarrier(cx, pc, target, type);
return;
}
target->addType(cx, type);
}
};
@ -2907,7 +2912,7 @@ TypeObject::setFlags(JSContext *cx, TypeObjectFlags flags)
this->flags |= flags;
InferSpew(ISpewOps, "%s: setFlags %u", TypeObjectString(this), flags);
InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
ObjectStateChange(cx, this, false, false);
}

Просмотреть файл

@ -1088,7 +1088,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == data + size);
#ifdef DEBUG
script->id_ = ++cx->compartment->types.scriptCount;
script->id_ = 0;
#endif
JS_ASSERT(script->getVersion() == version);

Просмотреть файл

@ -594,7 +594,7 @@ struct JSScript : public js::gc::Cell {
*/
uint32 id_;
uint32 idpad;
unsigned id() { return id_; }
unsigned id();
#else
unsigned id() { return 0; }
#endif

Просмотреть файл

@ -3033,11 +3033,9 @@ js_InitStringClass(JSContext *cx, JSObject *obj)
JSFixedString *
js_NewString(JSContext *cx, jschar *chars, size_t length)
{
if (!CheckStringLength(cx, length))
return NULL;
JSFixedString *s = JSFixedString::new_(cx, chars, length);
Probes::createString(cx, s, length);
if (s)
Probes::createString(cx, s, length);
return s;
}

Просмотреть файл

@ -45,30 +45,10 @@
#include "jscntxtinlines.h"
#include "jsgcinlines.h"
#include "vm/String-inl.h"
namespace js {
static inline bool
CheckStringLength(JSContext *cx, size_t length)
{
if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) {
if (JS_ON_TRACE(cx)) {
/*
* If we can't leave the trace, signal OOM condition, otherwise
* exit from trace before throwing.
*/
if (!CanLeaveTrace(cx))
return NULL;
LeaveTrace(cx);
}
js_ReportAllocationOverflow(cx);
return false;
}
return true;
}
/*
* String builder that eagerly checks for over-allocation past the maximum
* string length.
@ -242,7 +222,7 @@ StringBuffer::length() const
inline bool
StringBuffer::checkLength(size_t length)
{
return CheckStringLength(context(), length);
return JSString::validateLength(context(), length);
}
extern bool

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++ tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=99:
*
* ***** BEGIN LICENSE BLOCK *****

Просмотреть файл

@ -324,13 +324,11 @@ RegExpPrivate::create(JSContext *cx, JSString *source, RegExpFlag flags, TokenSt
return RetType(self);
}
/*
* This function should be deleted once we can. See bug 604774.
*/
static inline bool
EnableYarrJIT(JSContext *cx)
/* This function should be deleted once bad Android platforms phase out. See bug 604774. */
inline bool
RegExpPrivateCode::isJITRuntimeEnabled(JSContext *cx)
{
#if defined ANDROID && defined(JS_TRACER) && defined(JS_METHODJIT)
#if defined(ANDROID) && defined(JS_TRACER) && defined(JS_METHODJIT)
return cx->traceJitEnabled || cx->methodJitEnabled;
#else
return true;
@ -338,38 +336,47 @@ EnableYarrJIT(JSContext *cx)
}
inline bool
RegExpPrivate::compileHelper(JSContext *cx, JSLinearString &pattern, TokenStream *ts)
RegExpPrivateCode::compile(JSContext *cx, JSLinearString &pattern, TokenStream *ts,
uintN *parenCount, RegExpFlag flags)
{
#if ENABLE_YARR_JIT
JSC::Yarr::ErrorCode yarrError;
JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
/* Parse the pattern. */
ErrorCode yarrError;
YarrPattern yarrPattern(pattern, bool(flags & IgnoreCaseFlag), bool(flags & MultilineFlag),
&yarrError);
if (yarrError) {
reportYarrError(cx, ts, yarrError);
return false;
}
parenCount = yarrPattern.m_numSubpatterns;
*parenCount = yarrPattern.m_numSubpatterns;
#if defined(JS_METHODJIT)
if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
bool ok = cx->compartment->ensureJaegerCompartmentExists(cx);
if (!ok)
/*
* The YARR JIT compiler attempts to compile the parsed pattern. If
* it cannot, it informs us via |codeBlock.isFallBack()|, in which
* case we have to bytecode compile it.
*/
#ifdef JS_METHODJIT
if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) {
if (!cx->compartment->ensureJaegerCompartmentExists(cx))
return false;
JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment()->execAlloc());
JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
JSGlobalData globalData(cx->compartment->jaegerCompartment()->execAlloc());
jitCompile(yarrPattern, &globalData, codeBlock);
if (!codeBlock.isFallBack())
return true;
}
#endif
codeBlock.setFallBack(true);
byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
byteCode = byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
return true;
#else
#else /* !defined(ENABLE_YARR_JIT) */
int error = 0;
compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
&parenCount, &error);
ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
parenCount, &error);
if (error) {
reportPCREError(cx, error);
return false;
@ -386,7 +393,7 @@ RegExpPrivate::compile(JSContext *cx, TokenStream *ts)
return false;
if (!sticky())
return compileHelper(cx, *source, ts);
return code.compile(cx, *source, ts, &parenCount, getFlags());
/*
* The sticky case we implement hackily by prepending a caret onto the front
@ -405,7 +412,36 @@ RegExpPrivate::compile(JSContext *cx, TokenStream *ts)
JSLinearString *fakeySource = sb.finishString();
if (!fakeySource)
return false;
return compileHelper(cx, *fakeySource, ts);
return code.compile(cx, *fakeySource, ts, &parenCount, getFlags());
}
inline RegExpPrivateCode::ExecuteResult
RegExpPrivateCode::execute(JSContext *cx, const jschar *chars, size_t start, size_t length,
int *output, size_t outputCount)
{
int result;
#if ENABLE_YARR_JIT
(void) cx; /* Unused. */
if (codeBlock.isFallBack())
result = JSC::Yarr::interpret(byteCode, chars, start, length, output);
else
result = JSC::Yarr::execute(codeBlock, chars, start, length, output);
#else
result = jsRegExpExecute(cx, compiled, chars, length, start, output, outputCount);
#endif
if (result == -1)
return Success_NotFound;
#if !ENABLE_YARR_JIT
if (result < 0) {
reportPCREError(cx, result);
return Error;
}
#endif
JS_ASSERT(result >= 0);
return Success;
}
inline void

Просмотреть файл

@ -64,8 +64,8 @@ RegExpPrivate::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inpu
size_t *lastIndex, bool test, Value *rval)
{
const size_t pairCount = parenCount + 1;
const size_t bufCount = pairCount * 3; /* Should be x2, but PCRE has... needs. */
const size_t matchItemCount = pairCount * 2;
const size_t bufCount = RegExpPrivateCode::getOutputSize(pairCount);
LifoAllocScope las(&cx->tempLifoAlloc());
int *buf = cx->tempLifoAlloc().newArray<int>(bufCount);
@ -100,27 +100,19 @@ RegExpPrivate::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inpu
inputOffset = *lastIndex;
}
int result;
#if ENABLE_YARR_JIT
if (!codeBlock.isFallBack())
result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
else
result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
#else
result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, bufCount);
#endif
if (result == -1) {
size_t start = *lastIndex - inputOffset;
RegExpPrivateCode::ExecuteResult result = code.execute(cx, chars, start, len, buf, bufCount);
switch (result) {
case RegExpPrivateCode::Error:
return false;
case RegExpPrivateCode::Success_NotFound:
*rval = NullValue();
return true;
default:
JS_ASSERT(result == RegExpPrivateCode::Success);
}
#if !ENABLE_YARR_JIT
if (result < 0) {
reportPCREError(cx, result);
return false;
}
#endif
/*
* Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
* just do another pass.
@ -260,9 +252,42 @@ Class js::RegExpClass = {
NULL /* trace */
};
#if !ENABLE_YARR_JIT
#if ENABLE_YARR_JIT
void
RegExpPrivate::reportPCREError(JSContext *cx, int error)
RegExpPrivateCode::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error)
{
switch (error) {
case JSC::Yarr::NoError:
JS_NOT_REACHED("Called reportYarrError with value for no error");
return;
#define COMPILE_EMSG(__code, __msg) \
case JSC::Yarr::__code: \
if (ts) \
ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, __msg); \
else \
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, __msg); \
return
COMPILE_EMSG(PatternTooLarge, JSMSG_REGEXP_TOO_COMPLEX);
COMPILE_EMSG(QuantifierOutOfOrder, JSMSG_BAD_QUANTIFIER);
COMPILE_EMSG(QuantifierWithoutAtom, JSMSG_BAD_QUANTIFIER);
COMPILE_EMSG(MissingParentheses, JSMSG_MISSING_PAREN);
COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
#undef COMPILE_EMSG
default:
JS_NOT_REACHED("Unknown Yarr error code");
}
}
#else /* !ENABLE_YARR_JIT */
void
RegExpPrivateCode::reportPCREError(JSContext *cx, int error)
{
#define REPORT(msg_) \
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
@ -292,38 +317,7 @@ RegExpPrivate::reportPCREError(JSContext *cx, int error)
}
#undef REPORT
}
#endif
void
RegExpPrivate::reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error)
{
switch (error) {
case JSC::Yarr::NoError:
JS_NOT_REACHED("Called reportYarrError with value for no error");
return;
#define COMPILE_EMSG(__code, __msg) \
case JSC::Yarr::__code: \
if (ts) \
ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, __msg); \
else \
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, __msg); \
return
COMPILE_EMSG(PatternTooLarge, JSMSG_REGEXP_TOO_COMPLEX);
COMPILE_EMSG(QuantifierOutOfOrder, JSMSG_BAD_QUANTIFIER);
COMPILE_EMSG(QuantifierWithoutAtom, JSMSG_BAD_QUANTIFIER);
COMPILE_EMSG(MissingParentheses, JSMSG_MISSING_PAREN);
COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
#undef COMPILE_EMSG
default:
JS_NOT_REACHED("Unknown Yarr error code");
}
}
#endif /* ENABLE_YARR_JIT */
bool
js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)

Просмотреть файл

@ -149,6 +149,69 @@ ResetRegExpObject(JSContext *cx, RegExpObject *reobj, JSString *str, RegExpFlag
inline bool
ResetRegExpObject(JSContext *cx, AlreadyIncRefed<RegExpPrivate> rep);
/* Abstracts away the gross |RegExpPrivate| backend details. */
class RegExpPrivateCode
{
#if ENABLE_YARR_JIT
typedef JSC::Yarr::BytecodePattern BytecodePattern;
typedef JSC::Yarr::ErrorCode ErrorCode;
typedef JSC::Yarr::JSGlobalData JSGlobalData;
typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock;
typedef JSC::Yarr::YarrPattern YarrPattern;
/* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */
YarrCodeBlock codeBlock;
BytecodePattern *byteCode;
#else
JSRegExp *compiled;
#endif
public:
RegExpPrivateCode()
:
#if ENABLE_YARR_JIT
codeBlock(),
byteCode(NULL)
#else
compiled(NULL)
#endif
{ }
~RegExpPrivateCode() {
#if ENABLE_YARR_JIT
codeBlock.release();
if (byteCode)
Foreground::delete_<BytecodePattern>(byteCode);
#else
if (compiled)
jsRegExpFree(compiled);
#endif
}
#if ENABLE_YARR_JIT
static inline bool isJITRuntimeEnabled(JSContext *cx);
void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error);
#else
void reportPCREError(JSContext *cx, int error);
#endif
inline bool compile(JSContext *cx, JSLinearString &pattern, TokenStream *ts, uintN *parenCount,
RegExpFlag flags);
enum ExecuteResult { Error, Success, Success_NotFound };
inline ExecuteResult execute(JSContext *cx, const jschar *chars, size_t start, size_t length,
int *output, size_t outputCount);
static size_t getOutputSize(size_t pairCount) {
#if ENABLE_YARR_JIT
return pairCount * 2;
#else
return pairCount * 3; /* Should be x2, but PCRE has... needs. */
#endif
}
};
/*
* The "meat" of the builtin regular expression objects: it contains the
* mini-program that represents the source of the regular expression.
@ -165,58 +228,23 @@ ResetRegExpObject(JSContext *cx, AlreadyIncRefed<RegExpPrivate> rep);
*/
class RegExpPrivate
{
#if ENABLE_YARR_JIT
/* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */
JSC::Yarr::YarrCodeBlock codeBlock;
JSC::Yarr::BytecodePattern *byteCode;
#else
JSRegExp *compiled;
#endif
RegExpPrivateCode code;
JSLinearString *source;
size_t refCount;
uintN parenCount;
RegExpFlag flags;
JSLinearString *source;
size_t refCount;
unsigned parenCount; /* Must be |unsigned| to interface with YARR. */
RegExpFlag flags;
#ifdef DEBUG
public:
JSCompartment *compartment;
DebugOnly<JSCompartment *> compartment;
private:
#endif
RegExpPrivate(JSLinearString *source, RegExpFlag flags, JSCompartment *compartment)
:
#if ENABLE_YARR_JIT
codeBlock(),
byteCode(NULL),
#else
compiled(NULL),
#endif
source(source), refCount(1), parenCount(0), flags(flags)
#ifdef DEBUG
, compartment(compartment)
#endif
: source(source), refCount(1), parenCount(0), flags(flags), compartment(compartment)
{ }
JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
~RegExpPrivate() {
#if ENABLE_YARR_JIT
codeBlock.release();
if (byteCode)
Foreground::delete_<JSC::Yarr::BytecodePattern>(byteCode);
#else
if (compiled)
jsRegExpFree(compiled);
#endif
}
bool compileHelper(JSContext *cx, JSLinearString &pattern, TokenStream *ts);
bool compile(JSContext *cx, TokenStream *ts);
#if !ENABLE_YARR_JIT
void reportPCREError(JSContext *cx, int error);
#endif
void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error);
static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
bool executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,

Просмотреть файл

@ -43,8 +43,30 @@
#include "String.h"
#include "jscntxt.h"
#include "jsgcinlines.h"
JS_ALWAYS_INLINE bool
JSString::validateLength(JSContext *cx, size_t length)
{
if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) {
if (JS_ON_TRACE(cx)) {
/*
* If we can't leave the trace, signal OOM condition, otherwise
* exit from trace before throwing.
*/
if (!js::CanLeaveTrace(cx))
return NULL;
js::LeaveTrace(cx);
}
js_ReportAllocationOverflow(cx);
return false;
}
return true;
}
JS_ALWAYS_INLINE void
JSRope::init(JSString *left, JSString *right, size_t length)
{
@ -56,6 +78,8 @@ JSRope::init(JSString *left, JSString *right, size_t length)
JS_ALWAYS_INLINE JSRope *
JSRope::new_(JSContext *cx, JSString *left, JSString *right, size_t length)
{
if (!validateLength(cx, length))
return NULL;
JSRope *str = (JSRope *)js_NewGCString(cx);
if (!str)
return NULL;
@ -114,9 +138,10 @@ JSFixedString::init(const jschar *chars, size_t length)
JS_ALWAYS_INLINE JSFixedString *
JSFixedString::new_(JSContext *cx, const jschar *chars, size_t length)
{
JS_ASSERT(length <= MAX_LENGTH);
JS_ASSERT(chars[length] == jschar(0));
if (!validateLength(cx, length))
return NULL;
JSFixedString *str = (JSFixedString *)js_NewGCString(cx);
if (!str)
return NULL;
@ -185,6 +210,8 @@ JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length, intN t
JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT);
JS_ASSERT(chars[length] == 0);
if (!validateLength(cx, length))
return NULL;
JSExternalString *str = js_NewGCExternalString(cx);
if (!str)
return NULL;

Просмотреть файл

@ -268,6 +268,8 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
return left;
size_t wholeLength = leftLen + rightLen;
if (!JSString::validateLength(cx, wholeLength))
return NULL;
if (JSShortString::lengthFits(wholeLength)) {
JSShortString *str = js_NewGCShortString(cx);
@ -287,16 +289,6 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
return str;
}
if (wholeLength > JSString::MAX_LENGTH) {
if (JS_ON_TRACE(cx)) {
if (!CanLeaveTrace(cx))
return NULL;
LeaveTrace(cx);
}
js_ReportAllocationOverflow(cx);
return NULL;
}
return JSRope::new_(cx, left, right, wholeLength);
}

Просмотреть файл

@ -261,6 +261,13 @@ class JSString : public js::gc::Cell
return (length << LENGTH_SHIFT) | flags;
}
/*
* Helper function to validate that a string of a given length is
* representable by a JSString. An allocation overflow is reported if false
* is returned.
*/
static inline bool validateLength(JSContext *cx, size_t length);
static void staticAsserts() {
JS_STATIC_ASSERT(JS_BITS_PER_WORD >= 32);
JS_STATIC_ASSERT(((JSString::MAX_LENGTH << JSString::LENGTH_SHIFT) >>

Просмотреть файл

@ -139,5 +139,5 @@ XPCStringConvert::ReadableToJSVal(JSContext *cx,
if (!str)
JS_free(cx, chars);
}
return STRING_TO_JSVAL(str);
return str ? STRING_TO_JSVAL(str) : JSVAL_NULL;
}

Просмотреть файл

@ -2979,8 +2979,8 @@ CallMethodHelper::ConvertDependentParams()
if((datum_type.IsPointer() &&
(datum_type.TagPart() == nsXPTType::T_IID ||
datum_type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS) ||
datum_type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS) ||
datum_type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
datum_type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS)) ||
(isArray && datum_type.TagPart() == nsXPTType::T_CHAR_STR))
{
dp->SetValNeedsCleanup();

Просмотреть файл

@ -860,12 +860,11 @@ public:
resetMatches(term, context);
freeParenthesesDisjunctionContext(context);
if (result == JSRegExpNoMatch) {
JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
if (backtrackResult != JSRegExpMatch)
return backtrackResult;
} else
if (result != JSRegExpNoMatch)
return result;
JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
if (backtrackResult != JSRegExpMatch)
return backtrackResult;
}
}
@ -947,12 +946,11 @@ public:
resetMatches(term, context);
freeParenthesesDisjunctionContext(context);
if (result == JSRegExpNoMatch) {
JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
if (backtrackResult != JSRegExpMatch)
return backtrackResult;
} else
if (result != JSRegExpNoMatch)
return result;
JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
if (backtrackResult != JSRegExpMatch)
return backtrackResult;
}
}
@ -1036,7 +1034,8 @@ public:
popParenthesesDisjunctionContext(backTrack);
freeParenthesesDisjunctionContext(context);
return result;
if (result != JSRegExpNoMatch)
return result;
}
return JSRegExpNoMatch;

Просмотреть файл

@ -9931,14 +9931,12 @@ FirstLetterCount(const nsTextFragment* aFragment)
{
PRInt32 count = 0;
PRInt32 firstLetterLength = 0;
bool done = false;
PRInt32 i, n = aFragment->GetLength();
for (i = 0; i < n; i++) {
PRUnichar ch = aFragment->CharAt(i);
if (XP_IS_SPACE(ch)) {
if (firstLetterLength) {
done = PR_TRUE;
break;
}
count++;
@ -9947,7 +9945,6 @@ FirstLetterCount(const nsTextFragment* aFragment)
// XXX I18n
if ((ch == '\'') || (ch == '\"')) {
if (firstLetterLength) {
done = PR_TRUE;
break;
}
// keep looping
@ -9955,7 +9952,6 @@ FirstLetterCount(const nsTextFragment* aFragment)
}
else {
count++;
done = PR_TRUE;
break;
}
}

Просмотреть файл

@ -4948,6 +4948,9 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
}
// Draw text
const nsStyleText* textStyle = GetStyleText();
nsRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength,
aProvider, mTextRun, startXOffset);
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth,
@ -4955,11 +4958,23 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
&foreground, &background);
gfxPoint textBaselinePt(aFramePt.x + xOffset, aTextBaselinePt.y);
// Draw shadows, if any
if (textStyle->mTextShadow) {
for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
PaintOneShadow(offset, length,
textStyle->mTextShadow->ShadowAt(i - 1), &aProvider,
dirtyRect, aFramePt, textBaselinePt, aCtx,
foreground, aClipEdges, xOffset);
}
}
// Draw text segment
aCtx->SetColor(gfxRGBA(foreground));
gfxFloat advance;
DrawText(aCtx, aDirtyRect, aFramePt, gfxPoint(aFramePt.x + xOffset, aTextBaselinePt.y),
DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
offset, length, aProvider, aTextPaintStyle, aClipEdges, advance,
hyphenWidth > 0);
if (hyphenWidth) {
@ -5280,20 +5295,6 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge,
snappedRightEdge);
nsTextPaintStyle textPaintStyle(this);
nscolor foregroundColor = textPaintStyle.GetTextColor();
// Paint the text shadow before doing any foreground stuff
const nsStyleText* textStyle = GetStyleText();
if (textStyle->mTextShadow) {
// Text shadow happens with the last value being painted at the back,
// ie. it is painted first.
for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
PaintOneShadow(startOffset, maxLength,
textStyle->mTextShadow->ShadowAt(i - 1), &provider,
aDirtyRect, framePt, textBaselinePt, ctx,
foregroundColor, clipEdges, snappedLeftEdge);
}
}
gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
@ -5309,6 +5310,19 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
return;
}
nscolor foregroundColor = textPaintStyle.GetTextColor();
const nsStyleText* textStyle = GetStyleText();
if (textStyle->mTextShadow) {
// Text shadow happens with the last value being painted at the back,
// ie. it is painted first.
for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
PaintOneShadow(startOffset, maxLength,
textStyle->mTextShadow->ShadowAt(i - 1), &provider,
aDirtyRect, framePt, textBaselinePt, ctx,
foregroundColor, clipEdges, snappedLeftEdge);
}
}
ctx->SetColor(gfxRGBA(foregroundColor));
gfxFloat advanceWidth;

Просмотреть файл

@ -20,3 +20,6 @@ random-if(Android) == basic-negcoord.xul basic-negcoord-ref.xul
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
== overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
== overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
!= text-shadow-selected-1.html text-shadow-selected-1-notref.html
== text-shadow-selected-1.html text-shadow-selected-1-ref.html

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function onload() {
var range = document.createRange();
range.selectNodeContents(document.getElementById("selectMe"));
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
</script>
<style type="text/css">
body {
background: lightGray;
}
div {
position: absolute;
top: 10px;
left: 10px;
font: 36px monospace;
color: white;
}
</style>
</head>
<!-- NOTREF case has selected text but the shadow is missing -->
<body onload="onload()">
<div id="selectMe">
selected shadowed text
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function onload() {
var range = document.createRange();
range.selectNodeContents(document.getElementById("selectMe"));
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
</script>
<style type="text/css">
body {
background: lightGray;
}
div {
position: absolute;
top: 10px;
left: 10px;
font: 36px monospace;
color: white;
}
</style>
</head>
<!-- REF case renders the selection first, using &nbsp; to avoid any show-through of glyph edges,
then the shadowed text on top of that -->
<body onload="onload()">
<div id="selectMe">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>
<div style="text-shadow:1px 1px 1px red;">
selected shadowed text
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function onload() {
var range = document.createRange();
range.selectNodeContents(document.getElementById("selectMe"));
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
</script>
<style type="text/css">
body {
background: lightGray;
}
div {
position: absolute;
top: 10px;
left: 10px;
font: 36px monospace;
color: white;
}
</style>
</head>
<!-- test for bug 692752 - paint text shadow on top of selection highlight -->
<body onload="onload()">
<div style="text-shadow:1px 1px 1px red;" id="selectMe">
selected shadowed text
</div>
</body>
</html>

Просмотреть файл

@ -138,14 +138,24 @@ nsSVGUseFrame::AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType)
{
if (aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::x ||
aAttribute == nsGkAtoms::y)) {
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
if (aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::x ||
aAttribute == nsGkAtoms::y) {
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
return NS_OK;
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
} else if (aAttribute == nsGkAtoms::width ||
aAttribute == nsGkAtoms::height) {
static_cast<nsSVGUseElement*>(mContent)->SyncWidthHeight(aAttribute);
}
} else if (aNameSpaceID == kNameSpaceID_XLink &&
aAttribute == nsGkAtoms::href) {
// we're changing our nature, clear out the clone information
nsSVGUseElement *use = static_cast<nsSVGUseElement*>(mContent);
use->mOriginal = nsnull;
use->UnlinkSource();
use->TriggerReclone();
}
return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,

Просмотреть файл

@ -157,7 +157,7 @@
function openLocalePicker() {
let win = getChromeWin();
win.BrowserUI.showPanel("prefs-container");
win.document.getElementById("prefs-languages").click();
win.document.getElementById("prefs-uilanguage-button").click();
}
function init() {
@ -192,10 +192,15 @@
return;
}
let content = NetUtil.readInputStreamToString(aStream, aStream.available()) || "";
let fileSize = aStream.available();
let cvstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
cvstream.init(aStream, "UTF-8", fileSize, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
let content = {};
cvstream.readString(fileSize, content);
cvstream.close();
aStream.close();
aCallback(content.replace(/\r\n?/g, "\n"));
aCallback(content.value.replace(/\r\n?/g, "\n"));
});
}

Просмотреть файл

@ -899,6 +899,7 @@ var ContextHandler = {
}
let elem = popupNode;
let isText = false;
while (elem) {
if (elem.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
// Link?
@ -947,14 +948,16 @@ var ContextHandler = {
elem instanceof Ci.nsIDOMHTMLPreElement ||
elem instanceof Ci.nsIDOMHTMLHeadingElement ||
elem instanceof Ci.nsIDOMHTMLTableCellElement) {
state.types.push("content-text");
break;
isText = true;
}
}
elem = elem.parentNode;
}
if (isText)
state.types.push("content-text");
for (let i = 0; i < this._types.length; i++)
if (this._types[i].handler(state, popupNode))
state.types.push(this._types[i].name);

Просмотреть файл

@ -250,11 +250,11 @@
-moz-box-ordinal-group: 2; /* put the image on the right side */
}
.option-command {
.option-command:not([disabled="true"]):not(.optgroup) {
list-style-image: url("chrome://browser/skin/images/radio-unselected-hdpi.png");
}
.option-command.selected {
.option-command.selected:not(.optgroup) {
list-style-image: url("chrome://browser/skin/images/radio-selected-hdpi.png");
}

Просмотреть файл

@ -258,11 +258,11 @@
border-bottom: none;
}
.option-command {
.option-command:not([disabled="true"]):not(.optgroup) {
list-style-image: url("chrome://browser/skin/images/radio-unselected-hdpi.png");
}
.option-command.selected {
.option-command.selected:not(.optgroup) {
list-style-image: url("chrome://browser/skin/images/radio-selected-hdpi.png");
}

Просмотреть файл

@ -1525,10 +1525,8 @@ RasterImage::Notify(nsITimer *timer)
}
nsIntRect dirtyRect;
imgFrame *frameToUse = nsnull;
if (nextFrameIndex == 0) {
frameToUse = nextFrame;
dirtyRect = mAnim->firstFrameRefreshArea;
} else {
imgFrame *prevFrame = mFrames[previousFrameIndex];
@ -1536,7 +1534,7 @@ RasterImage::Notify(nsITimer *timer)
return NS_OK;
// Change frame and announce it
if (NS_FAILED(DoComposite(&frameToUse, &dirtyRect, prevFrame,
if (NS_FAILED(DoComposite(&dirtyRect, prevFrame,
nextFrame, nextFrameIndex))) {
// something went wrong, move on to next
NS_WARNING("RasterImage::Notify(): Composing Frame Failed\n");
@ -1559,8 +1557,7 @@ RasterImage::Notify(nsITimer *timer)
// DoComposite gets called when the timer for animation get fired and we have to
// update the composited frame of the animation.
nsresult
RasterImage::DoComposite(imgFrame** aFrameToUse,
nsIntRect* aDirtyRect,
RasterImage::DoComposite(nsIntRect* aDirtyRect,
imgFrame* aPrevFrame,
imgFrame* aNextFrame,
PRInt32 aNextFrameIndex)
@ -1568,7 +1565,6 @@ RasterImage::DoComposite(imgFrame** aFrameToUse,
NS_ENSURE_ARG_POINTER(aDirtyRect);
NS_ENSURE_ARG_POINTER(aPrevFrame);
NS_ENSURE_ARG_POINTER(aNextFrame);
NS_ENSURE_ARG_POINTER(aFrameToUse);
PRInt32 prevFrameDisposalMethod = aPrevFrame->GetFrameDisposalMethod();
if (prevFrameDisposalMethod == kDisposeRestorePrevious &&
@ -1597,7 +1593,6 @@ RasterImage::DoComposite(imgFrame** aFrameToUse,
// whole image
if (prevFrameDisposalMethod == kDisposeClearAll) {
aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
*aFrameToUse = aNextFrame;
return NS_OK;
}
@ -1607,7 +1602,6 @@ RasterImage::DoComposite(imgFrame** aFrameToUse,
(nextFrameDisposalMethod != kDisposeRestorePrevious) &&
!aNextFrame->GetHasAlpha()) {
aDirtyRect->SetRect(0, 0, mSize.width, mSize.height);
*aFrameToUse = aNextFrame;
return NS_OK;
}
}
@ -1648,7 +1642,6 @@ RasterImage::DoComposite(imgFrame** aFrameToUse,
// On the second loop, we do not need to rebuild the frame
// since it's still sitting in compositingFrame)
if (mAnim->lastCompositedFrameIndex == aNextFrameIndex) {
*aFrameToUse = mAnim->compositingFrame;
return NS_OK;
}
@ -1817,13 +1810,11 @@ RasterImage::DoComposite(imgFrame** aFrameToUse,
if (CopyFrameImage(mAnim->compositingFrame, aNextFrame)) {
aPrevFrame->SetFrameDisposalMethod(kDisposeClearAll);
mAnim->lastCompositedFrameIndex = -1;
*aFrameToUse = aNextFrame;
return NS_OK;
}
}
mAnim->lastCompositedFrameIndex = aNextFrameIndex;
*aFrameToUse = mAnim->compositingFrame;
return NS_OK;
}

Просмотреть файл

@ -408,14 +408,12 @@ private:
/** Function for doing the frame compositing of animations
*
* @param aFrameToUse Set by DoComposite
* (aNextFrame, compositingFrame, or compositingPrevFrame)
* @param aDirtyRect Area that the display will need to update
* @param aPrevFrame Last Frame seen/processed
* @param aNextFrame Frame we need to incorperate/display
* @param aNextFrameIndex Position of aNextFrame in mFrames list
*/
nsresult DoComposite(imgFrame** aFrameToUse, nsIntRect* aDirtyRect,
nsresult DoComposite(nsIntRect* aDirtyRect,
imgFrame* aPrevFrame,
imgFrame* aNextFrame,
PRInt32 aNextFrameIndex);

Просмотреть файл

@ -2268,6 +2268,8 @@ function run_single_closure_tests(library, abi, suffix)
function closure_fn(i)
{
if (i == 42)
throw "7.5 million years for that?";
return "a" in this ? i + this.a : i + b;
}
@ -2289,6 +2291,38 @@ function run_single_closure_tests(library, abi, suffix)
let closure2 = fn_t(closure_fn, thisobj);
do_check_eq(closure2(-17), -17 + thisobj.a);
do_check_eq(test_closure(-52, closure2), -52 + thisobj.a);
// Specify an error sentinel, and have the JS code throw (see bug 599791).
let closure3 = fn_t(closure_fn, null, 54);
do_check_eq(closure3(42), 54);
do_check_eq(test_closure(42, closure3), 54);
// Check what happens when the return type is bigger than a word.
var fn_64_t = ctypes.FunctionType(ctypes.default_abi, ctypes.uint64_t, [ctypes.bool]).ptr;
var bignum1 = ctypes.UInt64.join(0xDEADBEEF, 0xBADF00D);
var bignum2 = ctypes.UInt64.join(0xDEFEC8ED, 0xD15EA5E);
function closure_fn_64(fail)
{
if (fail)
throw "Just following orders, sir!";
return bignum1;
};
var closure64 = fn_64_t(closure_fn_64, null, bignum2);
do_check_eq(ctypes.UInt64.compare(closure64(false), bignum1), 0);
do_check_eq(ctypes.UInt64.compare(closure64(true), bignum2), 0);
// Test a callback that returns void (see bug 682504).
var fn_v_t = ctypes.FunctionType(ctypes.default_abi, ctypes.void_t, []).ptr;
fn_v_t(function() {})(); // Don't crash
// Make sure that a void callback can't return an error sentinel.
var sentinelThrew = false;
try {
fn_v_t(function() {}, null, -1);
} catch(e) {
sentinelThrew = true;
}
do_check_true(sentinelThrew);
}
function run_variadic_tests(library) {

Просмотреть файл

@ -43,10 +43,20 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
// Fired by TelemetryPing when async telemetry data should be collected.
const TOPIC_GATHER_TELEMETRY = "gather-telemetry";
// Seconds between maintenance runs.
const MAINTENANCE_INTERVAL_SECONDS = 7 * 86400;
////////////////////////////////////////////////////////////////////////////////
//// Imports
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesDBUtils",
"resource://gre/modules/PlacesDBUtils.jsm");
/**
* This component can be used as a starter for modules that have to run when
@ -54,6 +64,8 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
*/
function PlacesCategoriesStarter()
{
Services.obs.addObserver(this, TOPIC_GATHER_TELEMETRY, false);
Services.obs.addObserver(this, PlacesUtils.TOPIC_SHUTDOWN, false);
}
PlacesCategoriesStarter.prototype = {
@ -63,15 +75,22 @@ PlacesCategoriesStarter.prototype = {
observe: function PCS_observe(aSubject, aTopic, aData)
{
switch (aTopic) {
case PlacesUtils.TOPIC_SHUTDOWN:
Services.obs.removeObserver(this, PlacesUtils.TOPIC_SHUTDOWN);
Services.obs.removeObserver(this, TOPIC_GATHER_TELEMETRY);
break;
case TOPIC_GATHER_TELEMETRY:
PlacesDBUtils.telemetry();
break;
case "idle-daily":
// Once a week run places.sqlite maintenance tasks.
let lastMaintenance = 0;
try {
lastMaintenance = Services.prefs.getIntPref("places.database.lastMaintenance");
lastMaintenance =
Services.prefs.getIntPref("places.database.lastMaintenance");
} catch (ex) {}
let nowSeconds = parseInt(Date.now() / 1000);
if (lastMaintenance < nowSeconds - MAINTENANCE_INTERVAL_SECONDS) {
Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm");
PlacesDBUtils.maintenanceOnIdle();
}
break;

Просмотреть файл

@ -54,6 +54,8 @@ let EXPORTED_SYMBOLS = [ "PlacesDBUtils" ];
const FINISHED_MAINTENANCE_TOPIC = "places-maintenance-finished";
const BYTES_PER_MEBIBYTE = 1048576;
////////////////////////////////////////////////////////////////////////////////
//// Smart getters
@ -115,7 +117,6 @@ let PlacesDBUtils = {
this.checkIntegrity
, this.checkCoherence
, this._refreshUI
, this._telemetry
]);
tasks.callback = aCallback;
tasks.scope = aScope;
@ -861,7 +862,7 @@ let PlacesDBUtils = {
* @param [optional] aTasks
* Tasks object to execute.
*/
_telemetry: function PDBU__telemetry(aTasks)
telemetry: function PDBU_telemetry(aTasks)
{
let tasks = new Tasks(aTasks);
@ -911,7 +912,7 @@ let PlacesDBUtils = {
let DBFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
DBFile.append("places.sqlite");
try {
return parseInt(DBFile.fileSize / 1024);
return parseInt(DBFile.fileSize / BYTES_PER_MEBIBYTE);
} catch (ex) {
return 0;
}
@ -921,7 +922,7 @@ let PlacesDBUtils = {
let DBFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
DBFile.append("places.sqlite-wal");
try {
return parseInt(DBFile.fileSize / 1024);
return parseInt(DBFile.fileSize / BYTES_PER_MEBIBYTE);
} catch (ex) {
return 0;
}

Просмотреть файл

@ -163,7 +163,7 @@ using namespace mozilla::places;
// This is the schema version, update it at any schema change and add a
// corresponding migrateVxx method below.
#define DATABASE_SCHEMA_VERSION 11
#define DATABASE_SCHEMA_VERSION 12
// Filename of the database.
#define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite")
@ -313,6 +313,49 @@ namespace mozilla {
_sqlFragment.AppendLiteral(" AS tags ");
}
/**
* Updates sqlite_stat1 table through ANALYZE.
* Since also nsPlacesExpiration.js executes ANALYZE, the analyzed tables
* must be the same in both components. So ensure they are in sync.
*/
nsresult updateSQLiteStatistics(mozIStorageConnection* aDBConn)
{
nsCOMPtr<mozIStorageAsyncStatement> analyzePlacesStmt;
nsresult rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"ANALYZE moz_places"
), getter_AddRefs(analyzePlacesStmt));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageAsyncStatement> analyzeBookmarksStmt;
rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"ANALYZE moz_bookmarks"
), getter_AddRefs(analyzeBookmarksStmt));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageAsyncStatement> analyzeVisitsStmt;
rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"ANALYZE moz_historyvisits"
), getter_AddRefs(analyzeVisitsStmt));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageAsyncStatement> analyzeInputStmt;
rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"ANALYZE moz_inputhistory"
), getter_AddRefs(analyzeInputStmt));
NS_ENSURE_SUCCESS(rv, rv);
mozIStorageBaseStatement *stmts[] = {
analyzePlacesStmt,
analyzeBookmarksStmt,
analyzeVisitsStmt,
analyzeInputStmt
};
nsCOMPtr<mozIStoragePendingStatement> ps;
rv = aDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull,
getter_AddRefs(ps));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
} // namespace places
} // namespace mozilla
@ -928,6 +971,9 @@ nsNavHistory::InitDB()
rv = UpdateSchemaVersion();
NS_ENSURE_SUCCESS(rv, rv);
rv = updateSQLiteStatistics(mDBConn);
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -254,6 +254,22 @@ function nsPlacesAutoComplete()
// Create our in-memory tables for tab tracking.
initTempTable(db);
// Populate the table with current open pages cache contents.
if (this._openPagesCache.length > 0) {
// Avoid getter re-entrance from the _registerOpenPageQuery lazy getter.
let stmt = this._registerOpenPageQuery =
db.createAsyncStatement(this._registerOpenPageQuerySQL);
let params = stmt.newBindingParamsArray();
for (let i = 0; i < this._openPagesCache.length; i++) {
let bp = params.newBindingParams();
bp.bindByName("page_url", this._openPagesCache[i]);
params.addParams(bp);
}
stmt.bindParameters(params);
stmt.executeAsync();
delete this._openPagesCache;
}
return db;
});
@ -379,20 +395,20 @@ function nsPlacesAutoComplete()
);
});
this._registerOpenPageQuerySQL = "INSERT OR REPLACE INTO moz_openpages_temp "
+ "(url, open_count) "
+ "VALUES (:page_url, "
+ "IFNULL("
+ "("
+ "SELECT open_count + 1 "
+ "FROM moz_openpages_temp "
+ "WHERE url = :page_url "
+ "), "
+ "1"
+ ")"
+ ")";
XPCOMUtils.defineLazyGetter(this, "_registerOpenPageQuery", function() {
return this._db.createAsyncStatement(
"INSERT OR REPLACE INTO moz_openpages_temp (url, open_count) "
+ "VALUES (:page_url, "
+ "IFNULL("
+ "("
+ "SELECT open_count + 1 "
+ "FROM moz_openpages_temp "
+ "WHERE url = :page_url "
+ "), "
+ "1"
+ ")"
+ ")"
);
return this._db.createAsyncStatement(this._registerOpenPageQuerySQL);
});
XPCOMUtils.defineLazyGetter(this, "_unregisterOpenPageQuery", function() {
@ -509,19 +525,33 @@ nsPlacesAutoComplete.prototype = {
//////////////////////////////////////////////////////////////////////////////
//// mozIPlacesAutoComplete
// If the connection has not yet been started, use this local cache. This
// prevents autocomplete from initing the database till the first search.
_openPagesCache: [],
registerOpenPage: function PAC_registerOpenPage(aURI)
{
if (!this._databaseInitialized) {
this._openPagesCache.push(aURI.spec);
return;
}
let stmt = this._registerOpenPageQuery;
stmt.params.page_url = aURI.spec;
stmt.executeAsync();
},
unregisterOpenPage: function PAC_unregisterOpenPage(aURI)
{
if (!this._databaseInitialized) {
let index = this._openPagesCache.indexOf(aURI.spec);
if (index != -1) {
this._openPagesCache.splice(index, 1);
}
return;
}
let stmt = this._unregisterOpenPageQuery;
stmt.params.page_url = aURI.spec;
stmt.executeAsync();
},
@ -613,7 +643,7 @@ nsPlacesAutoComplete.prototype = {
}
}
if (Object.getOwnPropertyDescriptor(this, "_db").value !== undefined) {
if (this._databaseInitialized) {
this._db.asyncClose();
}
}
@ -625,6 +655,9 @@ nsPlacesAutoComplete.prototype = {
//////////////////////////////////////////////////////////////////////////////
//// nsPlacesAutoComplete
get _databaseInitialized()
Object.getOwnPropertyDescriptor(this, "_db").value !== undefined,
/**
* Used to unescape encoded URI strings, and drop information that we do not
* care about for searching.

Просмотреть файл

@ -404,6 +404,8 @@ const EXPIRATION_QUERIES = {
// The following queries are used to adjust the sqlite_stat1 table to help the
// query planner create better queries. These should always be run LAST, and
// are therefore at the end of the object.
// Since also nsNavHistory.cpp executes ANALYZE, the analyzed tables
// must be the same in both components. So ensure they are in sync.
QUERY_ANALYZE_MOZ_PLACES: {
sql: "ANALYZE moz_places",

Просмотреть файл

@ -35,6 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
const CURRENT_SCHEMA_VERSION = 12;
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
const NS_APP_BOOKMARKS_50_FILE = "BMarks";
@ -145,7 +147,7 @@ function readInputStreamData(aStream) {
bistream.setInputStream(aStream);
let expectedData = [];
let avail;
while (avail = bistream.available()) {
while ((avail = bistream.available())) {
expectedData = expectedData.concat(bistream.readByteArray(avail));
}
return expectedData;

Просмотреть файл

@ -2,8 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file tests migration invariants from schema version 10 to schema version
* 11.
* This file tests migration invariants from schema version 10 to the current
* schema version.
*/
////////////////////////////////////////////////////////////////////////////////
@ -296,7 +296,7 @@ function test_final_state()
do_check_true(db.indexExists("moz_bookmarks_guid_uniqueindex"));
do_check_true(db.indexExists("moz_places_guid_uniqueindex"));
do_check_eq(db.schemaVersion, 11);
do_check_eq(db.schemaVersion, CURRENT_SCHEMA_VERSION);
db.close();
run_next_test();

Просмотреть файл

@ -4,7 +4,7 @@
/**
* This file tests migration invariants from a database with schema version 11
* that was then downgraded to a database with a schema version 10. Places
* should then migrate this database to one with a schema version of 11.
* should then migrate this database to one with the current schema version.
*/
////////////////////////////////////////////////////////////////////////////////
@ -109,7 +109,7 @@ function test_final_state()
dbFile.append(kDBName);
let db = Services.storage.openUnsharedDatabase(dbFile);
do_check_eq(db.schemaVersion, 11);
do_check_eq(db.schemaVersion, CURRENT_SCHEMA_VERSION);
db.close();
run_next_test();

Просмотреть файл

@ -2,5 +2,5 @@
head = head_migration.js
tail =
[test_v11_from_v10.js]
[test_v11_from_v10_migrated_from_v11.js]
[test_current_from_v10.js]
[test_current_from_v10_migrated_from_v11.js]

Просмотреть файл

@ -0,0 +1,27 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests sqlite_sta1 table exists, it should be created by analyze, but since
// the tables are empty it won't contain any data.
function run_test() {
do_test_pending();
let stmt = DBConn().createAsyncStatement(
"SELECT ROWID FROM sqlite_stat1"
);
stmt.executeAsync({
_gotResult: false,
handleResult: function(aResultSet) {
this._gotResult = true;
},
handleError: function(aError) {
do_throw("Unexpected error (" + aError.result + "): " + aError.message);
},
handleCompletion: function(aReason) {
do_check_false(this._gotResult);
do_test_finished();
}
});
stmt.finalize();
}

Просмотреть файл

@ -64,8 +64,10 @@ function run_test() {
PlacesUtils.tagging.tagURI(uri, ["tag"]);
PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
// Test generic database probes.
PlacesDBUtils._telemetry();
// Request to gather telemetry data.
Cc["@mozilla.org/places/categoriesStarter;1"]
.getService(Ci.nsIObserver)
.observe(null, "gather-telemetry", null);
waitForAsyncUpdates(continue_test);
}

Просмотреть файл

@ -48,6 +48,7 @@ skip-if = os == "android"
# Bug 676989: test hangs consistently on Android
skip-if = os == "android"
[test_adaptive_bug527311.js]
[test_analyze.js]
[test_annotations.js]
[test_asyncExecuteLegacyQueries.js]
# Bug 676989: test hangs consistently on Android

Просмотреть файл

@ -184,6 +184,11 @@ var satchelFormListener = {
if (!name)
continue;
if (name == 'searchbar-history') {
this.log('addEntry for input name "' + name + '" is denied')
continue;
}
// Limit stored data to 200 characters.
if (name.length > 200 || value.length > 200) {
this.log("skipping input that has a name/value too large");

Просмотреть файл

@ -171,6 +171,12 @@ FormAutoComplete.prototype = {
if (!this._enabled)
return null;
// don't allow form inputs (aField != null) to get results from search bar history
if (aInputName == 'searchbar-history' && aField) {
this.log('autoCompleteSearch for input name "' + aInputName + '" is denied');
return null;
}
this.log("AutoCompleteSearch invoked. Search is: " + aUntrimmedSearchString);
let searchString = aUntrimmedSearchString.trim().toLowerCase();
let result = null;

Просмотреть файл

@ -62,6 +62,10 @@ const MEM_HISTOGRAMS = {
"heap-allocated": "MEMORY_HEAP_ALLOCATED",
"page-faults-hard": "PAGE_FAULTS_HARD"
};
// Seconds of idle time before pinging.
// On idle-daily a gather-telemetry notification is fired, during it probes can
// start asynchronous tasks to gather data. On the next idle the data is sent.
const IDLE_TIMEOUT_SECONDS = 5 * 60;
var gLastMemoryPoll = null;
@ -341,6 +345,10 @@ TelemetryPing.prototype = {
return;
Services.obs.removeObserver(this, "idle-daily");
Services.obs.removeObserver(this, "cycle-collector-begin");
if (this._isIdleObserver) {
idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS);
this._isIdleObserver = false;
}
},
/**
@ -416,11 +424,26 @@ TelemetryPing.prototype = {
this.attachObservers()
}
break;
case "idle-daily":
// Enqueue to main-thread, otherwise components may be inited by the
// idle-daily category and miss the gather-telemetry notification.
Services.tm.mainThread.dispatch((function() {
// Notify that data should be gathered now, since ping will happen soon.
Services.obs.notifyObservers(null, "gather-telemetry", null);
// The ping happens at the first idle of length IDLE_TIMEOUT_SECONDS.
idle.addIdleObserver(this, IDLE_TIMEOUT_SECONDS);
this._isIdleObserver = true;
}).bind(this), Ci.nsIThread.DISPATCH_NORMAL);
break;
case "test-ping":
server = aData;
// fall through
case "idle-daily":
this.send(aTopic, server);
case "idle":
if (this._isIdleObserver) {
idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS);
this._isIdleObserver = false;
}
this.send(aTopic == "idle" ? "idle-daily" : aTopic, server);
break;
}
},

Просмотреть файл

@ -0,0 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Check that TelemetryPing notifies correctly on idle.
Components.utils.import("resource://gre/modules/Services.jsm");
function run_test() {
do_test_pending();
Services.obs.addObserver(function observeTelemetry() {
Services.obs.removeObserver(observeTelemetry, "gather-telemetry");
do_test_finished();
}, "gather-telemetry", false);
Components.classes["@mozilla.org/base/telemetry-ping;1"]
.getService(Components.interfaces.nsIObserver)
.observe(null, "idle-daily", null);
}

Просмотреть файл

@ -6,3 +6,4 @@ tail =
[test_TelemetryPing.js]
# Bug 676989: test fails consistently on Android
# fail-if = os == "android"
[test_TelemetryPing_idle.js]

Просмотреть файл

@ -2651,32 +2651,46 @@ NS_IMETHODIMP nsWindow::HideWindowChrome(bool aShouldHide)
/**************************************************************
*
* SECTION: nsIWidget::Invalidate
* SECTION: nsWindow::Invalidate
*
* Invalidate an area of the client for painting.
*
**************************************************************/
// Invalidate this component visible area
NS_METHOD nsWindow::Invalidate(bool aIsSynchronous)
NS_METHOD nsWindow::Invalidate(bool aIsSynchronous,
bool aEraseBackground,
bool aUpdateNCArea,
bool aIncludeChildren)
{
if (mWnd)
{
if (!mWnd) {
return NS_OK;
}
#ifdef WIDGET_DEBUG_OUTPUT
debug_DumpInvalidate(stdout,
this,
nsnull,
aIsSynchronous,
nsCAutoString("noname"),
(PRInt32) mWnd);
debug_DumpInvalidate(stdout,
this,
nsnull,
aIsSynchronous,
nsCAutoString("noname"),
(PRInt32) mWnd);
#endif // WIDGET_DEBUG_OUTPUT
VERIFY(::InvalidateRect(mWnd, NULL, FALSE));
if (aIsSynchronous) {
VERIFY(::UpdateWindow(mWnd));
}
DWORD flags = RDW_INVALIDATE;
if (aEraseBackground) {
flags |= RDW_ERASE;
}
if (aIsSynchronous) {
flags |= RDW_UPDATENOW;
}
if (aUpdateNCArea) {
flags |= RDW_FRAME;
}
if (aIncludeChildren) {
flags |= RDW_ALLCHILDREN;
}
VERIFY(::RedrawWindow(mWnd, NULL, NULL, flags));
return NS_OK;
}
@ -4687,7 +4701,7 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
// Invalidate the window so that the repaint will
// pick up the new theme.
Invalidate(false);
Invalidate(true, true, true, true);
}
break;
@ -5366,7 +5380,7 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
DispatchStandardEvent(NS_THEMECHANGED);
UpdateGlass();
Invalidate(false);
Invalidate(true, true, true, true);
break;
#endif

Просмотреть файл

@ -145,7 +145,10 @@ public:
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
NS_IMETHOD MakeFullScreen(bool aFullScreen);
NS_IMETHOD HideWindowChrome(bool aShouldHide);
NS_IMETHOD Invalidate(bool aIsSynchronous);
NS_IMETHOD Invalidate(bool aIsSynchronous,
bool aEraseBackground = false,
bool aUpdateNCArea = false,
bool aIncludeChildren = false);
NS_IMETHOD Invalidate(const nsIntRect & aRect, bool aIsSynchronous);
NS_IMETHOD Update();
virtual void* GetNativeData(PRUint32 aDataType);

Просмотреть файл

@ -1289,12 +1289,14 @@ private:
template<class E, PRUint32 N, class Alloc=nsTArrayDefaultAllocator>
class nsAutoTArray : public nsAutoArrayBase<nsTArray<E, Alloc>, N>
{
typedef nsAutoArrayBase<nsTArray<E, Alloc>, N> Base;
public:
nsAutoTArray() {}
template<typename Allocator>
nsAutoTArray(const nsTArray<E, Allocator>& other) {
AppendElements(other);
Base::AppendElements(other);
}
};
@ -1317,12 +1319,14 @@ PR_STATIC_ASSERT(sizeof(nsAutoTArray<PRUint32, 2>) ==
template<class E, PRUint32 N>
class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
{
typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
public:
AutoFallibleTArray() {}
template<typename Allocator>
AutoFallibleTArray(const nsTArray<E, Allocator>& other) {
AppendElements(other);
Base::AppendElements(other);
}
};
@ -1330,12 +1334,14 @@ public:
template<class E, PRUint32 N>
class AutoInfallibleTArray : public nsAutoArrayBase<InfallibleTArray<E>, N>
{
typedef nsAutoArrayBase<InfallibleTArray<E>, N> Base;
public:
AutoInfallibleTArray() {}
template<typename Allocator>
AutoInfallibleTArray(const nsTArray<E, Allocator>& other) {
AppendElements(other);
Base::AppendElements(other);
}
};
#endif