This commit is contained in:
Wes Kocher 2014-05-19 15:49:19 -07:00
Родитель d78ffb2440 256814234b
Коммит ff55b5123d
418 изменённых файлов: 16523 добавлений и 4292 удалений

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

@ -90,6 +90,26 @@ struct GroupPos
int32_t setSize;
};
/**
* An index type. Assert if out of range value was attempted to be used.
*/
class index_t
{
public:
index_t(int32_t aVal) : mVal(aVal) {}
operator uint32_t() const
{
MOZ_ASSERT(mVal >= 0, "Attempt to use wrong index!");
return mVal;
}
bool IsValid() const { return mVal >= 0; }
private:
int32_t mVal;
};
typedef nsRefPtrHashtable<nsPtrHashKey<const void>, Accessible>
AccessibleHashtable;

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

@ -21,15 +21,17 @@ namespace a11y {
inline bool
HyperTextAccessible::IsValidOffset(int32_t aOffset)
{
return ConvertMagicOffset(aOffset) <= CharacterCount();
index_t offset = ConvertMagicOffset(aOffset);
return offset.IsValid() && offset <= CharacterCount();
}
inline bool
HyperTextAccessible::IsValidRange(int32_t aStartOffset, int32_t aEndOffset)
{
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
return ConvertMagicOffset(aStartOffset) <= endOffset &&
endOffset <= CharacterCount();
index_t startOffset = ConvertMagicOffset(aStartOffset);
index_t endOffset = ConvertMagicOffset(aEndOffset);
return startOffset.IsValid() && endOffset.IsValid() &&
startOffset <= endOffset && endOffset <= CharacterCount();
}
inline void
@ -110,7 +112,7 @@ HyperTextAccessible::PasteText(int32_t aPosition)
}
}
inline uint32_t
inline index_t
HyperTextAccessible::ConvertMagicOffset(int32_t aOffset) const
{
if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT)
@ -119,7 +121,7 @@ HyperTextAccessible::ConvertMagicOffset(int32_t aOffset) const
if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET)
return CaretOffset();
return aOffset < 0 ? std::numeric_limits<uint32_t>::max() : aOffset;
return aOffset;
}
inline uint32_t

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

@ -191,8 +191,13 @@ HyperTextAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOffset,
{
aText.Truncate();
uint32_t startOffset = ConvertMagicOffset(aStartOffset);
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
index_t startOffset = ConvertMagicOffset(aStartOffset);
index_t endOffset = ConvertMagicOffset(aEndOffset);
if (!startOffset.IsValid() || !endOffset.IsValid() ||
startOffset > endOffset || endOffset > CharacterCount()) {
NS_ERROR("Wrong in offset");
return;
}
int32_t startChildIdx = GetChildIndexAtOffset(startOffset);
if (startChildIdx == -1)
@ -608,9 +613,9 @@ HyperTextAccessible::TextBeforeOffset(int32_t aOffset,
*aStartOffset = *aEndOffset = 0;
aText.Truncate();
uint32_t convertedOffset = ConvertMagicOffset(aOffset);
if (convertedOffset == std::numeric_limits<uint32_t>::max()) {
NS_ERROR("Wrong given offset!");
index_t convertedOffset = ConvertMagicOffset(aOffset);
if (!convertedOffset.IsValid() || convertedOffset > CharacterCount()) {
NS_ERROR("Wrong in offset!");
return;
}
@ -744,9 +749,9 @@ HyperTextAccessible::TextAfterOffset(int32_t aOffset,
*aStartOffset = *aEndOffset = 0;
aText.Truncate();
uint32_t convertedOffset = ConvertMagicOffset(aOffset);
if (convertedOffset == std::numeric_limits<uint32_t>::max()) {
NS_ERROR("Wrong given offset!");
index_t convertedOffset = ConvertMagicOffset(aOffset);
if (!convertedOffset.IsValid() || convertedOffset > CharacterCount()) {
NS_ERROR("Wrong in offset!");
return;
}
@ -814,10 +819,15 @@ HyperTextAccessible::TextAttributes(bool aIncludeDefAttrs, int32_t aOffset,
// the attribute range itself can only stay the same or get smaller.
*aStartOffset = *aEndOffset = 0;
index_t offset = ConvertMagicOffset(aOffset);
if (!offset.IsValid() || offset > CharacterCount()) {
NS_ERROR("Wrong in offset!");
return nullptr;
}
nsCOMPtr<nsIPersistentProperties> attributes =
do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
uint32_t offset = ConvertMagicOffset(aOffset);
Accessible* accAtOffset = GetChildAtOffset(offset);
if (!accAtOffset) {
// Offset 0 is correct offset when accessible has empty text. Include
@ -1029,11 +1039,14 @@ nsIntRect
HyperTextAccessible::TextBounds(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aCoordType)
{
uint32_t startOffset = ConvertMagicOffset(aStartOffset);
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
NS_ASSERTION(startOffset < endOffset &&
endOffset != std::numeric_limits<uint32_t>::max(),
"Wrong bad in!");
index_t startOffset = ConvertMagicOffset(aStartOffset);
index_t endOffset = ConvertMagicOffset(aEndOffset);
if (!startOffset.IsValid() || !endOffset.IsValid() ||
startOffset > endOffset || endOffset > CharacterCount()) {
NS_ERROR("Wrong in offset");
return nsIntRect();
}
int32_t childIdx = GetChildIndexAtOffset(startOffset);
if (childIdx == -1)
@ -1417,8 +1430,13 @@ HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
int32_t aStartOffset,
int32_t aEndOffset)
{
uint32_t startOffset = ConvertMagicOffset(aStartOffset);
uint32_t endOffset = ConvertMagicOffset(aEndOffset);
index_t startOffset = ConvertMagicOffset(aStartOffset);
index_t endOffset = ConvertMagicOffset(aEndOffset);
if (!startOffset.IsValid() || !endOffset.IsValid() ||
startOffset > endOffset || endOffset > CharacterCount()) {
NS_ERROR("Wrong in offset");
return false;
}
dom::Selection* domSel = DOMSelection();
if (!domSel)
@ -1879,7 +1897,7 @@ HyperTextAccessible::GetSpellTextAttr(nsINode* aNode,
if (rangeCount <= 0)
return;
int32_t startOffset = 0, endOffset = 0;
uint32_t startOffset = 0, endOffset = 0;
for (int32_t idx = 0; idx < rangeCount; idx++) {
nsRange* range = domSel->GetRangeAt(idx);
if (range->Collapsed())

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

@ -296,7 +296,11 @@ public:
* system.
*/
nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType)
{ return TextBounds(aOffset, aOffset + 1, aCoordType); }
{
int32_t endOffset = aOffset == static_cast<int32_t>(CharacterCount()) ?
aOffset : aOffset + 1;
return TextBounds(aOffset, endOffset, aCoordType);
}
/**
* Get/set caret offset, if no caret then -1.
@ -421,7 +425,7 @@ protected:
/**
* Transform magic offset into text offset.
*/
uint32_t ConvertMagicOffset(int32_t aOffset) const;
index_t ConvertMagicOffset(int32_t aOffset) const;
/**
* Adjust an offset the caret stays at to get a text by line boundary.

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

@ -301,6 +301,7 @@ pref("dom.ipc.tabs.disabled", false);
pref("layers.acceleration.disabled", false);
pref("layers.offmainthreadcomposition.async-animations", true);
pref("layers.async-video.enabled", true);
pref("layers.async-video-oop.enabled",true);
pref("layers.async-pan-zoom.enabled", true);
pref("gfx.content.azure.backends", "cairo");
#endif

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

@ -51,7 +51,6 @@ MOZ_EXTENSION_MANAGER=1
MOZ_TIME_MANAGER=1
MOZ_B2G_CERTDATA=1
MOZ_PAY=1
MOZ_TOOLKIT_SEARCH=
MOZ_PLACES=

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

@ -811,11 +811,7 @@ pref("plugin.state.f5 sam inspection host plugin", 2);
// display door hanger if flash not installed
pref("plugins.notifyMissingFlash", true);
#ifdef XP_WIN
pref("browser.preferences.instantApply", false);
#else
pref("browser.preferences.instantApply", true);
#endif
#ifdef XP_MACOSX
pref("browser.preferences.animateFadeIn", true);
#else
@ -823,7 +819,7 @@ pref("browser.preferences.animateFadeIn", false);
#endif
// Toggles between the two Preferences implementations, pop-up window and in-content
pref("browser.preferences.inContent", false);
pref("browser.preferences.inContent", true);
pref("browser.download.show_plugins_in_list", true);
pref("browser.download.hide_plugins_without_extensions", true);

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

@ -99,10 +99,9 @@ function test_multiple_windows() {
ok(notification2, "2nd window has a global notification box.");
let policy;
let displayCount = 0;
let prefPaneClosed = false;
let childWindowClosed = false;
let prefWindowClosed = false;
let mutationObserversRemoved = false;
function onAlertDisplayed() {
displayCount++;
@ -116,24 +115,26 @@ function test_multiple_windows() {
// We register two independent observers and we need both to clean up
// properly. This handles gating for test completion.
function maybeFinish() {
if (!prefPaneClosed) {
if (!prefWindowClosed) {
dump("Not finishing test yet because pref pane isn't closed.\n");
return;
}
if (!childWindowClosed) {
dump("Not finishing test yet because child window isn't closed.\n");
if (!mutationObserversRemoved) {
dump("Not finishing test yet because mutation observers haven't been removed yet.\n");
return;
}
window2.close();
dump("Finishing multiple window test.\n");
rootLogger.removeAppender(dumpAppender);
delete dumpAppender;
delete rootLogger;
finish();
}
let closeCount = 0;
function onAlertClose() {
closeCount++;
@ -151,8 +152,7 @@ function test_multiple_windows() {
is(notification1.allNotifications.length, 0, "No notifications remain on main window.");
is(notification2.allNotifications.length, 0, "No notifications remain on 2nd window.");
window2.close();
childWindowClosed = true;
mutationObserversRemoved = true;
maybeFinish();
}
@ -170,11 +170,11 @@ function test_multiple_windows() {
Services.obs.addObserver(function observer(prefWin, topic, data) {
Services.obs.removeObserver(observer, "advanced-pane-loaded");
ok(true, "Pref pane opened on info bar button press.");
ok(true, "Advanced preferences opened on info bar button press.");
executeSoon(function soon() {
dump("Closing pref pane.\n");
dump("Closing preferences.\n");
prefWin.close();
prefPaneClosed = true;
prefWindowClosed = true;
maybeFinish();
});
}, "advanced-pane-loaded", false);

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

@ -38,6 +38,11 @@ function checkPreferences(prefsWin) {
}
function test() {
if (Services.prefs.getBoolPref("browser.preferences.inContent")) {
// Bug 881576 - ensure this works with inContent prefs.
todo(false, "Bug 881576 - this test needs to be updated for inContent prefs");
return;
}
waitForExplicitFinish();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
@ -50,18 +55,13 @@ function test() {
// window to open - which we track either via a window watcher (for
// the window-based prefs) or via an "Initialized" event (for
// in-content prefs.)
if (Services.prefs.getBoolPref("browser.preferences.inContent")) {
// Bug 881576 - ensure this works with inContent prefs.
todo(false, "Bug 881576 - this test needs to be updated for inContent prefs");
} else {
Services.ww.registerNotification(function wwobserver(aSubject, aTopic, aData) {
if (aTopic != "domwindowopened")
return;
Services.ww.unregisterNotification(wwobserver);
checkPreferences(aSubject);
});
PopupNotifications.panel.firstElementChild.button.click();
}
Services.ww.registerNotification(function wwobserver(aSubject, aTopic, aData) {
if (aTopic != "domwindowopened")
return;
Services.ww.unregisterNotification(wwobserver);
checkPreferences(aSubject);
});
PopupNotifications.panel.firstElementChild.button.click();
});
};
Services.prefs.setIntPref("offline-apps.quota.warn", 1);

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

@ -505,10 +505,13 @@ function openPreferences(paneID, extraArgs)
}
if (newLoad) {
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
Services.obs.addObserver(function advancedPaneLoadedObs(prefWin, topic, data) {
if (prefWin != browser.contentWindow) {
return;
}
Services.obs.removeObserver(advancedPaneLoadedObs, "advanced-pane-loaded");
switchToPane();
}, true);
}, "advanced-pane-loaded", false);
} else {
switchToPane();
}

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

@ -772,15 +772,16 @@ let CustomizableUIInternal = {
continue;
}
let container = areaNode.customizationTarget;
let widgetNode = window.document.getElementById(aWidgetId);
if (!widgetNode) {
if (widgetNode && isOverflowable) {
container = areaNode.overflowable.getContainerFor(widgetNode);
}
if (!widgetNode || !container.contains(widgetNode)) {
INFO("Widget not found, unable to remove");
continue;
}
let container = areaNode.customizationTarget;
if (isOverflowable) {
container = areaNode.overflowable.getContainerFor(widgetNode);
}
this.notifyListeners("onWidgetBeforeDOMChange", widgetNode, null, container, true);

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

@ -108,6 +108,7 @@ skip-if = os == "linux"
[browser_993322_widget_notoolbar.js]
[browser_995164_registerArea_during_customize_mode.js]
[browser_996364_registerArea_different_properties.js]
[browser_996635_remove_non_widgets.js]
[browser_1003588_no_specials_in_panel.js]
[browser_1008559_anchor_undo_restore.js]
[browser_bootstrapped_custom_toolbar.js]

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

@ -0,0 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// NB: This is testing what happens if something that /isn't/ a customizable
// widget gets used in CustomizableUI APIs. Don't use this as an example of
// what should happen in a "normal" case or how you should use the API.
function test() {
// First create a button that isn't customizable, and add it in the nav-bar,
// but not in the customizable part of it (the customization target) but
// next to the main (hamburger) menu button.
const buttonID = "Test-non-widget-non-removable-button";
let btn = document.createElement("toolbarbutton");
btn.id = buttonID;
btn.label = "Hi";
btn.setAttribute("style", "width: 20px; height: 20px; background-color: red");
document.getElementById("nav-bar").appendChild(btn);
registerCleanupFunction(function() {
btn.remove();
});
// Now try to add this non-customizable button to the tabstrip. This will
// update the internal bookkeeping (ie placements) information, but shouldn't
// move the node.
CustomizableUI.addWidgetToArea(buttonID, CustomizableUI.AREA_TABSTRIP);
let placement = CustomizableUI.getPlacementOfWidget(buttonID);
// Check our bookkeeping
ok(placement, "Button should be placed");
is(placement && placement.area, CustomizableUI.AREA_TABSTRIP, "Should be placed on tabstrip.");
// Check we didn't move the node.
is(btn.parentNode && btn.parentNode.id, "nav-bar", "Actual button should still be on navbar.");
// Now remove the node again. This should remove the bookkeeping, but again
// not affect the actual node.
CustomizableUI.removeWidgetFromArea(buttonID);
placement = CustomizableUI.getPlacementOfWidget(buttonID);
// Check our bookkeeping:
ok(!placement, "Button should no longer have a placement.");
// Check our node.
is(btn.parentNode && btn.parentNode.id, "nav-bar", "Actual button should still be on navbar.");
}

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

@ -71,6 +71,9 @@ var gAdvancedPane = {
#endif
this.updateActualCacheSize();
this.updateActualAppCacheSize();
// Notify observers that the UI is now ready
Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
},
/**

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

@ -44,6 +44,7 @@ function selectCategory(name) {
let categories = document.getElementById("categories");
let item = categories.querySelector(".category[value=" + name + "]");
categories.selectedItem = item;
gotoPref(name);
}
function gotoPref(page) {

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -19,6 +19,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -17,6 +17,10 @@ function init() {
Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function(histogramId, value) {
if (!this.telemetryInfo) {
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
return;
}
if (histogramId) {
if (!this.telemetryInfo[histogramId]) {
this.telemetryInfo[histogramId] = [];

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

@ -27,6 +27,12 @@
position: relative;
}
@media (min-resolution: 2dppx) {
.breakpoint {
background-image: url("chrome://browser/skin/devtools/editor-breakpoint@2x.png");
}
}
.breakpoint[adding] {
transition: transform .25s;
}
@ -35,12 +41,26 @@
background-image: url("chrome://browser/skin/devtools/editor-debug-location.png");
}
@media (min-resolution: 2dppx) {
.debugLocation {
background-image: url("chrome://browser/skin/devtools/editor-debug-location@2x.png");
}
}
.breakpoint.debugLocation {
background-image:
url("chrome://browser/skin/devtools/editor-debug-location.png"),
url("chrome://browser/skin/devtools/editor-breakpoint.png");
}
@media (min-resolution: 2dppx) {
.breakpoint.debugLocation {
background-image:
url("chrome://browser/skin/devtools/editor-debug-location@2x.png"),
url("chrome://browser/skin/devtools/editor-breakpoint@2x.png");
}
}
.CodeMirror {
cursor: text;
}

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

@ -3,7 +3,3 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/debugger.inc.css
.devtools-sidebar-tabs > tabs > tab {
min-height: 24px !important;
}

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

@ -217,6 +217,7 @@ browser.jar:
skin/classic/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
skin/classic/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
skin/classic/browser/devtools/breadcrumbs-divider@2x.png (../shared/devtools/images/breadcrumbs-divider@2x.png)
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (../shared/devtools/images/breadcrumbs-scrollbutton.png)
skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
@ -245,15 +246,24 @@ browser.jar:
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
skin/classic/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
skin/classic/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
skin/classic/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
skin/classic/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
skin/classic/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
skin/classic/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
skin/classic/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
skin/classic/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
skin/classic/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
skin/classic/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
skin/classic/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
skin/classic/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsive-se-resizer.png)
@ -266,7 +276,8 @@ browser.jar:
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
skin/classic/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
skin/classic/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
skin/classic/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
skin/classic/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)

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

@ -333,7 +333,9 @@ browser.jar:
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
skin/classic/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
skin/classic/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
skin/classic/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.png (../shared/devtools/images/webconsole.png)
@ -366,15 +368,24 @@ browser.jar:
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
skin/classic/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
skin/classic/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
skin/classic/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
skin/classic/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
skin/classic/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
skin/classic/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
skin/classic/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
skin/classic/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
skin/classic/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
skin/classic/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
skin/classic/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
@ -387,7 +398,8 @@ browser.jar:
skin/classic/browser/devtools/dock-bottom@2x.png (../shared/devtools/images/dock-bottom@2x.png)
skin/classic/browser/devtools/dock-side@2x.png (../shared/devtools/images/dock-side@2x.png)
* skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
skin/classic/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
skin/classic/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
skin/classic/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
skin/classic/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)

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

@ -35,8 +35,7 @@
min-width: 30px;
min-height: 28px;
margin: 0;
list-style-image: url(profiler-stopwatch.png);
-moz-image-region: rect(0px,16px,16px,0px);
list-style-image: url(profiler-stopwatch.svg);
}
#empty-notice > button .button-text {
@ -74,12 +73,11 @@
}
#record-snapshot {
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.png");
-moz-image-region: rect(0px,16px,16px,0px);
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.svg");
}
#record-snapshot[checked] {
-moz-image-region: rect(0px,32px,16px,16px);
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch-checked.svg");
}
/* Snapshots items */

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

@ -61,6 +61,12 @@
list-style-image: url(debugger-blackbox.png);
}
@media (min-resolution: 2dppx) {
#black-box {
list-style-image: url(debugger-blackbox@2x.png);
}
}
#pretty-print {
font-weight: bold;
}
@ -69,6 +75,12 @@
list-style-image: url(debugger-toggleBreakpoints.png);
}
@media (min-resolution: 2dppx) {
#toggle-breakpoints {
list-style-image: url(debugger-toggleBreakpoints@2x.png);
}
}
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0px,16px,16px,0px);
}
@ -77,6 +89,16 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0px,32px,32px,0px);
}
#sources-toolbar .devtools-toolbarbutton:not([label])[checked] {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
#sources .black-boxed {
color: rgba(128,128,128,0.4);
}
@ -93,7 +115,6 @@
#black-boxed-message,
#source-progress-container {
background: url(background-noise-toolbar.png);
/* Prevent the container deck from aquiring the size from this message. */
min-width: 1px;
min-height: 1px;
@ -184,6 +205,17 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
#trace {
list-style-image: url(tracer-icon@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#trace[checked] {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
#clear-tracer {
/* Make this button as narrow as the text inside it. */
min-width: 1px;
@ -280,13 +312,21 @@
}
.dbg-expression-arrow {
background: url(commandline-icon.png);
background-image: url(commandline-icon.png);
background-position: 16px;
background-repeat: no-repeat;
background-size: 32px 16px;
width: 16px;
height: 16px;
margin: 2px;
}
@media (min-resolution: 2dppx) {
.dbg-expression-arrow {
background-image: url(commandline-icon@2x.png);
}
}
.dbg-expression-input {
color: inherit;
}
@ -542,10 +582,16 @@
/* Toolbar controls */
.devtools-sidebar-tabs > tabs > tab {
min-height: 1em !important;
min-height: 24px !important;
padding: 0 !important;
}
#debugger-toolbar .devtools-toolbarbutton:not([label]) > .toolbarbutton-icon,
#sources-toolbar .devtools-toolbarbutton:not([label]) > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
#resume {
list-style-image: url(debugger-pause.png);
-moz-image-region: rect(0px,16px,16px,0px);
@ -558,6 +604,18 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
#resume {
list-style-image: url(debugger-pause@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#resume[checked] {
list-style-image: url(debugger-play@2x.png);
-moz-image-region: rect(0px,64px,32px,32px);
}
}
#resume ~ toolbarbutton {
transition: opacity 0.15s ease-in-out;
}
@ -578,6 +636,20 @@
list-style-image: url(debugger-step-out.png);
}
@media (min-resolution: 2dppx) {
#step-over {
list-style-image: url(debugger-step-over@2x.png);
}
#step-in {
list-style-image: url(debugger-step-in@2x.png);
}
#step-out {
list-style-image: url(debugger-step-out@2x.png);
}
}
#instruments-pane-toggle {
background: none;
box-shadow: none;
@ -590,10 +662,25 @@
list-style-image: url(debugger-expand.png);
}
#instruments-pane-toggle:active {
#instruments-pane-toggle:hover {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
#instruments-pane-toggle {
list-style-image: url(debugger-collapse@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
}
#instruments-pane-toggle[pane-collapsed] {
list-style-image: url(debugger-expand@2x.png);
}
#instruments-pane-toggle:hover {
-moz-image-region: rect(0px,64px,32px,32px);
}
}
/* Horizontal vs. vertical layout */
#vertical-layout-panes-container {

Двоичные данные
browser/themes/shared/devtools/images/debugger-blackbox@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 988 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-collapse@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 338 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-expand@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 350 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-pause@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 189 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-play@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 494 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-step-in@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 355 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-step-out@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 339 B

Двоичные данные
browser/themes/shared/devtools/images/debugger-step-over@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 472 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 577 B

После

Ширина:  |  Высота:  |  Размер: 430 B

Двоичные данные
browser/themes/shared/devtools/images/editor-breakpoint@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 773 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 308 B

После

Ширина:  |  Высота:  |  Размер: 266 B

Двоичные данные
browser/themes/shared/devtools/images/editor-debug-location@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 462 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.4 KiB

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

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 16 16">
<g fill="#3BACE5" fill-rule="evenodd">
<path d="m8,1c-3.9,0-7,3.1-7,7s3.1,7 7,7c3.9,0 7-3.1 7-7s-3.1-7-7-7zm-.1,12c-2.8,0-5-2.2-5-5 0-2.8 2.2-5 5-5s5,2.2 5,5c0,2.8-2.2,5-5,5z"/>
<path d="m8,6.9c.6,0 1.1,.5 1.1,1.1 0,.6-.5,1.1-1.1,1.1-.6,0-1.1-.5-1.1-1.1 0-.6 .5-1.1 1.1-1.1z"/>
<path d="m11.3,4.6l-3.9,2.5 1.5,1.4 2.4-3.9z"/>
<path opacity=".4" d="m4.6,10c.7,1.2 2,2 3.4,2 1.5,0 2.7-.8 3.4-2h-6.8z"/>
<g opacity=".3">
<path d="m7.1,5.1l-.6-1.3-.9,.4 .7,1.3c.2-.1 .5-.3 .8-.4z"/>
<path d="m9.8,5.6l.7-1.4-.9-.4-.7,1.3c.3,.2 .6,.3 .9,.5z"/>
<path d="m10.8,7c.1,.3 .2,.7 .2,1h2v-1h-2.2z"/>
<path d="m5,8c0-.3 .1-.7 .2-1h-2.2l-.1,1h2.1z"/>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 814 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 754 B

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

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 16 16">
<g fill="#edf0f1" fill-rule="evenodd">
<path d="m8,1c-3.9,0-7,3.1-7,7s3.1,7 7,7c3.9,0 7-3.1 7-7s-3.1-7-7-7zm-.1,12c-2.8,0-5-2.2-5-5 0-2.8 2.2-5 5-5s5,2.2 5,5c0,2.8-2.2,5-5,5z"/>
<path d="m8,6.9c.6,0 1.1,.5 1.1,1.1 0,.6-.5,1.1-1.1,1.1-.6,0-1.1-.5-1.1-1.1 0-.6 .5-1.1 1.1-1.1z"/>
<path d="m11.3,4.6l-3.9,2.5 1.5,1.4 2.4-3.9z"/>
<path opacity=".4" d="m4.6,10c.7,1.2 2,2 3.4,2 1.5,0 2.7-.8 3.4-2h-6.8z"/>
<g opacity=".3">
<path d="m7.1,5.1l-.6-1.3-.9,.4 .7,1.3c.2-.1 .5-.3 .8-.4z"/>
<path d="m9.8,5.6l.7-1.4-.9-.4-.7,1.3c.3,.2 .6,.3 .9,.5z"/>
<path d="m10.8,7c.1,.3 .2,.7 .2,1h2v-1h-2.2z"/>
<path d="m5,8c0-.3 .1-.7 .2-1h-2.2l-.1,1h2.1z"/>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 814 B

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

@ -21,8 +21,7 @@
min-width: 30px;
min-height: 28px;
margin: 0;
list-style-image: url(profiler-stopwatch.png);
-moz-image-region: rect(0px,16px,16px,0px);
list-style-image: url(profiler-stopwatch.svg);
}
#requests-menu-perf-notice-button .button-text {
@ -613,8 +612,7 @@ label.requests-menu-status-code {
background: none;
box-shadow: none;
border-color: transparent;
list-style-image: url(profiler-stopwatch.png);
-moz-image-region: rect(0px,16px,16px,0px);
list-style-image: url(profiler-stopwatch.svg);
-moz-padding-end: 0;
cursor: pointer;
}

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

@ -70,10 +70,9 @@
}
#profiler-start {
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.png");
-moz-image-region: rect(0px,16px,16px,0px);
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch.svg");
}
#profiler-start[checked] {
-moz-image-region: rect(0px,32px,16px,16px);
}
list-style-image: url("chrome://browser/skin/devtools/profiler-stopwatch-checked.svg");
}

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

@ -792,7 +792,9 @@
.theme-light .command-button-invertable[checked=true]:not(:active) > image,
.theme-light .devtools-tab[icon-invertable][selected] > image,
.theme-light .devtools-tab[icon-invertable][highlighted] > image,
.theme-light #resume[checked] > image {
.theme-light #resume[checked] > image,
.theme-light #record-snapshot[checked] > image,
.theme-light #profiler-start[checked] > image {
filter: none !important;
}

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

@ -3,15 +3,3 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../../shared/devtools/debugger.inc.css
.devtools-sidebar-tabs > tabs > tab {
min-height: 22px !important;
}
#instruments-pane-toggle:hover {
-moz-image-region: rect(0px,32px,16px,16px);
}
#instruments-pane-toggle:hover:active {
-moz-image-region: rect(0px,48px,16px,32px);
}

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

@ -249,7 +249,9 @@ browser.jar:
skin/classic/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
skin/classic/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
skin/classic/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
skin/classic/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
skin/classic/browser/devtools/webconsole.png (../shared/devtools/images/webconsole.png)
@ -282,15 +284,24 @@ browser.jar:
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
skin/classic/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
skin/classic/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
skin/classic/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
skin/classic/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
skin/classic/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
skin/classic/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
skin/classic/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
skin/classic/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
skin/classic/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
skin/classic/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
skin/classic/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
skin/classic/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
skin/classic/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
skin/classic/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsive-se-resizer.png)
@ -303,7 +314,8 @@ browser.jar:
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
skin/classic/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
skin/classic/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
skin/classic/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
skin/classic/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
skin/classic/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
skin/classic/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)
@ -624,7 +636,9 @@ browser.jar:
skin/classic/aero/browser/devtools/markup-view.css (../shared/devtools/markup-view.css)
skin/classic/aero/browser/devtools/editor-error.png (../shared/devtools/images/editor-error.png)
skin/classic/aero/browser/devtools/editor-breakpoint.png (../shared/devtools/images/editor-breakpoint.png)
skin/classic/aero/browser/devtools/editor-breakpoint@2x.png (../shared/devtools/images/editor-breakpoint@2x.png)
skin/classic/aero/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
skin/classic/aero/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
* skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/aero/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
skin/classic/aero/browser/devtools/webconsole.png (../shared/devtools/images/webconsole.png)
@ -656,15 +670,24 @@ browser.jar:
skin/classic/aero/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
skin/classic/aero/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
skin/classic/aero/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
skin/classic/aero/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
skin/classic/aero/browser/devtools/debugger-expand.png (../shared/devtools/images/debugger-expand.png)
skin/classic/aero/browser/devtools/debugger-expand@2x.png (../shared/devtools/images/debugger-expand@2x.png)
skin/classic/aero/browser/devtools/debugger-pause.png (../shared/devtools/images/debugger-pause.png)
skin/classic/aero/browser/devtools/debugger-pause@2x.png (../shared/devtools/images/debugger-pause@2x.png)
skin/classic/aero/browser/devtools/debugger-play.png (../shared/devtools/images/debugger-play.png)
skin/classic/aero/browser/devtools/debugger-play@2x.png (../shared/devtools/images/debugger-play@2x.png)
skin/classic/aero/browser/devtools/debugger-step-in.png (../shared/devtools/images/debugger-step-in.png)
skin/classic/aero/browser/devtools/debugger-step-in@2x.png (../shared/devtools/images/debugger-step-in@2x.png)
skin/classic/aero/browser/devtools/debugger-step-out.png (../shared/devtools/images/debugger-step-out.png)
skin/classic/aero/browser/devtools/debugger-step-out@2x.png (../shared/devtools/images/debugger-step-out@2x.png)
skin/classic/aero/browser/devtools/debugger-step-over.png (../shared/devtools/images/debugger-step-over.png)
skin/classic/aero/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
skin/classic/aero/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/aero/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
skin/classic/aero/browser/devtools/debugger-blackbox-eye.png (../shared/devtools/images/debugger-blackbox-eye.png)
skin/classic/aero/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
skin/classic/aero/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
skin/classic/aero/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
skin/classic/aero/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
skin/classic/aero/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
skin/classic/aero/browser/devtools/tracer-icon@2x.png (../shared/devtools/images/tracer-icon@2x.png)
skin/classic/aero/browser/devtools/responsive-se-resizer.png (../shared/devtools/images/responsive-se-resizer.png)
@ -677,7 +700,8 @@ browser.jar:
skin/classic/aero/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/aero/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
skin/classic/aero/browser/devtools/inspector.css (devtools/inspector.css)
skin/classic/aero/browser/devtools/profiler-stopwatch.png (../shared/devtools/images/profiler-stopwatch.png)
skin/classic/aero/browser/devtools/profiler-stopwatch.svg (../shared/devtools/images/profiler-stopwatch.svg)
skin/classic/aero/browser/devtools/profiler-stopwatch-checked.svg (../shared/devtools/images/profiler-stopwatch-checked.svg)
skin/classic/aero/browser/devtools/tool-options.svg (../shared/devtools/images/tool-options.svg)
skin/classic/aero/browser/devtools/tool-webconsole.svg (../shared/devtools/images/tool-webconsole.svg)
skin/classic/aero/browser/devtools/tool-debugger.svg (../shared/devtools/images/tool-debugger.svg)

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

@ -10,8 +10,9 @@ interface nsIURI;
interface nsIChannel;
interface nsIDocShell;
interface nsIDomainPolicy;
interface nsILoadContext;
[scriptable, uuid(2565769a-eaec-47a1-a076-605f5294d286)]
[scriptable, uuid(9875f4b2-f9cd-41d1-a461-fe14956823ac)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager
{
/**
@ -122,6 +123,14 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
in unsigned long appId,
in boolean inMozBrowser);
/**
* Returns a principal that has the appId and inMozBrowser of the load
* context.
* @param loadContext to get appId/inMozBrowser from.
*/
nsIPrincipal getLoadContextCodebasePrincipal(in nsIURI uri,
in nsILoadContext loadContext);
/**
* Returns a principal that has the appId and inMozBrowser of the docshell
* inside a mozbrowser frame.

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

@ -11,6 +11,7 @@
#include "js/OldDebugAPI.h"
#include "xpcprivate.h"
#include "XPCWrapper.h"
#include "nsILoadContext.h"
#include "nsIServiceManager.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
@ -295,11 +296,12 @@ nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocShell> docShell;
NS_QueryNotificationCallbacks(aChannel, docShell);
if (docShell) {
return GetDocShellCodebasePrincipal(uri, docShell, aPrincipal);
nsCOMPtr<nsILoadContext> loadContext;
NS_QueryNotificationCallbacks(aChannel, loadContext);
if (loadContext) {
return GetLoadContextCodebasePrincipal(uri, loadContext, aPrincipal);
}
return GetCodebasePrincipalInternal(uri, UNKNOWN_APP_ID,
@ -969,6 +971,22 @@ nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
return GetCodebasePrincipalInternal(aURI, aAppId, aInMozBrowser, aPrincipal);
}
NS_IMETHODIMP
nsScriptSecurityManager::
GetLoadContextCodebasePrincipal(nsIURI* aURI,
nsILoadContext* aLoadContext,
nsIPrincipal** aPrincipal)
{
uint32_t appId;
aLoadContext->GetAppId(&appId);
bool isInBrowserElement;
aLoadContext->GetIsInBrowserElement(&isInBrowserElement);
return GetCodebasePrincipalInternal(aURI,
appId,
isInBrowserElement,
aPrincipal);
}
NS_IMETHODIMP
nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
nsIDocShell* aDocShell,

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

@ -7522,15 +7522,6 @@ if test -n "$MOZ_B2G_CAMERA"; then
fi
AC_SUBST(MOZ_B2G_CAMERA)
dnl ========================================================
dnl = Enable Support B2G-specific changes to the NSS
dnl = certificate trust database.
dnl ========================================================
if test -n "$MOZ_B2G_CERTDATA"; then
AC_DEFINE(MOZ_B2G_CERTDATA)
fi
AC_SUBST(MOZ_B2G_CERTDATA)
dnl ========================================================
dnl = Enable Support for Payment API
dnl ========================================================

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

@ -175,4 +175,8 @@
#define THIRDPARTYUTIL_CID \
{0x08c6cc8b, 0xcfb0, 0x421d, {0xb1, 0xf7, 0x68, 0x3f, 0xf2, 0x98, 0x96, 0x81}}
// {7B121F7E-EBE4-43AB-9410-DC9087A1DBA6}
#define GECKO_MEDIA_PLUGIN_SERVICE_CID \
{0x7B121F7E, 0xEBE4, 0x43AB, {0x94, 0x10, 0xDC, 0x90, 0x87, 0xA1, 0xDB, 0xA6}}
#endif /* nsContentCID_h__ */

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

@ -28,6 +28,7 @@
#include "mozilla/Telemetry.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsUnicharUtils.h"
#include "nsContentList.h"
#include "nsIObserver.h"
@ -2337,21 +2338,21 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
nsIScriptSecurityManager *securityManager =
nsContentUtils::GetSecurityManager();
if (securityManager) {
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
nsCOMPtr<nsILoadContext> loadContext(mDocumentContainer);
if (!docShell && aLoadGroup) {
if (!loadContext && aLoadGroup) {
nsCOMPtr<nsIInterfaceRequestor> cbs;
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
docShell = do_GetInterface(cbs);
loadContext = do_GetInterface(cbs);
}
MOZ_ASSERT(docShell,
"must be in a docshell or pass in an explicit principal");
MOZ_ASSERT(loadContext,
"must have a load context or pass in an explicit principal");
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = securityManager->
GetDocShellCodebasePrincipal(mDocumentURI, docShell,
getter_AddRefs(principal));
GetLoadContextCodebasePrincipal(mDocumentURI, loadContext,
getter_AddRefs(principal));
if (NS_SUCCEEDED(rv)) {
SetPrincipal(principal);
}

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

@ -54,6 +54,7 @@
#include "mozilla/CORSMode.h"
#include "mozilla/Attributes.h"
#include "mozilla/Telemetry.h"
#include "mozilla/unused.h"
#ifdef PR_LOGGING
@ -86,9 +87,7 @@ public:
~nsScriptLoadRequest()
{
if (mScriptTextBuf) {
js_free(mScriptTextBuf);
}
js_free(mScriptTextBuf);
}
NS_DECL_THREADSAFE_ISUPPORTS
@ -433,7 +432,7 @@ ParseTypeAttribute(const nsAString& aType, JSVersion* aVersion)
return true;
}
bool
static bool
CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
{
nsCOMPtr<nsIContentSecurityPolicy> csp;
@ -540,6 +539,43 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
return true;
}
static void
AccumulateJavaScriptVersionTelemetry(nsIScriptElement* aElement,
JSVersion aVersion)
{
uint32_t minorVersion;
switch (aVersion) {
case JSVERSION_DEFAULT: minorVersion = 5; break;
case JSVERSION_1_6: minorVersion = 6; break;
case JSVERSION_1_7: minorVersion = 7; break;
case JSVERSION_1_8: minorVersion = 8; break;
default: MOZ_ASSERT_UNREACHABLE("Unexpected JSVersion");
case JSVERSION_UNKNOWN: minorVersion = 0; break;
}
// Only report SpiderMonkey's nonstandard JS versions: 1.6, 1.7, and 1.8.
if (minorVersion < 6) {
return;
}
nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
if (!scriptURI) {
return;
}
// We only care about web content, not chrome or add-on JS versions.
bool chrome = false;
scriptURI->SchemeIs("chrome", &chrome);
if (!chrome) {
scriptURI->SchemeIs("resource", &chrome);
}
if (chrome) {
return;
}
Telemetry::Accumulate(Telemetry::JS_MINOR_VERSION, minorVersion);
}
bool
nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
{
@ -568,6 +604,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
aElement->GetScriptType(type);
if (!type.IsEmpty()) {
NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false);
AccumulateJavaScriptVersionTelemetry(aElement, version);
} else {
// no 'type=' element
// "language" is a deprecated attribute of HTML, so we check it only for

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

@ -2,7 +2,14 @@ dump('loaded child cpow test\n');
content.document.title = "Hello, Kitty";
var done_count = 0;
var is_remote;
(function start() {
[is_remote] = sendSyncMessage("cpows:is_remote");
parent_test();
dom_test();
xray_test();
sync_test();
async_test();
rpc_test();
@ -10,7 +17,12 @@ content.document.title = "Hello, Kitty";
// The sync-ness of this call is important, because otherwise
// we tear down the child's document while we are
// still in the async test in the parent.
sendSyncMessage("cpows:done", {});
// This test races with itself to be the final test.
lifetime_test(function() {
done_count++;
if (done_count == 2)
sendSyncMessage("cpows:done", {});
});
}
)();
@ -56,6 +68,44 @@ function make_json()
return { check: "ok" };
}
function parent_test()
{
function f(check_func) {
let result = check_func(10);
ok(result == 20, "calling function in parent worked");
return result;
}
addMessageListener("cpows:from_parent", (msg) => {
let obj = msg.objects.obj;
ok(obj.a == 1, "correct value from parent");
done_count++;
if (done_count == 2)
sendSyncMessage("cpows:done", {});
});
sendSyncMessage("cpows:parent_test", {}, {func: f});
}
function dom_test()
{
let element = content.document.createElement("div");
element.id = "it_works";
content.document.body.appendChild(element);
sendAsyncMessage("cpows:dom_test", {}, {element: element});
Components.utils.schedulePreciseGC(function() {
sendSyncMessage("cpows:dom_test_after_gc");
});
}
function xray_test()
{
let element = content.document.createElement("div");
element.wrappedJSObject.foo = "hello";
sendSyncMessage("cpows:xray_test", {}, {element: element});
}
function sync_test()
{
dump('beginning cpow sync test\n');
@ -106,3 +156,28 @@ function nested_sync_test()
make_json(),
rpc_obj);
}
function lifetime_test(finish)
{
if (!is_remote) {
// Only run this test when running out-of-process. Otherwise it
// will fail, since local CPOWs don't follow the same ownership
// rules.
finish();
return;
}
dump("beginning lifetime test\n");
var obj = {"will_die": {"f": 1}};
let [result] = sendSyncMessage("cpows:lifetime_test_1", {}, {obj: obj});
ok(result == 10, "got sync result");
ok(obj.wont_die.f == 2, "got reverse CPOW");
obj.will_die = null;
Components.utils.schedulePreciseGC(function() {
addMessageListener("cpows:lifetime_test_3", (msg) => {
ok(obj.wont_die.f == 2, "reverse CPOW still works");
finish();
});
sendSyncMessage("cpows:lifetime_test_2");
});
}

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

@ -13,11 +13,20 @@
var test_state = "remote";
var test_node = null;
var reentered = false;
var savedMM = null;
function info(message) {
return opener.wrappedJSObject.info(message);
}
function ok(condition, message) {
return opener.wrappedJSObject.ok(condition, message);
}
function is(v1, v2, message) {
return opener.wrappedJSObject.is(v1, v2, message);
}
// Make sure that an error in this file actually causes the test to fail.
window.onerror = function (msg, url, line) {
ok(false, "Error while executing: \n" + msg + "\n" + url + ":" + line);
@ -145,13 +154,72 @@
finish();
}
function recvParentTest(message) {
let func = message.objects.func;
let result = func(n => 2*n);
ok(result == 20, "result == 20");
let obj = {a:1};
savedMM.sendAsyncMessage("cpows:from_parent", {}, {obj: obj});
}
let savedElement = null;
function recvDomTest(message) {
savedElement = message.objects.element;
}
function recvDomTestAfterGC(message) {
let id;
try {
id = savedElement.id;
} catch (e) {
ok(false, "Got exception using DOM element");
}
is(id, "it_works", "DOM element has expected ID");
}
function recvXrayTest(message) {
let element = message.objects.element;
is(element.foo, undefined, "DOM element does not expose content properties");
}
let savedWilldieObj;
let wontDie = {f:2};
function recvLifetimeTest1(message) {
let obj = message.objects.obj;
savedWilldieObj = obj.will_die;
ok(savedWilldieObj.f == 1, "limited-lifetime CPOW works at first");
obj.wont_die = wontDie;
obj = null;
return 10;
}
function recvLifetimeTest2(message) {
let threw = false;
try {
savedWilldieObj.f;
} catch (e) {
threw = true;
}
ok(threw, "limited-lifetime CPOW stopped working");
wontDie = null;
Components.utils.schedulePreciseGC(function() {
savedMM.sendAsyncMessage("cpows:lifetime_test_3");
});
}
function run_tests(type) {
info("Running tests: " + type);
var node = document.getElementById('cpowbrowser_' + type);
test_state = type;
test_node = node;
function recvIsRemote(message) {
return type == "remote";
}
var mm = node.messageManager;
savedMM = mm;
mm.addMessageListener("cpows:is_remote", recvIsRemote);
mm.addMessageListener("cpows:async", recvAsyncMessage);
mm.addMessageListener("cpows:sync", recvSyncMessage);
mm.addMessageListener("cpows:rpc", recvRpcMessage);
@ -161,6 +229,12 @@
mm.addMessageListener("cpows:reenter_sync", recvReenterSyncMessage);
mm.addMessageListener("cpows:done", recvDoneMessage);
mm.addMessageListener("cpows:fail", recvFailMessage);
mm.addMessageListener("cpows:parent_test", recvParentTest);
mm.addMessageListener("cpows:dom_test", recvDomTest);
mm.addMessageListener("cpows:dom_test_after_gc", recvDomTestAfterGC);
mm.addMessageListener("cpows:xray_test", recvXrayTest);
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
mm.addMessageListener("cpows:lifetime_test_2", recvLifetimeTest2);
mm.loadFrameScript("chrome://mochitests/content/chrome/content/base/test/chrome/cpows_child.js", true);
}

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

@ -5196,6 +5196,8 @@ HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart,
}
}
break;
default:
MOZ_CRASH("Unknown mode!");
}
Optional<nsAString> direction;

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

@ -985,6 +985,8 @@ HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
}
}
break;
default:
MOZ_CRASH("Unknown mode!");
}
Optional<nsAString> direction;

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

@ -77,6 +77,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
return;
STREAM_LOG(PR_LOG_DEBUG, ("MediaStream %p will finish", aStream));
aStream->mFinished = true;
aStream->mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX);
// Force at least one more iteration of the control loop, since we rely
// on UpdateCurrentTime to notify our listeners once the stream end
// has been reached.
@ -206,7 +207,9 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
aStream->mUpdateTracks.RemoveElementAt(i);
}
}
aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
if (!aStream->mFinished) {
aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
}
}
if (aStream->mBuffer.GetEnd() > 0) {
aStream->mHasCurrentData = true;
@ -2409,6 +2412,7 @@ void
SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(aKnownTime >= mUpdateKnownTracksTime);
mUpdateKnownTracksTime = aKnownTime;
if (!mDestroyed) {
GraphImpl()->EnsureNextIteration();

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

@ -737,8 +737,7 @@ public:
/**
* Indicate that this stream should enter the "finished" state. All tracks
* must have been ended via EndTrack. The finish time of the stream is
* when all tracks have ended and when latest time sent to
* AdvanceKnownTracksTime() has been reached.
* when all tracks have ended.
*/
void FinishWithLockHeld();
void Finish()

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

@ -49,6 +49,10 @@ StreamBuffer::GetEnd() const
StreamTime
StreamBuffer::GetAllTracksEnd() const
{
if (mTracksKnownTime < STREAM_TIME_MAX) {
// A track might be added.
return STREAM_TIME_MAX;
}
StreamTime t = 0;
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
Track* track = mTracks[i];
@ -57,11 +61,6 @@ StreamBuffer::GetAllTracksEnd() const
}
t = std::max(t, track->GetEndTimeRoundDown());
}
if (t > mTracksKnownTime) {
// It can't be later then mTracksKnownTime, since a track might be added
// after that.
return STREAM_TIME_MAX;
}
return t;
}

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

@ -106,8 +106,9 @@ public:
// all our tracks have actually finished and been removed from our map,
// so we're finished now.
FinishOnGraphThread();
} else {
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo));
}
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo));
if (allHaveCurrentData) {
// We can make progress if we're not blocked
mHasCurrentData = true;

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

@ -0,0 +1,202 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPChild.h"
#include "GMPVideoDecoderChild.h"
#include "GMPVideoEncoderChild.h"
#include "GMPVideoHost.h"
#include "nsIFile.h"
#include "nsXULAppAPI.h"
#include <stdlib.h>
#include "gmp-video-decode.h"
#include "gmp-video-encode.h"
#include "GMPPlatform.h"
namespace mozilla {
namespace gmp {
GMPChild::GMPChild()
: mLib(nullptr)
, mGetAPIFunc(nullptr)
, mGMPMessageLoop(MessageLoop::current())
{
}
GMPChild::~GMPChild()
{
}
bool
GMPChild::Init(const std::string& aPluginPath,
base::ProcessHandle aParentProcessHandle,
MessageLoop* aIOLoop,
IPC::Channel* aChannel)
{
return LoadPluginLibrary(aPluginPath) &&
Open(aChannel, aParentProcessHandle, aIOLoop);
}
bool
GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
{
nsDependentCString pluginPath(aPluginPath.c_str());
nsCOMPtr<nsIFile> libFile;
nsresult rv = NS_NewNativeLocalFile(pluginPath, true, getter_AddRefs(libFile));
if (NS_FAILED(rv)) {
return false;
}
nsAutoString leafName;
if (NS_FAILED(libFile->GetLeafName(leafName))) {
return false;
}
nsAutoString baseName(Substring(leafName, 4, leafName.Length() - 1));
#if defined(XP_MACOSX)
nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".dylib");
#elif defined(OS_POSIX)
nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".so");
#elif defined(XP_WIN)
nsAutoString binaryName = baseName + NS_LITERAL_STRING(".dll");
#else
#error not defined
#endif
libFile->AppendRelativePath(binaryName);
nsAutoCString nativePath;
libFile->GetNativePath(nativePath);
mLib = PR_LoadLibrary(nativePath.get());
if (!mLib) {
return false;
}
GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
if (!initFunc) {
return false;
}
auto platformAPI = new GMPPlatformAPI();
InitPlatformAPI(*platformAPI);
if (initFunc(platformAPI) != GMPNoErr) {
return false;
}
mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
if (!mGetAPIFunc) {
return false;
}
return true;
}
MessageLoop*
GMPChild::GMPMessageLoop()
{
return mGMPMessageLoop;
}
void
GMPChild::ActorDestroy(ActorDestroyReason aWhy)
{
if (mLib) {
GMPShutdownFunc shutdownFunc = reinterpret_cast<GMPShutdownFunc>(PR_FindFunctionSymbol(mLib, "GMPShutdown"));
if (shutdownFunc) {
shutdownFunc();
}
}
if (AbnormalShutdown == aWhy) {
NS_WARNING("Abnormal shutdown of GMP process!");
_exit(0);
}
XRE_ShutdownChildProcess();
}
void
GMPChild::ProcessingError(Result aWhat)
{
switch (aWhat) {
case MsgDropped:
_exit(0); // Don't trigger a crash report.
case MsgNotKnown:
MOZ_CRASH("aborting because of MsgNotKnown");
case MsgNotAllowed:
MOZ_CRASH("aborting because of MsgNotAllowed");
case MsgPayloadError:
MOZ_CRASH("aborting because of MsgPayloadError");
case MsgProcessingError:
MOZ_CRASH("aborting because of MsgProcessingError");
case MsgRouteError:
MOZ_CRASH("aborting because of MsgRouteError");
case MsgValueError:
MOZ_CRASH("aborting because of MsgValueError");
default:
MOZ_CRASH("not reached");
}
}
PGMPVideoDecoderChild*
GMPChild::AllocPGMPVideoDecoderChild()
{
return new GMPVideoDecoderChild(this);
}
bool
GMPChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
{
delete aActor;
return true;
}
PGMPVideoEncoderChild*
GMPChild::AllocPGMPVideoEncoderChild()
{
return new GMPVideoEncoderChild(this);
}
bool
GMPChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
{
delete aActor;
return true;
}
bool
GMPChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor)
{
auto vdc = static_cast<GMPVideoDecoderChild*>(aActor);
void* vd = nullptr;
GMPErr err = mGetAPIFunc("decode-video", &vdc->Host(), &vd);
if (err != GMPNoErr || !vd) {
return false;
}
vdc->Init(static_cast<GMPVideoDecoder*>(vd));
return true;
}
bool
GMPChild::RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor)
{
auto vec = static_cast<GMPVideoEncoderChild*>(aActor);
void* ve = nullptr;
GMPErr err = mGetAPIFunc("encode-video", &vec->Host(), &ve);
if (err != GMPNoErr || !ve) {
return false;
}
vec->Init(static_cast<GMPVideoEncoder*>(ve));
return true;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPChild_h_
#define GMPChild_h_
#include "mozilla/gmp/PGMPChild.h"
#include "gmp-entrypoints.h"
#include "prlink.h"
namespace mozilla {
namespace gmp {
class GMPChild : public PGMPChild
{
public:
GMPChild();
virtual ~GMPChild();
bool Init(const std::string& aPluginPath,
base::ProcessHandle aParentProcessHandle,
MessageLoop* aIOLoop,
IPC::Channel* aChannel);
bool LoadPluginLibrary(const std::string& aPluginPath);
MessageLoop* GMPMessageLoop();
private:
virtual PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
virtual PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) MOZ_OVERRIDE;
virtual bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
virtual bool RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
PRLibrary* mLib;
GMPGetAPIFunc mGetAPIFunc;
MessageLoop* mGMPMessageLoop;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPChild_h_

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

@ -0,0 +1,329 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPMessageUtils_h_
#define GMPMessageUtils_h_
#include "gmp-video-codec.h"
namespace IPC {
template <>
struct ParamTraits<GMPVideoCodecComplexity>
: public ContiguousEnumSerializer<GMPVideoCodecComplexity,
kGMPComplexityNormal,
kGMPComplexityInvalid>
{};
template <>
struct ParamTraits<GMPVP8ResilienceMode>
: public ContiguousEnumSerializer<GMPVP8ResilienceMode,
kResilienceOff,
kResilienceInvalid>
{};
template <>
struct ParamTraits<GMPVideoCodecType>
: public ContiguousEnumSerializer<GMPVideoCodecType,
kGMPVideoCodecVP8,
kGMPVideoCodecInvalid>
{};
template <>
struct ParamTraits<GMPVideoCodecMode>
: public ContiguousEnumSerializer<GMPVideoCodecMode,
kGMPRealtimeVideo,
kGMPCodecModeInvalid>
{};
template <>
struct ParamTraits<GMPVideoCodecVP8>
{
typedef GMPVideoCodecVP8 paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mPictureLossIndicationOn);
WriteParam(aMsg, aParam.mFeedbackModeOn);
WriteParam(aMsg, aParam.mComplexity);
WriteParam(aMsg, aParam.mResilience);
WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
WriteParam(aMsg, aParam.mDenoisingOn);
WriteParam(aMsg, aParam.mErrorConcealmentOn);
WriteParam(aMsg, aParam.mAutomaticResizeOn);
WriteParam(aMsg, aParam.mFrameDroppingOn);
WriteParam(aMsg, aParam.mKeyFrameInterval);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &(aResult->mPictureLossIndicationOn)) &&
ReadParam(aMsg, aIter, &(aResult->mFeedbackModeOn)) &&
ReadParam(aMsg, aIter, &(aResult->mComplexity)) &&
ReadParam(aMsg, aIter, &(aResult->mResilience)) &&
ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
ReadParam(aMsg, aIter, &(aResult->mDenoisingOn)) &&
ReadParam(aMsg, aIter, &(aResult->mErrorConcealmentOn)) &&
ReadParam(aMsg, aIter, &(aResult->mAutomaticResizeOn)) &&
ReadParam(aMsg, aIter, &(aResult->mFrameDroppingOn)) &&
ReadParam(aMsg, aIter, &(aResult->mKeyFrameInterval))) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%d, %d, %d, %d, %u, %d, %d, %d, %d, %d]",
aParam.mPictureLossIndicationOn,
aParam.mFeedbackModeOn,
aParam.mComplexity,
aParam.mResilience,
aParam.mNumberOfTemporalLayers,
aParam.mDenoisingOn,
aParam.mErrorConcealmentOn,
aParam.mAutomaticResizeOn,
aParam.mFrameDroppingOn,
aParam.mKeyFrameInterval));
}
};
template <>
struct ParamTraits<GMPSimulcastStream>
{
typedef GMPSimulcastStream paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mWidth);
WriteParam(aMsg, aParam.mHeight);
WriteParam(aMsg, aParam.mNumberOfTemporalLayers);
WriteParam(aMsg, aParam.mMaxBitrate);
WriteParam(aMsg, aParam.mTargetBitrate);
WriteParam(aMsg, aParam.mMinBitrate);
WriteParam(aMsg, aParam.mQPMax);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &(aResult->mWidth)) &&
ReadParam(aMsg, aIter, &(aResult->mHeight)) &&
ReadParam(aMsg, aIter, &(aResult->mNumberOfTemporalLayers)) &&
ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) &&
ReadParam(aMsg, aIter, &(aResult->mTargetBitrate)) &&
ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) &&
ReadParam(aMsg, aIter, &(aResult->mQPMax))) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%u, %u, %u, %u, %u, %u, %u]", aParam.mWidth, aParam.mHeight,
aParam.mNumberOfTemporalLayers, aParam.mMaxBitrate,
aParam.mTargetBitrate, aParam.mMinBitrate, aParam.mQPMax));
}
};
template <>
struct ParamTraits<GMPVideoCodec>
{
typedef GMPVideoCodec paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCodecType);
WriteParam(aMsg, nsAutoCString(aParam.mPLName));
WriteParam(aMsg, aParam.mPLType);
WriteParam(aMsg, aParam.mWidth);
WriteParam(aMsg, aParam.mHeight);
WriteParam(aMsg, aParam.mStartBitrate);
WriteParam(aMsg, aParam.mMaxBitrate);
WriteParam(aMsg, aParam.mMinBitrate);
WriteParam(aMsg, aParam.mMaxFramerate);
if (aParam.mCodecType == kGMPVideoCodecVP8) {
WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
} else {
MOZ_ASSERT(false, "Serializing unknown codec type!");
}
WriteParam(aMsg, aParam.mQPMax);
WriteParam(aMsg, aParam.mNumberOfSimulcastStreams);
for (uint32_t i = 0; i < aParam.mNumberOfSimulcastStreams; i++) {
WriteParam(aMsg, aParam.mSimulcastStream[i]);
}
WriteParam(aMsg, aParam.mMode);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
return false;
}
nsAutoCString plName;
if (!ReadParam(aMsg, aIter, &plName) ||
plName.Length() > kGMPPayloadNameSize - 1) {
return false;
}
memcpy(aResult->mPLName, plName.get(), plName.Length());
memset(aResult->mPLName + plName.Length(), 0, kGMPPayloadNameSize - plName.Length());
if (!ReadParam(aMsg, aIter, &(aResult->mPLType)) ||
!ReadParam(aMsg, aIter, &(aResult->mWidth)) ||
!ReadParam(aMsg, aIter, &(aResult->mHeight)) ||
!ReadParam(aMsg, aIter, &(aResult->mStartBitrate)) ||
!ReadParam(aMsg, aIter, &(aResult->mMaxBitrate)) ||
!ReadParam(aMsg, aIter, &(aResult->mMinBitrate)) ||
!ReadParam(aMsg, aIter, &(aResult->mMaxFramerate))) {
return false;
}
if (aResult->mCodecType == kGMPVideoCodecVP8) {
if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
return false;
}
} else {
MOZ_ASSERT(false, "De-serializing unknown codec type!");
return false;
}
if (!ReadParam(aMsg, aIter, &(aResult->mQPMax)) ||
!ReadParam(aMsg, aIter, &(aResult->mNumberOfSimulcastStreams))) {
return false;
}
if (aResult->mNumberOfSimulcastStreams > kGMPMaxSimulcastStreams) {
return false;
}
for (uint32_t i = 0; i < aResult->mNumberOfSimulcastStreams; i++) {
if (!ReadParam(aMsg, aIter, &(aResult->mSimulcastStream[i]))) {
return false;
}
}
if (!ReadParam(aMsg, aIter, &(aResult->mMode))) {
return false;
}
return true;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
const char* codecName = nullptr;
if (aParam.mCodecType == kGMPVideoCodecVP8) {
codecName = "VP8";
}
aLog->append(StringPrintf(L"[%s, %u, %u]",
codecName,
aParam.mWidth,
aParam.mHeight));
}
};
template <>
struct ParamTraits<GMPCodecSpecificInfoVP8>
{
typedef GMPCodecSpecificInfoVP8 paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mHasReceivedSLI);
WriteParam(aMsg, aParam.mPictureIdSLI);
WriteParam(aMsg, aParam.mHasReceivedRPSI);
WriteParam(aMsg, aParam.mPictureIdRPSI);
WriteParam(aMsg, aParam.mPictureId);
WriteParam(aMsg, aParam.mNonReference);
WriteParam(aMsg, aParam.mSimulcastIdx);
WriteParam(aMsg, aParam.mTemporalIdx);
WriteParam(aMsg, aParam.mLayerSync);
WriteParam(aMsg, aParam.mTL0PicIdx);
WriteParam(aMsg, aParam.mKeyIdx);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &(aResult->mHasReceivedSLI)) &&
ReadParam(aMsg, aIter, &(aResult->mPictureIdSLI)) &&
ReadParam(aMsg, aIter, &(aResult->mHasReceivedRPSI)) &&
ReadParam(aMsg, aIter, &(aResult->mPictureIdRPSI)) &&
ReadParam(aMsg, aIter, &(aResult->mPictureId)) &&
ReadParam(aMsg, aIter, &(aResult->mNonReference)) &&
ReadParam(aMsg, aIter, &(aResult->mSimulcastIdx)) &&
ReadParam(aMsg, aIter, &(aResult->mTemporalIdx)) &&
ReadParam(aMsg, aIter, &(aResult->mLayerSync)) &&
ReadParam(aMsg, aIter, &(aResult->mTL0PicIdx)) &&
ReadParam(aMsg, aIter, &(aResult->mKeyIdx))) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%d, %u, %d, %u, %d, %d, %u, %u, %d, %d, %d]",
aParam.mHasReceivedSLI,
aParam.mPictureIdSLI,
aParam.mHasReceivedRPSI,
aParam.mPictureIdRPSI,
aParam.mPictureId,
aParam.mNonReference,
aParam.mSimulcastIdx,
aParam.mTemporalIdx,
aParam.mLayerSync,
aParam.mTL0PicIdx,
aParam.mKeyIdx));
}
};
template <>
struct ParamTraits<GMPCodecSpecificInfo>
{
typedef GMPCodecSpecificInfo paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCodecType);
if (aParam.mCodecType == kGMPVideoCodecVP8) {
WriteParam(aMsg, aParam.mCodecSpecific.mVP8);
} else {
MOZ_ASSERT(false, "Serializing unknown codec type!");
}
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->mCodecType))) {
return false;
}
if (aResult->mCodecType == kGMPVideoCodecVP8) {
if (!ReadParam(aMsg, aIter, &(aResult->mCodecSpecific.mVP8))) {
return false;
}
} else {
MOZ_ASSERT(false, "De-serializing unknown codec type!");
return false;
}
return true;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
const char* codecName = nullptr;
if (aParam.mCodecType == kGMPVideoCodecVP8) {
codecName = "VP8";
}
aLog->append(StringPrintf(L"[%s]", codecName));
}
};
} // namespace IPC
#endif // GMPMessageUtils_h_

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

@ -0,0 +1,424 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPParent.h"
#include "nsComponentManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsIInputStream.h"
#include "nsILineInputStream.h"
#include "nsNetUtil.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsThreadUtils.h"
#include "nsIRunnable.h"
#include "mozIGeckoMediaPluginService.h"
namespace mozilla {
namespace gmp {
GMPParent::GMPParent()
: mState(GMPStateNotLoaded)
, mProcess(nullptr)
{
}
GMPParent::~GMPParent()
{
}
nsresult
GMPParent::Init(nsIFile* aPluginDir)
{
MOZ_ASSERT(aPluginDir);
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
mDirectory = aPluginDir;
nsAutoString leafname;
nsresult rv = aPluginDir->GetLeafName(leafname);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_ASSERT(leafname.Length() > 4);
mName = Substring(leafname, 4);
return ReadGMPMetaData();
}
nsresult
GMPParent::LoadProcess()
{
MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (mState == GMPStateLoaded) {
return NS_OK;
}
nsAutoCString path;
if (NS_FAILED(mDirectory->GetNativePath(path))) {
return NS_ERROR_FAILURE;
}
mProcess = new GMPProcessParent(path.get());
if (!mProcess->Launch(30 * 1000)) {
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
bool opened = Open(mProcess->GetChannel(), mProcess->GetChildProcessHandle());
if (!opened) {
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
mState = GMPStateLoaded;
return NS_OK;
}
void
GMPParent::MaybeUnloadProcess()
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (mVideoDecoders.Length() == 0 &&
mVideoEncoders.Length() == 0) {
UnloadProcess();
}
}
void
GMPParent::UnloadProcess()
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (mState == GMPStateNotLoaded) {
MOZ_ASSERT(mVideoDecoders.IsEmpty() && mVideoEncoders.IsEmpty());
return;
}
mState = GMPStateNotLoaded;
// Invalidate and remove any remaining API objects.
for (uint32_t i = mVideoDecoders.Length(); i > 0; i--) {
mVideoDecoders[i - 1]->DecodingComplete();
}
// Invalidate and remove any remaining API objects.
for (uint32_t i = mVideoEncoders.Length(); i > 0; i--) {
mVideoEncoders[i - 1]->EncodingComplete();
}
Close();
if (mProcess) {
mProcess->Delete();
mProcess = nullptr;
}
}
void
GMPParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ALWAYS_TRUE(mVideoDecoders.RemoveElement(aDecoder));
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
// until after this has completed.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::MaybeUnloadProcess);
NS_DispatchToCurrentThread(event);
}
void
GMPParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ALWAYS_TRUE(mVideoEncoders.RemoveElement(aEncoder));
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
// until after this has completed.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::MaybeUnloadProcess);
NS_DispatchToCurrentThread(event);
}
GMPState
GMPParent::State() const
{
return mState;
}
#ifdef DEBUG
nsIThread*
GMPParent::GMPThread()
{
if (!mGMPThread) {
nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mps);
if (!mps) {
return nullptr;
}
mps->GetThread(getter_AddRefs(mGMPThread));
MOZ_ASSERT(mGMPThread);
}
return mGMPThread;
}
#endif
bool
GMPParent::SupportsAPI(const nsCString& aAPI, const nsCString& aTag)
{
for (uint32_t i = 0; i < mCapabilities.Length(); i++) {
if (!mCapabilities[i]->mAPIName.Equals(aAPI)) {
continue;
}
nsTArray<nsCString>& tags = mCapabilities[i]->mAPITags;
for (uint32_t j = 0; j < tags.Length(); j++) {
if (tags[j].Equals(aTag)) {
return true;
}
}
}
return false;
}
bool
GMPParent::EnsureProcessLoaded()
{
if (mState == GMPStateLoaded) {
return true;
}
nsresult rv = LoadProcess();
return NS_SUCCEEDED(rv);
}
nsresult
GMPParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (!EnsureProcessLoaded()) {
return NS_ERROR_FAILURE;
}
PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor();
if (!pvdp) {
return NS_ERROR_FAILURE;
}
nsRefPtr<GMPVideoDecoderParent> vdp = static_cast<GMPVideoDecoderParent*>(pvdp);
mVideoDecoders.AppendElement(vdp);
vdp.forget(aGMPVD);
return NS_OK;
}
nsresult
GMPParent::GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (!EnsureProcessLoaded()) {
return NS_ERROR_FAILURE;
}
PGMPVideoEncoderParent* pvep = SendPGMPVideoEncoderConstructor();
if (!pvep) {
return NS_ERROR_FAILURE;
}
nsRefPtr<GMPVideoEncoderParent> vep = static_cast<GMPVideoEncoderParent*>(pvep);
mVideoEncoders.AppendElement(vep);
vep.forget(aGMPVE);
return NS_OK;
}
void
GMPParent::ActorDestroy(ActorDestroyReason aWhy)
{
UnloadProcess();
}
PGMPVideoDecoderParent*
GMPParent::AllocPGMPVideoDecoderParent()
{
GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);
NS_ADDREF(vdp);
return vdp;
}
bool
GMPParent::DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor)
{
GMPVideoDecoderParent* vdp = static_cast<GMPVideoDecoderParent*>(aActor);
NS_RELEASE(vdp);
return true;
}
PGMPVideoEncoderParent*
GMPParent::AllocPGMPVideoEncoderParent()
{
GMPVideoEncoderParent* vep = new GMPVideoEncoderParent(this);
NS_ADDREF(vep);
return vep;
}
bool
GMPParent::DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor)
{
GMPVideoEncoderParent* vep = static_cast<GMPVideoEncoderParent*>(aActor);
NS_RELEASE(vep);
return true;
}
nsresult
ParseNextRecord(nsILineInputStream* aLineInputStream,
const nsCString& aPrefix,
nsCString& aResult,
bool& aMoreLines)
{
nsAutoCString record;
nsresult rv = aLineInputStream->ReadLine(record, &aMoreLines);
if (NS_FAILED(rv)) {
return rv;
}
if (record.Length() <= aPrefix.Length() ||
!Substring(record, 0, aPrefix.Length()).Equals(aPrefix)) {
return NS_ERROR_FAILURE;
}
aResult = Substring(record, aPrefix.Length());
aResult.Trim("\b\t\r\n ");
return NS_OK;
}
nsresult
GMPParent::ReadGMPMetaData()
{
MOZ_ASSERT(mDirectory, "Plugin directory cannot be NULL!");
MOZ_ASSERT(!mName.IsEmpty(), "Plugin mName cannot be empty!");
nsCOMPtr<nsIFile> infoFile;
nsresult rv = mDirectory->Clone(getter_AddRefs(infoFile));
if (NS_FAILED(rv)) {
return rv;
}
infoFile->AppendRelativePath(mName + NS_LITERAL_STRING(".info"));
nsCOMPtr<nsIInputStream> inputStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), infoFile);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(inputStream, &rv);
if (NS_FAILED(rv)) {
return rv;
}
nsCString value;
bool moreLines = false;
// 'Name:' record
nsCString prefix = NS_LITERAL_CSTRING("Name:");
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
if (NS_FAILED(rv)) {
return rv;
}
if (value.IsEmpty()) {
// Not OK for name to be empty. Must have one non-whitespace character.
return NS_ERROR_FAILURE;
}
mDisplayName = value;
// 'Description:' record
if (!moreLines) {
return NS_ERROR_FAILURE;
}
prefix = NS_LITERAL_CSTRING("Description:");
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
if (NS_FAILED(rv)) {
return rv;
}
mDescription = value;
// 'Version:' record
if (!moreLines) {
return NS_ERROR_FAILURE;
}
prefix = NS_LITERAL_CSTRING("Version:");
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
if (NS_FAILED(rv)) {
return rv;
}
mVersion = value;
// 'Capability:' record
if (!moreLines) {
return NS_ERROR_FAILURE;
}
prefix = NS_LITERAL_CSTRING("APIs:");
rv = ParseNextRecord(lineInputStream, prefix, value, moreLines);
if (NS_FAILED(rv)) {
return rv;
}
nsCCharSeparatedTokenizer apiTokens(value, ',');
while (apiTokens.hasMoreTokens()) {
nsAutoCString api(apiTokens.nextToken());
api.StripWhitespace();
if (api.IsEmpty()) {
continue;
}
int32_t tagsStart = api.FindChar('[');
if (tagsStart == 0) {
// Not allowed to be the first character.
// API name must be at least one character.
continue;
}
auto cap = new GMPCapability();
if (tagsStart == -1) {
// No tags.
cap->mAPIName.Assign(api);
} else {
auto tagsEnd = api.FindChar(']');
if (tagsEnd == -1 || tagsEnd < tagsStart) {
// Invalid syntax, skip whole capability.
delete cap;
continue;
}
cap->mAPIName.Assign(Substring(api, 0, tagsStart));
if ((tagsEnd - tagsStart) > 1) {
const nsDependentCSubstring ts(Substring(api, tagsStart + 1, tagsEnd - tagsStart - 1));
nsCCharSeparatedTokenizer tagTokens(ts, ':');
while (tagTokens.hasMoreTokens()) {
const nsDependentCSubstring tag(tagTokens.nextToken());
cap->mAPITags.AppendElement(tag);
}
}
}
mCapabilities.AppendElement(cap);
}
if (mCapabilities.IsEmpty()) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPParent_h_
#define GMPParent_h_
#include "GMPProcessParent.h"
#include "GMPVideoDecoderParent.h"
#include "GMPVideoEncoderParent.h"
#include "mozilla/gmp/PGMPParent.h"
#include "nsCOMPtr.h"
#include "nscore.h"
#include "nsISupports.h"
#include "nsString.h"
#include "nsTArray.h"
class nsILineInputStream;
class nsIThread;
class nsIFile;
namespace mozilla {
namespace gmp {
class GMPCapability
{
public:
nsCString mAPIName;
nsTArray<nsCString> mAPITags;
};
enum GMPState {
GMPStateNotLoaded,
GMPStateLoaded
};
class GMPParent MOZ_FINAL : public PGMPParent
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPParent)
GMPParent();
nsresult Init(nsIFile* aPluginDir);
nsresult LoadProcess();
void MaybeUnloadProcess();
void UnloadProcess();
bool SupportsAPI(const nsCString& aAPI, const nsCString& aTag);
nsresult GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD);
void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
GMPState State() const;
#ifdef DEBUG
nsIThread* GMPThread();
#endif
private:
~GMPParent();
bool EnsureProcessLoaded();
nsresult ReadGMPMetaData();
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) MOZ_OVERRIDE;
virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) MOZ_OVERRIDE;
GMPState mState;
nsCOMPtr<nsIFile> mDirectory; // plugin directory on disk
nsString mName; // base name of plugin on disk, UTF-16 because used for paths
nsCString mDisplayName; // name of plugin displayed to users
nsCString mDescription; // description of plugin for display to users
nsCString mVersion;
nsTArray<nsAutoPtr<GMPCapability>> mCapabilities;
GMPProcessParent* mProcess;
nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
#ifdef DEBUG
nsCOMPtr<nsIThread> mGMPThread;
#endif
};
} // namespace gmp
} // namespace mozilla
#endif // GMPParent_h_

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

@ -0,0 +1,216 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPPlatform.h"
#include "mozilla/Monitor.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace gmp {
static MessageLoop* sMainLoop = nullptr;
// We just need a refcounted wrapper for GMPTask objects.
class Runnable MOZ_FINAL
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Runnable)
Runnable(GMPTask* aTask)
: mTask(aTask)
{
MOZ_ASSERT(mTask);
}
void Run()
{
mTask->Run();
mTask = nullptr;
}
private:
~Runnable()
{
}
nsAutoPtr<GMPTask> mTask;
};
class SyncRunnable MOZ_FINAL
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SyncRunnable)
SyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
: mDone(false)
, mTask(aTask)
, mMessageLoop(aMessageLoop)
, mMonitor("GMPSyncRunnable")
{
MOZ_ASSERT(mTask);
MOZ_ASSERT(mMessageLoop);
}
void Post()
{
// We assert here for two reasons.
// 1) Nobody should be blocking the main thread.
// 2) This prevents deadlocks when doing sync calls to main which if the
// main thread tries to do a sync call back to the calling thread.
MOZ_ASSERT(MessageLoop::current() != sMainLoop);
mMessageLoop->PostTask(FROM_HERE, NewRunnableMethod(this, &SyncRunnable::Run));
MonitorAutoLock lock(mMonitor);
while (!mDone) {
lock.Wait();
}
}
void Run()
{
mTask->Run();
mTask = nullptr;
MonitorAutoLock lock(mMonitor);
mDone = true;
lock.Notify();
}
private:
~SyncRunnable()
{
}
bool mDone;
nsAutoPtr<GMPTask> mTask;
MessageLoop* mMessageLoop;
Monitor mMonitor;
};
GMPErr
CreateThread(GMPThread** aThread)
{
if (!aThread) {
return GMPGenericErr;
}
*aThread = new GMPThreadImpl();
return GMPNoErr;
}
GMPErr
RunOnMainThread(GMPTask* aTask)
{
if (!aTask || !sMainLoop) {
return GMPGenericErr;
}
nsRefPtr<Runnable> r = new Runnable(aTask);
sMainLoop->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
return GMPNoErr;
}
GMPErr
SyncRunOnMainThread(GMPTask* aTask)
{
if (!aTask || !sMainLoop || sMainLoop == MessageLoop::current()) {
return GMPGenericErr;
}
nsRefPtr<SyncRunnable> r = new SyncRunnable(aTask, sMainLoop);
r->Post();
return GMPNoErr;
}
GMPErr
CreateMutex(GMPMutex** aMutex)
{
if (!aMutex) {
return GMPGenericErr;
}
*aMutex = new GMPMutexImpl();
return GMPNoErr;
}
void
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
{
if (!sMainLoop) {
sMainLoop = MessageLoop::current();
}
aPlatformAPI.version = 0;
aPlatformAPI.createthread = &CreateThread;
aPlatformAPI.runonmainthread = &RunOnMainThread;
aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
aPlatformAPI.createmutex = &CreateMutex;
}
GMPThreadImpl::GMPThreadImpl()
: mMutex("GMPThreadImpl"),
mThread("GMPThread")
{
}
GMPThreadImpl::~GMPThreadImpl()
{
}
void
GMPThreadImpl::Post(GMPTask* aTask)
{
MutexAutoLock lock(mMutex);
if (!mThread.IsRunning()) {
bool started = mThread.Start();
if (!started) {
NS_WARNING("Unable to start GMPThread!");
return;
}
}
nsRefPtr<Runnable> r = new Runnable(aTask);
mThread.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(r.get(), &Runnable::Run));
}
void
GMPThreadImpl::Join()
{
MutexAutoLock lock(mMutex);
if (mThread.IsRunning()) {
mThread.Stop();
}
}
GMPMutexImpl::GMPMutexImpl()
: mMutex("gmp-mutex")
{
}
GMPMutexImpl::~GMPMutexImpl()
{
}
void
GMPMutexImpl::Acquire()
{
mMutex.Lock();
}
void
GMPMutexImpl::Release()
{
mMutex.Unlock();
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPPlatform_h_
#define GMPPlatform_h_
#include "mozilla/Mutex.h"
#include "gmp-platform.h"
#include "base/thread.h"
namespace mozilla {
namespace gmp {
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
class GMPThreadImpl : public GMPThread
{
public:
GMPThreadImpl();
virtual ~GMPThreadImpl();
// GMPThread
virtual void Post(GMPTask* aTask) MOZ_OVERRIDE;
virtual void Join() MOZ_OVERRIDE;
private:
Mutex mMutex;
base::Thread mThread;
};
class GMPMutexImpl : public GMPMutex
{
public:
GMPMutexImpl();
virtual ~GMPMutexImpl();
// GMPMutex
virtual void Acquire() MOZ_OVERRIDE;
virtual void Release() MOZ_OVERRIDE;
private:
Mutex mMutex;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPPlatform_h_

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

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPProcessChild.h"
#include "base/command_line.h"
#include "base/string_util.h"
#include "chrome/common/chrome_switches.h"
#include "mozilla/ipc/IOThreadChild.h"
#include "mozilla/BackgroundHangMonitor.h"
using mozilla::ipc::IOThreadChild;
namespace mozilla {
namespace gmp {
GMPProcessChild::GMPProcessChild(ProcessHandle parentHandle)
: ProcessChild(parentHandle)
{
}
GMPProcessChild::~GMPProcessChild()
{
}
bool
GMPProcessChild::Init()
{
std::string pluginFilename;
#if defined(OS_POSIX)
// NB: need to be very careful in ensuring that the first arg
// (after the binary name) here is indeed the plugin module path.
// Keep in sync with dom/plugins/PluginModuleParent.
std::vector<std::string> values = CommandLine::ForCurrentProcess()->argv();
NS_ABORT_IF_FALSE(values.size() >= 2, "not enough args");
pluginFilename = values[1];
#elif defined(OS_WIN)
std::vector<std::wstring> values = CommandLine::ForCurrentProcess()->GetLooseValues();
NS_ABORT_IF_FALSE(values.size() >= 1, "not enough loose args");
pluginFilename = WideToUTF8(values[0]);
#else
#error Not implemented
#endif
BackgroundHangMonitor::Startup();
return mPlugin.Init(pluginFilename,
ParentHandle(),
IOThreadChild::message_loop(),
IOThreadChild::channel());
}
void
GMPProcessChild::CleanUp()
{
BackgroundHangMonitor::Shutdown();
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPProcessChild_h_
#define GMPProcessChild_h_
#include "mozilla/ipc/ProcessChild.h"
#include "GMPChild.h"
namespace mozilla {
namespace gmp {
class GMPProcessChild MOZ_FINAL : public mozilla::ipc::ProcessChild {
protected:
typedef mozilla::ipc::ProcessChild ProcessChild;
public:
GMPProcessChild(ProcessHandle parentHandle);
~GMPProcessChild();
virtual bool Init() MOZ_OVERRIDE;
virtual void CleanUp() MOZ_OVERRIDE;
private:
GMPChild mPlugin;
DISALLOW_COPY_AND_ASSIGN(GMPProcessChild);
};
} // namespace gmp
} // namespace mozilla
#endif // GMPProcessChild_h_

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

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPProcessParent.h"
#include "base/string_util.h"
#include "base/process_util.h"
using std::vector;
using std::string;
using mozilla::gmp::GMPProcessParent;
using mozilla::ipc::GeckoChildProcessHost;
using base::ProcessArchitecture;
template<>
struct RunnableMethodTraits<GMPProcessParent>
{
static void RetainCallee(GMPProcessParent* obj) { }
static void ReleaseCallee(GMPProcessParent* obj) { }
};
namespace mozilla {
namespace gmp {
GMPProcessParent::GMPProcessParent(const std::string& aGMPPath)
: GeckoChildProcessHost(GeckoProcessType_GMPlugin),
mGMPPath(aGMPPath)
{
}
GMPProcessParent::~GMPProcessParent()
{
}
bool
GMPProcessParent::Launch(int32_t aTimeoutMs)
{
vector<string> args;
args.push_back(mGMPPath);
return SyncLaunch(args, aTimeoutMs, base::GetCurrentProcessArchitecture());
}
void
GMPProcessParent::Delete()
{
MessageLoop* currentLoop = MessageLoop::current();
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
if (currentLoop == ioLoop) {
delete this;
return;
}
ioLoop->PostTask(FROM_HERE, NewRunnableMethod(this, &GMPProcessParent::Delete));
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPProcessParent_h
#define GMPProcessParent_h 1
#include "mozilla/Attributes.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "base/waitable_event.h"
#include "chrome/common/child_process_host.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
namespace mozilla {
namespace gmp {
class GMPProcessParent MOZ_FINAL : public mozilla::ipc::GeckoChildProcessHost
{
public:
GMPProcessParent(const std::string& aGMPPath);
~GMPProcessParent();
// Synchronously launch the plugin process. If the process fails to launch
// after timeoutMs, this method will return false.
bool Launch(int32_t aTimeoutMs);
void Delete();
virtual bool CanShutdown() MOZ_OVERRIDE { return true; }
const std::string& GetPluginFilePath() { return mGMPPath; }
using mozilla::ipc::GeckoChildProcessHost::GetShutDownEvent;
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
using mozilla::ipc::GeckoChildProcessHost::GetChildProcessHandle;
private:
std::string mGMPPath;
DISALLOW_COPY_AND_ASSIGN(GMPProcessParent);
};
} // namespace gmp
} // namespace mozilla
#endif // ifndef GMPProcessParent_h

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

@ -0,0 +1,485 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPService.h"
#include "GMPParent.h"
#include "GMPVideoDecoderParent.h"
#include "nsIObserverService.h"
#include "GeckoChildProcessHost.h"
#if defined(XP_WIN)
#include "nsIWindowsRegKey.h"
#endif
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/SyncRunnable.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsXPCOMPrivate.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/Services.h"
namespace mozilla {
namespace gmp {
static StaticRefPtr<GeckoMediaPluginService> sSingletonService;
class GMPServiceCreateHelper MOZ_FINAL : public nsRunnable
{
nsRefPtr<GeckoMediaPluginService> mService;
public:
static already_AddRefed<GeckoMediaPluginService>
GetOrCreate()
{
nsRefPtr<GeckoMediaPluginService> service;
if (NS_IsMainThread()) {
service = GetOrCreateOnMainThread();
} else {
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
nsRefPtr<GMPServiceCreateHelper> createHelper = new GMPServiceCreateHelper();
mozilla::SyncRunnable::DispatchToThread(mainThread, createHelper, true);
service = createHelper->mService.forget();
}
return service.forget();
}
private:
GMPServiceCreateHelper()
{
}
~GMPServiceCreateHelper()
{
MOZ_ASSERT(!mService);
}
static already_AddRefed<GeckoMediaPluginService>
GetOrCreateOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<GeckoMediaPluginService> service = sSingletonService.get();
if (!service) {
service = new GeckoMediaPluginService();
service->Init();
sSingletonService = service;
ClearOnShutdown(&sSingletonService);
}
return service.forget();
}
NS_IMETHOD
Run()
{
MOZ_ASSERT(NS_IsMainThread());
mService = GetOrCreateOnMainThread();
return NS_OK;
}
};
already_AddRefed<GeckoMediaPluginService>
GeckoMediaPluginService::GetGeckoMediaPluginService()
{
return GMPServiceCreateHelper::GetOrCreate();
}
NS_IMPL_ISUPPORTS(GeckoMediaPluginService, mozIGeckoMediaPluginService, nsIObserver)
GeckoMediaPluginService::GeckoMediaPluginService()
: mMutex("GeckoMediaPluginService::mMutex")
, mShuttingDown(false)
, mShuttingDownOnGMPThread(false)
{
MOZ_ASSERT(NS_IsMainThread());
}
GeckoMediaPluginService::~GeckoMediaPluginService()
{
MOZ_ASSERT(mPlugins.IsEmpty());
}
void
GeckoMediaPluginService::Init()
{
MOZ_ASSERT(NS_IsMainThread());
// Cache user directory while we're on the main thread. We do this because
// if we try to use "~" in a path during plugin lookup on a non-main thread,
// the nsIFile code will try to resolve it using NS_GetSpecialDirectory, which
// doesn't work on non-main threads.
nsCOMPtr<nsIFile> homeDir;
NS_GetSpecialDirectory(NS_OS_HOME_DIR, getter_AddRefs(homeDir));
if (homeDir) {
homeDir->GetPath(mHomePath);
}
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
MOZ_ASSERT(obsService);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
}
NS_IMETHODIMP
GeckoMediaPluginService::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aSomeData)
{
if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
nsCOMPtr<nsIThread> gmpThread;
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(!mShuttingDown);
mShuttingDown = true;
gmpThread = mGMPThread;
}
if (gmpThread) {
gmpThread->Dispatch(NS_NewRunnableMethod(this, &GeckoMediaPluginService::UnloadPlugins),
NS_DISPATCH_SYNC);
} else {
MOZ_ASSERT(mPlugins.IsEmpty());
}
} else if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
nsCOMPtr<nsIThread> gmpThread;
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(mShuttingDown);
mGMPThread.swap(gmpThread);
}
if (gmpThread) {
gmpThread->Shutdown();
}
}
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginService::GetThread(nsIThread** aThread)
{
MOZ_ASSERT(aThread);
// This can be called from any thread.
MutexAutoLock lock(mMutex);
if (!mGMPThread) {
// Don't allow the thread to be created after shutdown has started.
if (mShuttingDown) {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_NewNamedThread("GMPThread", getter_AddRefs(mGMPThread));
if (NS_FAILED(rv)) {
return rv;
}
}
NS_ADDREF(mGMPThread);
*aThread = mGMPThread;
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginService::GetGMPVideoDecoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoDecoder** aGMPVD)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
NS_LITERAL_CSTRING("vp8"));
if (!gmp) {
return NS_ERROR_FAILURE;
}
GMPVideoDecoderParent* gmpVDP;
nsresult rv = gmp->GetGMPVideoDecoder(&gmpVDP);
if (NS_FAILED(rv)) {
return rv;
}
*aGMPVD = gmpVDP;
*aOutVideoHost = &gmpVDP->Host();
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginService::GetGMPVideoEncoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoEncoder** aGMPVE)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
NS_LITERAL_CSTRING("vp8"));
if (!gmp) {
return NS_ERROR_FAILURE;
}
GMPVideoEncoderParent* gmpVEP;
nsresult rv = gmp->GetGMPVideoEncoder(&gmpVEP);
if (NS_FAILED(rv)) {
return rv;
}
*aGMPVE = gmpVEP;
*aOutVideoHost = &gmpVEP->Host();
return NS_OK;
}
void
GeckoMediaPluginService::UnloadPlugins()
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
MOZ_ASSERT(!mShuttingDownOnGMPThread);
mShuttingDownOnGMPThread = true;
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
mPlugins[i]->UnloadProcess();
}
mPlugins.Clear();
}
GMPParent*
GeckoMediaPluginService::SelectPluginForAPI(const nsCString& aAPI,
const nsCString& aTag)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
GMPParent* gmp = SelectPluginFromListForAPI(aAPI, aTag);
if (gmp) {
return gmp;
}
RefreshPluginList();
return SelectPluginFromListForAPI(aAPI, aTag);
}
GMPParent*
GeckoMediaPluginService::SelectPluginFromListForAPI(const nsCString& aAPI,
const nsCString& aTag)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
GMPParent* gmp = mPlugins[i];
if (gmp->SupportsAPI(aAPI, aTag)) {
return gmp;
}
}
return nullptr;
}
nsresult
GeckoMediaPluginService::GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>> &aDirs)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
#if defined(XP_MACOSX)
nsCOMPtr<nsIFile> searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
MOZ_ASSERT(!mHomePath.IsEmpty());
nsresult rv = searchDir->InitWithPath(mHomePath + NS_LITERAL_STRING("/Library/Internet Plug-Ins/"));
if (NS_FAILED(rv)) {
return rv;
}
aDirs.AppendElement(searchDir);
searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
rv = searchDir->InitWithPath(NS_LITERAL_STRING("/Library/Internet Plug-Ins/"));
if (NS_FAILED(rv)) {
return rv;
}
aDirs.AppendElement(searchDir);
#elif defined(OS_POSIX)
nsCOMPtr<nsIFile> searchDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
nsresult rv = searchDir->InitWithPath(NS_LITERAL_STRING("/usr/lib/mozilla/plugins/"));
if (NS_FAILED(rv)) {
return rv;
}
aDirs.AppendElement(searchDir);
#endif
return NS_OK;
}
#if defined(XP_WIN)
static nsresult
GetPossiblePluginsForRegRoot(uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs)
{
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey) {
return NS_ERROR_FAILURE;
}
nsresult rv = regKey->Open(aKey,
NS_LITERAL_STRING("Software\\MozillaPlugins"),
nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv)) {
return rv;
}
uint32_t childCount = 0;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(regKey->GetChildCount(&childCount)));
for (uint32_t index = 0; index < childCount; index++) {
nsAutoString childName;
rv = regKey->GetChildName(index, childName);
if (NS_FAILED(rv)) {
continue;
}
nsCOMPtr<nsIWindowsRegKey> childKey;
rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE,
getter_AddRefs(childKey));
if (NS_FAILED(rv) || !childKey) {
continue;
}
nsAutoString path;
rv = childKey->ReadStringValue(NS_LITERAL_STRING("Path"), path);
if (NS_FAILED(rv)) {
continue;
}
nsCOMPtr<nsIFile> localFile;
if (NS_SUCCEEDED(NS_NewLocalFile(path, true, getter_AddRefs(localFile))) &&
localFile) {
bool isFileThere = false;
if (NS_SUCCEEDED(localFile->Exists(&isFileThere)) && isFileThere) {
aDirs.AppendElement(localFile);
}
}
}
regKey->Close();
return NS_OK;
}
#endif
nsresult
GeckoMediaPluginService::GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
#if defined(XP_WIN)
// The ROOT_KEY_CURRENT_USER entry typically fails to open, causing this call to
// fail. Don't check any return values because if we find nothing we don't care.
GetPossiblePluginsForRegRoot(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, aDirs);
GetPossiblePluginsForRegRoot(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, aDirs);
#endif
return NS_OK;
}
nsresult
GeckoMediaPluginService::SearchDirectory(nsIFile* aSearchDir)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
MOZ_ASSERT(aSearchDir);
nsCOMPtr<nsISimpleEnumerator> iter;
nsresult rv = aSearchDir->GetDirectoryEntries(getter_AddRefs(iter));
if (NS_FAILED(rv)) {
return rv;
}
bool hasMore;
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
rv = iter->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv)) {
continue;
}
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv)) {
continue;
}
ProcessPossiblePlugin(dirEntry);
}
return NS_OK;
}
void
GeckoMediaPluginService::ProcessPossiblePlugin(nsIFile* aDir)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
MOZ_ASSERT(aDir);
bool isDirectory = false;
nsresult rv = aDir->IsDirectory(&isDirectory);
if (NS_FAILED(rv) || !isDirectory) {
return;
}
nsAutoString leafName;
rv = aDir->GetLeafName(leafName);
if (NS_FAILED(rv)) {
return;
}
NS_NAMED_LITERAL_STRING(prefix, "gmp-");
if (leafName.Length() <= prefix.Length() ||
!Substring(leafName, 0, prefix.Length()).Equals(prefix)) {
return;
}
nsRefPtr<GMPParent> gmp = new GMPParent();
rv = gmp->Init(aDir);
if (NS_FAILED(rv)) {
return;
}
mPlugins.AppendElement(gmp);
}
void
GeckoMediaPluginService::RefreshPluginList()
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
for (uint32_t iPlusOne = mPlugins.Length(); iPlusOne > 0; iPlusOne--) {
if (mPlugins[iPlusOne - 1]->State() == GMPStateNotLoaded) {
mPlugins.RemoveElementAt(iPlusOne - 1);
}
}
nsTArray<nsCOMPtr<nsIFile>> searchDirs;
nsresult rv = GetDirectoriesToSearch(searchDirs);
if (NS_FAILED(rv)) {
return;
}
for (uint32_t i = 0; i < searchDirs.Length(); i++) {
SearchDirectory(searchDirs[i]);
}
nsTArray<nsCOMPtr<nsIFile>> possiblePlugins;
rv = GetPossiblePlugins(possiblePlugins);
if (NS_FAILED(rv)) {
return;
}
for (uint32_t i = 0; i < possiblePlugins.Length(); i++) {
ProcessPossiblePlugin(possiblePlugins[i]);
}
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPService_h_
#define GMPService_h_
#include "mozIGeckoMediaPluginService.h"
#include "nsIObserver.h"
#include "nsTArray.h"
#include "mozilla/Mutex.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
class nsIFile;
template <class> class already_AddRefed;
namespace mozilla {
namespace gmp {
class GMPParent;
class GeckoMediaPluginService MOZ_FINAL : public mozIGeckoMediaPluginService
, public nsIObserver
{
public:
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
GeckoMediaPluginService();
void Init();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
NS_DECL_NSIOBSERVER
private:
~GeckoMediaPluginService();
GMPParent* SelectPluginFromListForAPI(const nsCString& aAPI, const nsCString& aTag);
GMPParent* SelectPluginForAPI(const nsCString& aAPI, const nsCString& aTag);
void UnloadPlugins();
void RefreshPluginList();
void ProcessPossiblePlugin(nsIFile* aDir);
nsresult SearchDirectory(nsIFile* aSearchDir);
nsresult GetPossiblePlugins(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
nsresult GetDirectoriesToSearch(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
nsTArray<nsRefPtr<GMPParent>> mPlugins;
Mutex mMutex; // Protects mGMPThread and mShuttingDown
nsCOMPtr<nsIThread> mGMPThread;
bool mShuttingDown;
bool mShuttingDownOnGMPThread;
nsString mHomePath;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPService_h_

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

@ -0,0 +1,26 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPSharedMemManager_h_
#define GMPSharedMemManager_h_
#include "mozilla/ipc/Shmem.h"
namespace mozilla {
namespace gmp {
class GMPSharedMemManager
{
public:
virtual bool MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem) = 0;
virtual bool MgrDeallocShmem(ipc::Shmem& aMem) = 0;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPSharedMemManager_h_

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

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace mozilla {
namespace gmp {
struct GMPVideoEncodedFrameData
{
int64_t mCaptureTime_ms;
uint32_t mEncodedWidth;
uint32_t mEncodedHeight;
uint32_t mTimeStamp;
uint32_t mFrameType;
uint32_t mSize;
Shmem mBuffer;
bool mCompleteFrame;
};
struct GMPPlaneData
{
int32_t mSize;
int32_t mStride;
Shmem mBuffer;
};
struct GMPVideoi420FrameData
{
GMPPlaneData mYPlane;
GMPPlaneData mUPlane;
GMPPlaneData mVPlane;
int32_t mWidth;
int32_t mHeight;
uint32_t mTimestamp;
int64_t mRenderTime_ms;
};
}
}

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

@ -0,0 +1,178 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoDecoderChild.h"
#include "GMPVideoi420FrameImpl.h"
#include "GMPChild.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPVideoEncodedFrameImpl.h"
namespace mozilla {
namespace gmp {
GMPVideoDecoderChild::GMPVideoDecoderChild(GMPChild* aPlugin)
: mPlugin(aPlugin),
mVideoDecoder(nullptr),
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
{
MOZ_ASSERT(mPlugin);
}
GMPVideoDecoderChild::~GMPVideoDecoderChild()
{
}
void
GMPVideoDecoderChild::Init(GMPVideoDecoder* aDecoder)
{
MOZ_ASSERT(aDecoder, "Cannot initialize video decoder child without a video decoder!");
mVideoDecoder = aDecoder;
}
GMPVideoHostImpl&
GMPVideoDecoderChild::Host()
{
return mVideoHost;
}
void
GMPVideoDecoderChild::Decoded(GMPVideoi420Frame* aDecodedFrame)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
if (!aDecodedFrame) {
MOZ_CRASH("Not given a decoded frame!");
}
auto df = static_cast<GMPVideoi420FrameImpl*>(aDecodedFrame);
GMPVideoi420FrameData frameData;
df->InitFrameData(frameData);
SendDecoded(frameData);
aDecodedFrame->Destroy();
}
void
GMPVideoDecoderChild::ReceivedDecodedReferenceFrame(const uint64_t aPictureId)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
SendReceivedDecodedReferenceFrame(aPictureId);
}
void
GMPVideoDecoderChild::ReceivedDecodedFrame(const uint64_t aPictureId)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
SendReceivedDecodedFrame(aPictureId);
}
void
GMPVideoDecoderChild::InputDataExhausted()
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
SendInputDataExhausted();
}
bool
GMPVideoDecoderChild::MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
return AllocShmem(aSize, aType, aMem);
}
bool
GMPVideoDecoderChild::MgrDeallocShmem(Shmem& aMem)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
return DeallocShmem(aMem);
}
bool
GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
const int32_t& aCoreCount)
{
if (!mVideoDecoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoDecoder->InitDecode(aCodecSettings, this, aCoreCount);
return true;
}
bool
GMPVideoDecoderChild::RecvDecode(const GMPVideoEncodedFrameData& aInputFrame,
const bool& aMissingFrames,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
const int64_t& aRenderTimeMs)
{
if (!mVideoDecoder) {
return false;
}
auto f = new GMPVideoEncodedFrameImpl(aInputFrame, &mVideoHost);
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoDecoder->Decode(f, aMissingFrames, aCodecSpecificInfo, aRenderTimeMs);
return true;
}
bool
GMPVideoDecoderChild::RecvReset()
{
if (!mVideoDecoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoDecoder->Reset();
return true;
}
bool
GMPVideoDecoderChild::RecvDrain()
{
if (!mVideoDecoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoDecoder->Drain();
return true;
}
bool
GMPVideoDecoderChild::RecvDecodingComplete()
{
if (mVideoDecoder) {
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoDecoder->DecodingComplete();
mVideoDecoder = nullptr;
}
mVideoHost.DoneWithAPI();
mPlugin = nullptr;
unused << Send__delete__(this);
return true;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoDecoderChild_h_
#define GMPVideoDecoderChild_h_
#include "nsString.h"
#include "mozilla/gmp/PGMPVideoDecoderChild.h"
#include "gmp-video-decode.h"
#include "GMPSharedMemManager.h"
#include "GMPVideoHost.h"
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
public GMPDecoderCallback,
public GMPSharedMemManager
{
public:
GMPVideoDecoderChild(GMPChild* aPlugin);
virtual ~GMPVideoDecoderChild();
void Init(GMPVideoDecoder* aDecoder);
GMPVideoHostImpl& Host();
// GMPDecoderCallback
virtual void Decoded(GMPVideoi420Frame* decodedFrame) MOZ_OVERRIDE;
virtual void ReceivedDecodedReferenceFrame(const uint64_t pictureId) MOZ_OVERRIDE;
virtual void ReceivedDecodedFrame(const uint64_t pictureId) MOZ_OVERRIDE;
virtual void InputDataExhausted() MOZ_OVERRIDE;
// GMPSharedMemManager
virtual bool MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem) MOZ_OVERRIDE;
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
private:
// PGMPVideoDecoderChild
virtual bool RecvInitDecode(const GMPVideoCodec& codecSettings,
const int32_t& coreCount) MOZ_OVERRIDE;
virtual bool RecvDecode(const GMPVideoEncodedFrameData& inputFrame,
const bool& missingFrames,
const GMPCodecSpecificInfo& codecSpecificInfo,
const int64_t& renderTimeMs) MOZ_OVERRIDE;
virtual bool RecvReset() MOZ_OVERRIDE;
virtual bool RecvDrain() MOZ_OVERRIDE;
virtual bool RecvDecodingComplete() MOZ_OVERRIDE;
GMPChild* mPlugin;
GMPVideoDecoder* mVideoDecoder;
GMPVideoHostImpl mVideoHost;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoDecoderChild_h_

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

@ -0,0 +1,256 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoDecoderParent.h"
#include "GMPVideoEncodedFrameImpl.h"
#include "GMPVideoi420FrameImpl.h"
#include "GMPParent.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPMessageUtils.h"
#include "nsAutoRef.h"
#include "nsThreadUtils.h"
template <>
class nsAutoRefTraits<GMPVideoEncodedFrame> : public nsPointerRefTraits<GMPVideoEncodedFrame>
{
public:
static void Release(GMPVideoEncodedFrame* aFrame) { aFrame->Destroy(); }
};
namespace mozilla {
namespace gmp {
GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
: mCanSendMessages(true)
, mPlugin(aPlugin)
, mCallback(nullptr)
, mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
{
MOZ_ASSERT(mPlugin);
}
GMPVideoDecoderParent::~GMPVideoDecoderParent()
{
}
GMPVideoHostImpl&
GMPVideoDecoderParent::Host()
{
return mVideoHost;
}
bool
GMPVideoDecoderParent::MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem)
{
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
return AllocShmem(aSize, aType, aMem);
}
bool
GMPVideoDecoderParent::MgrDeallocShmem(Shmem& aMem)
{
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
return DeallocShmem(aMem);
}
GMPVideoErr
GMPVideoDecoderParent::InitDecode(const GMPVideoCodec& aCodecSettings,
GMPDecoderCallback* aCallback,
int32_t aCoreCount)
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video decoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!aCallback) {
return GMPVideoGenericErr;
}
mCallback = aCallback;
if (!SendInitDecode(aCodecSettings, aCoreCount)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoDecoderParent::Decode(GMPVideoEncodedFrame* aInputFrame,
bool aMissingFrames,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
int64_t aRenderTimeMs)
{
nsAutoRef<GMPVideoEncodedFrame> autoDestroy(aInputFrame);
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video decoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
auto inputFrameImpl = static_cast<GMPVideoEncodedFrameImpl*>(aInputFrame);
GMPVideoEncodedFrameData frameData;
inputFrameImpl->RelinquishFrameData(frameData);
if (!SendDecode(frameData,
aMissingFrames,
aCodecSpecificInfo,
aRenderTimeMs)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoDecoderParent::Reset()
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video decoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!SendReset()) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoDecoderParent::Drain()
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video decoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!SendDrain()) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
void
GMPVideoDecoderParent::DecodingComplete()
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video decoder!");
return;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
mCanSendMessages = false;
mCallback = nullptr;
mVideoHost.DoneWithAPI();
unused << SendDecodingComplete();
}
// Note: Keep this sync'd up with DecodingComplete
void
GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
if (mPlugin) {
// Ignore any return code. It is OK for this to fail without killing the process.
mPlugin->VideoDecoderDestroyed(this);
mPlugin = nullptr;
}
mCanSendMessages = false;
mCallback = nullptr;
mVideoHost.ActorDestroyed();
}
bool
GMPVideoDecoderParent::RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame)
{
if (!mCallback) {
return false;
}
auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost);
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->Decoded(f);
return true;
}
bool
GMPVideoDecoderParent::RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId)
{
if (!mCallback) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->ReceivedDecodedReferenceFrame(aPictureId);
return true;
}
bool
GMPVideoDecoderParent::RecvReceivedDecodedFrame(const uint64_t& aPictureId)
{
if (!mCallback) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->ReceivedDecodedFrame(aPictureId);
return true;
}
bool
GMPVideoDecoderParent::RecvInputDataExhausted()
{
if (!mCallback) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->InputDataExhausted();
return true;
}
bool
GMPVideoDecoderParent::Recv__delete__()
{
if (mPlugin) {
// Ignore any return code. It is OK for this to fail without killing the process.
mPlugin->VideoDecoderDestroyed(this);
mPlugin = nullptr;
}
return true;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoDecoderParent_h_
#define GMPVideoDecoderParent_h_
#include "mozilla/RefPtr.h"
#include "gmp-video-decode.h"
#include "mozilla/gmp/PGMPVideoDecoderParent.h"
#include "GMPMessageUtils.h"
#include "GMPSharedMemManager.h"
#include "GMPVideoHost.h"
namespace mozilla {
namespace gmp {
class GMPParent;
class GMPVideoDecoderParent MOZ_FINAL : public GMPVideoDecoder
, public PGMPVideoDecoderParent
, public GMPSharedMemManager
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPVideoDecoderParent)
GMPVideoDecoderParent(GMPParent *aPlugin);
GMPVideoHostImpl& Host();
// GMPSharedMemManager
virtual bool MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem) MOZ_OVERRIDE;
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
// GMPVideoDecoder
virtual GMPVideoErr InitDecode(const GMPVideoCodec& aCodecSettings,
GMPDecoderCallback* aCallback,
int32_t aCoreCount) MOZ_OVERRIDE;
virtual GMPVideoErr Decode(GMPVideoEncodedFrame* aInputFrame,
bool aMissingFrames,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
int64_t aRenderTimeMs = -1) MOZ_OVERRIDE;
virtual GMPVideoErr Reset() MOZ_OVERRIDE;
virtual GMPVideoErr Drain() MOZ_OVERRIDE;
virtual void DecodingComplete() MOZ_OVERRIDE;
private:
~GMPVideoDecoderParent();
// PGMPVideoDecoderParent
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame) MOZ_OVERRIDE;
virtual bool RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
virtual bool RecvReceivedDecodedFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
virtual bool Recv__delete__() MOZ_OVERRIDE;
bool mCanSendMessages;
GMPParent* mPlugin;
GMPDecoderCallback* mCallback;
GMPVideoHostImpl mVideoHost;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoDecoderParent_h_

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

@ -0,0 +1,286 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoEncodedFrameImpl.h"
#include "GMPVideoHost.h"
#include "mozilla/gmp/GMPTypes.h"
#include "GMPSharedMemManager.h"
namespace mozilla {
namespace gmp {
GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost)
: mEncodedWidth(0),
mEncodedHeight(0),
mTimeStamp(0),
mCaptureTime_ms(0),
mFrameType(kGMPDeltaFrame),
mSize(0),
mCompleteFrame(false),
mHost(aHost)
{
MOZ_ASSERT(aHost);
aHost->EncodedFrameCreated(this);
}
GMPVideoEncodedFrameImpl::GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData,
GMPVideoHostImpl* aHost)
: mEncodedWidth(aFrameData.mEncodedWidth()),
mEncodedHeight(aFrameData.mEncodedHeight()),
mTimeStamp(aFrameData.mTimeStamp()),
mCaptureTime_ms(aFrameData.mCaptureTime_ms()),
mFrameType(static_cast<GMPVideoFrameType>(aFrameData.mFrameType())),
mSize(aFrameData.mSize()),
mCompleteFrame(aFrameData.mCompleteFrame()),
mHost(aHost),
mBuffer(aFrameData.mBuffer())
{
MOZ_ASSERT(aHost);
aHost->EncodedFrameCreated(this);
}
GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
{
DestroyBuffer();
if (mHost) {
mHost->EncodedFrameDestroyed(this);
}
}
GMPVideoFrameFormat
GMPVideoEncodedFrameImpl::GetFrameFormat()
{
return kGMPEncodedVideoFrame;
}
void
GMPVideoEncodedFrameImpl::DoneWithAPI()
{
DestroyBuffer();
// Do this after destroying the buffer because destruction
// involves deallocation, which requires a host.
mHost = nullptr;
}
void
GMPVideoEncodedFrameImpl::ActorDestroyed()
{
// Simply clear out Shmem reference, do not attempt to
// properly free it. It has already been freed.
mBuffer = ipc::Shmem();
// No more host.
mHost = nullptr;
}
bool
GMPVideoEncodedFrameImpl::RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData)
{
aFrameData.mEncodedWidth() = mEncodedWidth;
aFrameData.mEncodedHeight() = mEncodedHeight;
aFrameData.mTimeStamp() = mTimeStamp;
aFrameData.mCaptureTime_ms() = mCaptureTime_ms;
aFrameData.mFrameType() = mFrameType;
aFrameData.mSize() = mSize;
aFrameData.mCompleteFrame() = mCompleteFrame;
aFrameData.mBuffer() = mBuffer;
// This method is called right before Shmem is sent to another process.
// We need to effectively zero out our member copy so that we don't
// try to delete Shmem we don't own later.
mBuffer = ipc::Shmem();
return true;
}
void
GMPVideoEncodedFrameImpl::DestroyBuffer()
{
if (mHost && mBuffer.IsWritable()) {
mHost->SharedMemMgr()->MgrDeallocShmem(mBuffer);
}
mBuffer = ipc::Shmem();
}
GMPVideoErr
GMPVideoEncodedFrameImpl::CreateEmptyFrame(uint32_t aSize)
{
DestroyBuffer();
if (aSize != 0) {
if (!mHost->SharedMemMgr()->MgrAllocShmem(aSize, ipc::SharedMemory::TYPE_BASIC, &mBuffer) ||
!Buffer()) {
return GMPVideoAllocErr;
}
}
mSize = aSize;
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoEncodedFrameImpl::CopyFrame(const GMPVideoEncodedFrame& aFrame)
{
auto& f = static_cast<const GMPVideoEncodedFrameImpl&>(aFrame);
if (f.mSize != 0) {
GMPVideoErr err = CreateEmptyFrame(f.mSize);
if (err != GMPVideoNoErr) {
return err;
}
memcpy(Buffer(), f.Buffer(), f.mSize);
}
mEncodedWidth = f.mEncodedWidth;
mEncodedHeight = f.mEncodedHeight;
mTimeStamp = f.mTimeStamp;
mCaptureTime_ms = f.mCaptureTime_ms;
mFrameType = f.mFrameType;
mSize = f.mSize;
mCompleteFrame = f.mCompleteFrame;
// Don't copy host, that should have been set properly on object creation via host.
return GMPVideoNoErr;
}
void
GMPVideoEncodedFrameImpl::SetEncodedWidth(uint32_t aEncodedWidth)
{
mEncodedWidth = aEncodedWidth;
}
uint32_t
GMPVideoEncodedFrameImpl::EncodedWidth()
{
return mEncodedWidth;
}
void
GMPVideoEncodedFrameImpl::SetEncodedHeight(uint32_t aEncodedHeight)
{
mEncodedHeight = aEncodedHeight;
}
uint32_t
GMPVideoEncodedFrameImpl::EncodedHeight()
{
return mEncodedHeight;
}
void
GMPVideoEncodedFrameImpl::SetTimeStamp(uint32_t aTimeStamp)
{
mTimeStamp = aTimeStamp;
}
uint32_t
GMPVideoEncodedFrameImpl::TimeStamp()
{
return mTimeStamp;
}
void
GMPVideoEncodedFrameImpl::SetCaptureTime(int64_t aCaptureTime)
{
mCaptureTime_ms = aCaptureTime;
}
int64_t
GMPVideoEncodedFrameImpl::CaptureTime()
{
return mCaptureTime_ms;
}
void
GMPVideoEncodedFrameImpl::SetFrameType(GMPVideoFrameType aFrameType)
{
mFrameType = aFrameType;
}
GMPVideoFrameType
GMPVideoEncodedFrameImpl::FrameType()
{
return mFrameType;
}
void
GMPVideoEncodedFrameImpl::SetAllocatedSize(uint32_t aNewSize)
{
if (aNewSize <= AllocatedSize()) {
return;
}
if (!mHost) {
return;
}
ipc::Shmem new_mem;
if (!mHost->SharedMemMgr()->MgrAllocShmem(aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
!new_mem.get<uint8_t>()) {
return;
}
if (mBuffer.IsReadable()) {
memcpy(new_mem.get<uint8_t>(), Buffer(), mSize);
}
DestroyBuffer();
mBuffer = new_mem;
}
uint32_t
GMPVideoEncodedFrameImpl::AllocatedSize()
{
if (mBuffer.IsWritable()) {
return mBuffer.Size<uint8_t>();
}
return 0;
}
void
GMPVideoEncodedFrameImpl::SetSize(uint32_t aSize)
{
mSize = aSize;
}
uint32_t
GMPVideoEncodedFrameImpl::Size()
{
return mSize;
}
void
GMPVideoEncodedFrameImpl::SetCompleteFrame(bool aCompleteFrame)
{
mCompleteFrame = aCompleteFrame;
}
bool
GMPVideoEncodedFrameImpl::CompleteFrame()
{
return mCompleteFrame;
}
const uint8_t*
GMPVideoEncodedFrameImpl::Buffer() const
{
return mBuffer.get<uint8_t>();
}
uint8_t*
GMPVideoEncodedFrameImpl::Buffer()
{
return mBuffer.get<uint8_t>();
}
void
GMPVideoEncodedFrameImpl::Destroy()
{
delete this;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* Copyright (c) 2014, Mozilla Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GMPVideoEncodedFrameImpl_h_
#define GMPVideoEncodedFrameImpl_h_
#include "gmp-video-errors.h"
#include "gmp-video-frame.h"
#include "gmp-video-frame-encoded.h"
#include "mozilla/ipc/Shmem.h"
namespace mozilla {
namespace gmp {
class GMPVideoHostImpl;
class GMPVideoEncodedFrameData;
class GMPVideoEncodedFrameImpl: public GMPVideoEncodedFrame
{
friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoEncodedFrameImpl>;
public:
GMPVideoEncodedFrameImpl(GMPVideoHostImpl* aHost);
GMPVideoEncodedFrameImpl(const GMPVideoEncodedFrameData& aFrameData, GMPVideoHostImpl* aHost);
virtual ~GMPVideoEncodedFrameImpl();
// This is called during a normal destroy sequence, which is
// when a consumer is finished or during XPCOM shutdown.
void DoneWithAPI();
// Does not attempt to release Shmem, as the Shmem has already been released.
void ActorDestroyed();
bool RelinquishFrameData(GMPVideoEncodedFrameData& aFrameData);
// GMPVideoFrame
virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
virtual void Destroy() MOZ_OVERRIDE;
// GMPVideoEncodedFrame
virtual GMPVideoErr CreateEmptyFrame(uint32_t aSize) MOZ_OVERRIDE;
virtual GMPVideoErr CopyFrame(const GMPVideoEncodedFrame& aFrame) MOZ_OVERRIDE;
virtual void SetEncodedWidth(uint32_t aEncodedWidth) MOZ_OVERRIDE;
virtual uint32_t EncodedWidth() MOZ_OVERRIDE;
virtual void SetEncodedHeight(uint32_t aEncodedHeight) MOZ_OVERRIDE;
virtual uint32_t EncodedHeight() MOZ_OVERRIDE;
virtual void SetTimeStamp(uint32_t aTimeStamp) MOZ_OVERRIDE;
virtual uint32_t TimeStamp() MOZ_OVERRIDE;
virtual void SetCaptureTime(int64_t aCaptureTime) MOZ_OVERRIDE;
virtual int64_t CaptureTime() MOZ_OVERRIDE;
virtual void SetFrameType(GMPVideoFrameType aFrameType) MOZ_OVERRIDE;
virtual GMPVideoFrameType FrameType() MOZ_OVERRIDE;
virtual void SetAllocatedSize(uint32_t aNewSize) MOZ_OVERRIDE;
virtual uint32_t AllocatedSize() MOZ_OVERRIDE;
virtual void SetSize(uint32_t aSize) MOZ_OVERRIDE;
virtual uint32_t Size() MOZ_OVERRIDE;
virtual void SetCompleteFrame(bool aCompleteFrame) MOZ_OVERRIDE;
virtual bool CompleteFrame() MOZ_OVERRIDE;
virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
virtual uint8_t* Buffer() MOZ_OVERRIDE;
private:
void DestroyBuffer();
uint32_t mEncodedWidth;
uint32_t mEncodedHeight;
uint32_t mTimeStamp;
int64_t mCaptureTime_ms;
GMPVideoFrameType mFrameType;
uint32_t mSize;
bool mCompleteFrame;
GMPVideoHostImpl* mHost;
ipc::Shmem mBuffer;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoEncodedFrameImpl_h_

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

@ -0,0 +1,173 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoEncoderChild.h"
#include "GMPChild.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPVideoEncodedFrameImpl.h"
#include "GMPVideoi420FrameImpl.h"
namespace mozilla {
namespace gmp {
GMPVideoEncoderChild::GMPVideoEncoderChild(GMPChild* aPlugin)
: mPlugin(aPlugin),
mVideoEncoder(nullptr),
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
{
MOZ_ASSERT(mPlugin);
}
GMPVideoEncoderChild::~GMPVideoEncoderChild()
{
}
void
GMPVideoEncoderChild::Init(GMPVideoEncoder* aEncoder)
{
MOZ_ASSERT(aEncoder, "Cannot initialize video encoder child without a video encoder!");
mVideoEncoder = aEncoder;
}
GMPVideoHostImpl&
GMPVideoEncoderChild::Host()
{
return mVideoHost;
}
void
GMPVideoEncoderChild::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
auto ef = static_cast<GMPVideoEncodedFrameImpl*>(aEncodedFrame);
GMPVideoEncodedFrameData frameData;
ef->RelinquishFrameData(frameData);
SendEncoded(frameData, aCodecSpecificInfo);
aEncodedFrame->Destroy();
}
bool
GMPVideoEncoderChild::MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
return AllocShmem(aSize, aType, aMem);
}
bool
GMPVideoEncoderChild::MgrDeallocShmem(Shmem& aMem)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
return DeallocShmem(aMem);
}
bool
GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
const int32_t& aNumberOfCores,
const uint32_t& aMaxPayloadSize)
{
if (!mVideoEncoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoEncoder->InitEncode(aCodecSettings, this, aNumberOfCores, aMaxPayloadSize);
return true;
}
bool
GMPVideoEncoderChild::RecvEncode(const GMPVideoi420FrameData& aInputFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
const InfallibleTArray<int>& aFrameTypes)
{
if (!mVideoEncoder) {
return false;
}
auto f = new GMPVideoi420FrameImpl(aInputFrame, &mVideoHost);
std::vector<GMPVideoFrameType> frameTypes(aFrameTypes.Length());
for (uint32_t i = 0; i < aFrameTypes.Length(); i++) {
frameTypes[i] = static_cast<GMPVideoFrameType>(aFrameTypes[i]);
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoEncoder->Encode(f, aCodecSpecificInfo, frameTypes);
return true;
}
bool
GMPVideoEncoderChild::RecvSetChannelParameters(const uint32_t& aPacketLoss,
const uint32_t& aRTT)
{
if (!mVideoEncoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoEncoder->SetChannelParameters(aPacketLoss, aRTT);
return true;
}
bool
GMPVideoEncoderChild::RecvSetRates(const uint32_t& aNewBitRate,
const uint32_t& aFrameRate)
{
if (!mVideoEncoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoEncoder->SetRates(aNewBitRate, aFrameRate);
return true;
}
bool
GMPVideoEncoderChild::RecvSetPeriodicKeyFrames(const bool& aEnable)
{
if (!mVideoEncoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoEncoder->SetPeriodicKeyFrames(aEnable);
return true;
}
bool
GMPVideoEncoderChild::RecvEncodingComplete()
{
if (!mVideoEncoder) {
return false;
}
// Ignore any return code. It is OK for this to fail without killing the process.
mVideoEncoder->EncodingComplete();
mVideoHost.DoneWithAPI();
mPlugin = nullptr;
unused << Send__delete__(this);
return true;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoEncoderChild_h_
#define GMPVideoEncoderChild_h_
#include "nsString.h"
#include "mozilla/gmp/PGMPVideoEncoderChild.h"
#include "gmp-video-encode.h"
#include "GMPSharedMemManager.h"
#include "GMPVideoHost.h"
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPVideoEncoderChild : public PGMPVideoEncoderChild,
public GMPEncoderCallback,
public GMPSharedMemManager
{
public:
GMPVideoEncoderChild(GMPChild* aPlugin);
virtual ~GMPVideoEncoderChild();
void Init(GMPVideoEncoder* aEncoder);
GMPVideoHostImpl& Host();
// GMPEncoderCallback
virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
// GMPSharedMemManager
virtual bool MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem) MOZ_OVERRIDE;
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
private:
// PGMPVideoEncoderChild
virtual bool RecvInitEncode(const GMPVideoCodec& aCodecSettings,
const int32_t& aNumberOfCores,
const uint32_t& aMaxPayloadSize) MOZ_OVERRIDE;
virtual bool RecvEncode(const GMPVideoi420FrameData& aInputFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
const InfallibleTArray<int>& aFrameTypes) MOZ_OVERRIDE;
virtual bool RecvSetChannelParameters(const uint32_t& aPacketLoss,
const uint32_t& aRTT) MOZ_OVERRIDE;
virtual bool RecvSetRates(const uint32_t& aNewBitRate,
const uint32_t& aFrameRate) MOZ_OVERRIDE;
virtual bool RecvSetPeriodicKeyFrames(const bool& aEnable) MOZ_OVERRIDE;
virtual bool RecvEncodingComplete() MOZ_OVERRIDE;
GMPChild* mPlugin;
GMPVideoEncoder* mVideoEncoder;
GMPVideoHostImpl mVideoHost;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoEncoderChild_h_

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

@ -0,0 +1,242 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoEncoderParent.h"
#include "GMPVideoi420FrameImpl.h"
#include "GMPVideoEncodedFrameImpl.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPMessageUtils.h"
#include "nsAutoRef.h"
#include "GMPParent.h"
#include "mozilla/gmp/GMPTypes.h"
#include "nsThreadUtils.h"
template <>
class nsAutoRefTraits<GMPVideoi420Frame> : public nsPointerRefTraits<GMPVideoi420Frame>
{
public:
static void Release(GMPVideoi420Frame* aFrame) { aFrame->Destroy(); }
};
namespace mozilla {
namespace gmp {
GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
: mCanSendMessages(true),
mPlugin(aPlugin),
mCallback(nullptr),
mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
{
MOZ_ASSERT(mPlugin);
}
GMPVideoEncoderParent::~GMPVideoEncoderParent()
{
}
GMPVideoHostImpl&
GMPVideoEncoderParent::Host()
{
return mVideoHost;
}
bool
GMPVideoEncoderParent::MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem)
{
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
return AllocShmem(aSize, aType, aMem);
}
bool
GMPVideoEncoderParent::MgrDeallocShmem(Shmem& aMem)
{
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
return DeallocShmem(aMem);
}
GMPVideoErr
GMPVideoEncoderParent::InitEncode(const GMPVideoCodec& aCodecSettings,
GMPEncoderCallback* aCallback,
int32_t aNumberOfCores,
uint32_t aMaxPayloadSize)
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video encoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!aCallback) {
return GMPVideoGenericErr;
}
mCallback = aCallback;
if (!SendInitEncode(aCodecSettings, aNumberOfCores, aMaxPayloadSize)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoEncoderParent::Encode(GMPVideoi420Frame* aInputFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
const std::vector<GMPVideoFrameType>& aFrameTypes)
{
nsAutoRef<GMPVideoi420Frame> frameRef(aInputFrame);
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video encoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
auto inputFrameImpl = static_cast<GMPVideoi420FrameImpl*>(aInputFrame);
GMPVideoi420FrameData frameData;
inputFrameImpl->InitFrameData(frameData);
InfallibleTArray<int> frameTypes;
frameTypes.SetCapacity(aFrameTypes.size());
for (std::vector<int>::size_type i = 0; i != aFrameTypes.size(); i++) {
frameTypes.AppendElement(static_cast<int>(aFrameTypes[i]));
}
if (!SendEncode(frameData,
aCodecSpecificInfo,
frameTypes)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoEncoderParent::SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT)
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video encoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!SendSetChannelParameters(aPacketLoss, aRTT)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoEncoderParent::SetRates(uint32_t aNewBitRate, uint32_t aFrameRate)
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video encoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!SendSetRates(aNewBitRate, aFrameRate)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoEncoderParent::SetPeriodicKeyFrames(bool aEnable)
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video encoder!");
return GMPVideoGenericErr;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
if (!SendSetPeriodicKeyFrames(aEnable)) {
return GMPVideoGenericErr;
}
// Async IPC, we don't have access to a return value.
return GMPVideoNoErr;
}
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
void
GMPVideoEncoderParent::EncodingComplete()
{
if (!mCanSendMessages) {
NS_WARNING("Trying to use an invalid GMP video encoder!");
return;
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
mCanSendMessages = false;
mCallback = nullptr;
mVideoHost.DoneWithAPI();
unused << SendEncodingComplete();
}
// Note: Keep this sync'd up with DecodingComplete
void
GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
if (mPlugin) {
// Ignore any return code. It is OK for this to fail without killing the process.
mPlugin->VideoEncoderDestroyed(this);
mPlugin = nullptr;
}
mCanSendMessages = false;
mCallback = nullptr;
mVideoHost.ActorDestroyed();
}
bool
GMPVideoEncoderParent::RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo)
{
if (!mCallback) {
return false;
}
auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost);
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->Encoded(f, aCodecSpecificInfo);
return true;
}
bool
GMPVideoEncoderParent::Recv__delete__()
{
if (mPlugin) {
// Ignore any return code. It is OK for this to fail without killing the process.
mPlugin->VideoEncoderDestroyed(this);
mPlugin = nullptr;
}
return true;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoEncoderParent_h_
#define GMPVideoEncoderParent_h_
#include "mozilla/RefPtr.h"
#include "gmp-video-encode.h"
#include "mozilla/gmp/PGMPVideoEncoderParent.h"
#include "GMPMessageUtils.h"
#include "GMPSharedMemManager.h"
#include "GMPVideoHost.h"
namespace mozilla {
namespace gmp {
class GMPParent;
class GMPVideoEncoderParent : public GMPVideoEncoder,
public PGMPVideoEncoderParent,
public GMPSharedMemManager
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPVideoEncoderParent)
GMPVideoEncoderParent(GMPParent *aPlugin);
GMPVideoHostImpl& Host();
// GMPSharedMemManager
virtual bool MgrAllocShmem(size_t aSize,
ipc::Shmem::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aMem) MOZ_OVERRIDE;
virtual bool MgrDeallocShmem(Shmem& aMem) MOZ_OVERRIDE;
// GMPVideoEncoder
virtual GMPVideoErr InitEncode(const GMPVideoCodec& aCodecSettings,
GMPEncoderCallback* aCallback,
int32_t aNumberOfCores,
uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
virtual GMPVideoErr Encode(GMPVideoi420Frame* aInputFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo,
const std::vector<GMPVideoFrameType>& aFrameTypes) MOZ_OVERRIDE;
virtual GMPVideoErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) MOZ_OVERRIDE;
virtual GMPVideoErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
virtual GMPVideoErr SetPeriodicKeyFrames(bool aEnable) MOZ_OVERRIDE;
virtual void EncodingComplete() MOZ_OVERRIDE;
private:
virtual ~GMPVideoEncoderParent();
// PGMPVideoEncoderParent
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
const GMPCodecSpecificInfo& aCodecSpecificInfo) MOZ_OVERRIDE;
virtual bool Recv__delete__() MOZ_OVERRIDE;
bool mCanSendMessages;
GMPParent* mPlugin;
GMPEncoderCallback* mCallback;
GMPVideoHostImpl mVideoHost;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoEncoderParent_h_

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

@ -0,0 +1,127 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoHost.h"
#include "mozilla/Assertions.h"
#include "GMPVideoi420FrameImpl.h"
#include "GMPVideoEncodedFrameImpl.h"
namespace mozilla {
namespace gmp {
GMPVideoHostImpl::GMPVideoHostImpl(GMPSharedMemManager* aSharedMemMgr)
: mSharedMemMgr(aSharedMemMgr)
{
}
GMPVideoHostImpl::~GMPVideoHostImpl()
{
}
GMPVideoErr
GMPVideoHostImpl::CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame)
{
if (!mSharedMemMgr) {
return GMPVideoGenericErr;
}
if (!aFrame) {
return GMPVideoGenericErr;
}
*aFrame = nullptr;
switch (aFormat) {
case kGMPI420VideoFrame:
*aFrame = new GMPVideoi420FrameImpl(this);
return GMPVideoNoErr;
case kGMPEncodedVideoFrame:
*aFrame = new GMPVideoEncodedFrameImpl(this);
return GMPVideoNoErr;
default:
NS_NOTREACHED("Unknown frame format!");
}
return GMPVideoGenericErr;
}
GMPVideoErr
GMPVideoHostImpl::CreatePlane(GMPPlane** aPlane)
{
if (!mSharedMemMgr) {
return GMPVideoGenericErr;
}
if (!aPlane) {
return GMPVideoGenericErr;
}
*aPlane = nullptr;
auto p = new GMPPlaneImpl(this);
*aPlane = p;
return GMPVideoNoErr;
}
GMPSharedMemManager*
GMPVideoHostImpl::SharedMemMgr()
{
return mSharedMemMgr;
}
void
GMPVideoHostImpl::DoneWithAPI()
{
for (uint32_t i = mPlanes.Length(); i > 0; i--) {
mPlanes[i - 1]->DoneWithAPI();
mPlanes.RemoveElementAt(i - 1);
}
for (uint32_t i = mEncodedFrames.Length(); i > 0; i--) {
mEncodedFrames[i - 1]->DoneWithAPI();
mEncodedFrames.RemoveElementAt(i - 1);
}
mSharedMemMgr = nullptr;
}
void
GMPVideoHostImpl::ActorDestroyed()
{
for (uint32_t i = mPlanes.Length(); i > 0; i--) {
mPlanes[i - 1]->ActorDestroyed();
mPlanes.RemoveElementAt(i - 1);
}
for (uint32_t i = mEncodedFrames.Length(); i > 0; i--) {
mEncodedFrames[i - 1]->ActorDestroyed();
mEncodedFrames.RemoveElementAt(i - 1);
}
mSharedMemMgr = nullptr;
}
void
GMPVideoHostImpl::PlaneCreated(GMPPlaneImpl* aPlane)
{
mPlanes.AppendElement(aPlane);
}
void
GMPVideoHostImpl::PlaneDestroyed(GMPPlaneImpl* aPlane)
{
MOZ_ALWAYS_TRUE(mPlanes.RemoveElement(aPlane));
}
void
GMPVideoHostImpl::EncodedFrameCreated(GMPVideoEncodedFrameImpl* aEncodedFrame)
{
mEncodedFrames.AppendElement(aEncodedFrame);
}
void
GMPVideoHostImpl::EncodedFrameDestroyed(GMPVideoEncodedFrameImpl* aFrame)
{
MOZ_ALWAYS_TRUE(mEncodedFrames.RemoveElement(aFrame));
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoHost_h_
#define GMPVideoHost_h_
#include "gmp-video-host.h"
#include "gmp-video-plane.h"
#include "gmp-video-frame.h"
#include "gmp-video-host.h"
#include "nsTArray.h"
namespace mozilla {
namespace gmp {
class GMPSharedMemManager;
class GMPPlaneImpl;
class GMPVideoEncodedFrameImpl;
class GMPVideoHostImpl : public GMPVideoHost
{
public:
GMPVideoHostImpl(GMPSharedMemManager* aSharedMemMgr);
virtual ~GMPVideoHostImpl();
// Used for shared memory allocation and deallocation.
GMPSharedMemManager* SharedMemMgr();
void DoneWithAPI();
void ActorDestroyed();
void PlaneCreated(GMPPlaneImpl* aPlane);
void PlaneDestroyed(GMPPlaneImpl* aPlane);
void EncodedFrameCreated(GMPVideoEncodedFrameImpl* aEncodedFrame);
void EncodedFrameDestroyed(GMPVideoEncodedFrameImpl* aFrame);
// GMPVideoHost
virtual GMPVideoErr CreateFrame(GMPVideoFrameFormat aFormat, GMPVideoFrame** aFrame) MOZ_OVERRIDE;
virtual GMPVideoErr CreatePlane(GMPPlane** aPlane) MOZ_OVERRIDE;
private:
// All shared memory allocations have to be made by an IPDL actor.
// This is a reference to the owning actor. If this reference is
// null then the actor has died and all allocations must fail.
GMPSharedMemManager* mSharedMemMgr;
// We track all of these things because they need to handle further
// allocations through us and we need to notify them when they
// can't use us any more.
nsTArray<GMPPlaneImpl*> mPlanes;
nsTArray<GMPVideoEncodedFrameImpl*> mEncodedFrames;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoHost_h_

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

@ -0,0 +1,224 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoPlaneImpl.h"
#include "mozilla/gmp/GMPTypes.h"
#include "GMPVideoHost.h"
#include "GMPSharedMemManager.h"
namespace mozilla {
namespace gmp {
GMPPlaneImpl::GMPPlaneImpl(GMPVideoHostImpl* aHost)
: mSize(0),
mStride(0),
mHost(aHost)
{
MOZ_ASSERT(mHost);
mHost->PlaneCreated(this);
}
GMPPlaneImpl::GMPPlaneImpl(const GMPPlaneData& aPlaneData, GMPVideoHostImpl* aHost)
: mBuffer(aPlaneData.mBuffer()),
mSize(aPlaneData.mSize()),
mStride(aPlaneData.mStride()),
mHost(aHost)
{
MOZ_ASSERT(mHost);
mHost->PlaneCreated(this);
}
GMPPlaneImpl::~GMPPlaneImpl()
{
DestroyBuffer();
if (mHost) {
mHost->PlaneDestroyed(this);
}
}
void
GMPPlaneImpl::DoneWithAPI()
{
DestroyBuffer();
// Do this after destroying the buffer because destruction
// involves deallocation, which requires a host.
mHost = nullptr;
}
void
GMPPlaneImpl::ActorDestroyed()
{
// Simply clear out Shmem reference, do not attempt to
// properly free it. It has already been freed.
mBuffer = ipc::Shmem();
// No more host.
mHost = nullptr;
}
bool
GMPPlaneImpl::InitPlaneData(GMPPlaneData& aPlaneData)
{
aPlaneData.mBuffer() = mBuffer;
aPlaneData.mSize() = mSize;
aPlaneData.mStride() = mStride;
// This method is called right before Shmem is sent to another process.
// We need to effectively zero out our member copy so that we don't
// try to delete memory we don't own later.
mBuffer = ipc::Shmem();
return true;
}
GMPVideoErr
GMPPlaneImpl::MaybeResize(int32_t aNewSize) {
if (aNewSize <= AllocatedSize()) {
return GMPVideoNoErr;
}
if (!mHost) {
return GMPVideoGenericErr;
}
ipc::Shmem new_mem;
if (!mHost->SharedMemMgr()->MgrAllocShmem(aNewSize, ipc::SharedMemory::TYPE_BASIC, &new_mem) ||
!new_mem.get<uint8_t>()) {
return GMPVideoAllocErr;
}
if (mBuffer.IsReadable()) {
memcpy(new_mem.get<uint8_t>(), Buffer(), mSize);
}
DestroyBuffer();
mBuffer = new_mem;
return GMPVideoNoErr;
}
void
GMPPlaneImpl::DestroyBuffer()
{
if (mHost && mBuffer.IsWritable()) {
mHost->SharedMemMgr()->MgrDeallocShmem(mBuffer);
}
mBuffer = ipc::Shmem();
}
GMPVideoErr
GMPPlaneImpl::CreateEmptyPlane(int32_t aAllocatedSize, int32_t aStride, int32_t aPlaneSize)
{
if (aAllocatedSize < 1 || aStride < 1 || aPlaneSize < 1) {
return GMPVideoGenericErr;
}
GMPVideoErr err = MaybeResize(aAllocatedSize);
if (err != GMPVideoNoErr) {
return err;
}
mSize = aPlaneSize;
mStride = aStride;
return GMPVideoNoErr;
}
GMPVideoErr
GMPPlaneImpl::Copy(const GMPPlane& aPlane)
{
auto& planeimpl = static_cast<const GMPPlaneImpl&>(aPlane);
GMPVideoErr err = MaybeResize(planeimpl.mSize);
if (err != GMPVideoNoErr) {
return err;
}
if (planeimpl.Buffer() && planeimpl.mSize > 0) {
memcpy(Buffer(), planeimpl.Buffer(), mSize);
}
mSize = planeimpl.mSize;
mStride = planeimpl.mStride;
return GMPVideoNoErr;
}
GMPVideoErr
GMPPlaneImpl::Copy(int32_t aSize, int32_t aStride, const uint8_t* aBuffer)
{
GMPVideoErr err = MaybeResize(aSize);
if (err != GMPVideoNoErr) {
return err;
}
if (aBuffer && aSize > 0) {
memcpy(Buffer(), aBuffer, aSize);
}
mSize = aSize;
mStride = aStride;
return GMPVideoNoErr;
}
void
GMPPlaneImpl::Swap(GMPPlane& aPlane)
{
auto& planeimpl = static_cast<GMPPlaneImpl&>(aPlane);
std::swap(mStride, planeimpl.mStride);
std::swap(mSize, planeimpl.mSize);
std::swap(mBuffer, planeimpl.mBuffer);
}
int32_t
GMPPlaneImpl::AllocatedSize() const
{
if (mBuffer.IsWritable()) {
return mBuffer.Size<uint8_t>();
}
return 0;
}
void
GMPPlaneImpl::ResetSize()
{
mSize = 0;
}
bool
GMPPlaneImpl::IsZeroSize() const
{
return (mSize == 0);
}
int32_t
GMPPlaneImpl::Stride() const
{
return mStride;
}
const uint8_t*
GMPPlaneImpl::Buffer() const
{
return mBuffer.get<uint8_t>();
}
uint8_t*
GMPPlaneImpl::Buffer()
{
return mBuffer.get<uint8_t>();
}
void
GMPPlaneImpl::Destroy()
{
delete this;
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoPlaneImpl_h_
#define GMPVideoPlaneImpl_h_
#include "gmp-video-plane.h"
#include "mozilla/ipc/Shmem.h"
namespace mozilla {
namespace gmp {
class GMPVideoHostImpl;
class GMPPlaneData;
class GMPPlaneImpl : public GMPPlane
{
friend struct IPC::ParamTraits<mozilla::gmp::GMPPlaneImpl>;
public:
GMPPlaneImpl(GMPVideoHostImpl* aHost);
GMPPlaneImpl(const GMPPlaneData& aPlaneData, GMPVideoHostImpl* aHost);
virtual ~GMPPlaneImpl();
// This is called during a normal destroy sequence, which is
// when a consumer is finished or during XPCOM shutdown.
void DoneWithAPI();
// This is called when something has gone wrong - specicifically,
// a child process has crashed. Does not attempt to release Shmem,
// as the Shmem has already been released.
void ActorDestroyed();
bool InitPlaneData(GMPPlaneData& aPlaneData);
// GMPPlane
virtual GMPVideoErr CreateEmptyPlane(int32_t aAllocatedSize,
int32_t aStride,
int32_t aPlaneSize) MOZ_OVERRIDE;
virtual GMPVideoErr Copy(const GMPPlane& aPlane) MOZ_OVERRIDE;
virtual GMPVideoErr Copy(int32_t aSize,
int32_t aStride,
const uint8_t* aBuffer) MOZ_OVERRIDE;
virtual void Swap(GMPPlane& aPlane) MOZ_OVERRIDE;
virtual int32_t AllocatedSize() const MOZ_OVERRIDE;
virtual void ResetSize() MOZ_OVERRIDE;
virtual bool IsZeroSize() const MOZ_OVERRIDE;
virtual int32_t Stride() const MOZ_OVERRIDE;
virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
virtual uint8_t* Buffer() MOZ_OVERRIDE;
virtual void Destroy() MOZ_OVERRIDE;
private:
GMPVideoErr MaybeResize(int32_t aNewSize);
void DestroyBuffer();
ipc::Shmem mBuffer;
int32_t mSize;
int32_t mStride;
GMPVideoHostImpl* mHost;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoPlaneImpl_h_

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

@ -0,0 +1,337 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoi420FrameImpl.h"
#include "mozilla/gmp/GMPTypes.h"
namespace mozilla {
namespace gmp {
GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost)
: mYPlane(aHost),
mUPlane(aHost),
mVPlane(aHost),
mWidth(0),
mHeight(0),
mTimestamp(0),
mRenderTime_ms(0)
{
MOZ_ASSERT(aHost);
}
GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData,
GMPVideoHostImpl* aHost)
: mYPlane(aFrameData.mYPlane(), aHost),
mUPlane(aFrameData.mUPlane(), aHost),
mVPlane(aFrameData.mVPlane(), aHost),
mWidth(aFrameData.mWidth()),
mHeight(aFrameData.mHeight()),
mTimestamp(aFrameData.mTimestamp()),
mRenderTime_ms(aFrameData.mRenderTime_ms())
{
MOZ_ASSERT(aHost);
}
GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl()
{
}
bool
GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData)
{
mYPlane.InitPlaneData(aFrameData.mYPlane());
mUPlane.InitPlaneData(aFrameData.mUPlane());
mVPlane.InitPlaneData(aFrameData.mVPlane());
aFrameData.mWidth() = mWidth;
aFrameData.mHeight() = mHeight;
aFrameData.mTimestamp() = mTimestamp;
aFrameData.mRenderTime_ms() = mRenderTime_ms;
return true;
}
GMPVideoFrameFormat
GMPVideoi420FrameImpl::GetFrameFormat()
{
return kGMPI420VideoFrame;
}
void
GMPVideoi420FrameImpl::Destroy()
{
delete this;
}
bool
GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight,
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
{
int32_t half_width = (aWidth + 1) / 2;
if (aWidth < 1 || aHeight < 1 || aStride_y < aWidth ||
aStride_u < half_width ||
aStride_v < half_width) {
return false;
}
return true;
}
const GMPPlaneImpl*
GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) const {
switch (aType) {
case kGMPYPlane:
return &mYPlane;
case kGMPUPlane:
return &mUPlane;
case kGMPVPlane:
return &mVPlane;
default:
MOZ_CRASH("Unknown plane type!");
}
return nullptr;
}
GMPPlaneImpl*
GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) {
switch (aType) {
case kGMPYPlane :
return &mYPlane;
case kGMPUPlane :
return &mUPlane;
case kGMPVPlane :
return &mVPlane;
default:
MOZ_CRASH("Unknown plane type!");
}
return nullptr;
}
GMPVideoErr
GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight,
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
{
if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
return GMPVideoGenericErr;
}
int32_t size_y = aStride_y * aHeight;
int32_t half_height = (aHeight + 1) / 2;
int32_t size_u = aStride_u * half_height;
int32_t size_v = aStride_v * half_height;
GMPVideoErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y);
if (err != GMPVideoNoErr) {
return err;
}
err = mUPlane.CreateEmptyPlane(size_u, aStride_u, size_u);
if (err != GMPVideoNoErr) {
return err;
}
err = mVPlane.CreateEmptyPlane(size_v, aStride_v, size_v);
if (err != GMPVideoNoErr) {
return err;
}
mWidth = aWidth;
mHeight = aHeight;
mTimestamp = 0;
mRenderTime_ms = 0;
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
int32_t aSize_u, const uint8_t* aBuffer_u,
int32_t aSize_v, const uint8_t* aBuffer_v,
int32_t aWidth, int32_t aHeight,
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v)
{
MOZ_ASSERT(aBuffer_y);
MOZ_ASSERT(aBuffer_u);
MOZ_ASSERT(aBuffer_v);
if (aSize_y < 1 || aSize_u < 1 || aSize_v < 1) {
return GMPVideoGenericErr;
}
if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) {
return GMPVideoGenericErr;
}
GMPVideoErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y);
if (err != GMPVideoNoErr) {
return err;
}
err = mUPlane.Copy(aSize_u, aStride_u, aBuffer_u);
if (err != GMPVideoNoErr) {
return err;
}
err = mVPlane.Copy(aSize_v, aStride_v, aBuffer_v);
if (err != GMPVideoNoErr) {
return err;
}
mWidth = aWidth;
mHeight = aHeight;
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame)
{
auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame);
GMPVideoErr err = mYPlane.Copy(f.mYPlane);
if (err != GMPVideoNoErr) {
return err;
}
err = mUPlane.Copy(f.mUPlane);
if (err != GMPVideoNoErr) {
return err;
}
err = mVPlane.Copy(f.mVPlane);
if (err != GMPVideoNoErr) {
return err;
}
mWidth = f.mWidth;
mHeight = f.mHeight;
mTimestamp = f.mTimestamp;
mRenderTime_ms = f.mRenderTime_ms;
return GMPVideoNoErr;
}
void
GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame)
{
auto f = static_cast<GMPVideoi420FrameImpl*>(aFrame);
mYPlane.Swap(f->mYPlane);
mUPlane.Swap(f->mUPlane);
mVPlane.Swap(f->mVPlane);
std::swap(mWidth, f->mWidth);
std::swap(mHeight, f->mHeight);
std::swap(mTimestamp, f->mTimestamp);
std::swap(mRenderTime_ms, f->mRenderTime_ms);
}
uint8_t*
GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType)
{
GMPPlane* p = GetPlane(aType);
if (p) {
return p->Buffer();
}
return nullptr;
}
const uint8_t*
GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) const
{
const GMPPlane* p = GetPlane(aType);
if (p) {
return p->Buffer();
}
return nullptr;
}
int32_t
GMPVideoi420FrameImpl::AllocatedSize(GMPPlaneType aType) const
{
const GMPPlane* p = GetPlane(aType);
if (p) {
return p->AllocatedSize();
}
return -1;
}
int32_t
GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const
{
const GMPPlane* p = GetPlane(aType);
if (p) {
return p->Stride();
}
return -1;
}
GMPVideoErr
GMPVideoi420FrameImpl::SetWidth(int32_t aWidth)
{
if (!CheckDimensions(aWidth, mHeight,
mYPlane.Stride(), mUPlane.Stride(),
mVPlane.Stride())) {
return GMPVideoGenericErr;
}
mWidth = aWidth;
return GMPVideoNoErr;
}
GMPVideoErr
GMPVideoi420FrameImpl::SetHeight(int32_t aHeight)
{
if (!CheckDimensions(mWidth, aHeight,
mYPlane.Stride(), mUPlane.Stride(),
mVPlane.Stride())) {
return GMPVideoGenericErr;
}
mHeight = aHeight;
return GMPVideoNoErr;
}
int32_t
GMPVideoi420FrameImpl::Width() const
{
return mWidth;
}
int32_t
GMPVideoi420FrameImpl::Height() const
{
return mHeight;
}
void
GMPVideoi420FrameImpl::SetTimestamp(uint32_t aTimestamp)
{
mTimestamp = aTimestamp;
}
uint32_t
GMPVideoi420FrameImpl::Timestamp() const
{
return mTimestamp;
}
void
GMPVideoi420FrameImpl::SetRenderTime_ms(int64_t aRenderTime_ms)
{
mRenderTime_ms = aRenderTime_ms;
}
int64_t
GMPVideoi420FrameImpl::RenderTime_ms() const
{
return mRenderTime_ms;
}
bool
GMPVideoi420FrameImpl::IsZeroSize() const
{
return (mYPlane.IsZeroSize() && mUPlane.IsZeroSize() && mVPlane.IsZeroSize());
}
void
GMPVideoi420FrameImpl::ResetSize()
{
mYPlane.ResetSize();
mUPlane.ResetSize();
mVPlane.ResetSize();
}
} // namespace gmp
} // namespace mozilla

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

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GMPVideoi420FrameImpl_h_
#define GMPVideoi420FrameImpl_h_
#include "gmp-video-frame-i420.h"
#include "mozilla/ipc/Shmem.h"
#include "GMPVideoPlaneImpl.h"
namespace mozilla {
namespace gmp {
class GMPVideoi420FrameData;
class GMPVideoi420FrameImpl : public GMPVideoi420Frame
{
friend struct IPC::ParamTraits<mozilla::gmp::GMPVideoi420FrameImpl>;
public:
GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost);
GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData, GMPVideoHostImpl* aHost);
virtual ~GMPVideoi420FrameImpl();
bool InitFrameData(GMPVideoi420FrameData& aFrameData);
const GMPPlaneImpl* GetPlane(GMPPlaneType aType) const;
GMPPlaneImpl* GetPlane(GMPPlaneType aType);
// GMPVideoFrame
virtual GMPVideoFrameFormat GetFrameFormat() MOZ_OVERRIDE;
virtual void Destroy() MOZ_OVERRIDE;
// GMPVideoi420Frame
virtual GMPVideoErr CreateEmptyFrame(int32_t aWidth,
int32_t aHeight,
int32_t aStride_y,
int32_t aStride_u,
int32_t aStride_v) MOZ_OVERRIDE;
virtual GMPVideoErr CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y,
int32_t aSize_u, const uint8_t* aBuffer_u,
int32_t aSize_v, const uint8_t* aBuffer_v,
int32_t aWidth,
int32_t aHeight,
int32_t aStride_y,
int32_t aStride_u,
int32_t aStride_v) MOZ_OVERRIDE;
virtual GMPVideoErr CopyFrame(const GMPVideoi420Frame& aFrame) MOZ_OVERRIDE;
virtual void SwapFrame(GMPVideoi420Frame* aFrame) MOZ_OVERRIDE;
virtual uint8_t* Buffer(GMPPlaneType aType) MOZ_OVERRIDE;
virtual const uint8_t* Buffer(GMPPlaneType aType) const MOZ_OVERRIDE;
virtual int32_t AllocatedSize(GMPPlaneType aType) const MOZ_OVERRIDE;
virtual int32_t Stride(GMPPlaneType aType) const MOZ_OVERRIDE;
virtual GMPVideoErr SetWidth(int32_t aWidth) MOZ_OVERRIDE;
virtual GMPVideoErr SetHeight(int32_t aHeight) MOZ_OVERRIDE;
virtual int32_t Width() const MOZ_OVERRIDE;
virtual int32_t Height() const MOZ_OVERRIDE;
virtual void SetTimestamp(uint32_t aTimestamp) MOZ_OVERRIDE;
virtual uint32_t Timestamp() const MOZ_OVERRIDE;
virtual void SetRenderTime_ms(int64_t aRenderTime_ms) MOZ_OVERRIDE;
virtual int64_t RenderTime_ms() const MOZ_OVERRIDE;
virtual bool IsZeroSize() const MOZ_OVERRIDE;
virtual void ResetSize() MOZ_OVERRIDE;
private:
bool CheckDimensions(int32_t aWidth, int32_t aHeight,
int32_t aStride_y, int32_t aStride_u, int32_t aStride_v);
GMPPlaneImpl mYPlane;
GMPPlaneImpl mUPlane;
GMPPlaneImpl mVPlane;
int32_t mWidth;
int32_t mHeight;
uint32_t mTimestamp;
int64_t mRenderTime_ms;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPVideoi420FrameImpl_h_

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше