Merge m-c to m-i

This commit is contained in:
Phil Ringnalda 2013-03-25 21:53:39 -07:00
commit cbb612338e
145 changed files with 5498 additions and 4165 deletions

View File

@ -226,7 +226,7 @@ let SocialUI = {
return;
}
}
Social.installProvider(targetDoc.location.href, data, function(manifest) {
Social.installProvider(targetDoc, data, function(manifest) {
this.doActivation(manifest.origin);
}.bind(this));
},

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="s1" id="bad.com@services.mozilla.org"></emItem>
<emItem blockID="s1" id="test1.example.com@services.mozilla.org"></emItem>
</emItems>
</blocklist>

View File

@ -17,10 +17,10 @@ let manifest = { // normal provider
};
let manifest2 = { // used for testing install
name: "provider 2",
origin: "https://example1.com",
sidebarURL: "https://example1.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://example1.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://example1.com/browser/browser/base/content/test/moz.png"
origin: "https://test1.example.com",
sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png"
};
function test() {
@ -174,62 +174,73 @@ var tests = {
// we expect the addon install dialog to appear, we need to accept the
// install from the dialog.
let windowListener = {
info("Waiting for install dialog");
Services.wm.addListener({
onWindowTitleChange: function() {},
onCloseWindow: function() {},
onOpenWindow: function(window) {
var domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
onOpenWindow: function(xulwindow) {
Services.wm.removeListener(this);
var domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
var self = this;
waitForFocus(function() {
self.windowReady(domwindow);
}, domwindow);
},
windowReady: function(window) {
if (window.document.location.href == XPINSTALL_URL) {
info("Saw install dialog");
is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
// Initially the accept button is disabled on a countdown timer
var button = window.document.documentElement.getButton("accept");
var button = domwindow.document.documentElement.getButton("accept");
button.disabled = false;
window.document.documentElement.acceptDialog();
Services.wm.removeListener(windowListener);
}
domwindow.document.documentElement.acceptDialog();
}, domwindow);
}
};
Services.wm.addListener(windowListener);
});
let installFrom = "https://example1.com";
Services.prefs.setCharPref("social.whitelist", "");
is(SocialService.getOriginActivationType(installFrom), "foreign", "testing foriegn install");
Social.installProvider(installFrom, manifest2, function(addonManifest) {
Services.prefs.clearUserPref("social.whitelist");
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
Social.uninstallProvider(addonManifest.origin);
let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
addTab(activationURL, function(tab) {
let doc = tab.linkedBrowser.contentDocument;
let installFrom = doc.nodePrincipal.origin;
Services.prefs.setCharPref("social.whitelist", "");
is(SocialService.getOriginActivationType(installFrom), "foreign", "testing foriegn install");
Social.installProvider(doc, manifest2, function(addonManifest) {
Services.prefs.clearUserPref("social.whitelist");
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
Social.uninstallProvider(addonManifest.origin);
gBrowser.removeTab(tab);
});
});
});
},
testWhitelistInstall: function(next) {
AddonManager.addAddonListener(installListener(next));
let installFrom = "https://example1.com";
Services.prefs.setCharPref("social.whitelist", installFrom);
is(SocialService.getOriginActivationType(installFrom), "whitelist", "testing whitelist install");
Social.installProvider(installFrom, manifest2, function(addonManifest) {
Services.prefs.clearUserPref("social.whitelist");
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
Social.uninstallProvider(addonManifest.origin);
let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
addTab(activationURL, function(tab) {
let doc = tab.linkedBrowser.contentDocument;
let installFrom = doc.nodePrincipal.origin;
Services.prefs.setCharPref("social.whitelist", installFrom);
is(SocialService.getOriginActivationType(installFrom), "whitelist", "testing whitelist install");
Social.installProvider(doc, manifest2, function(addonManifest) {
Services.prefs.clearUserPref("social.whitelist");
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
Social.uninstallProvider(addonManifest.origin);
gBrowser.removeTab(tab);
});
});
});
},
testDirectoryInstall: function(next) {
AddonManager.addAddonListener(installListener(next));
let installFrom = "https://addons.allizom.org";
Services.prefs.setCharPref("social.directories", installFrom);
is(SocialService.getOriginActivationType(installFrom), "directory", "testing directory install");
Social.installProvider(installFrom, manifest2, function(addonManifest) {
Services.prefs.clearUserPref("social.directories");
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
Social.uninstallProvider(addonManifest.origin);
let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
addTab(activationURL, function(tab) {
let doc = tab.linkedBrowser.contentDocument;
let installFrom = doc.nodePrincipal.origin;
Services.prefs.setCharPref("social.directories", installFrom);
is(SocialService.getOriginActivationType(installFrom), "directory", "testing directory install");
Social.installProvider(doc, manifest2, function(addonManifest) {
Services.prefs.clearUserPref("social.directories");
SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
Social.uninstallProvider(addonManifest.origin);
gBrowser.removeTab(tab);
});
});
});
}

View File

@ -11,18 +11,18 @@ let blocklistURL = "http://test:80/browser/browser/base/content/test/social/bloc
let blocklistEmpty = "http://test:80/browser/browser/base/content/test/social/blocklistEmpty.xml";
let manifest = { // normal provider
name: "provider 1",
name: "provider ok",
origin: "https://example.com",
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
};
let manifest_bad = { // normal provider
name: "provider 1",
origin: "https://bad.com",
sidebarURL: "https://bad.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://bad.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://bad.com/browser/browser/base/content/test/moz.png"
name: "provider blocked",
origin: "https://test1.example.com",
sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png"
};
function test() {
@ -40,10 +40,10 @@ var tests = {
var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
.getService(Components.interfaces.nsIBlocklistService);
setAndUpdateBlocklist(blocklistURL, function() {
ok(blocklist.isAddonBlocklisted("bad.com@services.mozilla.org", "0", "0", "0"), "blocking 'blocked'");
ok(!blocklist.isAddonBlocklisted("good.cpm@services.mozilla.org", "0", "0", "0"), "not blocking 'good'");
ok(blocklist.isAddonBlocklisted("test1.example.com@services.mozilla.org", "0", "0", "0"), "blocking 'blocked'");
ok(!blocklist.isAddonBlocklisted("example.com@services.mozilla.org", "0", "0", "0"), "not blocking 'good'");
setAndUpdateBlocklist(blocklistEmpty, function() {
ok(!blocklist.isAddonBlocklisted("bad.com@services.mozilla.org", "0", "0", "0"), "blocklist cleared");
ok(!blocklist.isAddonBlocklisted("test1.example.com@services.mozilla.org", "0", "0", "0"), "blocklist cleared");
next();
});
});
@ -102,20 +102,26 @@ var tests = {
Services.prefs.clearUserPref("social.whitelist");
setAndUpdateBlocklist(blocklistEmpty, next);
}
let installFrom = "https://bad.com";
// whitelist to avoid the 3rd party install dialog, we only want to test
// the blocklist inside installProvider.
Services.prefs.setCharPref("social.whitelist", installFrom);
setAndUpdateBlocklist(blocklistURL, function() {
try {
// expecting an exception when attempting to install a hard blocked
// provider
Social.installProvider(installFrom, manifest_bad, function(addonManifest) {
finish(false);
});
} catch(e) {
finish(true);
}
let activationURL = manifest_bad.origin + "/browser/browser/base/content/test/social/social_activate.html"
addTab(activationURL, function(tab) {
let doc = tab.linkedBrowser.contentDocument;
let installFrom = doc.nodePrincipal.origin;
// whitelist to avoid the 3rd party install dialog, we only want to test
// the blocklist inside installProvider.
Services.prefs.setCharPref("social.whitelist", installFrom);
setAndUpdateBlocklist(blocklistURL, function() {
try {
// expecting an exception when attempting to install a hard blocked
// provider
Social.installProvider(doc, manifest_bad, function(addonManifest) {
gBrowser.removeTab(tab);
finish(false);
});
} catch(e) {
gBrowser.removeTab(tab);
finish(true);
}
});
});
},
testBlockingExistingProvider: function(next) {

View File

@ -251,3 +251,11 @@ function addWindowListener(aURL, aCallback) {
onWindowTitleChange: function(aXULWindow, aNewTitle) { }
});
}
function addTab(url, callback) {
let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
executeSoon(function() {callback(tab)});
}, true);
}

View File

@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 0.7.337
Current extension version is: 0.7.390

View File

@ -0,0 +1,155 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, NetUtil, dump */
'use strict';
var EXPORTED_SYMBOLS = ['PdfRedirector'];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PDF_CONTENT_TYPE = 'application/pdf';
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/NetUtil.jsm');
function getDOMWindow(aChannel) {
var requestor = aChannel.notificationCallbacks ?
aChannel.notificationCallbacks :
aChannel.loadGroup.notificationCallbacks;
var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
return win;
}
function getObjectUrl(window) {
var url;
var element = window.frameElement;
var isOverlay = false;
var params = {};
if (element) {
var tagName = element.nodeName;
while (tagName != 'EMBED' && tagName != 'OBJECT') {
// plugin overlay skipping until the target plugin is found
isOverlay = true;
element = element.parentNode;
if (!element)
throw 'Plugin element is not found';
tagName = element.nodeName;
}
if (tagName == 'EMBED') {
for (var i = 0; i < element.attributes.length; ++i) {
params[element.attributes[i].localName] = element.attributes[i].value;
}
url = params.src;
} else {
for (var i = 0; i < element.childNodes.length; ++i) {
var paramElement = element.childNodes[i];
if (paramElement.nodeType != Ci.nsIDOMNode.ELEMENT_NODE ||
paramElement.nodeName != 'PARAM') {
continue;
}
params[paramElement.getAttribute('name')] =
paramElement.getAttribute('value');
}
var dataAttribute = element.getAttribute('data');
url = dataAttribute || params.movie || params.src;
}
}
if (!url) {
return url; // src is not specified
}
var element = window.frameElement;
// XXX base uri?
var baseUri = !element ? null :
Services.io.newURI(element.ownerDocument.location.href, null, null);
return Services.io.newURI(url, null, baseUri).spec;
}
function PdfRedirector() {
}
PdfRedirector.prototype = {
// properties required for XPCOM registration:
classID: Components.ID('{8cbfd8d0-2042-4976-b3ef-d9dee1efb975}'),
classDescription: 'pdf.js Redirector',
contractID:
'@mozilla.org/streamconv;1?from=application/x-moz-playpreview-pdfjs&to=*/*',
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIStreamConverter,
Ci.nsIStreamListener,
Ci.nsIRequestObserver
]),
// nsIStreamConverter::convert
convert: function(aFromStream, aFromType, aToType, aCtxt) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
// nsIStreamConverter::asyncConvertData
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
// Store the listener passed to us
this.listener = aListener;
},
// nsIStreamListener::onDataAvailable
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
// Do nothing since all the data loading is handled by the viewer.
},
// nsIRequestObserver::onStartRequest
onStartRequest: function(aRequest, aContext) {
// Setup the request so we can use it below.
aRequest.QueryInterface(Ci.nsIChannel);
// Cancel the request so the viewer can handle it.
aRequest.cancel(Cr.NS_BINDING_ABORTED);
var domWindow = getDOMWindow(aRequest);
var pdfUrl = getObjectUrl(domWindow);
if (!pdfUrl) {
Services.console.logStringMessage(
'PdfRedirector.js: PDF location is not specified for OBJECT/EMBED tag');
return;
}
// Create a new channel that is viewer loaded as a resource.
var ioService = Services.io;
var channel = ioService.newChannel(pdfUrl, null, null);
channel.loadGroup = aRequest.loadGroup;
channel.asyncOpen(this.listener, aContext);
},
// nsIRequestObserver::onStopRequest
onStopRequest: function(aRequest, aContext, aStatusCode) {
// Do nothing
}
};
var NSGetFactory = XPCOMUtils.generateNSGetFactory([PdfRedirector]);

View File

@ -337,6 +337,7 @@ ChromeActions.prototype = {
}, '*');
};
var self = this;
this.dataListener.oncomplete =
function ChromeActions_dataListenerComplete(data, errorCode) {
@ -346,7 +347,7 @@ ChromeActions.prototype = {
errorCode: errorCode
}, '*');
delete this.dataListener;
delete self.dataListener;
};
return true;
@ -385,21 +386,19 @@ ChromeActions.prototype = {
var message = getLocalizedString(strings, 'unsupported_feature');
var notificationBox = null;
// Multiple browser windows can be opened, finding one for notification box
var windowsEnum = Services.wm
.getZOrderDOMWindowEnumerator('navigator:browser', true);
while (windowsEnum.hasMoreElements()) {
var win = windowsEnum.getNext();
if (win.closed)
continue;
var browser = win.gBrowser.getBrowserForDocument(domWindow.top.document);
if (browser) {
// right window/browser is found, getting the notification box
notificationBox = win.gBrowser.getNotificationBox(browser);
break;
}
}
if (!notificationBox) {
try {
// Based on MDN's "Working with windows in chrome code"
var mainWindow = domWindow
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
var browser = mainWindow.gBrowser
.getBrowserForDocument(domWindow.top.document);
notificationBox = mainWindow.gBrowser.getNotificationBox(browser);
} catch (e) {
log('Unable to get a notification box for the fallback message');
return;
}

View File

@ -33,11 +33,15 @@ const PDF_CONTENT_TYPE = 'application/pdf';
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://pdf.js.components/PdfStreamConverter.js');
Cu.import('resource://pdf.js.components/PdfRedirector.js');
let Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1',
'nsIMIMEService');
XPCOMUtils.defineLazyServiceGetter(Svc, 'pluginHost',
'@mozilla.org/plugin/host;1',
'nsIPluginHost');
function getBoolPref(aPref, aDefaultValue) {
try {
@ -55,8 +59,10 @@ function getIntPref(aPref, aDefaultValue) {
}
}
// Register/unregister a constructor as a component.
let Factory = {
// Factory that registers/unregisters a constructor as a component.
function Factory() {}
Factory.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
_targetConstructor: null,
@ -193,7 +199,14 @@ let PdfJs = {
if (this._registered)
return;
Factory.register(PdfStreamConverter);
this._pdfStreamConverterFactory = new Factory();
this._pdfStreamConverterFactory.register(PdfStreamConverter);
this._pdfRedirectorFactory = new Factory();
this._pdfRedirectorFactory.register(PdfRedirector);
Svc.pluginHost.registerPlayPreviewMimeType('application/pdf', true,
'data:application/x-moz-playpreview-pdfjs;,');
this._registered = true;
},
@ -201,7 +214,13 @@ let PdfJs = {
if (!this._registered)
return;
Factory.unregister();
this._pdfStreamConverterFactory.unregister();
delete this._pdfStreamConverterFactory;
this._pdfRedirectorFactory.unregister;
delete this._pdfRedirectorFactory;
Svc.pluginHost.unregisterPlayPreviewMimeType('application/pdf');
this._registered = false;
}
};

View File

@ -16,8 +16,8 @@
*/
var PDFJS = {};
PDFJS.version = '0.7.337';
PDFJS.build = 'f58aee1';
PDFJS.version = '0.7.390';
PDFJS.build = '921f321';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@ -832,6 +832,23 @@ var Util = PDFJS.Util = (function UtilClosure() {
return [xt, yt];
};
// Applies the transform to the rectangle and finds the minimum axially
// aligned bounding box.
Util.getAxialAlignedBoundingBox =
function Util_getAxialAlignedBoundingBox(r, m) {
var p1 = Util.applyTransform(r, m);
var p2 = Util.applyTransform(r.slice(2, 4), m);
var p3 = Util.applyTransform([r[0], r[3]], m);
var p4 = Util.applyTransform([r[2], r[1]], m);
return [
Math.min(p1[0], p2[0], p3[0], p4[0]),
Math.min(p1[1], p2[1], p3[1], p4[1]),
Math.max(p1[0], p2[0], p3[0], p4[0]),
Math.max(p1[1], p2[1], p3[1], p4[1])
];
};
Util.inverseTransform = function Util_inverseTransform(m) {
var d = m[0] * m[3] - m[1] * m[2];
return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
@ -2260,6 +2277,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.objs = objs;
this.textLayer = textLayer;
this.imageLayer = imageLayer;
this.groupStack = [];
if (canvasCtx) {
addContextCurrentTransform(canvasCtx);
}
@ -2392,6 +2410,25 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return tmpCanvas;
}
function copyCtxState(sourceCtx, destCtx) {
var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
'globalCompositeOperation', 'font'];
for (var i = 0, ii = properties.length; i < ii; i++) {
var property = properties[i];
if (property in sourceCtx) {
destCtx[property] = sourceCtx[property];
}
}
if ('setLineDash' in sourceCtx) {
destCtx.setLineDash(sourceCtx.getLineDash());
destCtx.lineDashOffset = sourceCtx.lineDashOffset;
} else if ('mozDash' in sourceCtx) {
destCtx.mozDash = sourceCtx.mozDash;
destCtx.mozDashOffset = sourceCtx.mozDashOffset;
}
}
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
var NORMAL_CLIP = {};
@ -2596,6 +2633,22 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.current.fillAlpha = state[1];
this.ctx.globalAlpha = state[1];
break;
case 'BM':
if (value && value.name && (value.name !== 'Normal')) {
var mode = value.name.replace(/([A-Z])/g,
function(c) {
return '-' + c.toLowerCase();
}
).substring(1);
this.ctx.globalCompositeOperation = mode;
if (this.ctx.globalCompositeOperation !== mode) {
warn('globalCompositeOperation "' + mode +
'" is not supported');
}
} else {
this.ctx.globalCompositeOperation = 'source-over';
}
break;
}
}
},
@ -3008,7 +3061,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var character = glyph.fontChar;
var vmetric = glyph.vmetric || defaultVMetrics;
if (vertical) {
var vx = vmetric[1] * fontSize * current.fontMatrix[0];
var vx = glyph.vmetric ? vmetric[1] : glyph.width * 0.5;
vx = -vx * fontSize * current.fontMatrix[0];
var vy = vmetric[2] * fontSize * current.fontMatrix[0];
}
var width = vmetric ? -vmetric[0] : glyph.width;
@ -3083,7 +3137,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
geom.canvasWidth = canvasWidth;
if (vertical) {
var vmetric = font.defaultVMetrics;
geom.x -= vmetric[1] * fontSize * current.fontMatrix[0] /
geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
fontSizeScale * geom.hScale;
geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
fontSizeScale * geom.vScale;
@ -3144,7 +3198,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
if (vertical) {
var fontSizeScale = current.fontSizeScale;
var vmetric = font.defaultVMetrics;
geom.x -= vmetric[1] * fontSize * current.fontMatrix[0] /
geom.x += vmetric[1] * fontSize * current.fontMatrix[0] /
fontSizeScale * geom.hScale;
geom.y += vmetric[2] * fontSize * current.fontMatrix[0] /
fontSizeScale * geom.vScale;
@ -3365,6 +3419,89 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
} while (this.current.paintFormXObjectDepth >= depth);
},
beginGroup: function CanvasGraphics_beginGroup(group) {
this.save();
var currentCtx = this.ctx;
// TODO non-isolated groups - according to Rik at adobe non-isolated
// group results aren't usually that different and they even have tools
// that ignore this setting. Notes from Rik on implmenting:
// - When you encounter an transparency group, create a new canvas with
// the dimensions of the bbox
// - copy the content from the previous canvas to the new canvas
// - draw as usual
// - remove the backdrop alpha:
// alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
// value of your transparency group and 'alphaBackdrop' the alpha of the
// backdrop
// - remove background color:
// colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
if (!group.isolated) {
TODO('Support non-isolated groups.');
}
// TODO knockout - supposedly possible with the clever use of compositing
// modes.
if (group.knockout) {
TODO('Support knockout groups.');
}
var currentTransform = currentCtx.mozCurrentTransform;
if (group.matrix) {
currentCtx.transform.apply(currentCtx, group.matrix);
}
assert(group.bbox, 'Bounding box is required.');
// Based on the current transform figure out how big the bounding box
// will actually be.
var bounds = Util.getAxialAlignedBoundingBox(
group.bbox,
currentCtx.mozCurrentTransform);
// Use ceil in case we're between sizes so we don't create canvas that is
// too small.
var drawnWidth = Math.ceil(bounds[2] - bounds[0]);
var drawnHeight = Math.ceil(bounds[3] - bounds[1]);
var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
var groupCtx = scratchCanvas.getContext('2d');
addContextCurrentTransform(groupCtx);
// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
var offsetX = bounds[0];
var offsetY = bounds[1];
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
// Setup the current ctx so when the group is popped we draw it the right
// location.
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
currentCtx.translate(offsetX, offsetY);
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
copyCtxState(currentCtx, groupCtx);
this.ctx = groupCtx;
this.setGState([
['SMask', 'None'],
['BM', 'Normal'],
['ca', 1],
['CA', 1]
]);
this.groupStack.push(currentCtx);
},
endGroup: function CanvasGraphics_endGroup(group) {
var groupCtx = this.ctx;
this.ctx = this.groupStack.pop();
// Turn off image smoothing to avoid sub pixel interpolation which can
// look kind of blurry for some pdfs.
if ('imageSmoothingEnabled' in this.ctx) {
this.ctx.imageSmoothingEnabled = false;
} else {
this.ctx.mozImageSmoothingEnabled = false;
}
this.ctx.drawImage(groupCtx.canvas, 0, 0);
this.restore();
},
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
if (!domImage) {
@ -3920,7 +4057,7 @@ var Catalog = (function CatalogClosure() {
if (isStream(js)) {
js = bytesToString(js.getBytes());
}
javaScript.push(js);
javaScript.push(stringToPDFString(js));
}
}
return shadow(this, 'javaScript', javaScript);
@ -4385,6 +4522,9 @@ var NameTree = (function NameTreeClosure() {
while (queue.length > 0) {
var i, n;
var obj = xref.fetchIfRef(queue.shift());
if (!isDict(obj)) {
continue;
}
if (obj.has('Kids')) {
var kids = obj.get('Kids');
for (i = 0, n = kids.length; i < n; i++) {
@ -14652,6 +14792,60 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return loadedName;
}
function buildFormXObject(xobj, smask) {
var matrix = xobj.dict.get('Matrix');
var bbox = xobj.dict.get('BBox');
var group = xobj.dict.get('Group');
if (group) {
var groupOptions = {
matrix: matrix,
bbox: bbox,
smask: !!smask,
isolated: false,
knockout: false
};
var groupSubtype = group.get('S');
if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
groupOptions.isolated = group.get('I') || false;
groupOptions.knockout = group.get('K') || false;
// There is also a group colorspace, but since we put everything in
// RGB I'm not sure we need it.
}
fnArray.push('beginGroup');
argsArray.push([groupOptions]);
}
fnArray.push('paintFormXObjectBegin');
argsArray.push([matrix, bbox]);
// This adds the operatorList of the xObj to the current queue.
var depIdx = dependencyArray.length;
// Pass in the current `queue` object. That means the `fnArray`
// and the `argsArray` in this scope is reused and new commands
// are added to them.
self.getOperatorList(xobj,
xobj.dict.get('Resources') || resources,
dependencyArray, queue);
self.getOperatorList(xobj,
xobj.dict.get('Resources') || resources,
dependencyArray, queue);
// Add the dependencies that are required to execute the
// operatorList.
insertDependency(dependencyArray.slice(depIdx));
fnArray.push('paintFormXObjectEnd');
argsArray.push([]);
if (group) {
fnArray.push('endGroup');
argsArray.push([groupOptions]);
}
}
function buildPaintImageXObject(image, inline) {
var dict = image.dict;
var w = dict.get('Width', 'W');
@ -14825,28 +15019,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
);
if ('Form' == type.name) {
var matrix = xobj.dict.get('Matrix');
var bbox = xobj.dict.get('BBox');
fnArray.push('paintFormXObjectBegin');
argsArray.push([matrix, bbox]);
// This adds the operatorList of the xObj to the current queue.
var depIdx = dependencyArray.length;
// Pass in the current `queue` object. That means the `fnArray`
// and the `argsArray` in this scope is reused and new commands
// are added to them.
this.getOperatorList(xobj,
xobj.dict.get('Resources') || resources,
dependencyArray, queue);
// Add the dependencies that are required to execute the
// operatorList.
insertDependency(dependencyArray.slice(depIdx));
fn = 'paintFormXObjectEnd';
buildFormXObject(xobj);
args = [];
continue;
} else if ('Image' == type.name) {
buildPaintImageXObject(xobj, false);
} else {
@ -14905,6 +15080,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case 'FL':
case 'CA':
case 'ca':
case 'BM':
gsStateObj.push([key, value]);
break;
case 'Font':
@ -14914,11 +15090,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
value[1]
]);
break;
case 'BM':
// We support the default so don't trigger the TODO.
if (!isName(value) || value.name != 'Normal')
TODO('graphic state operator ' + key);
break;
case 'SMask':
// We support the default so don't trigger the TODO.
if (!isName(value) || value.name != 'None')
@ -15459,7 +15630,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (properties.vertical) {
var vmetrics = dict.get('DW2') || [880, -1000];
defaultVMetrics = [vmetrics[1], vmetrics[1] / 2, vmetrics[0]];
defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
vmetrics = dict.get('W2');
if (vmetrics) {
for (var i = 0, ii = vmetrics.length; i < ii; i++) {
@ -16073,7 +16244,23 @@ var nonStdFontMap = {
'LucidaConsole': 'Courier',
'LucidaConsole-Bold': 'Courier-Bold',
'LucidaConsole-BoldItalic': 'Courier-BoldOblique',
'LucidaConsole-Italic': 'Courier-Oblique'
'LucidaConsole-Italic': 'Courier-Oblique',
'MS-Gothic': 'MS Gothic',
'MS-Gothic-Bold': 'MS Gothic-Bold',
'MS-Gothic-BoldItalic': 'MS Gothic-BoldItalic',
'MS-Gothic-Italic': 'MS Gothic-Italic',
'MS-Mincho': 'MS Mincho',
'MS-Mincho-Bold': 'MS Mincho-Bold',
'MS-Mincho-BoldItalic': 'MS Mincho-BoldItalic',
'MS-Mincho-Italic': 'MS Mincho-Italic',
'MS-PGothic': 'MS PGothic',
'MS-PGothic-Bold': 'MS PGothic-Bold',
'MS-PGothic-BoldItalic': 'MS PGothic-BoldItalic',
'MS-PGothic-Italic': 'MS PGothic-Italic',
'MS-PMincho': 'MS PMincho',
'MS-PMincho-Bold': 'MS PMincho-Bold',
'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
'MS-PMincho-Italic': 'MS PMincho-Italic',
};
var serifFonts = {
@ -16139,6 +16326,7 @@ var CMapConverterList = {
'90msp-RKSJ-H': sjisToUnicode,
'90msp-RKSJ-V': sjisToUnicode,
'GBK-EUC-H': gbkToUnicode,
'B5pc-H': big5ToUnicode,
'ETenms-B5-H': big5ToUnicode,
'ETenms-B5-V': big5ToUnicode,
};
@ -18164,8 +18352,8 @@ var Font = (function FontClosure() {
}
var bmpLength = i + 1;
var trailingRangesCount = ranges[bmpLength - 1][1] < 0xFFFF ? 1 : 0;
var segCount = bmpLength + trailingRangesCount;
if (ranges[i][1] === 0xFFFF) { ranges[i][1] = 0xFFFE; }
var segCount = bmpLength + 1;
var segCount2 = segCount * 2;
var searchRange = getMaxPower2(segCount) * 2;
var searchEntry = Math.log(segCount) / Math.log(2);
@ -18210,12 +18398,10 @@ var Font = (function FontClosure() {
}
}
if (trailingRangesCount > 0) {
endCount += '\xFF\xFF';
startCount += '\xFF\xFF';
idDeltas += '\x00\x01';
idRangeOffsets += '\x00\x00';
}
endCount += '\xFF\xFF';
startCount += '\xFF\xFF';
idDeltas += '\x00\x01';
idRangeOffsets += '\x00\x00';
var format314 = '\x00\x00' + // language
string16(segCount2) +
@ -18302,6 +18488,14 @@ var Font = (function FontClosure() {
if (firstChar > lastChar) {
return false;
}
stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
var usWinAscent = int16(stream.getBytes(2));
if (usWinAscent === 0) { // makes font unreadable by windows
return false;
}
// OS/2 appears to be valid, resetting some fields
os2.data[8] = os2.data[9] = 0; // IE rejects fonts if fsType != 0
return true;
}
@ -19151,16 +19345,6 @@ var Font = (function FontClosure() {
return names;
}
function isOS2Valid(os2Table) {
var data = os2Table.data;
// usWinAscent == 0 makes font unreadable by windows
var usWinAscent = (data[74] << 8) | data[75];
if (usWinAscent === 0)
return false;
return true;
}
var TTOpsStackDeltas = [
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
@ -19355,12 +19539,6 @@ var Font = (function FontClosure() {
// of missing tables
createOpenTypeHeader(header.version, ttf, numTables);
// Invalid OS/2 can break the font for the Windows
if (os2 && !isOS2Valid(os2)) {
tables.splice(tables.indexOf(os2), 1);
os2 = null;
}
// Ensure the hmtx table contains the advance width and
// sidebearings information for numGlyphs in the maxp table
font.pos = (font.start || 0) + maxp.offset;
@ -21658,10 +21836,19 @@ var CFFParser = (function CFFParserClosure() {
}
return { charStrings: charStrings, seacs: seacs };
},
emptyPrivateDictionary:
function CFFParser_emptyPrivateDictionary(parentDict) {
var privateDict = this.createDict(CFFPrivateDict, [],
parentDict.strings);
parentDict.setByKey(18, [0, 0]);
parentDict.privateDict = privateDict;
},
parsePrivateDict: function CFFParser_parsePrivateDict(parentDict) {
// no private dict, do nothing
if (!parentDict.hasName('Private'))
if (!parentDict.hasName('Private')) {
this.emptyPrivateDictionary(parentDict);
return;
}
var privateOffset = parentDict.getByName('Private');
// make sure the params are formatted correctly
if (!isArray(privateOffset) || privateOffset.length !== 2) {
@ -21672,7 +21859,7 @@ var CFFParser = (function CFFParserClosure() {
var offset = privateOffset[1];
// remove empty dicts or ones that refer to invalid location
if (size === 0 || offset >= this.bytes.length) {
parentDict.removeByName('Private');
this.emptyPrivateDictionary(parentDict);
return;
}
@ -21690,7 +21877,7 @@ var CFFParser = (function CFFParserClosure() {
var relativeOffset = offset + subrsOffset;
// Validate the offset.
if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
privateDict.removeByName('Subrs');
this.emptyPrivateDictionary(parentDict);
return;
}
var subrsIndex = this.parseIndex(relativeOffset);
@ -22371,15 +22558,23 @@ var CFFCompiler = (function CFFCompilerClosure() {
output) {
for (var i = 0, ii = dicts.length; i < ii; ++i) {
var fontDict = dicts[i];
if (!fontDict.privateDict || !fontDict.hasName('Private'))
continue;
assert(fontDict.privateDict && fontDict.hasName('Private'),
'There must be an private dictionary.');
var privateDict = fontDict.privateDict;
var privateDictTracker = new CFFOffsetTracker();
var privateDictData = this.compileDict(privateDict, privateDictTracker);
privateDictTracker.offset(output.length);
var outputLength = output.length;
privateDictTracker.offset(outputLength);
if (!privateDictData.length) {
// The private dictionary was empty, set the output length to zero to
// ensure the offset length isn't out of bounds in the eyes of the
// sanitizer.
outputLength = 0;
}
trackers[i].setEntryLocation('Private',
[privateDictData.length, output.length],
[privateDictData.length, outputLength],
output);
output.add(privateDictData);

View File

@ -826,6 +826,11 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
padding-top: 4px;
}
#viewBookmark[href='#'] {
opacity: .5;
pointer-events: none;
}
.toolbarButton.bookmark::before {
content: url(images/toolbarButton-bookmark.png);
}

View File

@ -1290,6 +1290,7 @@ var PDFView = {
if (PDFView.supportsPrinting) {
pdfDocument.getJavaScript().then(function(javaScript) {
if (javaScript.length) {
console.warn('Warning: JavaScript is not supported');
PDFView.fallback();
}
// Hack to support auto printing.
@ -1363,7 +1364,7 @@ var PDFView = {
self.setTitle(pdfTitle + ' - ' + document.title);
if (info.IsAcroFormPresent) {
// AcroForm/XFA was found
console.warn('Warning: AcroForm/XFA is not supported');
PDFView.fallback();
}
});
@ -1565,55 +1566,52 @@ var PDFView = {
},
getVisiblePages: function pdfViewGetVisiblePages() {
return this.getVisibleElements(this.container,
this.pages, true);
if (!this.isFullscreen) {
return this.getVisibleElements(this.container, this.pages, true);
} else {
// The algorithm in getVisibleElements is broken in fullscreen mode.
var visible = [], page = this.page;
var currentPage = this.pages[page - 1];
visible.push({ id: currentPage.id, view: currentPage });
return { first: currentPage, last: currentPage, views: visible};
}
},
getVisibleThumbs: function pdfViewGetVisibleThumbs() {
return this.getVisibleElements(this.thumbnailContainer,
this.thumbnails);
return this.getVisibleElements(this.thumbnailContainer, this.thumbnails);
},
// Generic helper to find out what elements are visible within a scroll pane.
getVisibleElements: function pdfViewGetVisibleElements(
scrollEl, views, sortByVisibility) {
var currentHeight = 0, view;
var top = scrollEl.scrollTop;
var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
for (var i = 1, ii = views.length; i <= ii; ++i) {
view = views[i - 1];
var visible = [], view;
var currentHeight, viewHeight, hiddenHeight, percentHeight;
var currentWidth, viewWidth;
for (var i = 0, ii = views.length; i < ii; ++i) {
view = views[i];
currentHeight = view.el.offsetTop + view.el.clientTop;
if (currentHeight + view.el.clientHeight > top)
break;
currentHeight += view.el.clientHeight;
}
var visible = [];
// Algorithm broken in fullscreen mode
if (this.isFullscreen) {
var currentPage = this.pages[this.page - 1];
visible.push({
id: currentPage.id,
view: currentPage
});
return { first: currentPage, last: currentPage, views: visible};
}
var bottom = top + scrollEl.clientHeight;
var nextHeight, hidden, percent, viewHeight;
for (; i <= ii && currentHeight < bottom; ++i) {
view = views[i - 1];
viewHeight = view.el.clientHeight;
currentHeight = view.el.offsetTop + view.el.clientTop;
nextHeight = currentHeight + viewHeight;
hidden = Math.max(0, top - currentHeight) +
Math.max(0, nextHeight - bottom);
percent = Math.floor((viewHeight - hidden) * 100.0 / viewHeight);
if ((currentHeight + viewHeight) < top) {
continue;
}
if (currentHeight > bottom) {
break;
}
currentWidth = view.el.offsetLeft + view.el.clientLeft;
viewWidth = view.el.clientWidth;
if ((currentWidth + viewWidth) < left || currentWidth > right) {
continue;
}
hiddenHeight = Math.max(0, top - currentHeight) +
Math.max(0, currentHeight + viewHeight - bottom);
percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
visible.push({ id: view.id, y: currentHeight,
view: view, percent: percent });
currentHeight = nextHeight;
view: view, percent: percentHeight });
}
var first = visible[0];
@ -1622,13 +1620,12 @@ var PDFView = {
if (sortByVisibility) {
visible.sort(function(a, b) {
var pc = a.percent - b.percent;
if (Math.abs(pc) > 0.001)
if (Math.abs(pc) > 0.001) {
return -pc;
}
return a.id - b.id; // ensure stability
});
}
return {first: first, last: last, views: visible};
},
@ -1704,6 +1701,10 @@ var PDFView = {
this.page = this.page;
this.clearMouseScrollState();
this.hidePresentationControls();
// Ensure that the thumbnail of the current page is visible
// when exiting fullscreen mode.
scrollIntoView(document.getElementById('thumbnailContainer' + this.page));
},
showPresentationControls: function pdfViewShowPresentationControls() {
@ -2086,7 +2087,6 @@ var PageView = function pageView(container, pdfPage, id, scale,
var canvas = document.createElement('canvas');
canvas.id = 'page' + this.id;
canvas.mozOpaque = true;
div.appendChild(canvas);
this.canvas = canvas;
@ -2116,13 +2116,10 @@ var PageView = function pageView(container, pdfPage, id, scale,
}
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
// TODO(mack): use data attributes to store these
ctx._scaleX = outputScale.sx;
ctx._scaleY = outputScale.sy;
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
if (outputScale.scaled) {
ctx.scale(outputScale.sx, outputScale.sy);
}
@ -2337,7 +2334,6 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
function getPageDrawContext() {
var canvas = document.createElement('canvas');
canvas.id = 'thumbnail' + id;
canvas.mozOpaque = true;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
@ -2599,7 +2595,7 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) {
var textDiv = document.createElement('div');
// vScale and hScale already contain the scaling to pixel units
var fontHeight = geom.fontSize * geom.vScale;
var fontHeight = geom.fontSize * Math.abs(geom.vScale);
textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale;
textDiv.dataset.fontName = geom.fontName;
@ -3250,7 +3246,8 @@ window.addEventListener('keydown', function keydown(evt) {
// First, handle the key bindings that are independent whether an input
// control is selected or not.
if (cmd == 1 || cmd == 8) { // either CTRL or META key.
if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
// either CTRL or META key with optional SHIFT.
switch (evt.keyCode) {
case 70:
if (!PDFView.supportsIntegratedFind) {

View File

@ -1,4 +1,5 @@
chrome.manifest
components/PdfRedirector.js
components/PdfStreamConverter.js
content/build/pdf.js
content/PdfJs.jsm

View File

@ -45,7 +45,6 @@ var SelectionHandler = {
_contentOffset: { x:0, y:0 },
_domWinUtils: null,
_selectionMoveActive: false,
_lastMarker: "",
_debugOptions: { dumpRanges: false, displayRanges: false },
_snap: true,
@ -189,6 +188,14 @@ var SelectionHandler = {
// We bail if things get out of sync here implying we missed a message.
this._selectionMoveActive = true;
if (this._targetIsEditable) {
// If we're coming out of an out-of-bounds scroll, the node the user is
// trying to drag may be hidden (the monocle will be pegged to the edge
// of the edit). Make sure the node the user wants to move is visible
// and has focus.
this._updateInputFocus(aMsg.change);
}
// Update the position of our selection monocles
this._updateSelectionUI(true, true);
},
@ -594,63 +601,16 @@ var SelectionHandler = {
}
// Adjust our y position up such that we are sending coordinates on
// the text line vs. below it where the monocle is positioned. This
// applies to free floating text areas. For text inputs we'll constrain
// coordinates further below.
// the text line vs. below it where the monocle is positioned.
let halfLineHeight = this._queryHalfLineHeight(aMarker, selection);
clientPoint.yPos -= halfLineHeight;
// Modify selection based on monocle movement
if (this._targetIsEditable) {
// Check to see if we are beyond the bounds of selection in a input
// control. If we are we want to add selection and scroll the added
// selection into view.
let result = this.updateTextEditSelection(clientPoint);
// If we're targeting a text input of any kind, make sure clientPoint
// is contained within the bounds of the text control. For example, if
// a user drags up too close to an upper bounds, selectAtPoint might
// select the content above the control. This looks crappy and breaks
// our selection rect management.
clientPoint =
this._constrainPointWithinControl(clientPoint, halfLineHeight);
// If result.trigger is true, the monocle is outside the bounds of the
// control. If it's false, fall through to our additive text selection
// below.
if (result.trigger) {
// _handleSelectionPoint is triggered by input movement, so if we've
// tested positive for out-of-bounds scrolling here, we need to set a
// recurring timer to keep the expected selection behavior going as
// long as the user keeps the monocle out of bounds.
if (!this._scrollTimer)
this._scrollTimer = new Util.Timeout();
this._setTextEditUpdateInterval(result.speed);
// Smooth the selection
this._setContinuousSelection();
// Update the other monocle's position if we've dragged off to one side
this._updateSelectionUI(result.start, result.end);
return;
}
}
this._lastMarker = aMarker;
// If we aren't out-of-bounds, clear the scroll timer if it exists.
this._clearTimers();
// Adjusts the selection based on monocle movement
this._adjustSelection(aMarker, clientPoint, aEndOfSelection);
// Update the other monocle's position. We do this because the dragging
// monocle may reset the static monocle to a new position if the dragging
// monocle drags ahead or behind the other.
if (aMarker == "start") {
this._updateSelectionUI(false, true);
this._adjustEditableSelection(aMarker, clientPoint,
halfLineHeight, aEndOfSelection);
} else {
this._updateSelectionUI(true, false);
this._adjustSelection(aMarker, clientPoint, aEndOfSelection);
}
},
@ -659,6 +619,59 @@ var SelectionHandler = {
*/
/*
* _adjustEditableSelection
*
* Based on a monocle marker and position, adds or subtracts from the
* existing selection in editable controls. Handles auto-scroll as well.
*
* @param the marker currently being manipulated
* @param aAdjustedClientPoint client point adjusted for line height.
* @param aHalfLineHeight half line height in pixels
* @param aEndOfSelection indicates if this is the end of a selection
* move, in which case we may want to snap to the end of a word or
* sentence.
*/
_adjustEditableSelection: function _adjustEditableSelection(aMarker,
aAdjustedClientPoint,
aHalfLineHeight,
aEndOfSelection) {
// Test to see if we need to handle auto-scroll in cases where the
// monocle is outside the bounds of the control. This also handles
// adjusting selection if out-of-bounds is true.
let result = this.updateTextEditSelection(aAdjustedClientPoint);
// If result.trigger is true, the monocle is outside the bounds of the
// control.
if (result.trigger) {
// _handleSelectionPoint is triggered by input movement, so if we've
// tested positive for out-of-bounds scrolling here, we need to set a
// recurring timer to keep the expected selection behavior going as
// long as the user keeps the monocle out of bounds.
this._setTextEditUpdateInterval(result.speed);
// Smooth the selection
this._setContinuousSelection();
// Update the other monocle's position if we've dragged off to one side
this._updateSelectionUI(result.start, result.end);
} else {
// If we aren't out-of-bounds, clear the scroll timer if it exists.
this._clearTimers();
// Restrict the client point to the interior of the control. Prevents
// _adjustSelection from accidentally selecting content outside the
// control.
let constrainedPoint =
this._constrainPointWithinControl(aAdjustedClientPoint, aHalfLineHeight);
// Add or subtract selection
this._adjustSelection(aMarker, constrainedPoint, aEndOfSelection);
}
},
/*
* _adjustSelection
*
* Based on a monocle marker and position, adds or subtracts from the
* existing selection.
*
@ -707,6 +720,15 @@ var SelectionHandler = {
// Smooth over the selection between all existing ranges.
this._setContinuousSelection();
// Update the other monocle's position. We do this because the dragging
// monocle may reset the static monocle to a new position if the dragging
// monocle drags ahead or behind the other.
if (aMarker == "start") {
this._updateSelectionUI(false, true);
} else {
this._updateSelectionUI(true, false);
}
},
/*
@ -780,9 +802,9 @@ var SelectionHandler = {
/*
* updateTextEditSelection(aPoint, aClientPoint)
*
* Checks to see if the monocle point is outside the bounds of the
* target edit. If so, use the selection controller to select and
* scroll the edit appropriately.
* Checks to see if the monocle point is outside the bounds of the target
* edit. If so, use the selection controller to select and scroll the edit
* appropriately.
*
* @param aClientPoint raw pointer position
* @return { speed: 0.0 -> 1.0,
@ -823,6 +845,8 @@ var SelectionHandler = {
_setTextEditUpdateInterval: function _setTextEditUpdateInterval(aSpeedValue) {
let timeout = (75 - (aSpeedValue * 75));
if (!this._scrollTimer)
this._scrollTimer = new Util.Timeout();
this._scrollTimer.interval(timeout, this.scrollTimerCallback);
},
@ -836,7 +860,6 @@ var SelectionHandler = {
* _addEditSelection - selection control call wrapper for text inputs.
* Adds selection on the anchor or focus side of selection in a text
* input. Scrolls the location into view as well.
* (TBD: anchor side scrolling is currently broken, see bug 848594)
*
* @param const selection node identifier
*/
@ -844,16 +867,32 @@ var SelectionHandler = {
let selCtrl = this._getSelectController();
try {
if (aLocation == kSelectionNodeAnchor) {
this._targetElement.selectionStart = this._targetElement.selectionStart - 1;
selCtrl.scrollSelectionIntoView(Ci.nsISelectionController.SELECTION_NORMAL,
Ci.nsISelectionController.SELECTION_ANCHOR_REGION,
Ci.nsISelectionController.SCROLL_SYNCHRONOUS);
let start = Math.max(this._targetElement.selectionStart - 1, 0);
this._targetElement.setSelectionRange(start, this._targetElement.selectionEnd,
"backward");
} else {
this._targetElement.selectionEnd = this._targetElement.selectionEnd + 1;
selCtrl.scrollSelectionIntoView(Ci.nsISelectionController.SELECTION_NORMAL,
Ci.nsISelectionController.SELECTION_FOCUS_REGION,
Ci.nsISelectionController.SCROLL_SYNCHRONOUS);
let end = Math.min(this._targetElement.selectionEnd + 1,
this._targetElement.textLength);
this._targetElement.setSelectionRange(this._targetElement.selectionStart,
end,
"forward");
}
selCtrl.scrollSelectionIntoView(Ci.nsISelectionController.SELECTION_NORMAL,
Ci.nsISelectionController.SELECTION_FOCUS_REGION,
Ci.nsISelectionController.SCROLL_SYNCHRONOUS);
} catch (ex) { Util.dumpLn(ex);}
},
_updateInputFocus: function _updateInputFocus(aMarker) {
try {
let selCtrl = this._getSelectController();
this._targetElement.setSelectionRange(this._targetElement.selectionStart,
this._targetElement.selectionEnd,
aMarker == "start" ?
"backward" : "forward");
selCtrl.scrollSelectionIntoView(Ci.nsISelectionController.SELECTION_NORMAL,
Ci.nsISelectionController.SELECTION_FOCUS_REGION,
Ci.nsISelectionController.SCROLL_SYNCHRONOUS);
} catch (ex) {}
},

View File

@ -178,8 +178,8 @@ this.Social = {
return null;
},
installProvider: function(origin ,sourceURI, data, installCallback) {
SocialService.installProvider(origin ,sourceURI, data, installCallback);
installProvider: function(doc, data, installCallback) {
SocialService.installProvider(doc, data, installCallback);
},
uninstallProvider: function(origin) {

View File

@ -441,6 +441,12 @@ public class DoCommand {
strReturn += GetProcessInfo();
strReturn += "\n";
strReturn += GetSutUserInfo();
strReturn += "\n";
strReturn += GetDiskInfo("/data");
strReturn += "\n";
strReturn += GetDiskInfo("/system");
strReturn += "\n";
strReturn += GetDiskInfo("/mnt/sdcard");
}
else
{
@ -495,6 +501,15 @@ public class DoCommand {
strReturn += GetTemperatureInfo();
break;
case DISK:
strReturn += "\n";
strReturn += GetDiskInfo("/data");
strReturn += "\n";
strReturn += GetDiskInfo("/system");
strReturn += "\n";
strReturn += GetDiskInfo("/mnt/sdcard");
break;
default:
break;
}
@ -2670,18 +2685,19 @@ private void CancelNotification()
return "Temperature: " + sTempVal;
}
// todo
public String GetDiskInfo(String sPath)
{
String sRet = "";
StatFs statFS = new StatFs(sPath);
int nBlockCount = statFS.getBlockCount();
int nBlockSize = statFS.getBlockSize();
int nBlocksAvail = statFS.getAvailableBlocks();
int nBlocksFree = statFS.getFreeBlocks();
long nBlockCount = statFS.getBlockCount();
long nBlockSize = statFS.getBlockSize();
long nBlocksAvail = statFS.getAvailableBlocks();
// Free is often the same as Available, but can include reserved
// blocks that are not available to normal applications.
// long nBlocksFree = statFS.getFreeBlocks();
sRet = "total: " + (nBlockCount * nBlockSize) + "\nfree: " + (nBlocksFree * nBlockSize) + "\navailable: " + (nBlocksAvail * nBlockSize);
sRet = sPath + ": " + (nBlockCount * nBlockSize) + " total, " + (nBlocksAvail * nBlockSize) + " available";
return (sRet);
}

View File

@ -70,7 +70,7 @@ GCONF_VERSION=1.2.1
GIO_VERSION=2.20
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.7.15.2
SQLITE_VERSION=3.7.16
MSMANIFEST_TOOL=

View File

@ -18,8 +18,8 @@ class nsTextControlFrame;
// IID for the nsITextControl interface
#define NS_ITEXTCONTROLELEMENT_IID \
{ 0x3558afa1, 0x6136, 0x4421, \
{ 0xbd, 0xdc, 0x2c, 0x9d, 0x5f, 0xc1, 0xfb, 0x91 } }
{ 0x3dd53b59, 0x9d8f, 0x40a3, \
{ 0x81, 0xd7, 0xb3, 0x43, 0xa0, 0x51, 0xfc, 0xb5 } }
/**
* This interface is used for the text control frame to get the editor and
@ -76,6 +76,11 @@ public:
*/
NS_IMETHOD_(int32_t) GetRows() = 0;
/**
* Get the default value of the text control
*/
NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue) = 0;
/**
* Return true if the value of the control has been changed.
*/

View File

@ -353,6 +353,9 @@ HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
bool previousValue = mValueChanged;
mValueChanged = aValueChanged;
if (!aValueChanged && !mState.IsEmpty()) {
mState.EmptyValue();
}
if (mValueChanged != previousValue) {
UpdateState(true);
@ -1379,6 +1382,12 @@ HTMLTextAreaElement::GetRows()
return DEFAULT_ROWS_TEXTAREA;
}
NS_IMETHODIMP_(void)
HTMLTextAreaElement::GetDefaultValueFromContent(nsAString& aValue)
{
GetDefaultValue(aValue);
}
NS_IMETHODIMP_(bool)
HTMLTextAreaElement::ValueChanged() const
{

View File

@ -87,6 +87,7 @@ public:
NS_IMETHOD_(int32_t) GetCols();
NS_IMETHOD_(int32_t) GetWrapCols();
NS_IMETHOD_(int32_t) GetRows();
NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue);
NS_IMETHOD_(bool) ValueChanged() const;
NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, bool aIgnoreWrap) const;
NS_IMETHOD_(nsIEditor*) GetTextEditor();

View File

@ -5557,6 +5557,20 @@ nsHTMLInputElement::GetRows()
return DEFAULT_ROWS;
}
NS_IMETHODIMP_(void)
nsHTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
{
nsTextEditorState *state = GetEditorState();
if (state) {
GetDefaultValue(aValue);
// This is called by the frame to show the value.
// We have to sanitize it when needed.
if (!mParserCreating) {
SanitizeValue(aValue);
}
}
}
NS_IMETHODIMP_(bool)
nsHTMLInputElement::ValueChanged() const
{

View File

@ -147,6 +147,7 @@ public:
NS_IMETHOD_(int32_t) GetCols();
NS_IMETHOD_(int32_t) GetWrapCols();
NS_IMETHOD_(int32_t) GetRows();
NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue);
NS_IMETHOD_(bool) ValueChanged() const;
NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, bool aIgnoreWrap) const;
NS_IMETHOD_(nsIEditor*) GetTextEditor();

View File

@ -1747,7 +1747,9 @@ nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
mCachedValue.Truncate();
}
} else {
if (mValue) {
if (!mTextCtrlElement->ValueChanged() || !mValue) {
mTextCtrlElement->GetDefaultValueFromContent(aValue);
} else {
aValue = NS_ConvertUTF8toUTF16(*mValue);
}
}

View File

@ -137,6 +137,8 @@ public:
void SetValue(const nsAString& aValue, bool aUserInput,
bool aSetValueAsChanged);
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
void EmptyValue() { if (mValue) mValue->Truncate(); }
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
nsresult CreatePlaceholderNode();

View File

@ -2282,96 +2282,81 @@ nsHTMLDocument::Plugins()
return Embeds();
}
nsresult
nsHTMLDocument::ResolveName(const nsAString& aName,
nsIContent *aForm,
nsISupports **aResult,
nsWrapperCache **aCache)
nsISupports*
nsHTMLDocument::ResolveName(const nsAString& aName, nsWrapperCache **aCache)
{
*aResult = nullptr;
*aCache = nullptr;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
if (!entry) {
return NS_OK;
*aCache = nullptr;
return nullptr;
}
uint32_t length = 0;
nsBaseContentList *list = entry->GetNameContentList();
if (list) {
list->GetLength(&length);
}
uint32_t length = list ? list->Length() : 0;
if (length > 0) {
if (length == 1) {
// Only one element in the list, return the element instead of
// returning the list
// Only one element in the list, return the element instead of returning
// the list.
nsIContent *node = list->Item(0);
if (!aForm || nsContentUtils::BelongsInForm(aForm, node)) {
NS_ADDREF(*aResult = node);
*aCache = node;
}
return NS_OK;
*aCache = node;
return node;
}
// The list contains more than one element, return the whole
// list, unless...
if (aForm) {
// ... we're called from a form, in that case we create a
// nsFormContentList which will filter out the elements in the
// list that don't belong to aForm
nsFormContentList *fc_list = new nsFormContentList(aForm, *list);
NS_ENSURE_TRUE(fc_list, NS_ERROR_OUT_OF_MEMORY);
uint32_t len;
fc_list->GetLength(&len);
if (len < 2) {
// After the nsFormContentList is done filtering there's either
// nothing or one element in the list. Return that element, or null
// if there's no element in the list.
nsIContent *node = fc_list->Item(0);
NS_IF_ADDREF(*aResult = node);
*aCache = node;
delete fc_list;
return NS_OK;
}
list = fc_list;
}
return CallQueryInterface(list, aResult);
// The list contains more than one element, return the whole list.
*aCache = list;
return list;
}
// No named items were found, see if there's one registerd by id for
// aName. If we get this far, FindNamedItems() will have been called
// for aName, so we're guaranteed that if there is an element with
// the id aName, it'll be entry's IdContent.
// No named items were found, see if there's one registerd by id for aName.
Element *e = entry->GetIdElement();
if (e && e->IsHTML()) {
nsIAtom *tag = e->Tag();
if ((tag == nsGkAtoms::embed ||
tag == nsGkAtoms::img ||
tag == nsGkAtoms::object ||
tag == nsGkAtoms::applet) &&
(!aForm || nsContentUtils::BelongsInForm(aForm, e))) {
NS_ADDREF(*aResult = e);
if (tag == nsGkAtoms::embed ||
tag == nsGkAtoms::img ||
tag == nsGkAtoms::object ||
tag == nsGkAtoms::applet) {
*aCache = e;
return e;
}
}
return NS_OK;
*aCache = nullptr;
return nullptr;
}
already_AddRefed<nsISupports>
nsHTMLDocument::ResolveName(const nsAString& aName,
nsIContent *aForm,
nsWrapperCache **aCache)
{
nsISupports* result = ResolveName(aName, aCache);
if (!result) {
return nullptr;
}
nsCOMPtr<nsIContent> node = do_QueryInterface(result);
if (!node) {
// We create a nsFormContentList which will filter out the elements in the
// list that don't belong to aForm.
nsRefPtr<nsBaseContentList> list =
new nsFormContentList(aForm, *static_cast<nsBaseContentList*>(result));
if (list->Length() > 1) {
*aCache = list;
return list.forget();
}
// After the nsFormContentList is done filtering there's either nothing or
// one element in the list. Return that element, or null if there's no
// element in the list.
node = list->Item(0);
} else if (!nsContentUtils::BelongsInForm(aForm, node)) {
node = nullptr;
}
*aCache = node;
return node.forget();
}
//----------------------------

View File

@ -114,10 +114,10 @@ public:
nsWrapperCache **aCache,
nsresult *aResult);
virtual nsresult ResolveName(const nsAString& aName,
nsIContent *aForm,
nsISupports **aResult,
nsWrapperCache **aCache);
nsISupports* ResolveName(const nsAString& aName, nsWrapperCache **aCache);
virtual already_AddRefed<nsISupports> ResolveName(const nsAString& aName,
nsIContent *aForm,
nsWrapperCache **aCache);
virtual void AddedForm();
virtual void RemovedForm();

View File

@ -33,10 +33,9 @@ public:
*/
virtual void SetCompatibilityMode(nsCompatibility aMode) = 0;
virtual nsresult ResolveName(const nsAString& aName,
nsIContent *aForm,
nsISupports **aResult,
nsWrapperCache **aCache) = 0;
virtual already_AddRefed<nsISupports> ResolveName(const nsAString& aName,
nsIContent *aForm,
nsWrapperCache **aCache) = 0;
/**
* Called when form->BindToTree() is called so that document knows

View File

@ -108,7 +108,7 @@ AudioContext::CreateGain()
already_AddRefed<DelayNode>
AudioContext::CreateDelay(double aMaxDelayTime, ErrorResult& aRv)
{
if (aMaxDelayTime > 0. && aMaxDelayTime < 3.) {
if (aMaxDelayTime > 0. && aMaxDelayTime < 180.) {
nsRefPtr<DelayNode> delayNode = new DelayNode(this, aMaxDelayTime);
return delayNode.forget();
}

View File

@ -57,7 +57,7 @@ addLoadEvent(function() {
context.createDelay(0);
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
context.createDelay(3);
context.createDelay(180);
}, DOMException.NOT_SUPPORTED_ERR);
expectTypeError(function() {
context.createDelay(NaN);

View File

@ -1,6 +1,6 @@
This is sqlite 3.7.15.2
This is sqlite 3.7.16
-- Ryan VanderMeulen <ryanvm@gmail.com>, 01/2013
-- Ryan VanderMeulen <ryanvm@gmail.com>, 03/2013
See http://www.sqlite.org/ for more info.

File diff suppressed because it is too large Load Diff

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.7.15.2"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID "2013-01-09 11:53:05 c0e09560d26f0a6456be9dd3447f5311eb4f238f"
#define SQLITE_VERSION "3.7.16"
#define SQLITE_VERSION_NUMBER 3007016
#define SQLITE_SOURCE_ID "2013-03-18 11:39:23 66d5f2b76750f3520eb7a495f6247206758f5b90"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -288,7 +288,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
** with the [sqlite3] object prior to attempting to close the object. ^If
** sqlite3_close() is called on a [database connection] that still has
** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles],
@ -483,7 +483,17 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
/*
** CAPI3REF: Flags For File Open Operations

View File

@ -14,21 +14,24 @@
"use strict";
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function() {
if (SpecialPowers.hasPermission("alarms", document)) {
SpecialPowers.removePermission("alarms", document);
window.location.reload();
} else {
SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function() {
SpecialPowers.removePermission("alarms", document);
// mozAlarms is intalled on all platforms except Android for the moment.
if (navigator.appVersion.indexOf("Android") != -1) {
ok(!('mozAlarms' in navigator), "navigator.mozAlarms should not exist");
} else {
ok('mozAlarms' in navigator, "navigator.mozAlarms should exist");
is(navigator.mozAlarms, null, "navigator.mozAlarms should return null");
}
SimpleTest.finish();
});
// mozAlarms is intalled on all platforms except Android for the moment.
if (navigator.appVersion.indexOf("Android") != -1) {
ok(!('mozAlarms' in navigator), "navigator.mozAlarms should not exist");
} else {
ok('mozAlarms' in navigator, "navigator.mozAlarms should exist");
is(navigator.mozAlarms, null, "navigator.mozAlarms should return null");
}
SpecialPowers.addPermission("alarms", true, document);
SimpleTest.finish();
});
}
</script>
</pre>
</body>

View File

@ -28,7 +28,6 @@ SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function()
"navigator.mozAlarms should be an nsIDOMMozAlarmsManager object");
}
SpecialPowers.removePermission("alarms", document);
SimpleTest.finish();
});

View File

@ -9,6 +9,7 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
this.EXPORTED_SYMBOLS = ["FreeSpaceWatcher"];
@ -42,15 +43,7 @@ this.FreeSpaceWatcher = {
currentStatus: null,
notify: function(aTimer) {
try {
let deviceStorage = Services.wm.getMostRecentWindow("navigator:browser")
.navigator.getDeviceStorage("apps");
let req = deviceStorage.freeSpace();
req.onsuccess = req.onerror = function statResult(e) {
if (!e.target.result) {
return;
}
let freeBytes = e.target.result;
let checkFreeSpace = function (freeBytes) {
debug("Free bytes: " + freeBytes);
let newStatus = freeBytes > aThreshold;
if (newStatus != callback.currentStatus) {
@ -58,8 +51,44 @@ this.FreeSpaceWatcher = {
aOnStatusChange(newStatus ? "free" : "full");
callback.currentStatus = newStatus;
}
};
let deviceStorage = Services.wm.getMostRecentWindow("navigator:browser")
.navigator.getDeviceStorage("apps");
if (deviceStorage) {
let req = deviceStorage.freeSpace();
req.onsuccess = req.onerror = function statResult(e) {
if (!e.target.result) {
return;
}
let freeBytes = e.target.result;
checkFreeSpace(freeBytes);
}
} else {
// deviceStorage isn't available, so use the webappsDir instead.
// This needs to be moved from a hardcoded string to DIRECTORY_NAME
// in AppsUtils. See bug 852685.
let dir = FileUtils.getDir("webappsDir", ["webapps"], true, true);
let freeBytes;
try {
freeBytes = dir.diskSpaceAvailable;
} catch(e) {
// If disk space information isn't available, we should assume
// that there is enough free space, and that we'll fail when
// we actually run out of disk space.
callback.currentStatus = true;
}
if (freeBytes) {
// We have disk space information. Call this here so that
// any exceptions are caught in the outer catch block.
checkFreeSpace(freeBytes);
}
}
} catch(e) { debug(e); }
} catch(e) {
// If the aOnStatusChange callback has errored we'll end up here.
debug(e);
}
}
}

View File

@ -267,6 +267,8 @@ WebappsRegistry.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationRegistry,
#ifdef MOZ_B2G
Ci.mozIDOMApplicationRegistry2,
#elifdef MOZ_WIDGET_ANDROID
Ci.mozIDOMApplicationRegistry2,
#endif
Ci.nsIDOMGlobalPropertyInitializer]),
@ -275,6 +277,8 @@ WebappsRegistry.prototype = {
interfaces: [Ci.mozIDOMApplicationRegistry,
#ifdef MOZ_B2G
Ci.mozIDOMApplicationRegistry2,
#elifdef MOZ_WIDGET_ANDROID
Ci.mozIDOMApplicationRegistry2,
#endif
],
flags: Ci.nsIClassInfo.DOM_OBJECT,

View File

@ -1799,7 +1799,9 @@ this.DOMApplicationRegistry = {
delete this.queuedDownload[aManifestURL];
},
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
confirmInstall: function(aData, aFromSync, aProfileDir,
aOfflineCacheObserver,
aZipDownloadSuccessCallback) {
let isReinstall = false;
let app = aData.app;
app.removable = true;
@ -1956,6 +1958,9 @@ this.DOMApplicationRegistry = {
manifestURL: appObject.manifestURL,
app: app,
manifest: aManifest });
if (aZipDownloadSuccessCallback) {
aZipDownloadSuccessCallback(aManifest);
}
}).bind(this));
}).bind(this));
}
@ -2401,28 +2406,45 @@ this.DOMApplicationRegistry = {
sendProgressEvent();
};
let checkDownloadSize = function (freeBytes) {
if (freeBytes) {
debug("Free storage: " + freeBytes + ". Download size: " +
aApp.downloadSize);
if (freeBytes <=
aApp.downloadSize + AppDownloadManager.MIN_REMAINING_FREESPACE) {
cleanup("INSUFFICIENT_STORAGE");
return;
}
}
download();
};
let deviceStorage = Services.wm.getMostRecentWindow("navigator:browser")
.navigator.getDeviceStorage("apps");
let req = deviceStorage.freeSpace();
req.onsuccess = req.onerror = function statResult(e) {
// Even if we could not retrieve the device storage free space, we try
// to download the package.
if (!e.target.result) {
download();
return;
}
let freeBytes = e.target.result;
if (freeBytes) {
debug("Free storage: " + freeBytes + ". Download size: " +
aApp.downloadSize);
if (freeBytes <=
aApp.downloadSize + AppDownloadManager.MIN_REMAINING_FREESPACE) {
cleanup("INSUFFICIENT_STORAGE");
if (deviceStorage) {
let req = deviceStorage.freeSpace();
req.onsuccess = req.onerror = function statResult(e) {
// Even if we could not retrieve the device storage free space, we try
// to download the package.
if (!e.target.result) {
download();
return;
}
let freeBytes = e.target.result;
checkDownloadSize(freeBytes);
}
} else {
// deviceStorage isn't available, so use FileUtils to find the size of available storage.
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true);
try {
checkDownloadSize(dir.diskSpaceAvailable);
} catch(ex) {
// If disk space information isn't available, we'll end up here.
// We should either proceed anyway, otherwise devices that support neither
// deviceStorage nor diskSpaceAvailable will never be able to install packaged apps.
download();
}
download();
}
},

View File

@ -3637,7 +3637,7 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj,
}
if (!result) {
document->ResolveName(str, nullptr, getter_AddRefs(result), &cache);
result = document->ResolveName(str, &cache);
}
if (result) {
@ -6612,7 +6612,8 @@ ResolveImpl(JSContext *cx, nsIXPConnectWrappedNative *wrapper, jsid id,
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, str), NS_ERROR_UNEXPECTED);
return doc->ResolveName(depStr, nullptr, result, aCache);
NS_IF_ADDREF(*result = doc->ResolveName(depStr, aCache));
return NS_OK;
}
@ -7218,7 +7219,7 @@ nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, jsid id,
do_QueryInterface(content->GetDocument());
if (html_doc && content) {
html_doc->ResolveName(name, content, aResult, aCache);
*aResult = html_doc->ResolveName(name, content, aCache).get();
}
}

View File

@ -467,6 +467,7 @@ BluetoothOppManager::AfterOppDisconnected()
mConnected = false;
mLastCommand = 0;
mBlob = nullptr;
mPacketLeftLength = 0;
// We can't reset mSuccessFlag here since this function may be called
// before we send system message of transfer complete

View File

@ -3,7 +3,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_DIRS += ['test']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
TEST_DIRS += ['test']
XPIDL_SOURCES += [
'nsIDOMPowerManager.idl',

View File

@ -19,24 +19,24 @@ SimpleTest.waitForExplicitFinish();
function startTest() {
window.frames[0].frameElement.setAttribute('onload', 'doTest2()');
power = window.frames[0].navigator.mozPower;
ok(!power, "Shouldn't be able to access power manager without permission.");
SpecialPowers.addPermission("power", true, window.frames[0].document);
window.frames[0].location.reload();
}
function doTest2() {
window.frames[0].frameElement.setAttribute('onload', 'doTest3()');
power = window.frames[0].navigator.mozPower;
ok(power, "Should be able to access power manager with permission.");
SpecialPowers.removePermission("power", window.frames[0].document);
window.frames[0].location.reload();
}
function doTest2() {
window.frames[0].frameElement.setAttribute('onload', 'doTest3()');
power = window.frames[0].navigator.mozPower;
ok(!power, "Shouldn't be able to access power manager with permission.");
SpecialPowers.addPermission("power",true, window.frames[0].document);
window.frames[0].location.reload();
}
function doTest3() {
power = window.frames[0].navigator.mozPower;
ok(!power, "Shouldn't be able to access power manager without permission.");
ok(power, "Should be able to access power manager with permission.");
SimpleTest.finish();
}
</script>

View File

@ -204,6 +204,8 @@ win32-gdi-font-cache-no-HFONT.patch: Bug 717178, don't cache GDI font faces when
fix-win32-font-assertion.patch: Bug 838617, fix assertion from bug 717178 that was in the wrong place
xlib-flush-glyphs.patch: bug 839745, flush glyphs when necessary
==== pixman patches ====
pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.

View File

@ -55,8 +55,10 @@
#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-region-private.h"
#include "cairo-xlib-xrender-private.h"
#include <X11/Xutil.h> /* for XDestroyImage */
#include <X11/Xlibint.h> /* for access to XDisplay's innards */
#define XLIB_COORD_MAX 32767
@ -73,7 +75,6 @@
#endif
#if DEBUG
#include <X11/Xlibint.h>
static void CAIRO_PRINTF_FORMAT (2, 3)
_x_bread_crumb (Display *dpy,
const char *fmt,
@ -4318,6 +4319,13 @@ _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
}
/* XXX assume X server wants pixman padding. Xft assumes this as well */
struct _XDisplay *dpy = (struct _XDisplay *) display->display;
int req_length = sz_xRenderAddGlyphsReq + 4;
if (req_length & 3)
req_length += 4 - (req_length & 3);
if (dpy->bufptr + req_length > dpy->bufmax)
XFlush (display->display);
XRenderAddGlyphs (display->display, glyphset_info->glyphset,
&glyph_index, &glyph_info, 1,
(char *) data,

View File

@ -0,0 +1,66 @@
diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface.c b/gfx/cairo/cairo/src/cairo-xlib-surface.c
index f0de3c7..e24c962 100644
--- a/gfx/cairo/cairo/src/cairo-xlib-surface.c
+++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c
@@ -50,35 +50,36 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-scaled-font-private.h"
#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-region-private.h"
+#include "cairo-xlib-xrender-private.h"
#include <X11/Xutil.h> /* for XDestroyImage */
+#include <X11/Xlibint.h> /* for access to XDisplay's innards */
#define XLIB_COORD_MAX 32767
#define DEBUG 0
#if DEBUG
#define UNSUPPORTED(reason) \
fprintf (stderr, \
"cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \
__FUNCTION__, __LINE__, reason), \
CAIRO_INT_STATUS_UNSUPPORTED
#else
#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
#endif
#if DEBUG
-#include <X11/Xlibint.h>
static void CAIRO_PRINTF_FORMAT (2, 3)
_x_bread_crumb (Display *dpy,
const char *fmt,
...)
{
xReq *req;
char buf[2048];
unsigned int len, len_dwords;
@@ -4313,16 +4314,23 @@ _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
}
break;
default:
ASSERT_NOT_REACHED;
break;
}
/* XXX assume X server wants pixman padding. Xft assumes this as well */
+ struct _XDisplay *dpy = (struct _XDisplay *) display->display;
+ int req_length = sz_xRenderAddGlyphsReq + 4;
+ if (req_length & 3)
+ req_length += 4 - (req_length & 3);
+ if (dpy->bufptr + req_length > dpy->bufmax)
+ XFlush (display->display);
+
XRenderAddGlyphs (display->display, glyphset_info->glyphset,
&glyph_index, &glyph_info, 1,
(char *) data,
glyph_surface->stride * glyph_surface->height);
if (data != glyph_surface->data)
free (data);

View File

@ -379,7 +379,17 @@ gfxPlatform::Init()
= do_CreateInstance("@mozilla.org/gfx/init;1");
if (Preferences::GetBool("gfx.2d.recording", false)) {
gPlatform->mRecorder = Factory::CreateEventRecorderForFile("browserrecording.aer");
nsAutoCString fileName;
nsAdoptingString prefFileName = Preferences::GetString("gfx.2d.recordingfile");
if (prefFileName) {
fileName.Append(NS_ConvertUTF16toUTF8(prefFileName));
} else {
fileName.AssignLiteral("browserrecording.aer");
}
gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
}

View File

@ -53,4 +53,5 @@ Includes = (
'nsTArray.h',
'nsIFile.h',
'mozilla/ipc/ProtocolUtils.h',
'GeckoProfiler.h'
)

View File

@ -4932,6 +4932,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
args=[ ExprLiteral.String(md.prettyMsgName(self.protocol.name
+'::')) ])),
self.logMessage(md, md.msgCast(msgexpr), 'Received '),
self.profilerLabel('Recv', md.decl.progname),
Whitespace.NL
])
@ -4986,13 +4987,13 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return stmts
def sendAsync(self, md, msgexpr, actor=None):
sendok = ExprVar('__sendok')
return (
sendok,
([ Whitespace.NL,
self.logMessage(md, msgexpr, 'Sending ') ]
self.logMessage(md, msgexpr, 'Sending '),
self.profilerLabel('AsyncSend', md.decl.progname) ]
+ self.transition(md, 'out', actor)
+ [ Whitespace.NL,
StmtDecl(Decl(Type.BOOL, sendok.name),
@ -5008,7 +5009,8 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return (
sendok,
([ Whitespace.NL,
self.logMessage(md, msgexpr, 'Sending ') ]
self.logMessage(md, msgexpr, 'Sending '),
self.profilerLabel('Send', md.decl.progname) ]
+ self.transition(md, 'out', actor)
+ [ Whitespace.NL,
StmtDecl(
@ -5084,6 +5086,11 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
args=[ ExprLiteral.String('['+ actorname +'] '+ pfx),
ExprVar('stderr') ])) ])
def profilerLabel(self, tag, msgname):
return StmtExpr(ExprCall(ExprVar('PROFILER_LABEL'),
[ ExprLiteral.String('IPDL::' + self.protocol.name),
ExprLiteral.String(tag + msgname) ]))
def saveActorId(self, md):
idvar = ExprVar('__id')
if md.decl.type.hasReply():

View File

@ -79,13 +79,13 @@ ParallelArrayObject::initProps(JSContext *cx, HandleObject obj)
RootedValue undef(cx, UndefinedValue());
RootedValue zero(cx, Int32Value(0));
if (!JSObject::setProperty(cx, obj, obj, cx->names().buffer, &undef, true))
if (!JSObject::defineProperty(cx, obj, cx->names().buffer, undef))
return false;
if (!JSObject::setProperty(cx, obj, obj, cx->names().offset, &zero, true))
if (!JSObject::defineProperty(cx, obj, cx->names().offset, zero))
return false;
if (!JSObject::setProperty(cx, obj, obj, cx->names().shape, &undef, true))
if (!JSObject::defineProperty(cx, obj, cx->names().shape, undef))
return false;
if (!JSObject::setProperty(cx, obj, obj, cx->names().get, &undef, true))
if (!JSObject::defineProperty(cx, obj, cx->names().get, undef))
return false;
return true;

View File

@ -46,7 +46,7 @@ ParseContext<ParseHandler>::ParseContext(Parser<ParseHandler> *prs, SharedContex
decls_(prs->context),
args_(prs->context),
vars_(prs->context),
yieldNode(ParseHandler::null()),
yieldOffset(0),
parserPC(&prs->pc),
lexdeps(prs->context),
parent(prs->pc),

View File

@ -332,12 +332,9 @@ ParseContext<ParseHandler>::generateFunctionBindings(JSContext *cx, InternalHand
template <typename ParseHandler>
bool
Parser<ParseHandler>::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...)
Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
unsigned errorNumber, va_list args)
{
uint32_t offset = (pn ? handler.getPosition(pn) : tokenStream.currentToken().pos).begin;
va_list args;
va_start(args, errorNumber);
bool result = false;
switch (kind) {
case ParseError:
@ -354,6 +351,30 @@ Parser<ParseHandler>::report(ParseReportKind kind, bool strict, Node pn, unsigne
result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
break;
}
return result;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...)
{
uint32_t offset = (pn ? handler.getPosition(pn) : tokenStream.currentToken().pos).begin;
va_list args;
va_start(args, errorNumber);
bool result = reportHelper(kind, strict, offset, errorNumber, args);
va_end(args);
return result;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset,
unsigned errorNumber, ...)
{
va_list args;
va_start(args, errorNumber);
bool result = reportHelper(kind, strict, offset, errorNumber, args);
va_end(args);
return result;
}
@ -2882,7 +2903,7 @@ Parser<ParseHandler>::returnOrYield(bool useAssignExpr)
pc->sc->asFunctionBox()->setIsGenerator();
} else {
pc->yieldCount++;
pc->yieldNode = pn;
pc->yieldOffset = handler.getPosition(pn).begin;
}
}
#endif
@ -5215,7 +5236,7 @@ class GenexpGuard
ParseContext<ParseHandler> *pc = parser->pc;
if (pc->parenDepth == 0) {
pc->yieldCount = 0;
pc->yieldNode = ParseHandler::null();
pc->yieldOffset = 0;
}
startYieldCount = pc->yieldCount;
pc->parenDepth++;
@ -5246,10 +5267,12 @@ GenexpGuard<ParseHandler>::checkValidBody(Node pn, unsigned err)
{
ParseContext<ParseHandler> *pc = parser->pc;
if (pc->yieldCount > startYieldCount) {
Node errorNode = pc->yieldNode;
if (!errorNode)
errorNode = pn;
parser->report(ParseError, false, errorNode, err, js_yield_str);
uint32_t offset = pc->yieldOffset
? pc->yieldOffset
: (pn ? parser->handler.getPosition(pn)
: parser->tokenStream.currentToken().pos).begin;
parser->reportWithOffset(ParseError, false, offset, err, js_yield_str);
return false;
}

View File

@ -155,10 +155,10 @@ struct ParseContext /* tree context for semantic checks */
bool generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const;
public:
Node yieldNode; /* parse node for a yield expression that might
be an error if we turn out to be inside a
generator expression */
uint32_t yieldOffset; /* offset of a yield expression that might
be an error if we turn out to be inside
a generator expression. Zero means
there isn't one. */
private:
ParseContext **parserPC; /* this points to the Parser's active pc
and holds either |this| or one of
@ -296,7 +296,13 @@ struct Parser : private AutoGCRooter, public StrictModeGetter
/* State specific to the kind of parse being performed. */
ParseHandler handler;
private:
bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
unsigned errorNumber, va_list args);
public:
bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...);
bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber,
...);
Parser(JSContext *cx, const CompileOptions &options,
const jschar *chars, size_t length, bool foldConstants);

View File

@ -395,6 +395,46 @@ class StrictModeGetter {
virtual bool strictMode() = 0;
};
// TokenStream is the lexical scanner for Javascript source text.
//
// It takes a buffer of jschars and linearly scans it into |Token|s.
// Internally the class uses a four element circular buffer |tokens| of
// |Token|s. As an index for |tokens|, the member |cursor| points to the
// current token.
// Calls to getToken() increase |cursor| by one and return the new current
// token. If a TokenStream was just created, the current token is initialized
// with random data (i.e. not initialized). It is therefore important that
// either of the first four member functions listed below is called first.
// The circular buffer lets us go back up to two tokens from the last
// scanned token. Internally, the relative number of backward steps that were
// taken (via ungetToken()) after the last token was scanned is stored in
// |lookahead|.
//
// The following table lists in which situations it is safe to call each listed
// function. No checks are made by the functions in non-debug builds.
//
// Function Name | Precondition; changes to |lookahead|
// ------------------+---------------------------------------------------------
// getToken | none; if |lookahead > 0| then |lookahead--|
// peekToken | none; none
// peekTokenSameLine | none; none
// matchToken | none; if |lookahead > 0| and the match succeeds then
// | |lookahead--|
// consumeKnownToken | none; if |lookahead > 0| then |lookahead--|
// ungetToken | 0 <= |lookahead| <= |maxLookahead - 1|; |lookahead++|
//
// The behavior of the token scanning process (see getTokenInternal()) can be
// modified by calling one of the first four above listed member functions with
// an optional argument of type TokenStreamFlags. The two flags that do
// influence the scanning process are TSF_OPERAND and TSF_KEYWORD_IS_NAME.
// However, they will be ignored unless |lookahead == 0| holds.
// Due to constraints of the grammar, this turns out not to be a problem in
// practice. See the mozilla.dev.tech.js-engine.internals thread entitled 'Bug
// in the scanner?' for more details (https://groups.google.com/forum/?
// fromgroups=#!topic/mozilla.dev.tech.js-engine.internals/2JLH5jRcr7E).
//
// The methods seek() and tell() allow to rescan from a previous visited
// location of the buffer.
class TokenStream
{
/* Unicode separators that are treated as line terminators, in addition to \n, \r */
@ -535,7 +575,7 @@ class TokenStream
* Push the last scanned token back into the stream.
*/
void ungetToken() {
JS_ASSERT(lookahead < ntokensMask);
JS_ASSERT(lookahead < maxLookahead);
lookahead++;
cursor = (cursor - 1) & ntokensMask;
}

View File

@ -255,7 +255,7 @@ class RelocatablePtr : public EncapsulatedPtr<T>
if (v)
post();
}
explicit RelocatablePtr(const RelocatablePtr<T> &v) : EncapsulatedPtr<T>(v) {
RelocatablePtr(const RelocatablePtr<T> &v) : EncapsulatedPtr<T>(v) {
if (this->value)
post();
}

View File

@ -99,3 +99,35 @@ function assertTypeFailInEval(str)
assertTypeFailInEval('function f({}) { "use asm"; function g() {} return g }');
assertTypeFailInEval('function f({global}) { "use asm"; function g() {} return g }');
assertTypeFailInEval('function f(global, {imports}) { "use asm"; function g() {} return g }');
function assertLinkFailInEval(str)
{
if (!isAsmJSCompilationAvailable())
return;
var caught = false;
var oldOpts = options("werror");
assertEq(oldOpts.indexOf("werror"), -1);
try {
eval(str);
} catch (e) {
assertEq((''+e).indexOf(ASM_OK_STRING) == -1, false);
caught = true;
}
assertEq(caught, true);
options("werror");
var code = eval(str);
var caught = false;
var oldOpts = options("werror");
assertEq(oldOpts.indexOf("werror"), -1);
try {
code.apply(null, Array.slice(arguments, 1));
} catch (e) {
caught = true;
}
assertEq(caught, true);
options("werror");
}
assertLinkFailInEval('(function(global) { "use asm"; var im=global.Math.imul; function g() {} return g })');

View File

@ -1,4 +1,4 @@
// |jit-test| error:InternalError
// |jit-test| slow; error:InternalError
// Binary: cache/js-dbg-64-a2bbe9c999b4-linux
// Flags: -m -n

View File

@ -0,0 +1,6 @@
// Don't assert.
try {
eval("function x(y = {\
x: (7) ? 0 : yield(0)\
}");
} catch (e) {}

View File

@ -165,7 +165,7 @@ class JSFunction : public JSObject
}
JSAtom *atom() const { return hasGuessedAtom() ? NULL : atom_.get(); }
js::PropertyName *name() const { return hasGuessedAtom() ? NULL : atom_->asPropertyName(); }
js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? NULL : atom_->asPropertyName(); }
inline void initAtom(JSAtom *atom);
JSAtom *displayAtom() const { return atom_; }

View File

@ -235,6 +235,7 @@ JSObject::finalize(js::FreeOp *fop)
js::Probes::finalizeObject(this);
#ifdef DEBUG
JS_ASSERT(isTenured());
if (!IsBackgroundFinalized(tenuredGetAllocKind())) {
/* Assert we're on the main thread. */
fop->runtime()->assertValidThread();

View File

@ -2593,7 +2593,6 @@ template<typename T>
JSBool
ArrayBufferObject::createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp)
{
typedef TypedArrayTemplate<T> ArrayType;
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, createTypedArrayFromBufferImpl<T> >(cx, args);
}

0
layout/base/crashtests/317934-1-inner.html Executable file → Normal file
View File

0
layout/forms/crashtests/317502-1.xhtml Executable file → Normal file
View File

0
layout/generic/crashtests/289864-1.html Executable file → Normal file
View File

0
layout/generic/crashtests/289864-1.jpg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

0
layout/generic/crashtests/592118.html Executable file → Normal file
View File

View File

@ -1105,8 +1105,23 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres
}
}
if (!overflowContainers)
// Our own excess overflow containers from a previous reflow can still be
// present if our next-in-flow hasn't been reflown yet.
nsFrameList* selfExcessOCFrames =
RemovePropTableFrames(aPresContext, ExcessOverflowContainersProperty());
if (selfExcessOCFrames) {
if (overflowContainers) {
overflowContainers->AppendFrames(nullptr, *selfExcessOCFrames);
delete selfExcessOCFrames;
} else {
overflowContainers = selfExcessOCFrames;
SetPropTableFrames(aPresContext, overflowContainers,
OverflowContainersProperty());
}
}
if (!overflowContainers) {
return NS_OK; // nothing to reflow
}
nsOverflowContinuationTracker tracker(aPresContext, this, false, false);
bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids();
@ -1655,7 +1670,17 @@ nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
nsresult rv = NS_OK;
bool reparented = false;
nsPresContext* presContext = aOverflowCont->PresContext();
const bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
// If we have a list and aOverflowCont is already in it then don't try to
// add it again.
if (addToList && aOverflowCont->GetParent() == mParent &&
(aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
mOverflowContList && mOverflowContList->ContainsFrame(aOverflowCont)) {
addToList = false;
mPrevOverflowCont = aOverflowCont->GetPrevSibling();
}
if (addToList) {
if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
// aOverflowCont is in some other overflow container list,
@ -1682,6 +1707,27 @@ nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
mParent);
reparented = true;
}
// If aOverflowCont has a prev/next-in-flow that might be in
// mOverflowContList we need to find it and insert after/before it to
// maintain the order amongst next-in-flows in this list.
nsIFrame* pif = aOverflowCont->GetPrevInFlow();
nsIFrame* nif = aOverflowCont->GetNextInFlow();
if ((pif && pif->GetParent() == mParent && pif != mPrevOverflowCont) ||
(nif && nif->GetParent() == mParent && mPrevOverflowCont)) {
for (nsFrameList::Enumerator e(*mOverflowContList); !e.AtEnd(); e.Next()) {
nsIFrame* f = e.get();
if (f == pif) {
mPrevOverflowCont = pif;
break;
}
if (f == nif) {
mPrevOverflowCont = f->GetPrevSibling();
break;
}
}
}
mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
}

0
layout/generic/test/file_bug514732_window.xul Executable file → Normal file
View File

View File

@ -16,6 +16,7 @@ PARALLEL_DIRS += [
'mathml',
'inspector/public',
'inspector/src',
'tools/recording',
]
if CONFIG['NS_PRINTING']:

View File

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 396 B

0
layout/reftests/fonts/sil/PigLatinBenchmark_v3.ttf Executable file → Normal file
View File

View File

0
layout/style/crashtests/592698-1.html Executable file → Normal file
View File

0
layout/svg/crashtests/322215-1.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 843 B

After

Width:  |  Height:  |  Size: 843 B

View File

@ -3091,7 +3091,10 @@ nsSVGTextFrame2::FindCloserFrameForSelection(
nsPoint aPoint,
nsIFrame::FrameWithDistance* aCurrentBestFrame)
{
UpdateGlyphPositioning(false);
if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) {
return;
}
UpdateGlyphPositioning(true);
nsPresContext* presContext = PresContext();

0
layout/tables/crashtests/308752-1-inner.html Executable file → Normal file
View File

0
layout/tables/crashtests/308752-2-inner.html Executable file → Normal file
View File

0
layout/tables/crashtests/316636-1.html Executable file → Normal file
View File

View File

@ -0,0 +1,19 @@
# vim: set shiftwidth=8 tabstop=8 autoindent noexpandtab copyindent:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
EXTRA_COMPONENTS = \
recording-cmdline.js \
$(NULL)
EXTRA_COMPONENTS += recording-cmdline.manifest
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,4 @@
recording.jar:
% content recording %content/
content/recording.xul (recording.xul)
content/recording.js (recording.js)

View File

@ -0,0 +1,6 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'recording'

View File

@ -0,0 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const nsISupports = Components.interfaces.nsISupports;
const nsICommandLine = Components.interfaces.nsICommandLine;
const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler;
const nsISupportsString = Components.interfaces.nsISupportsString;
const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher;
function RecordingCmdLineHandler() {}
RecordingCmdLineHandler.prototype =
{
classID: Components.ID('{86FB70EC-90FF-45AD-A1C1-F77D3C1184E9}'),
/* nsISupports */
QueryInterface: XPCOMUtils.generateQI([nsICommandLineHandler]),
/* nsICommandLineHandler */
handle : function handler_handle(cmdLine) {
var args = { };
args.wrappedJSObject = args;
try {
var uristr = cmdLine.handleFlagWithParam("recording", false);
if (uristr == null)
return;
try {
args.uri = cmdLine.resolveURI(uristr).spec;
}
catch (e) {
return;
}
}
catch (e) {
cmdLine.handleFlag("recording", true);
}
/**
* Manipulate preferences by adding to the *default* branch. Adding
* to the default branch means the changes we make won't get written
* back to user preferences.
*
* We want to do this here rather than in reftest.js because it's
* important to set the recording pref before the platform Init gets
* called.
*/
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);
var branch = prefs.getDefaultBranch("");
branch.setBoolPref("gfx.2d.recording", true);
try {
var outputstr = cmdLine.handleFlagWithParam("recording-output", false);
if (outputstr != null) {
branch.setCharPref("gfx.2d.recordingfile", outputstr);
}
} catch (e) { }
var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(nsIWindowWatcher);
wwatch.openWindow(null, "chrome://recording/content/recording.xul", "_blank",
"chrome,dialog=no,all", args);
cmdLine.preventDefault = true;
},
helpInfo : " -recording <file> Record drawing for a given URL.\n" +
" -recording-output <file> Specify destination file for a drawing recording.\n"
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RecordingCmdLineHandler]);

View File

@ -0,0 +1,3 @@
component {86FB70EC-90FF-45AD-A1C1-F77D3C1184E9} recording-cmdline.js
contract @mozilla.org/commandlinehandler/general-startup;1?type=recording {86FB70EC-90FF-45AD-A1C1-F77D3C1184E9}
category command-line-handler m-recording @mozilla.org/commandlinehandler/general-startup;1?type=recording

View File

@ -0,0 +1,53 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const CC = Components.classes;
const CI = Components.interfaces;
const CR = Components.results;
const XHTML_NS = "http://www.w3.org/1999/xhtml";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const NS_GFXINFO_CONTRACTID = "@mozilla.org/gfx/info;1";
var gContainingWindow = null;
var gBrowser;
function OnDocumentLoad() {
gContainingWindow.close();
}
this.OnRecordingLoad = function OnRecordingLoad(win) {
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
if (win === undefined || win == null) {
win = window;
}
if (gContainingWindow == null && win != null) {
gContainingWindow = win;
}
gBrowser = gContainingWindow.document.getElementById("browser");
var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
var info = gfxInfo.getInfo();
dump(info.AzureContentBackend);
if (info.AzureContentBackend == "none") {
alert("Page recordings may only be made with Azure content enabled.");
gContainingWindow.close();
return;
}
gContainingWindow.document.addEventListener("load", OnDocumentLoad, true);
var args = window.arguments[0].wrappedJSObject;
gBrowser.loadURI(args.uri);
}
function OnRecordingUnload() {
}

View File

@ -0,0 +1,22 @@
<!-- vim: set shiftwidth=4 tabstop=8 autoindent expandtab: -->
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet type="text/css" href="data:text/css,
%23_box_windowsDefaultTheme:-moz-system-metric(windows-default-theme) {
display: none;
}
" ?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="recording-window"
hidechrome="true"
onload="OnRecordingLoad();"
onunload="OnRecordingUnload();"
style="background:white; overflow:hidden; width:800px; height:600px;"
>
<script type="application/ecmascript" src="recording.js" />
<browser id="browser" type="content-primary" style="min-width: 1024px; min-height: 768px; max-width: 1024px; max-height: 768px"/>
</window>

0
layout/xul/grid/crashtests/311710-1.xul Executable file → Normal file
View File

0
layout/xul/grid/crashtests/312784-1.xul Executable file → Normal file
View File

0
layout/xul/grid/crashtests/313173-1-inner.xul Executable file → Normal file
View File

View File

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
The git commit ID used was c9c97571980ca77c990a763802c11682a332cbd6.
The git commit ID used was bfaee9a6c7a15dfe8ae2ffda8dcd156d5a562010.

View File

@ -52,8 +52,9 @@ struct cubeb_stream {
};
static void
bufferqueue_callback(SLBufferQueueItf caller, struct cubeb_stream *stm)
bufferqueue_callback(SLBufferQueueItf caller, void * user_ptr)
{
cubeb_stream * stm = user_ptr;
SLBufferQueueState state;
(*stm->bufq)->GetState(stm->bufq, &state);
@ -78,8 +79,13 @@ bufferqueue_callback(SLBufferQueueItf caller, struct cubeb_stream *stm)
return;
}
(*stm->bufq)->Enqueue(stm->bufq, buf, written * stm->framesize);
stm->queuebuf_idx = (stm->queuebuf_idx + 1) % NBUFS;
if (written) {
(*stm->bufq)->Enqueue(stm->bufq, buf, written * stm->framesize);
stm->queuebuf_idx = (stm->queuebuf_idx + 1) % NBUFS;
} else if (!i) {
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
return;
}
if ((written * stm->framesize) < stm->queuebuf_len) {
stm->draining = 1;

View File

@ -27,7 +27,7 @@ if [ -n "$rev" ]; then
version=$version-dirty
echo "WARNING: updating from a dirty git repository."
fi
sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\+\(-dirty\)\?\./$version./" README_MOZILLA
sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\}\./$version./" README_MOZILLA
rm README_MOZILLA.bak
else
echo "Remember to update README_MOZILLA with the version details."

View File

@ -229,9 +229,6 @@ int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) {
ctx->SetState(ICE_CTX_OPEN);
// Signal that we are done
ctx->SignalCompleted(ctx);
return 0;
}
@ -413,12 +410,21 @@ nsresult NrIceCtx::SetResolver(nr_resolver *resolver) {
}
nsresult NrIceCtx::StartGathering() {
MOZ_ASSERT(ctx_->state == ICE_CTX_INIT);
if (ctx_->state != ICE_CTX_INIT) {
MOZ_MTLOG(PR_LOG_ERROR, "ICE ctx in the wrong state for gathering: '"
<< name_ << "'");
SetState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb,
this);
if (r && r != R_WOULDBLOCK) {
MOZ_MTLOG(PR_LOG_ERROR, "Couldn't gather ICE candidates for '"
<< name_ << "'");
SetState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
@ -434,8 +440,6 @@ void NrIceCtx::EmitAllCandidates() {
for(size_t i=0; i<streams_.size(); ++i) {
streams_[i]->EmitAllCandidates();
}
SignalGatheringCompleted(this);
}
RefPtr<NrIceMediaStream> NrIceCtx::FindStream(
@ -498,6 +502,7 @@ nsresult NrIceCtx::StartChecks() {
if (r) {
MOZ_MTLOG(PR_LOG_ERROR, "Couldn't pair candidates on "
<< name_ << "'");
SetState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
@ -509,6 +514,7 @@ nsresult NrIceCtx::StartChecks() {
} else {
MOZ_MTLOG(PR_LOG_ERROR, "Couldn't start peer checks on "
<< name_ << "'");
SetState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
} else {
@ -522,10 +528,9 @@ nsresult NrIceCtx::StartChecks() {
void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
ctx->SetState(ICE_CTX_GATHERED);
// Report that we are done gathering
ctx->EmitAllCandidates();
ctx->SetState(ICE_CTX_GATHERED);
}
nsresult NrIceCtx::Finalize() {
@ -541,12 +546,29 @@ nsresult NrIceCtx::Finalize() {
}
void NrIceCtx::SetState(State state) {
MOZ_MTLOG(PR_LOG_DEBUG, "NrIceCtx(" << name_ << "): state " <<
state_ << "->" << state);
state_ = state;
}
} // close namespace
if (state == state_)
return;
MOZ_MTLOG(PR_LOG_DEBUG, "NrIceCtx(" << name_ << "): state " <<
state_ << "->" << state);
state_ = state;
switch(state_) {
case ICE_CTX_GATHERED:
SignalGatheringCompleted(this);
break;
case ICE_CTX_OPEN:
SignalCompleted(this);
break;
case ICE_CTX_FAILED:
SignalFailed(this);
break;
default:
break;
}
}
} // close namespace
extern "C" {

View File

@ -198,8 +198,11 @@ class NrIceCtx {
// Signals to indicate events. API users can (and should)
// register for these.
// TODO(ekr@rtfm.com): refactor this to be state change instead
// so we don't need to keep adding signals?
sigslot::signal1<NrIceCtx *> SignalGatheringCompleted; // Done gathering
sigslot::signal1<NrIceCtx *> SignalCompleted; // Done handshaking
sigslot::signal1<NrIceCtx *> SignalFailed; // Failure.
// The thread to direct method calls to
nsCOMPtr<nsIEventTarget> thread() { return sts_target_; }

View File

@ -211,14 +211,15 @@ class TransportTestPeer : public sigslot::has_slots<> {
ice_ = new TransportLayerIce(name, ice_ctx_, stream, 1);
// Assemble the stack
std::queue<mozilla::TransportLayer *> layers;
layers.push(ice_);
layers.push(dtls_);
nsAutoPtr<std::queue<mozilla::TransportLayer *> > layers(
new std::queue<mozilla::TransportLayer *>);
layers->push(ice_);
layers->push(dtls_);
test_utils->sts_target()->Dispatch(
WrapRunnableRet(flow_, &TransportFlow::PushLayers, layers, &res),
NS_DISPATCH_SYNC);
ASSERT_EQ((nsresult)NS_OK, res);
// Listen for media events

View File

@ -7,11 +7,16 @@
// Original author: ekr@rtfm.com
#include <deque>
#include <prlog.h>
#include "logging.h"
#include "transportflow.h"
#include "transportlayer.h"
namespace mozilla {
MOZ_MTLOG_MODULE("mtransport")
TransportFlow::~TransportFlow() {
for (std::deque<TransportLayer *>::iterator it = layers_.begin();
it != layers_.end(); ++it) {
@ -20,9 +25,19 @@ TransportFlow::~TransportFlow() {
}
nsresult TransportFlow::PushLayer(TransportLayer *layer) {
// Don't allow pushes once we are in error state.
if (state_ == TransportLayer::TS_ERROR) {
MOZ_MTLOG(PR_LOG_ERROR, id_ + ": Can't call PushLayer in error state for flow ");
return NS_ERROR_FAILURE;
}
nsresult rv = layer->Init();
if (!NS_SUCCEEDED(rv))
if (!NS_SUCCEEDED(rv)) {
// Set ourselves to have failed.
MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Layer initialization failed; invalidating");
StateChangeInt(TransportLayer::TS_ERROR);
return rv;
}
TransportLayer *old_layer = layers_.empty() ? nullptr : layers_.front();
@ -31,32 +46,79 @@ nsresult TransportFlow::PushLayer(TransportLayer *layer) {
old_layer->SignalStateChange.disconnect(this);
old_layer->SignalPacketReceived.disconnect(this);
}
layer->SignalStateChange.connect(this, &TransportFlow::StateChange);
layer->SignalPacketReceived.connect(this, &TransportFlow::PacketReceived);
layers_.push_front(layer);
layer->Inserted(this, old_layer);
layer->SignalStateChange.connect(this, &TransportFlow::StateChange);
layer->SignalPacketReceived.connect(this, &TransportFlow::PacketReceived);
StateChangeInt(layer->state());
return NS_OK;
}
nsresult TransportFlow::PushLayers(std::queue<TransportLayer *> layers) {
nsresult rv;
while (!layers.empty()) {
rv = PushLayer(layers.front());
layers.pop();
if (NS_FAILED(rv)) {
// Destroy any layers we could not push.
while (!layers.empty()) {
delete layers.front();
layers.pop();
}
return rv;
}
// This is all-or-nothing.
nsresult TransportFlow::PushLayers(nsAutoPtr<std::queue<TransportLayer *> > layers) {
MOZ_ASSERT(!layers->empty());
if (layers->empty()) {
MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Can't call PushLayers with empty layers");
return NS_ERROR_INVALID_ARG;
}
// Don't allow pushes once we are in error state.
if (state_ == TransportLayer::TS_ERROR) {
MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Can't call PushLayers in error state for flow ");
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
// Disconnect all the old signals.
disconnect_all();
TransportLayer *layer;
while (!layers->empty()) {
TransportLayer *old_layer = layers_.empty() ? nullptr : layers_.front();
layer = layers->front();
rv = layer->Init();
if (NS_FAILED(rv)) {
MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Layer initialization failed; invalidating flow ");
break;
}
// Push the layer onto the queue.
layers_.push_front(layer);
layers->pop();
layer->Inserted(this, old_layer);
}
if (NS_FAILED(rv)) {
// Destroy any layers we could not push.
while (!layers->empty()) {
delete layers->front();
layers->pop();
}
// Now destroy the rest of the flow, because it's no longer
// in an acceptable state.
while (!layers_.empty()) {
delete layers_.front();
layers_.pop_front();
}
// Set ourselves to have failed.
StateChangeInt(TransportLayer::TS_ERROR);
// Return failure.
return rv;
}
// Finally, attach ourselves to the top layer.
layer->SignalStateChange.connect(this, &TransportFlow::StateChange);
layer->SignalPacketReceived.connect(this, &TransportFlow::PacketReceived);
StateChangeInt(layer->state()); // Signals if the state changes.
return NS_OK;
}
@ -75,17 +137,29 @@ TransportLayer *TransportFlow::GetLayer(const std::string& id) const {
}
TransportLayer::State TransportFlow::state() {
return top() ? top()->state() : TransportLayer::TS_NONE;
return state_;
}
TransportResult TransportFlow::SendPacket(const unsigned char *data,
size_t len) {
if (state_ != TransportLayer::TS_OPEN) {
return TE_ERROR;
}
return top() ? top()->SendPacket(data, len) : TE_ERROR;
}
void TransportFlow::StateChangeInt(TransportLayer::State state) {
if (state == state_) {
return;
}
state_ = state;
SignalStateChange(this, state_);
}
void TransportFlow::StateChange(TransportLayer *layer,
TransportLayer::State state) {
SignalStateChange(this, state);
StateChangeInt(state);
}
void TransportFlow::PacketReceived(TransportLayer* layer,
@ -94,9 +168,4 @@ void TransportFlow::PacketReceived(TransportLayer* layer,
SignalPacketReceived(this, data, len);
}
} // close namespace

View File

@ -24,8 +24,13 @@ namespace mozilla {
class TransportFlow : public sigslot::has_slots<> {
public:
TransportFlow() : id_("(anonymous)") {}
TransportFlow(const std::string id) : id_(id) {}
TransportFlow()
: id_("(anonymous)"),
state_(TransportLayer::TS_NONE) {}
TransportFlow(const std::string id)
: id_(id),
state_(TransportLayer::TS_NONE) {}
~TransportFlow();
const std::string& id() const { return id_; }
@ -41,10 +46,10 @@ class TransportFlow : public sigslot::has_slots<> {
// Convenience function to push multiple layers on. Layers
// are pushed on in the order that they are in the queue.
// Any layers which cannot be pushed on are just deleted
// and an error is returned.
// Any failures cause the flow to become inoperable and
// destroys all the layers including those already pushed.
// TODO(ekr@rtfm.com): Change layers to be ref-counted.
nsresult PushLayers(std::queue<TransportLayer *> layers);
nsresult PushLayers(nsAutoPtr<std::queue<TransportLayer *> > layers);
TransportLayer *top() const;
TransportLayer *GetLayer(const std::string& id) const;
@ -68,11 +73,13 @@ class TransportFlow : public sigslot::has_slots<> {
DISALLOW_COPY_ASSIGN(TransportFlow);
void StateChange(TransportLayer *layer, TransportLayer::State state);
void StateChangeInt(TransportLayer::State state);
void PacketReceived(TransportLayer* layer, const unsigned char *data,
size_t len);
std::string id_;
std::deque<TransportLayer *> layers_;
TransportLayer::State state_;
};
} // close namespace

View File

@ -705,20 +705,19 @@ static short vcmSetIceCandidate_m(const char *peerconnection,
if (!stream)
return VCM_ERROR;
nsresult res;
nsresult rv = pc.impl()->media()->ice_ctx()->thread()->Dispatch(
WrapRunnableRet(stream, &NrIceMediaStream::ParseTrickleCandidate, icecandidate, &res),
NS_DISPATCH_SYNC);
nsresult rv = RUN_ON_THREAD(pc.impl()->media()->ice_ctx()->thread(),
WrapRunnable(stream,
&NrIceMediaStream::ParseTrickleCandidate,
std::string(icecandidate)),
NS_DISPATCH_NORMAL);
if (!NS_SUCCEEDED(rv)) {
CSFLogError( logTag, "%s(): Could not dispatch to ICE thread", __FUNCTION__, level);
return VCM_ERROR;
}
if (!NS_SUCCEEDED(res)) {
CSFLogError( logTag, "%s(): Could not parse trickle candidate for stream %d", __FUNCTION__, level);
return VCM_ERROR;
}
// TODO(ekr@rtfm.com): generate an error if the parse
// fails. Bug 847449.
return 0;
}
@ -769,18 +768,17 @@ static short vcmStartIceChecks_m(const char *peerconnection, cc_boolean isContro
CSFLogError( logTag, "%s: couldn't set controlling", __FUNCTION__ );
return VCM_ERROR;
}
// TODO(ekr@rtfm.com): Figure out how to report errors here.
// Bug 854516.
nsresult rv = pc.impl()->media()->ice_ctx()->thread()->Dispatch(
WrapRunnableRet(pc.impl()->media()->ice_ctx(), &NrIceCtx::StartChecks, &res),
NS_DISPATCH_SYNC);
WrapRunnable(pc.impl()->media()->ice_ctx(), &NrIceCtx::StartChecks),
NS_DISPATCH_NORMAL);
if (!NS_SUCCEEDED(rv)) {
CSFLogError( logTag, "%s(): Could not dispatch to ICE thread", __FUNCTION__);
return VCM_ERROR;
}
if (!NS_SUCCEEDED(res)) {
CSFLogError( logTag, "%s: couldn't start ICE checks", __FUNCTION__ );
return VCM_ERROR;
}
return 0;
}
@ -2683,19 +2681,24 @@ vcmCreateTransportFlow(sipcc::PeerConnectionImpl *pc, int level, bool rtcp,
return NULL;
}
std::queue<TransportLayer *> layers;
layers.push(ice.forget());
layers.push(dtls.forget());
nsAutoPtr<std::queue<TransportLayer *> > layers(new std::queue<TransportLayer *>);
layers->push(ice.forget());
layers->push(dtls.forget());
// Layers are now owned by the flow.
// TODO(ekr@rtfm.com): Propagate errors for when this fails.
// Bug 854518.
nsresult rv = pc->media()->ice_ctx()->thread()->Dispatch(
WrapRunnableRet(flow, &TransportFlow::PushLayers, layers, &res),
NS_DISPATCH_SYNC);
WrapRunnable(flow, &TransportFlow::PushLayers, layers),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv) || NS_FAILED(res) || !pc->media().get()) { // SYNC re-check
if (NS_FAILED(rv)) {
return NULL;
}
// Note, this flow may actually turn out to be invalid
// because PushLayers is async and can fail.
pc->media()->AddTransportFlow(level, rtcp, flow);
}
return flow;

View File

@ -54,43 +54,52 @@ static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
nsresult MediaPipeline::Init() {
ASSERT_ON_THREAD(main_thread_);
// TODO(ekr@rtfm.com): is there a way to make this async?
nsresult ret;
RUN_ON_THREAD(sts_thread_,
WrapRunnableRet(this, &MediaPipeline::Init_s, &ret),
NS_DISPATCH_SYNC);
return ret;
WrapRunnable(
nsRefPtr<MediaPipeline>(this),
&MediaPipeline::Init_s),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::Init_s() {
ASSERT_ON_THREAD(sts_thread_);
conduit_->AttachTransport(transport_);
MOZ_ASSERT(rtp_transport_);
nsresult res;
MOZ_ASSERT(rtp_transport_);
// Look to see if the transport is ready
rtp_transport_->SignalStateChange.connect(this,
&MediaPipeline::StateChange);
if (rtp_transport_->state() == TransportLayer::TS_OPEN) {
res = TransportReady(rtp_transport_);
res = TransportReady_s(rtp_transport_);
if (NS_FAILED(res)) {
MOZ_MTLOG(PR_LOG_ERROR, "Error calling TransportReady()");
MOZ_MTLOG(PR_LOG_ERROR, "Error calling TransportReady(); res="
<< static_cast<uint32_t>(res) << " in " << __FUNCTION__);
return res;
}
} else if (rtp_transport_->state() == TransportLayer::TS_ERROR) {
MOZ_MTLOG(PR_LOG_ERROR, "RTP transport is already in error state");
TransportFailed_s(rtp_transport_);
return NS_ERROR_FAILURE;
} else {
if (!muxed_) {
rtcp_transport_->SignalStateChange.connect(this,
&MediaPipeline::StateChange);
if (rtcp_transport_->state() == TransportLayer::TS_OPEN) {
res = TransportReady(rtcp_transport_);
res = TransportReady_s(rtcp_transport_);
if (NS_FAILED(res)) {
MOZ_MTLOG(PR_LOG_ERROR, "Error calling TransportReady()");
MOZ_MTLOG(PR_LOG_ERROR, "Error calling TransportReady(); res="
<< static_cast<uint32_t>(res) << " in " << __FUNCTION__);
return res;
}
} else if (rtcp_transport_->state() == TransportLayer::TS_ERROR) {
MOZ_MTLOG(PR_LOG_ERROR, "RTCP transport is already in error state");
TransportFailed_s(rtcp_transport_);
return NS_ERROR_FAILURE;
}
}
}
@ -100,7 +109,7 @@ nsresult MediaPipeline::Init_s() {
// Disconnect us from the transport so that we can cleanly destruct
// the pipeline on the main thread.
void MediaPipeline::DetachTransport_s() {
void MediaPipeline::ShutdownTransport_s() {
ASSERT_ON_THREAD(sts_thread_);
disconnect_all();
@ -109,42 +118,23 @@ void MediaPipeline::DetachTransport_s() {
rtcp_transport_ = NULL;
}
void MediaPipeline::DetachTransport() {
RUN_ON_THREAD(sts_thread_,
WrapRunnable(this, &MediaPipeline::DetachTransport_s),
NS_DISPATCH_SYNC);
}
void MediaPipeline::StateChange(TransportFlow *flow, TransportLayer::State state) {
if (state == TransportLayer::TS_OPEN) {
MOZ_MTLOG(MP_LOG_INFO, "Flow is ready");
TransportReady(flow);
TransportReady_s(flow);
} else if (state == TransportLayer::TS_CLOSED ||
state == TransportLayer::TS_ERROR) {
TransportFailed(flow);
TransportFailed_s(flow);
}
}
nsresult MediaPipeline::TransportReady(TransportFlow *flow) {
nsresult rv;
nsresult res;
rv = RUN_ON_THREAD(sts_thread_,
WrapRunnableRet(this, &MediaPipeline::TransportReadyInt, flow, &res),
NS_DISPATCH_SYNC);
// res is invalid unless the dispatch succeeded
if (NS_FAILED(rv))
return rv;
return res;
}
nsresult MediaPipeline::TransportReadyInt(TransportFlow *flow) {
nsresult MediaPipeline::TransportReady_s(TransportFlow *flow) {
MOZ_ASSERT(!description_.empty());
bool rtcp = !(flow == rtp_transport_);
State *state = rtcp ? &rtcp_state_ : &rtp_state_;
// TODO(ekr@rtfm.com): implement some kind of notification on
// failure. bug 852665.
if (*state != MP_CONNECTING) {
MOZ_MTLOG(PR_LOG_ERROR, "Transport ready for flow in wrong state:" <<
description_ << ": " << (rtcp ? "rtcp" : "rtp"));
@ -166,6 +156,7 @@ nsresult MediaPipeline::TransportReadyInt(TransportFlow *flow) {
res = dtls->GetSrtpCipher(&cipher_suite);
if (NS_FAILED(res)) {
MOZ_MTLOG(PR_LOG_ERROR, "Failed to negotiate DTLS-SRTP. This is an error");
*state = MP_CLOSED;
return res;
}
@ -268,7 +259,8 @@ nsresult MediaPipeline::TransportReadyInt(TransportFlow *flow) {
return NS_OK;
}
nsresult MediaPipeline::TransportFailed(TransportFlow *flow) {
nsresult MediaPipeline::TransportFailed_s(TransportFlow *flow) {
ASSERT_ON_THREAD(sts_thread_);
bool rtcp = !(flow == rtp_transport_);
State *state = rtcp ? &rtcp_state_ : &rtp_state_;
@ -368,6 +360,16 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
return;
}
if (rtp_state_ != MP_OPEN) {
MOZ_MTLOG(PR_LOG_DEBUG, "Discarding incoming packet; pipeline not open");
return;
}
if (rtp_transport_->state() != TransportLayer::TS_OPEN) {
MOZ_MTLOG(PR_LOG_ERROR, "Discarding incoming packet; transport not open");
return;
}
MOZ_ASSERT(rtp_recv_srtp_); // This should never happen
if (direction_ == TRANSMIT) {
@ -406,6 +408,16 @@ void MediaPipeline::RtcpPacketReceived(TransportLayer *layer,
return;
}
if (rtcp_state_ != MP_OPEN) {
MOZ_MTLOG(PR_LOG_DEBUG, "Discarding incoming packet; pipeline not open");
return;
}
if (rtcp_transport_->state() != TransportLayer::TS_OPEN) {
MOZ_MTLOG(PR_LOG_ERROR, "Discarding incoming packet; transport not open");
return;
}
if (direction_ == RECEIVE) {
// Discard any RTCP that is being transmitted to us
// This will be unnecessary when we have SSRC filtering.
@ -503,9 +515,9 @@ nsresult MediaPipelineTransmit::Init() {
return MediaPipeline::Init();
}
nsresult MediaPipelineTransmit::TransportReady(TransportFlow *flow) {
nsresult MediaPipelineTransmit::TransportReady_s(TransportFlow *flow) {
// Call base ready function.
MediaPipeline::TransportReady(flow);
MediaPipeline::TransportReady_s(flow);
if (flow == rtp_transport_) {
// TODO(ekr@rtfm.com): Move onto MSG thread.
@ -910,7 +922,9 @@ MediaPipelineReceiveVideo::PipelineListener::PipelineListener(
SourceMediaStream* source, TrackID track_id)
: source_(source),
track_id_(track_id),
#ifdef MOZILLA_INTERNAL_API
played_(0),
#endif
width_(640),
height_(480),
#ifdef MOZILLA_INTERNAL_API

View File

@ -100,13 +100,19 @@ class MediaPipeline : public sigslot::has_slots<> {
MOZ_ASSERT(!stream_); // Check that we have shut down already.
}
void Shutdown() {
// Must be called on the STS thread. Must be called
// before ShutdownMedia_m.
void ShutdownTransport_s();
// Must be called on the main thread.
void ShutdownMedia_m() {
ASSERT_ON_THREAD(main_thread_);
// First shut down networking and then disconnect from
// the media streams. DetachTransport() is sync so
// we are sure that the transport is shut down before
// we touch stream_ or conduit_.
DetachTransport();
MOZ_ASSERT(!rtp_transport_);
MOZ_ASSERT(!rtcp_transport_);
if (stream_) {
DetachMediaStream();
}
@ -152,8 +158,8 @@ class MediaPipeline : public sigslot::has_slots<> {
};
friend class PipelineTransport;
virtual nsresult TransportReady(TransportFlow *flow); // The transport is ready
virtual nsresult TransportFailed(TransportFlow *flow); // The transport is down
virtual nsresult TransportFailed_s(TransportFlow *flow); // The transport is down
virtual nsresult TransportReady_s(TransportFlow *flow); // The transport is ready
void increment_rtp_packets_sent();
void increment_rtcp_packets_sent();
@ -216,10 +222,6 @@ class MediaPipeline : public sigslot::has_slots<> {
private:
nsresult Init_s();
void DetachTransport();
void DetachTransport_s();
nsresult TransportReadyInt(TransportFlow *flow);
bool IsRtp(const unsigned char *data, size_t len);
};
@ -268,7 +270,7 @@ class MediaPipelineTransmit : public MediaPipeline {
}
// Override MediaPipeline::TransportReady.
virtual nsresult TransportReady(TransportFlow *flow);
virtual nsresult TransportReady_s(TransportFlow *flow);
// Separate class to allow ref counting
class PipelineListener : public MediaStreamListener {
@ -507,7 +509,9 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive {
private:
SourceMediaStream *source_;
TrackID track_id_;
#ifdef MOZILLA_INTERNAL_API
TrackTicks played_; // Amount of media played.
#endif
int width_;
int height_;
#ifdef MOZILLA_INTERNAL_API

View File

@ -331,7 +331,7 @@ PeerConnectionImpl::CreateRemoteSourceStreamInfo(nsRefPtr<RemoteSourceStreamInfo
static_cast<mozilla::SourceMediaStream*>(comstream->GetStream())->SetPullEnabled(true);
nsRefPtr<RemoteSourceStreamInfo> remote;
remote = new RemoteSourceStreamInfo(comstream);
remote = new RemoteSourceStreamInfo(comstream, mMedia);
*aInfo = remote;
return NS_OK;
@ -498,6 +498,7 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* aObserver,
// Connect ICE slots.
mMedia->SignalIceGatheringCompleted.connect(this, &PeerConnectionImpl::IceGatheringCompleted);
mMedia->SignalIceCompleted.connect(this, &PeerConnectionImpl::IceCompleted);
mMedia->SignalIceFailed.connect(this, &PeerConnectionImpl::IceFailed);
// Initialize the media object.
if (aRTCConfiguration) {
@ -590,15 +591,7 @@ PeerConnectionImpl::CreateFakeMediaStream(uint32_t aHint, nsIDOMMediaStream** aR
aHint &= ~MEDIA_STREAM_MUTE;
}
nsresult res;
if (!mThread || NS_IsMainThread()) {
res = MakeMediaStream(mWindow, aHint, aRetval);
} else {
mThread->Dispatch(WrapRunnableNMRet(
&PeerConnectionImpl::MakeMediaStream, mWindow, aHint, aRetval, &res
), NS_DISPATCH_SYNC);
}
nsresult res = MakeMediaStream(mWindow, aHint, aRetval);
if (NS_FAILED(res)) {
return res;
}
@ -1196,19 +1189,9 @@ PeerConnectionImpl::ShutdownMedia(bool aIsSynchronous)
if (!mMedia)
return;
// Post back to our own thread to shutdown the media objects.
// This avoids reentrancy issues with the garbage collector.
// Note that no media calls may be made after this point
// because we have removed the pointer.
// For the aIsSynchronous case, we *know* the PeerConnection is
// still alive, and are shutting it down on network teardown/etc, so
// recursive GC isn't an issue. (Recursive GC should assert)
// Forget the reference so that we can transfer it to
// SelfDestruct().
RUN_ON_THREAD(mThread, WrapRunnable(mMedia.forget().get(),
&PeerConnectionMedia::SelfDestruct),
aIsSynchronous ? NS_DISPATCH_SYNC : NS_DISPATCH_NORMAL);
mMedia.forget().get()->SelfDestruct();
}
#ifdef MOZILLA_INTERNAL_API
@ -1327,34 +1310,11 @@ PeerConnectionImpl::IceGatheringCompleted(NrIceCtx *aCtx)
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mThread,
WrapRunnable(pc,
&PeerConnectionImpl::IceGatheringCompleted_m),
&PeerConnectionImpl::IceStateChange_m,
kIceWaiting),
NS_DISPATCH_NORMAL);
}
nsresult
PeerConnectionImpl::IceGatheringCompleted_m()
{
PC_AUTO_ENTER_API_CALL(false);
CSFLogDebug(logTag, __FUNCTION__);
mIceState = kIceWaiting;
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return NS_OK;
}
RUN_ON_THREAD(mThread,
WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
#endif
return NS_OK;
}
void
PeerConnectionImpl::IceCompleted(NrIceCtx *aCtx)
{
@ -1363,18 +1323,32 @@ PeerConnectionImpl::IceCompleted(NrIceCtx *aCtx)
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mThread,
WrapRunnable(pc,
&PeerConnectionImpl::IceCompleted_m),
&PeerConnectionImpl::IceStateChange_m,
kIceConnected),
NS_DISPATCH_NORMAL);
}
void
PeerConnectionImpl::IceFailed(NrIceCtx *aCtx)
{
(void) aCtx;
// Do an async call here to unwind the stack. refptr keeps the PC alive.
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mThread,
WrapRunnable(pc,
&PeerConnectionImpl::IceStateChange_m,
kIceFailed),
NS_DISPATCH_NORMAL);
}
nsresult
PeerConnectionImpl::IceCompleted_m()
PeerConnectionImpl::IceStateChange_m(IceState aState)
{
PC_AUTO_ENTER_API_CALL(false);
CSFLogDebug(logTag, __FUNCTION__);
mIceState = kIceConnected;
mIceState = aState;
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);

View File

@ -178,6 +178,7 @@ public:
// ICE events
void IceGatheringCompleted(NrIceCtx *aCtx);
void IceCompleted(NrIceCtx *aCtx);
void IceFailed(NrIceCtx *aCtx);
void IceStreamReady(NrIceMediaStream *aStream);
static void ListenThread(void *aData);
@ -269,8 +270,7 @@ private:
void ShutdownMedia(bool isSynchronous);
// ICE callbacks run on the right thread.
nsresult IceGatheringCompleted_m();
nsresult IceCompleted_m();
nsresult IceStateChange_m(IceState aState);
// The role we are adopting
Role mRole;

View File

@ -60,6 +60,55 @@ LocalSourceStreamInfo::VideoTrackCount()
return mVideoTracks.Length();
}
void LocalSourceStreamInfo::DetachTransport_s()
{
ASSERT_ON_THREAD(mParent->GetSTSThread());
// walk through all the MediaPipelines and call the shutdown
// functions for transport. Must be on the STS thread.
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
mPipelines.begin(); it != mPipelines.end();
++it) {
it->second->ShutdownTransport_s();
}
}
void LocalSourceStreamInfo::DetachMedia_m()
{
ASSERT_ON_THREAD(mParent->GetMainThread());
// walk through all the MediaPipelines and call the shutdown
// functions. Must be on the main thread.
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
mPipelines.begin(); it != mPipelines.end();
++it) {
it->second->ShutdownMedia_m();
}
}
void RemoteSourceStreamInfo::DetachTransport_s()
{
ASSERT_ON_THREAD(mParent->GetSTSThread());
// walk through all the MediaPipelines and call the shutdown
// transport functions. Must be on the STS thread.
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
mPipelines.begin(); it != mPipelines.end();
++it) {
it->second->ShutdownTransport_s();
}
}
void RemoteSourceStreamInfo::DetachMedia_m()
{
ASSERT_ON_THREAD(mParent->GetMainThread());
// walk through all the MediaPipelines and call the shutdown
// media functions. Must be on the main thread.
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
mPipelines.begin(); it != mPipelines.end();
++it) {
it->second->ShutdownMedia_m();
}
}
PeerConnectionImpl* PeerConnectionImpl::CreatePeerConnection()
{
PeerConnectionImpl *pc = new PeerConnectionImpl();
@ -72,6 +121,9 @@ PeerConnectionImpl* PeerConnectionImpl::CreatePeerConnection()
nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_servers)
{
mMainThread = mParent->GetMainThread();
mSTSThread = mParent->GetSTSThread();
// TODO(ekr@rtfm.com): need some way to set not offerer later
// Looks like a bug in the NrIceCtx API.
mIceCtx = NrIceCtx::Create("PC:" + mParent->GetHandle(), true);
@ -96,6 +148,8 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
&PeerConnectionMedia::IceGatheringCompleted);
mIceCtx->SignalCompleted.connect(this,
&PeerConnectionMedia::IceCompleted);
mIceCtx->SignalFailed.connect(this,
&PeerConnectionMedia::IceFailed);
// Create three streams to start with.
// One each for audio, video and DataChannel
@ -131,17 +185,10 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
mIceStreams[i]->SignalReady.connect(this, &PeerConnectionMedia::IceStreamReady);
}
// Start gathering
nsresult res;
mIceCtx->thread()->Dispatch(WrapRunnableRet(
mIceCtx, &NrIceCtx::StartGathering, &res), NS_DISPATCH_SYNC
);
if (NS_FAILED(res)) {
CSFLogError(logTag, "%s: StartGathering failed: %u",
__FUNCTION__, static_cast<uint32_t>(res));
return res;
}
// TODO(ekr@rtfm.com): When we have a generic error reporting mechanism,
// figure out how to report that StartGathering failed. Bug 827982.
RUN_ON_THREAD(mIceCtx->thread(),
WrapRunnable(mIceCtx, &NrIceCtx::StartGathering), NS_DISPATCH_NORMAL);
return NS_OK;
}
@ -184,7 +231,7 @@ PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream
// OK, we're good to add
nsRefPtr<LocalSourceStreamInfo> localSourceStream =
new LocalSourceStreamInfo(stream);
new LocalSourceStreamInfo(stream, this);
*stream_id = mLocalSourceStreams.Length();
if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) {
@ -225,43 +272,63 @@ PeerConnectionMedia::RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *str
void
PeerConnectionMedia::SelfDestruct()
{
CSFLogDebug(logTag, "%s: Disconnecting media streams from PC", __FUNCTION__);
ASSERT_ON_THREAD(mMainThread);
DisconnectMediaStreams();
CSFLogDebug(logTag, "%s: ", __FUNCTION__);
CSFLogDebug(logTag, "%s: Disconnecting transport", __FUNCTION__);
// Shutdown the transport.
RUN_ON_THREAD(mParent->GetSTSThread(), WrapRunnable(
this, &PeerConnectionMedia::ShutdownMediaTransport), NS_DISPATCH_SYNC);
// Shutdown the transport.
RUN_ON_THREAD(mSTSThread, WrapRunnable(
this, &PeerConnectionMedia::ShutdownMediaTransport_s),
NS_DISPATCH_NORMAL);
CSFLogDebug(logTag, "%s: Media shut down", __FUNCTION__);
// This should destroy the object.
this->Release();
}
void
PeerConnectionMedia::DisconnectMediaStreams()
PeerConnectionMedia::SelfDestruct_m()
{
ASSERT_ON_THREAD(mMainThread);
CSFLogDebug(logTag, "%s: ", __FUNCTION__);
// Shut down the media
for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
mLocalSourceStreams[i]->Detach();
mLocalSourceStreams[i]->DetachMedia_m();
}
for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
mRemoteSourceStreams[i]->Detach();
mRemoteSourceStreams[i]->DetachMedia_m();
}
mLocalSourceStreams.Clear();
mRemoteSourceStreams.Clear();
// Final self-destruct.
this->Release();
}
void
PeerConnectionMedia::ShutdownMediaTransport()
PeerConnectionMedia::ShutdownMediaTransport_s()
{
ASSERT_ON_THREAD(mSTSThread);
CSFLogDebug(logTag, "%s: ", __FUNCTION__);
for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
mLocalSourceStreams[i]->DetachTransport_s();
}
for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
mRemoteSourceStreams[i]->DetachTransport_s();
}
disconnect_all();
mTransportFlows.clear();
mIceStreams.clear();
mIceCtx = NULL;
mMainThread->Dispatch(WrapRunnable(this, &PeerConnectionMedia::SelfDestruct_m),
NS_DISPATCH_NORMAL);
}
LocalSourceStreamInfo*
@ -314,6 +381,13 @@ PeerConnectionMedia::IceCompleted(NrIceCtx *aCtx)
SignalIceCompleted(aCtx);
}
void
PeerConnectionMedia::IceFailed(NrIceCtx *aCtx)
{
MOZ_ASSERT(aCtx);
SignalIceFailed(aCtx);
}
void
PeerConnectionMedia::IceStreamReady(NrIceMediaStream *aStream)
{

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