Merge mozilla-central and mozilla-inbound

This commit is contained in:
Matt Brubeck 2012-03-01 20:07:54 -08:00
commit 15e67715c7
242 changed files with 4391 additions and 2870 deletions

View File

@ -1,165 +0,0 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Command Updater
*/
let CommandUpdater = {
/**
* Gets a controller that can handle a particular command.
* @param {string} command
* A command to locate a controller for, preferring controllers that
* show the command as enabled.
* @return {object} In this order of precedence:
* - the first controller supporting the specified command
* associated with the focused element that advertises the
* command as ENABLED.
* - the first controller supporting the specified command
* associated with the global window that advertises the
* command as ENABLED.
* - the first controller supporting the specified command
* associated with the focused element.
* - the first controller supporting the specified command
* associated with the global window.
*/
_getControllerForCommand: function(command) {
try {
let commandDispatcher = top.document.commandDispatcher;
let controller = commandDispatcher.getControllerForCommand(command);
if (controller && controller.isCommandEnabled(command))
return controller;
}
catch (e) { }
let controllerCount = window.controllers.getControllerCount();
for (let i = 0; i < controllerCount; ++i) {
let current = window.controllers.getControllerAt(i);
try {
if (current.supportsCommand(command) &&
current.isCommandEnabled(command))
return current;
}
catch (e) { }
}
return controller || window.controllers.getControllerForCommand(command);
},
/**
* Updates the state of a XUL <command> element for the specified command
* depending on its state.
* @param {string} command
* The name of the command to update the XUL <command> element for.
*/
updateCommand: function(command) {
let enabled = false;
try {
let controller = this._getControllerForCommand(command);
if (controller) {
enabled = controller.isCommandEnabled(command);
}
}
catch (ex) { }
this.enableCommand(command, enabled);
},
/**
* Updates the state of a XUL <command> element for the specified command
* depending on its state.
* @param {string} command
* The name of the command to update the XUL <command> element for.
*/
updateCommands: function(_commands) {
let commands = _commands.split(',');
for (let command in commands) {
this.updateCommand(commands[command]);
}
},
/**
* Enables or disables a XUL <command> element.
* @param {string} command
* The name of the command to enable or disable.
* @param {bool} enabled
* true if the command should be enabled, false otherwise.
*/
enableCommand: function(command, enabled) {
let element = document.getElementById(command);
if (!element)
return;
if (enabled)
element.removeAttribute('disabled');
else
element.setAttribute('disabled', 'true');
},
/**
* Performs the action associated with a specified command using the most
* relevant controller.
* @param {string} command
* The command to perform.
*/
doCommand: function(command) {
let controller = this._getControllerForCommand(command);
if (!controller)
return;
controller.doCommand(command);
},
/**
* Changes the label attribute for the specified command.
* @param {string} command
* The command to update.
* @param {string} labelAttribute
* The label value to use.
*/
setMenuValue: function(command, labelAttribute) {
let commandNode = top.document.getElementById(command);
if (commandNode) {
let label = commandNode.getAttribute(labelAttribute);
if (label)
commandNode.setAttribute('label', label);
}
},
/**
* Changes the accesskey attribute for the specified command.
* @param {string} command
* The command to update.
* @param {string} valueAttribute
* The value attribute to use.
*/
setAccessKey: function(command, valueAttribute) {
let commandNode = top.document.getElementById(command);
if (commandNode) {
let value = commandNode.getAttribute(valueAttribute);
if (value)
commandNode.setAttribute('accesskey', value);
}
},
/**
* Inform all the controllers attached to a node that an event has occurred
* (e.g. the tree controllers need to be informed of blur events so that they
* can change some of the menu items back to their default values)
* @param {node} node
* The node receiving the event.
* @param {event} event
* The event.
*/
onEvent: function(node, event) {
let numControllers = node.controllers.getControllerCount();
let controller;
for (let i = 0; i < numControllers; i++) {
controller = node.controllers.getControllerAt(i);
if (controller)
controller.onEvent(event);
}
}
};

View File

@ -33,11 +33,15 @@ XPCOMUtils.defineLazyGetter(Services, 'idle', function() {
.getService(Ci.nsIIdleService);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function(){
return Cc['@mozilla.org/focus-managr;1']
.getService(Ci.nsFocusManager);
XPCOMUtils.defineLazyGetter(Services, 'audioManager', function() {
return Cc['@mozilla.org/telephony/audiomanager;1']
.getService(Ci.nsIAudioManager);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function() {
return Cc['@mozilla.org/focus-manager;1']
.getService(Ci.nsFocusManager);
});
#ifndef MOZ_WIDGET_GONK
// In order to use http:// scheme instead of file:// scheme
@ -74,9 +78,6 @@ function addPermissions(urls) {
}
var shell = {
// FIXME/bug 678695: this should be a system setting
preferredScreenBrightness: 1.0,
isDebug: false,
get contentBrowser() {
@ -111,13 +112,23 @@ var shell = {
return alert(msg);
}
window.controllers.appendController(this);
window.addEventListener('keypress', this);
['keydown', 'keypress', 'keyup'].forEach((function listenKey(type) {
window.addEventListener(type, this, false, true);
window.addEventListener(type, this, true, true);
}).bind(this));
window.addEventListener('MozApplicationManifest', this);
window.addEventListener("AppCommand", this);
window.addEventListener('mozfullscreenchange', this);
this.contentBrowser.addEventListener('load', this, true);
// Until the volume can be set from the content side, set it to a
// a specific value when the device starts. This way the front-end
// can display a notification when the volume change and show a volume
// level modified from this point.
try {
Services.audioManager.masterVolume = 0.5;
} catch(e) {}
try {
Services.io.offline = false;
@ -159,35 +170,8 @@ var shell = {
},
stop: function shell_stop() {
window.controllers.removeController(this);
window.removeEventListener('keypress', this);
window.removeEventListener('MozApplicationManifest', this);
window.removeEventListener('AppCommand', this);
},
supportsCommand: function shell_supportsCommand(cmd) {
let isSupported = false;
switch (cmd) {
case 'cmd_close':
isSupported = true;
break;
default:
isSupported = false;
break;
}
return isSupported;
},
isCommandEnabled: function shell_isCommandEnabled(cmd) {
return true;
},
doCommand: function shell_doCommand(cmd) {
switch (cmd) {
case 'cmd_close':
content.postMessage('appclose', '*');
break;
}
window.removeEventListener('mozfullscreenchange', this);
},
toggleDebug: function shell_toggleDebug() {
@ -202,9 +186,7 @@ var shell = {
}
},
changeVolume: function shell_changeVolume(aDelta) {
let audioManager = Cc["@mozilla.org/telephony/audiomanager;1"].getService(Ci.nsIAudioManager);
changeVolume: function shell_changeVolume(delta) {
let steps = 10;
try {
steps = Services.prefs.getIntPref("media.volume.steps");
@ -212,7 +194,11 @@ var shell = {
steps = 1;
} catch(e) {}
let volume = audioManager.masterVolume + aDelta / steps;
let audioManager = Services.audioManager;
if (!audioManager)
return;
let volume = audioManager.masterVolume + delta / steps;
if (volume > 1)
volume = 1;
if (volume < 0)
@ -220,44 +206,58 @@ var shell = {
audioManager.masterVolume = volume;
},
forwardKeyToHomescreen: function shell_forwardKeyToHomescreen(evt) {
let generatedEvent = content.document.createEvent('KeyboardEvent');
generatedEvent.initKeyEvent(evt.type, true, true, evt.view, evt.ctrlKey,
evt.altKey, evt.shiftKey, evt.metaKey,
evt.keyCode, evt.charCode);
content.dispatchEvent(generatedEvent);
},
handleEvent: function shell_handleEvent(evt) {
switch (evt.type) {
case 'keydown':
case 'keyup':
case 'keypress':
switch (evt.keyCode) {
case evt.DOM_VK_HOME:
this.sendEvent(content, 'home');
break;
case evt.DOM_VK_SLEEP:
this.toggleScreen();
let details = {
'enabled': screen.mozEnabled
};
this.sendEvent(content, 'sleep', details);
break;
case evt.DOM_VK_ESCAPE:
if (evt.defaultPrevented)
return;
this.doCommand('cmd_close');
break;
// If the home key is pressed, always forward it to the homescreen
if (evt.eventPhase == evt.CAPTURING_PHASE) {
if (evt.keyCode == evt.VK_DOM_HOME) {
window.setTimeout(this.forwardKeyToHomescreen, 0, evt);
evt.preventDefault();
evt.stopPropagation();
}
return;
}
break;
case 'AppCommand':
switch (evt.command) {
case 'Menu':
if (Services.prefs.getBoolPref('b2g.keys.menu.enabled'))
this.sendEvent(content, 'menu');
break;
case 'Search':
if (Services.prefs.getBoolPref('b2g.keys.search.enabled'))
this.toggleDebug();
break;
case 'VolumeUp':
this.changeVolume(1);
break;
case 'VolumeDown':
this.changeVolume(-1);
break;
// If one of the other keys is used in an application and is
// cancelled via preventDefault, do nothing.
let homescreen = (evt.target.ownerDocument.defaultView == content);
if (!homescreen && evt.defaultPrevented)
return;
// If one of the other keys is used in an application and is
// not used forward it to the homescreen
if (!homescreen)
window.setTimeout(this.forwardKeyToHomescreen, 0, evt);
// For debug purposes and because some of the APIs are not yet exposed
// to the content, let's react on some of the keyup events.
if (evt.type == 'keyup') {
switch (evt.keyCode) {
case evt.DOM_VK_F5:
if (Services.prefs.getBoolPref('b2g.keys.search.enabled'))
this.toggleDebug();
break;
case evt.DOM_VK_PAGE_DOWN:
this.changeVolume(-1);
break;
case evt.DOM_VK_PAGE_UP:
this.changeVolume(1);
break;
}
}
break;
@ -270,7 +270,6 @@ var shell = {
break;
case 'load':
this.contentBrowser.removeEventListener('load', this, true);
this.turnScreenOn();
let chromeWindow = window.QueryInterface(Ci.nsIDOMChromeWindow);
chromeWindow.browserDOMWindow = new nsBrowserAccess();
@ -317,20 +316,6 @@ var shell = {
let event = content.document.createEvent('CustomEvent');
event.initCustomEvent(type, true, true, details ? details : {});
content.dispatchEvent(event);
},
toggleScreen: function shell_toggleScreen() {
if (screen.mozEnabled)
this.turnScreenOff();
else
this.turnScreenOn();
},
turnScreenOff: function shell_turnScreenOff() {
screen.mozEnabled = false;
screen.mozBrightness = 0.0;
},
turnScreenOn: function shell_turnScreenOn() {
screen.mozEnabled = true;
screen.mozBrightness = this.preferredScreenBrightness;
}
};
@ -339,7 +324,7 @@ var shell = {
observe: function(subject, topic, time) {
if (topic === "idle") {
// TODO: Check wakelock status. See bug 697132.
shell.turnScreenOff();
screen.mozEnabled = false;
}
},
}

View File

@ -15,7 +15,6 @@
onload="shell.start();"
onunload="shell.stop();">
<script type="application/javascript" src="chrome://browser/content/commandUtil.js"/>
<script type="application/javascript" src="chrome://browser/content/shell.js"/>
#ifndef MOZ_TOUCH
<script type="application/javascript" src="chrome://browser/content/touch.js"/>
@ -24,10 +23,6 @@
<script type="application/javascript" src="chrome://browser/content/httpd.js"/>
#endif
<commandset id="mainCommandSet">
<command id="cmd_close" oncommand="CommandUpdater.doCommand(this.id);"/>
</commandset>
<browser id="homescreen"
type="content-primary"
flex="1"

View File

@ -9,7 +9,6 @@ chrome.jar:
#ifndef MOZ_TOUCH
content/touch.js (content/touch.js)
#endif
content/commandUtil.js (content/commandUtil.js)
#ifndef MOZ_WIDGET_GONK
content/httpd.js (content/httpd.js)
#endif
@ -22,4 +21,4 @@ chrome.jar:
content/netError.css (content/netError.css)
content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png)
content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png)
content/images/errorpage-warning.png (content/images/errorpage-warning.png)
content/images/errorpage-warning.png (content/images/errorpage-warning.png)

View File

@ -320,6 +320,8 @@ pref("browser.urlbar.default.behavior", 0);
pref("browser.urlbar.formatting.enabled", true);
pref("browser.urlbar.trimURLs", true);
pref("browser.altClickSave", false);
// Number of milliseconds to wait for the http headers (and thus
// the Content-Disposition filename) before giving up and falling back to
// picking a filename without that info in hand so that the user sees some

View File

@ -48,6 +48,9 @@
<!ENTITY % syncSetupDTD
SYSTEM "chrome://browser/locale/syncSetup.dtd">
%syncSetupDTD;
<!ENTITY % globalDTD
SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
@ -63,7 +66,7 @@
<script type="text/javascript;version=1.8"
src="chrome://browser/content/sync/progress.js"/>
</head>
<body onload="onLoad(event)" onunload="onUnload(event)">
<body onload="onLoad(event)" onunload="onUnload(event)" dir="&locale.dir;">
<title>&setup.successPage.title;</title>
<div id="floatingBox" class="main-content">
<div id="title">

View File

@ -93,7 +93,6 @@ endif
# browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
# browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
# browser_urlbarAutoFillTrimURLs.js is disabled till bug 720792 is fixed
_BROWSER_FILES = \
head.js \
@ -223,6 +222,7 @@ _BROWSER_FILES = \
browser_tabfocus.js \
browser_tabs_isActive.js \
browser_tabs_owner.js \
browser_urlbarAutoFillTrimURLs.js \
browser_urlbarCopying.js \
browser_urlbarEnter.js \
browser_urlbarRevert.js \

View File

@ -73,8 +73,12 @@ let gTests = [
// just be like Alt click.
{
desc: "Shift+Alt left click",
setup: function() {},
clean: function() {},
setup: function() {
gPrefService.setBoolPref("browser.altClickSave", true);
},
clean: function() {
gPrefService.clearUserPref("browser.altClickSave");
},
event: { shiftKey: true,
altKey: true },
targets: [ "commonlink", "maplink" ],
@ -84,8 +88,12 @@ let gTests = [
{
desc: "Shift+Alt left click on XLinks",
setup: function() {},
clean: function() {},
setup: function() {
gPrefService.setBoolPref("browser.altClickSave", true);
},
clean: function() {
gPrefService.clearUserPref("browser.altClickSave");
},
event: { shiftKey: true,
altKey: true },
targets: [ "mathxlink", "svgxlink"],
@ -105,8 +113,12 @@ let gTests = [
{
desc: "Alt click",
setup: function() {},
clean: function() {},
setup: function() {
gPrefService.setBoolPref("browser.altClickSave", true);
},
clean: function() {
gPrefService.clearUserPref("browser.altClickSave");
},
event: { altKey: true },
targets: [ "commonlink", "maplink" ],
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
@ -115,8 +127,12 @@ let gTests = [
{
desc: "Alt click on XLinks",
setup: function() {},
clean: function() {},
setup: function() {
gPrefService.setBoolPref("browser.altClickSave", true);
},
clean: function() {
gPrefService.clearUserPref("browser.altClickSave");
},
event: { altKey: true },
targets: [ "mathxlink", "svgxlink" ],
expectedInvokedMethods: [ "saveURL" ],
@ -149,9 +165,7 @@ let gTests = [
gPrefService.setBoolPref("browser.tabs.opentabfor.middleclick", false);
},
clean: function() {
try {
gPrefService.clearUserPref("browser.tabs.opentabfor.middleclick");
} catch(ex) {}
gPrefService.clearUserPref("browser.tabs.opentabfor.middleclick");
},
event: { button: 1 },
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
@ -166,12 +180,8 @@ let gTests = [
gPrefService.setBoolPref("general.autoScroll", false);
},
clean: function() {
try {
gPrefService.clearUserPref("middlemouse.contentLoadURL");
} catch(ex) {}
try {
gPrefService.clearUserPref("general.autoScroll");
} catch(ex) {}
gPrefService.clearUserPref("middlemouse.contentLoadURL");
gPrefService.clearUserPref("general.autoScroll");
},
event: { button: 1 },
targets: [ "emptylink" ],

View File

@ -9,6 +9,12 @@ let gFocusManager = Cc["@mozilla.org/focus-manager;1"].
function test() {
waitForExplicitFinish();
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.altClickSave");
});
Services.prefs.setBoolPref("browser.altClickSave", true);
runAltLeftClickTest();
}

View File

@ -147,7 +147,7 @@ function whereToOpenLink( e, ignoreButton, ignoreAlt )
#endif
return shift ? "tabshifted" : "tab";
if (alt)
if (alt && getBoolPref("browser.altClickSave", false))
return "save";
if (shift || (middle && !middleUsesTabs))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 926 B

View File

@ -3,8 +3,13 @@ dnl disabling frame pointers in this architecture based on the configure
dnl options
AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [
case "$target" in
*android*)
unwind_tables="-funwind-tables"
;;
esac
if test "$GNU_CC"; then
MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer"
MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer $unwind_tables"
MOZ_DISABLE_FRAME_PTR="-fomit-frame-pointer"
else
case "$target" in

View File

@ -913,6 +913,7 @@ sechash.h
secoidt.h
certdb.h
secerr.h
nssutil.h
nssb64.h
secasn1.h
secder.h

View File

@ -5157,10 +5157,10 @@ incorrect])
else
AC_CHECK_LIB(QtSensors, main, [
MOZ_ENABLE_QTMOBILITY=1
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtMobility"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtSensors"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtFeedback"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I/usr/include/qt4/QtLocation"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtMobility"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtSensors"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtFeedback"
MOZ_QT_CFLAGS="$MOZ_QT_CFLAGS -I$QTDIR/include/QtLocation"
MOZ_QT_LIBS="$MOZ_QT_LIBS -lQtSensors -lQtFeedback -lQtLocation"
])
fi

View File

@ -422,8 +422,8 @@ public:
/**
* Returns true if aChar is of class Ps, Pi, Po, Pf, or Pe.
*/
static bool IsPunctuationMark(PRUint32 aChar);
static bool IsPunctuationMarkAt(const nsTextFragment* aFrag, PRUint32 aOffset);
static bool IsFirstLetterPunctuation(PRUint32 aChar);
static bool IsFirstLetterPunctuationAt(const nsTextFragment* aFrag, PRUint32 aOffset);
/**
* Returns true if aChar is of class Lu, Ll, Lt, Lm, Lo, Nd, Nl or No

View File

@ -210,6 +210,7 @@ INCLUDES += \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT
DEFINES += -DHB_DONT_DEFINE_STDINT
# gcc requires -msse2 for this file since it uses SSE2 intrinsics. (See bug
# 585538 comment 12.)

View File

@ -123,6 +123,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsILineBreaker.h"
#include "nsIWordBreaker.h"
#include "nsUnicodeProperties.h"
#include "harfbuzz/hb-common.h"
#include "jsdbgapi.h"
#include "nsIJSRuntimeService.h"
#include "nsIDOMDocumentXBL.h"
@ -1117,34 +1118,38 @@ nsContentUtils::CopyNewlineNormalizedUnicodeTo(nsReadingIterator<PRUnichar>& aSr
return normalizer.GetCharsWritten();
}
// Replaced by precompiled CCMap (see bug 180266). To update the list
// of characters, see one of files included below. As for the way
// the original list of characters was obtained by Frank Tang, see bug 54467.
// Updated to fix the regression (bug 263411). The list contains
// characters of the following Unicode character classes : Ps, Pi, Po, Pf, Pe.
// (ref.: http://www.w3.org/TR/2004/CR-CSS21-20040225/selector.html#first-letter)
#include "punct_marks.x-ccmap"
DEFINE_X_CCMAP(gPuncCharsCCMapExt, const);
/**
* This is used to determine whether a character is in one of the punctuation
* mark classes which CSS says should be part of the first-letter.
* See http://www.w3.org/TR/CSS2/selector.html#first-letter and
* http://www.w3.org/TR/selectors/#first-letter
*/
// static
bool
nsContentUtils::IsPunctuationMark(PRUint32 aChar)
nsContentUtils::IsFirstLetterPunctuation(PRUint32 aChar)
{
return CCMAP_HAS_CHAR_EXT(gPuncCharsCCMapExt, aChar);
PRUint8 cat = mozilla::unicode::GetGeneralCategory(aChar);
return (cat == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION || // Ps
cat == HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION || // Pe
cat == HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION || // Pi
cat == HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION || // Pf
cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION); // Po
}
// static
bool
nsContentUtils::IsPunctuationMarkAt(const nsTextFragment* aFrag, PRUint32 aOffset)
nsContentUtils::IsFirstLetterPunctuationAt(const nsTextFragment* aFrag, PRUint32 aOffset)
{
PRUnichar h = aFrag->CharAt(aOffset);
if (!IS_SURROGATE(h)) {
return IsPunctuationMark(h);
return IsFirstLetterPunctuation(h);
}
if (NS_IS_HIGH_SURROGATE(h) && aOffset + 1 < aFrag->GetLength()) {
PRUnichar l = aFrag->CharAt(aOffset + 1);
if (NS_IS_LOW_SURROGATE(l)) {
return IsPunctuationMark(SURROGATE_TO_UCS4(h, l));
return IsFirstLetterPunctuation(SURROGATE_TO_UCS4(h, l));
}
}
return false;

View File

@ -65,7 +65,7 @@ SetupCapitalization(const PRUnichar* aWord, PRUint32 aLength,
// The only space character a word can contain is NBSP.
bool capitalizeNextChar = true;
for (PRUint32 i = 0; i < aLength; ++i) {
if (capitalizeNextChar && !nsContentUtils::IsPunctuationMark(aWord[i])) {
if (capitalizeNextChar && !nsContentUtils::IsFirstLetterPunctuation(aWord[i])) {
aCapitalization[i] = true;
capitalizeNextChar = false;
}

View File

@ -467,6 +467,13 @@ public:
NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
double *destX, double *destY, NPCoordinateSpace destSpace);
void SendIdleEvent();
NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface)
{ return NPERR_GENERIC_ERROR; }
NPError FinalizeAsyncSurface(NPAsyncSurface *surface) { return NPERR_GENERIC_ERROR; }
void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) { return; }
NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
@ -605,6 +612,12 @@ nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDummyJavaPluginOwner::RedrawPlugin()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
{

View File

@ -11,7 +11,7 @@ VPATH = \
include $(DEPTH)/config/autoconf.mk
ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
ifeq ($(MOZ_BUILD_APP),b2g)
VPATH += $(srcdir)/fallback
endif
@ -19,17 +19,16 @@ MODULE = dom
LIBRARY_NAME = jsdomcontacts_s
LIBXUL_LIBRARY = 1
EXTRA_COMPONENTS = \
ContactManager.js \
ContactManager.manifest \
EXTRA_COMPONENTS = \
ContactManager.js \
ContactManager.manifest \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
EXTRA_JS_MODULES = ContactService.jsm \
$(NULL)
EXTRA_JS_MODULES += ContactDB.jsm \
$(NULL)
ifeq ($(MOZ_BUILD_APP),b2g)
EXTRA_JS_MODULES = \
ContactService.jsm \
ContactDB.jsm \
$(NULL)
endif
ifdef ENABLE_TESTS

View File

@ -228,6 +228,33 @@ typedef enum {
NPFocusPrevious = 1
} NPFocusDirection;
/* These formats describe the format in the memory byte-order. This means if
* a 32-bit value of a pixel is viewed on a little-endian system the layout will
* be 0xAARRGGBB. The Alpha channel will be stored in the most significant
* bits. */
typedef enum {
/* 32-bit per pixel 8-bit per channel - premultiplied alpha */
NPImageFormatBGRA32 = 0x1,
/* 32-bit per pixel 8-bit per channel - 1 unused channel */
NPImageFormatBGRX32 = 0x2
} NPImageFormat;
typedef struct _NPAsyncSurface
{
uint32_t version;
NPSize size;
NPImageFormat format;
union {
struct {
uint32_t stride;
void *data;
} bitmap;
#if defined(XP_WIN)
HANDLE sharedHandle;
#endif
};
} NPAsyncSurface;
/* Return values for NPP_HandleEvent */
#define kNPEventNotHandled 0
#define kNPEventHandled 1
@ -273,17 +300,26 @@ typedef struct
#endif /* XP_UNIX */
#if defined(XP_MACOSX)
typedef enum {
#ifndef NP_NO_QUICKDRAW
NPDrawingModelQuickDraw = 0,
#endif
#if defined(XP_MACOSX)
NPDrawingModelCoreGraphics = 1,
NPDrawingModelOpenGL = 2,
NPDrawingModelCoreAnimation = 3,
NPDrawingModelInvalidatingCoreAnimation = 4
NPDrawingModelInvalidatingCoreAnimation = 4,
#endif
NPDrawingModelSyncWin = 5,
NPDrawingModelSyncX = 6,
NPDrawingModelAsyncBitmapSurface = 7
#if defined(XP_WIN)
, NPDrawingModelAsyncWindowsDXGISurface = 8,
NPDrawingModelAsyncWindowsDX9ExSurface = 9
#endif
} NPDrawingModel;
#if defined(XP_MACOSX)
typedef enum {
#ifndef NP_NO_CARBON
NPEventModelCarbon = 0,
@ -370,9 +406,9 @@ typedef enum {
NPPVpluginUsesDOMForCursorBool = 22
#if defined(XP_MACOSX)
/* Used for negotiating drawing models */
, NPPVpluginDrawingModel = 1000
#if defined(XP_MACOSX)
/* Used for negotiating event models */
, NPPVpluginEventModel = 1001
/* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */
@ -415,9 +451,9 @@ typedef enum {
NPNVdocumentOrigin = 22
#if defined(XP_MACOSX)
/* Used for negotiating drawing models */
, NPNVpluginDrawingModel = 1000
#if defined(XP_MACOSX)
#ifndef NP_NO_QUICKDRAW
, NPNVsupportsQuickDrawBool = 2000
#endif
@ -425,6 +461,15 @@ typedef enum {
, NPNVsupportsOpenGLBool = 2002
, NPNVsupportsCoreAnimationBool = 2003
, NPNVsupportsInvalidatingCoreAnimationBool = 2004
#endif
, NPNVsupportsSyncDrawingBool = 2005
, NPNVsupportsAsyncBitmapSurfaceBool = 2006
#if defined(XP_WIN)
, NPNVsupportsAsyncWindowsDXGISurfaceBool = 2007
, NPNVsupportsAsyncWindowsDX9ExSurfaceBool = 2008
#endif
#if defined(XP_MACOSX)
#ifndef NP_NO_CARBON
, NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
#endif
@ -820,6 +865,7 @@ void NP_LOADDS NPP_LostFocus(NPP instance);
void NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData);
NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge);
char** NP_LOADDS NPP_GetSitesWithData(void);
void NP_LOADDS NPP_DidComposite(NPP instance);
/* NPN_* functions are provided by the navigator and called by the plugin. */
void NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
@ -882,6 +928,11 @@ NPBool NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sour
NPBool NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled);
NPBool NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
void NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
NPError NP_LOADDS NPN_InitAsyncSurface(NPP instance, NPSize *size,
NPImageFormat format, void *initData,
NPAsyncSurface *surface);
NPError NP_LOADDS NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface);
void NP_LOADDS NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
#ifdef __cplusplus
} /* end extern "C" */

View File

@ -72,6 +72,7 @@ typedef void (* NP_LOADDS NPP_LostFocusPtr)(NPP instance);
typedef void (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData);
typedef NPError (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge);
typedef char** (* NP_LOADDS NPP_GetSitesWithDataPtr)(void);
typedef void (* NP_LOADDS NPP_DidCompositePtr)(NPP instance);
typedef NPError (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value);
typedef NPError (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value);
@ -130,6 +131,9 @@ typedef NPBool (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double
typedef NPBool (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
typedef NPBool (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
typedef void (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
typedef NPError (*NPN_InitAsyncSurfacePtr)(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface);
typedef NPError (*NPN_FinalizeAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface);
typedef void (*NPN_SetCurrentAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface, NPRect *changed);
typedef struct _NPPluginFuncs {
uint16_t size;
@ -153,6 +157,7 @@ typedef struct _NPPluginFuncs {
NPP_URLRedirectNotifyPtr urlredirectnotify;
NPP_ClearSiteDataPtr clearsitedata;
NPP_GetSitesWithDataPtr getsiteswithdata;
NPP_DidCompositePtr didComposite;
} NPPluginFuncs;
typedef struct _NPNetscapeFuncs {
@ -213,6 +218,9 @@ typedef struct _NPNetscapeFuncs {
NPN_HandleEventPtr handleevent;
NPN_UnfocusInstancePtr unfocusinstance;
NPN_URLRedirectResponsePtr urlredirectresponse;
NPN_InitAsyncSurfacePtr initasyncsurface;
NPN_FinalizeAsyncSurfacePtr finalizeasyncsurface;
NPN_SetCurrentAsyncSurfacePtr setcurrentasyncsurface;
} NPNetscapeFuncs;
#ifdef XP_MACOSX

View File

@ -118,6 +118,11 @@ interface nsIPluginInstanceOwner : nsISupports
*/
void invalidateRegion(in NPRegion aRegion);
/**
* Have the plugin recomposited.
*/
void redrawPlugin();
/**
* Get NetscapeWindow, corresponds to NPNVnetscapeWindow
*/
@ -130,6 +135,10 @@ interface nsIPluginInstanceOwner : nsISupports
virtual NPError ShowNativeContextMenu(NPMenu* menu, void* event) = 0;
virtual NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
double *destX, double *destY, NPCoordinateSpace destSpace) = 0;
virtual NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface) = 0;
virtual NPError FinalizeAsyncSurface(NPAsyncSurface *surface) = 0;
virtual void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) = 0;
%}
void setEventModel(in PRInt32 eventModel);

View File

@ -220,8 +220,8 @@ static JSClass sNPObjectMemberClass =
static void
OnWrapperDestroyed();
static JSBool
DelayedReleaseGCCallback(JSContext* cx, JSGCStatus status)
static void
DelayedReleaseGCCallback(JSRuntime* rt, JSGCStatus status)
{
if (JSGC_END == status) {
// Take ownership of sDelayedReleases and null it out now. The
@ -238,7 +238,6 @@ DelayedReleaseGCCallback(JSContext* cx, JSGCStatus status)
}
}
}
return JS_TRUE;
}
static void

View File

@ -200,7 +200,10 @@ static NPNetscapeFuncs sBrowserFuncs = {
_convertpoint,
NULL, // handleevent, unimplemented
NULL, // unfocusinstance, unimplemented
_urlredirectresponse
_urlredirectresponse,
_initasyncsurface,
_finalizeasyncsurface,
_setcurrentasyncsurface
};
static Mutex *sPluginThreadAsyncCallLock = nsnull;
@ -2525,7 +2528,8 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
return inst->SetUsesDOMForCursor(useDOMForCursor);
}
#ifdef XP_MACOSX
#ifndef MOZ_WIDGET_ANDROID
// On android, their 'drawing model' uses the same constant!
case NPPVpluginDrawingModel: {
if (inst) {
inst->SetDrawingModel((NPDrawingModel)NS_PTR_TO_INT32(result));
@ -2535,7 +2539,9 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
return NPERR_GENERIC_ERROR;
}
}
#endif
#ifdef XP_MACOSX
case NPPVpluginEventModel: {
if (inst) {
inst->SetEventModel((NPEventModel)NS_PTR_TO_INT32(result));
@ -2883,6 +2889,36 @@ _popupcontextmenu(NPP instance, NPMenu* menu)
return inst->PopUpContextMenu(menu);
}
NPError NP_CALLBACK
_initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface)
{
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst)
return NPERR_GENERIC_ERROR;
return inst->InitAsyncSurface(size, format, initData, surface);
}
NPError NP_CALLBACK
_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
{
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst)
return NPERR_GENERIC_ERROR;
return inst->FinalizeAsyncSurface(surface);
}
void NP_CALLBACK
_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
{
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst)
return;
inst->SetCurrentAsyncSurface(surface, changed);
}
NPBool NP_CALLBACK
_convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
{

View File

@ -297,6 +297,15 @@ _unscheduletimer(NPP instance, uint32_t timerID);
NPError NP_CALLBACK
_popupcontextmenu(NPP instance, NPMenu* menu);
NPError NP_CALLBACK
_initasyncsurface(NPP instance, NPSize *size, NPImageFormat format, void *initData, NPAsyncSurface *surface);
NPError NP_CALLBACK
_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
void NP_CALLBACK
_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
NPBool NP_CALLBACK
_convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);

View File

@ -80,13 +80,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsNPAPIPluginInstance)
nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
:
#ifdef XP_MACOSX
#ifdef NP_NO_QUICKDRAW
mDrawingModel(NPDrawingModelCoreGraphics),
#else
mDrawingModel(NPDrawingModelQuickDraw),
#endif
#endif
mDrawingModel(kDefaultDrawingModel),
#ifdef MOZ_WIDGET_ANDROID
mSurface(nsnull),
mANPDrawingModel(0),
@ -704,12 +698,17 @@ nsNPAPIPluginInstance::UsesDOMForCursor()
return mUsesDOMForCursor;
}
#if defined(XP_MACOSX)
void nsNPAPIPluginInstance::SetDrawingModel(NPDrawingModel aModel)
{
mDrawingModel = aModel;
}
void nsNPAPIPluginInstance::RedrawPlugin()
{
mOwner->RedrawPlugin();
}
#if defined(XP_MACOSX)
void nsNPAPIPluginInstance::SetEventModel(NPEventModel aModel)
{
// the event model needs to be set for the object frame immediately
@ -1482,6 +1481,32 @@ nsNPAPIPluginInstance::URLRedirectResponse(void* notifyData, NPBool allow)
}
}
NPError
nsNPAPIPluginInstance::InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface)
{
if (mOwner)
return mOwner->InitAsyncSurface(size, format, initData, surface);
return NS_ERROR_FAILURE;
}
NPError
nsNPAPIPluginInstance::FinalizeAsyncSurface(NPAsyncSurface *surface)
{
if (mOwner)
return mOwner->FinalizeAsyncSurface(surface);
return NS_ERROR_FAILURE;
}
void
nsNPAPIPluginInstance::SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
{
if (mOwner)
mOwner->SetCurrentAsyncSurface(surface, changed);
}
class CarbonEventModelFailureEvent : public nsRunnable {
public:
nsCOMPtr<nsIContent> mContent;

View File

@ -64,6 +64,18 @@ class nsIPluginInstanceOwner;
class nsIPluginStreamListener;
class nsIOutputStream;
#if defined(OS_WIN)
const NPDrawingModel kDefaultDrawingModel = NPDrawingModelSyncWin;
#elif defined(MOZ_X11)
const NPDrawingModel kDefaultDrawingModel = NPDrawingModelSyncX;
#else
#ifndef NP_NO_QUICKDRAW
const NPDrawingModel kDefaultDrawingModel = NPDrawingModelQuickDraw;
#else
const NPDrawingModel kDefaultDrawingModel = NPDrawingModelCoreGraphics;
#endif
#endif
class nsNPAPITimer
{
public:
@ -141,8 +153,9 @@ public:
NPError SetUsesDOMForCursor(bool aUsesDOMForCursor);
bool UsesDOMForCursor();
#ifdef XP_MACOSX
void SetDrawingModel(NPDrawingModel aModel);
void RedrawPlugin();
#ifdef XP_MACOSX
void SetEventModel(NPEventModel aModel);
#endif
@ -214,6 +227,11 @@ public:
void URLRedirectResponse(void* notifyData, NPBool allow);
NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface);
NPError FinalizeAsyncSurface(NPAsyncSurface *surface);
void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
// Called when the instance fails to instantiate beceause the Carbon
// event model is not supported.
void CarbonNPAPIFailure();
@ -232,9 +250,7 @@ protected:
// the browser.
NPP_t mNPP;
#ifdef XP_MACOSX
NPDrawingModel mDrawingModel;
#endif
#ifdef MOZ_WIDGET_ANDROID
PRUint32 mANPDrawingModel;

View File

@ -212,9 +212,10 @@ nsPluginInstanceOwner::GetImageContainer()
mInstance->GetImageContainer(getter_AddRefs(container));
if (container) {
#ifdef XP_MACOSX
nsRefPtr<Image> image = container->GetCurrentImage();
AutoLockImage autoLock(container);
Image* image = autoLock.GetImage();
if (image && image->GetFormat() == Image::MAC_IO_SURFACE && mObjectFrame) {
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
NS_ADDREF_THIS();
oglImage->SetUpdateCallback(&DrawPlugin, this);
oglImage->SetDestroyCallback(&OnDestroyImage);
@ -670,6 +671,15 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsPluginInstanceOwner::RedrawPlugin()
{
if (mObjectFrame) {
mObjectFrame->InvalidateLayer(mObjectFrame->GetContentRectRelativeToSelf(), nsDisplayItem::TYPE_PLUGIN);
}
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
{
@ -791,6 +801,21 @@ NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoo
#endif
}
NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface)
{
return NPERR_GENERIC_ERROR;
}
NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
{
return NPERR_GENERIC_ERROR;
}
void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
{
}
NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
{
NS_ENSURE_ARG_POINTER(result);
@ -3704,10 +3729,11 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
if (container) {
#ifdef XP_MACOSX
nsRefPtr<Image> image = container->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
// Undo what we did to the current image in SetCurrentImage().
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
oglImage->SetUpdateCallback(nsnull, nsnull);
oglImage->SetDestroyCallback(nsnull);
// If we have a current image here, its destructor hasn't yet been
@ -3715,6 +3741,9 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
// to do ourselves what OnDestroyImage() would have done.
NS_RELEASE_THIS();
}
// Important! Unlock here otherwise SetCurrentImage will deadlock with
// our lock if we have a RemoteImage.
autoLock.Unlock();
#endif
container->SetCurrentImage(nsnull);
}

View File

@ -128,6 +128,11 @@ public:
NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
double *destX, double *destY, NPCoordinateSpace destSpace);
virtual NPError InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface);
virtual NPError FinalizeAsyncSurface(NPAsyncSurface *surface);
virtual void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
//nsIPluginTagInfo interface
NS_DECL_NSIPLUGINTAGINFO

View File

@ -52,6 +52,7 @@ using NPError;
using NPRemoteWindow;
using NPRemoteEvent;
using NPRect;
using NPImageFormat;
using NPNURLVariable;
using NPCoordinateSpace;
using mozilla::plugins::NativeWindowHandle;
@ -59,6 +60,8 @@ using mozilla::gfxSurfaceType;
using gfxIntSize;
using mozilla::null_t;
using mozilla::plugins::WindowsSharedMemoryHandle;
using mozilla::plugins::DXGISharedSurfaceHandle;
using mozilla::CrossProcessMutexHandle;
using SurfaceDescriptorX11;
using nsIntRect;
using nsTextEvent;
@ -84,6 +87,26 @@ union SurfaceDescriptor {
null_t;
};
union OptionalShmem {
Shmem;
null_t;
};
union AsyncSurfaceDescriptor {
Shmem;
DXGISharedSurfaceHandle;
};
struct NPRemoteAsyncSurface
{
uint32_t version;
gfxIntSize size;
NPImageFormat format;
uint32_t stride;
AsyncSurfaceDescriptor data;
uintptr_t hostPtr;
};
rpc protocol PPluginInstance
{
manager PPluginModule;
@ -150,6 +173,8 @@ child:
rpc HandleKeyEvent(nsKeyEvent event)
returns (bool handled);
async NPP_DidComposite();
rpc NPP_Destroy()
returns (NPError rv);
@ -176,7 +201,7 @@ parent:
rpc NPN_SetValue_NPPVpluginUsesDOMForCursor(bool useDOMForCursor)
returns (NPError result);
rpc NPN_SetValue_NPPVpluginDrawingModel(int drawingModel)
returns (NPError result);
returns (OptionalShmem remoteImageData, CrossProcessMutexHandle mutex, NPError result);
rpc NPN_SetValue_NPPVpluginEventModel(int eventModel)
returns (NPError result);
@ -232,6 +257,11 @@ parent:
NPCoordinateSpace destSpace)
returns (double destX, double destY, bool result);
async RedrawPlugin();
rpc NPN_InitAsyncSurface(gfxIntSize size, NPImageFormat format)
returns (NPRemoteAsyncSurface surfData, bool result);
// Send notification that a plugin tried to negotiate Carbon NPAPI so that
// users can be notified that restarting the browser in i386 mode may allow
// them to use the plugin.

View File

@ -87,7 +87,7 @@ child:
rpc NP_GetEntryPoints()
returns (NPError rv);
rpc NP_Initialize()
rpc NP_Initialize(uint32_t aFlags)
returns (NPError rv);
rpc PPluginInstance(nsCString aMimeType,

View File

@ -54,6 +54,7 @@
#include "PluginProcessChild.h"
#include "gfxASurface.h"
#include "gfxContext.h"
#include "nsNPAPIPluginInstance.h"
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
#endif
@ -74,6 +75,7 @@ using mozilla::gfx::SharedDIBSurface;
using namespace mozilla;
using mozilla::ipc::ProcessChild;
using namespace mozilla::plugins;
using namespace std;
#ifdef MOZ_WIDGET_GTK2
@ -131,6 +133,10 @@ struct RunnableMethodTraits<PluginInstanceChild>
PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
: mPluginIface(aPluginIface)
, mDrawingModel(kDefaultDrawingModel)
, mCurrentAsyncSurface(0)
, mAsyncInvalidateMutex("PluginInstanceChild::mAsyncInvalidateMutex")
, mAsyncInvalidateTask(0)
, mCachedWindowActor(nsnull)
, mCachedElementActor(nsnull)
#if defined(OS_WIN)
@ -149,7 +155,6 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
#endif
, mShColorSpace(nsnull)
, mShContext(nsnull)
, mDrawingModel(NPDrawingModelCoreGraphics)
, mCGLayer(nsnull)
, mCurrentEvent(nsnull)
#endif
@ -174,6 +179,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface)
memset(&mWindow, 0, sizeof(mWindow));
mData.ndata = (void*) this;
mData.pdata = nsnull;
mAsyncBitmaps.Init();
#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
mWindow.ws_info = &mWsInfo;
memset(&mWsInfo, 0, sizeof(mWsInfo));
@ -414,6 +420,16 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
#endif
}
case NPNVsupportsAsyncBitmapSurfaceBool: {
#ifdef XP_WIN
*((NPBool*)aValue) = PluginModuleChild::current()->AsyncDrawingAllowed();
#else
// We do not support non-windows yet.
*((NPBool*)aValue) = false;
#endif
return NPERR_NO_ERROR;
}
#ifdef XP_MACOSX
case NPNVsupportsCoreGraphicsBool: {
*((NPBool*)aValue) = true;
@ -519,18 +535,35 @@ PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
return rv;
}
#ifdef XP_MACOSX
case NPPVpluginDrawingModel: {
NPError rv;
int drawingModel = (int16) (intptr_t) aValue;
if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &rv))
if (!PluginModuleChild::current()->AsyncDrawingAllowed() &&
IsDrawingModelAsync(drawingModel)) {
return NPERR_GENERIC_ERROR;
}
CrossProcessMutexHandle handle;
OptionalShmem optionalShmem;
if (!CallNPN_SetValue_NPPVpluginDrawingModel(drawingModel, &optionalShmem, &handle, &rv))
return NPERR_GENERIC_ERROR;
if (drawingModel == NPDrawingModelAsyncBitmapSurface) {
if (optionalShmem.type() != OptionalShmem::TShmem) {
return NPERR_GENERIC_ERROR;
}
mRemoteImageDataShmem = optionalShmem.get_Shmem();
mRemoteImageData = mRemoteImageDataShmem.get<RemoteImageData>();
mRemoteImageDataMutex = new CrossProcessMutex(handle);
}
mDrawingModel = drawingModel;
#ifdef XP_MACOSX
if (drawingModel == NPDrawingModelCoreAnimation) {
mCARefreshTimer = ScheduleTimer(DEFAULT_REFRESH_MS, true, CAUpdate);
}
#endif
PLUGIN_LOG_DEBUG((" Plugin requested drawing model id #%i\n",
mDrawingModel));
@ -538,6 +571,7 @@ PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
return rv;
}
#ifdef XP_MACOSX
case NPPVpluginEventModel: {
NPError rv;
int eventModel = (int16) (intptr_t) aValue;
@ -2061,6 +2095,15 @@ PluginInstanceChild::AnswerUpdateWindow()
#endif
}
bool
PluginInstanceChild::RecvNPP_DidComposite()
{
if (mPluginIface->didComposite) {
mPluginIface->didComposite(GetNPP());
}
return true;
}
PPluginScriptableObjectChild*
PluginInstanceChild::AllocPPluginScriptableObject()
{
@ -2314,6 +2357,172 @@ PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow)
NS_ASSERTION(false, "Couldn't find stream for redirect response!");
}
NPError
PluginInstanceChild::DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface)
{
AsyncBitmapData* data;
if (!mAsyncBitmaps.Get(aSurface, &data)) {
return NPERR_INVALID_PARAM;
}
DeallocShmem(data->mShmem);
aSurface->bitmap.data = nsnull;
mAsyncBitmaps.Remove(aSurface);
return NPERR_NO_ERROR;
}
bool
PluginInstanceChild::IsAsyncDrawing()
{
return IsDrawingModelAsync(mDrawingModel);
}
NPError
PluginInstanceChild::NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface)
{
AssertPluginThread();
surface->bitmap.data = NULL;
if (!IsAsyncDrawing()) {
return NPERR_GENERIC_ERROR;
}
switch (mDrawingModel) {
case NPDrawingModelAsyncBitmapSurface: {
if (mAsyncBitmaps.Get(surface, nsnull)) {
return NPERR_INVALID_PARAM;
}
if (size->width < 0 || size->height < 0) {
return NPERR_INVALID_PARAM;
}
bool result;
NPRemoteAsyncSurface remote;
if (!CallNPN_InitAsyncSurface(gfxIntSize(size->width, size->height), format, &remote, &result) || !result) {
return NPERR_OUT_OF_MEMORY_ERROR;
}
NS_ABORT_IF_FALSE(remote.data().get_Shmem().IsWritable(),
"Failed to create writable shared memory.");
AsyncBitmapData *data = new AsyncBitmapData;
mAsyncBitmaps.Put(surface, data);
data->mRemotePtr = (void*)remote.hostPtr();
data->mShmem = remote.data().get_Shmem();
surface->bitmap.data = data->mShmem.get<unsigned char>();
surface->bitmap.stride = remote.stride();
surface->format = remote.format();
surface->size.width = remote.size().width;
surface->size.height = remote.size().height;
return NPERR_NO_ERROR;
}
}
return NPERR_GENERIC_ERROR;
}
NPError
PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
{
AssertPluginThread();
if (!IsAsyncDrawing()) {
return NPERR_GENERIC_ERROR;
}
switch (mDrawingModel) {
case NPDrawingModelAsyncBitmapSurface: {
AsyncBitmapData *bitmapData;
if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
return NPERR_GENERIC_ERROR;
}
{
CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
RemoteImageData *data = mRemoteImageData;
if (data->mBitmap.mData == bitmapData->mRemotePtr) {
data->mBitmap.mData = NULL;
data->mSize = gfxIntSize(0, 0);
data->mWasUpdated = true;
}
}
return DeallocateAsyncBitmapSurface(surface);
}
}
return NPERR_GENERIC_ERROR;
}
void
PluginInstanceChild::NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed)
{
if (!IsAsyncDrawing()) {
return;
}
RemoteImageData *data = mRemoteImageData;
if (!surface) {
CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
data->mBitmap.mData = NULL;
data->mSize = gfxIntSize(0, 0);
data->mWasUpdated = true;
} else {
switch (mDrawingModel) {
case NPDrawingModelAsyncBitmapSurface:
{
AsyncBitmapData *bitmapData;
if (!mAsyncBitmaps.Get(surface, &bitmapData)) {
return;
}
CrossProcessMutexAutoLock autoLock(*mRemoteImageDataMutex);
data->mBitmap.mData = (unsigned char*)bitmapData->mRemotePtr;
data->mSize = gfxIntSize(surface->size.width, surface->size.height);
data->mFormat = surface->format == NPImageFormatBGRX32 ?
RemoteImageData::BGRX32 : RemoteImageData::BGRA32;
data->mBitmap.mStride = surface->bitmap.stride;
data->mWasUpdated = true;
break;
}
}
}
{
MutexAutoLock autoLock(mAsyncInvalidateMutex);
if (!mAsyncInvalidateTask) {
mAsyncInvalidateTask =
NewRunnableMethod<PluginInstanceChild, void (PluginInstanceChild::*)()>
(this, &PluginInstanceChild::DoAsyncRedraw);
ProcessChild::message_loop()->PostTask(FROM_HERE, mAsyncInvalidateTask);
}
}
}
void
PluginInstanceChild::DoAsyncRedraw()
{
{
MutexAutoLock autoLock(mAsyncInvalidateMutex);
mAsyncInvalidateTask = NULL;
}
SendRedrawPlugin();
}
bool
PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
const NPRemoteWindow& aWindow)
@ -3665,6 +3874,16 @@ PluginInstanceChild::ClearAllSurfaces()
#endif
}
PLDHashOperator
PluginInstanceChild::DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg)
{
PluginInstanceChild *inst = static_cast<PluginInstanceChild*>(userArg);
inst->DeallocShmem(data->mShmem);
return PL_DHASH_REMOVE;
}
bool
PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
{
@ -3705,6 +3924,13 @@ PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
mCurrentAsyncSetWindowTask->Cancel();
mCurrentAsyncSetWindowTask = nsnull;
}
{
MutexAutoLock autoLock(mAsyncInvalidateMutex);
if (mAsyncInvalidateTask) {
mAsyncInvalidateTask->Cancel();
mAsyncInvalidateTask = nsnull;
}
}
ClearAllSurfaces();
@ -3733,6 +3959,11 @@ PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
mPendingAsyncCalls[i]->Cancel();
mPendingAsyncCalls.Clear();
if (mAsyncBitmaps.Count()) {
NS_ERROR("Not all AsyncBitmaps were finalized by a plugin!");
mAsyncBitmaps.Enumerate(DeleteSurface, this);
}
return true;
}

View File

@ -43,6 +43,8 @@
#include "mozilla/plugins/PluginScriptableObjectChild.h"
#include "mozilla/plugins/StreamNotifyChild.h"
#include "mozilla/plugins/PPluginSurfaceChild.h"
#include "mozilla/ipc/CrossProcessMutex.h"
#include "nsClassHashtable.h"
#if defined(OS_WIN)
#include "mozilla/gfx/SharedDIBWin.h"
#elif defined(MOZ_WIDGET_COCOA)
@ -63,7 +65,14 @@ using namespace mozilla::plugins::PluginUtilsOSX;
#include "mozilla/PaintTracker.h"
#include "gfxASurface.h"
#include <map>
namespace mozilla {
namespace layers {
struct RemoteImageData;
}
namespace plugins {
class PBrowserStreamChild;
@ -209,6 +218,9 @@ protected:
virtual bool
AnswerUpdateWindow();
virtual bool
RecvNPP_DidComposite();
public:
PluginInstanceChild(const NPPluginFuncs* aPluginIface);
@ -249,6 +261,13 @@ public:
void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
NPError NPN_InitAsyncSurface(NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface);
NPError NPN_FinalizeAsyncSurface(NPAsyncSurface *surface);
void NPN_SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed);
void DoAsyncRedraw();
private:
friend class PluginModuleChild;
@ -256,6 +275,10 @@ private:
InternalGetNPObjectForValue(NPNVariable aValue,
NPObject** aObject);
bool IsAsyncDrawing();
NPError DeallocateAsyncBitmapSurface(NPAsyncSurface *aSurface);
NS_OVERRIDE
virtual bool RecvUpdateBackground(const SurfaceDescriptor& aBackground,
const nsIntRect& aRect);
@ -360,10 +383,23 @@ private:
};
#endif
const NPPluginFuncs* mPluginIface;
NPP_t mData;
NPWindow mWindow;
int16_t mDrawingModel;
NPAsyncSurface* mCurrentAsyncSurface;
struct AsyncBitmapData {
void *mRemotePtr;
Shmem mShmem;
};
static PLDHashOperator DeleteSurface(NPAsyncSurface* surf, nsAutoPtr<AsyncBitmapData> &data, void* userArg);
nsClassHashtable<nsPtrHashKey<NPAsyncSurface>, AsyncBitmapData> mAsyncBitmaps;
Shmem mRemoteImageDataShmem;
mozilla::layers::RemoteImageData *mRemoteImageData;
nsAutoPtr<CrossProcessMutex> mRemoteImageDataMutex;
mozilla::Mutex mAsyncInvalidateMutex;
CancelableTask *mAsyncInvalidateTask;
// Cached scriptable actors to avoid IPC churn
PluginScriptableObjectChild* mCachedWindowActor;
@ -426,7 +462,6 @@ private:
#endif
CGColorSpaceRef mShColorSpace;
CGContextRef mShContext;
int16_t mDrawingModel;
nsCARenderer mCARenderer;
void *mCGLayer;

View File

@ -50,6 +50,7 @@
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfxSharedImageSurface.h"
#include "nsNPAPIPluginInstance.h"
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
#endif
@ -91,6 +92,7 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
, mNPP(npp)
, mNPNIface(npniface)
, mWindowType(NPWindowTypeWindow)
, mDrawingModel(kDefaultDrawingModel)
#if defined(OS_WIN)
, mPluginHWND(NULL)
, mPluginWndProc(NULL)
@ -100,7 +102,6 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
, mShWidth(0)
, mShHeight(0)
, mShColorSpace(nsnull)
, mDrawingModel(NPDrawingModelCoreGraphics)
#endif
{
}
@ -121,6 +122,16 @@ PluginInstanceParent::~PluginInstanceParent()
if (mShColorSpace)
::CGColorSpaceRelease(mShColorSpace);
#endif
if (mRemoteImageDataShmem.IsWritable()) {
ImageContainer *container =
GetImageContainer();
if (container) {
container->SetRemoteImageData(nsnull, nsnull);
container->SetCompositionNotifySink(nsnull);
DeallocShmem(mRemoteImageDataShmem);
}
}
}
bool
@ -281,6 +292,12 @@ PluginInstanceParent::InternalGetValueForNPObject(
return true;
}
bool
PluginInstanceParent::IsAsyncDrawing()
{
return IsDrawingModelAsync(mDrawingModel);
}
bool
PluginInstanceParent::AnswerNPN_GetValue_NPNVWindowNPObject(
PPluginScriptableObjectParent** aValue,
@ -349,9 +366,20 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginUsesDOMForCursor(
return true;
}
class NotificationSink : public CompositionNotifySink
{
public:
NotificationSink(PluginInstanceParent *aInstance) : mInstance(aInstance)
{ }
virtual void DidComposite() { mInstance->DidComposite(); }
private:
PluginInstanceParent *mInstance;
};
bool
PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
const int& drawingModel, NPError* result)
const int& drawingModel, OptionalShmem *shmem, CrossProcessMutexHandle *mutex, NPError* result)
{
#ifdef XP_MACOSX
if (drawingModel == NPDrawingModelCoreAnimation ||
@ -362,16 +390,68 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
mDrawingModel = drawingModel;
*result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
(void*)NPDrawingModelCoreGraphics);
} else {
*shmem = null_t();
} else
#endif
if (drawingModel == NPDrawingModelAsyncBitmapSurface) {
ImageContainer *container = GetImageContainer();
if (!container) {
*result = NPERR_GENERIC_ERROR;
return true;
}
mDrawingModel = drawingModel;
*result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
(void*)drawingModel);
(void*)drawingModel);
if (*result != NPERR_NO_ERROR) {
return true;
}
AllocUnsafeShmem(sizeof(RemoteImageData), SharedMemory::TYPE_BASIC, &mRemoteImageDataShmem);
*shmem = mRemoteImageDataShmem;
mRemoteImageDataMutex = new CrossProcessMutex("PluginInstanceParent.mRemoteImageDataMutex");
*mutex = mRemoteImageDataMutex->ShareToProcess(OtherProcess());
container->SetRemoteImageData(mRemoteImageDataShmem.get<RemoteImageData>(), mRemoteImageDataMutex);
mNotifySink = new NotificationSink(this);
container->SetCompositionNotifySink(mNotifySink);
} else if (drawingModel == NPDrawingModelSyncWin ||
#ifdef XP_MACOSX
#ifndef NP_NO_QUICKDRAW
drawingModel == NPDrawingModelQuickDraw ||
#endif
drawingModel == NPDrawingModelOpenGL ||
drawingModel == NPDrawingModelCoreGraphics ||
#endif
drawingModel == NPDrawingModelSyncX) {
*shmem = null_t();
ImageContainer *container = GetImageContainer();
if (!container) {
*result = NPERR_GENERIC_ERROR;
return true;
}
mDrawingModel = drawingModel;
*result = mNPNIface->setvalue(mNPP, NPPVpluginDrawingModel,
(void*)drawingModel);
if (mRemoteImageDataShmem.IsWritable()) {
container->SetRemoteImageData(nsnull, nsnull);
container->SetCompositionNotifySink(nsnull);
DeallocShmem(mRemoteImageDataShmem);
mRemoteImageDataMutex = NULL;
}
} else {
*result = NPERR_GENERIC_ERROR;
}
return true;
#else
*result = NPERR_GENERIC_ERROR;
return true;
#endif
}
bool
@ -647,6 +727,12 @@ PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
return NS_ERROR_FAILURE;
}
if (IsAsyncDrawing()) {
NS_IF_ADDREF(container);
*aContainer = container;
return NS_OK;
}
nsRefPtr<Image> image;
image = container->CreateImage(&format, 1);
if (!image) {
@ -1101,6 +1187,12 @@ PluginInstanceParent::NPP_HandleEvent(void* event)
#if defined(OS_WIN)
if (mWindowType == NPWindowTypeDrawable) {
if (IsAsyncDrawing()) {
if (npevent->event == WM_PAINT || npevent->event == DoublePassRenderingEvent()) {
// This plugin maintains its own async drawing.
return handled;
}
}
if (DoublePassRenderingEvent() == npevent->event) {
CallPaint(npremoteevent, &handled);
return handled;
@ -1602,15 +1694,58 @@ PluginInstanceParent::AnswerNPN_ConvertPoint(const double& sourceX,
return true;
}
bool
PluginInstanceParent::AnswerNPN_InitAsyncSurface(const gfxIntSize& size,
const NPImageFormat& format,
NPRemoteAsyncSurface* surfData,
bool* result)
{
if (!IsAsyncDrawing()) {
*result = false;
return true;
}
switch (mDrawingModel) {
case NPDrawingModelAsyncBitmapSurface: {
Shmem sharedMem;
if (!AllocUnsafeShmem(size.width * size.height * 4, SharedMemory::TYPE_BASIC, &sharedMem)) {
*result = false;
return true;
}
surfData->size() = size;
surfData->hostPtr() = (uintptr_t)sharedMem.get<unsigned char>();
surfData->stride() = size.width * 4;
surfData->format() = format;
surfData->data() = sharedMem;
*result = true;
}
}
return true;
}
bool
PluginInstanceParent::RecvRedrawPlugin()
{
nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
if (!inst) {
return false;
}
inst->RedrawPlugin();
return true;
}
bool
PluginInstanceParent::RecvNegotiatedCarbon()
{
nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
if (!inst) {
return false;
}
inst->CarbonNPAPIFailure();
return true;
nsNPAPIPluginInstance *inst = static_cast<nsNPAPIPluginInstance*>(mNPP->ndata);
if (!inst) {
return false;
}
inst->CarbonNPAPIFailure();
return true;
}
#if defined(OS_WIN)

View File

@ -144,7 +144,9 @@ public:
NPError* result);
virtual bool
AnswerNPN_SetValue_NPPVpluginDrawingModel(const int& drawingModel,
NPError* result);
OptionalShmem *remoteImageData,
CrossProcessMutexHandle *mutex,
NPError* result);
virtual bool
AnswerNPN_SetValue_NPPVpluginEventModel(const int& eventModel,
NPError* result);
@ -229,6 +231,15 @@ public:
double *destY,
bool *result);
virtual bool
AnswerNPN_InitAsyncSurface(const gfxIntSize& size,
const NPImageFormat& format,
NPRemoteAsyncSurface* surfData,
bool* result);
virtual bool
RecvRedrawPlugin();
NS_OVERRIDE virtual bool
RecvNegotiatedCarbon();
@ -294,6 +305,8 @@ public:
nsresult HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled);
#endif
void DidComposite() { SendNPP_DidComposite(); }
private:
// Create an appropriate platform surface for a background of size
// |aSize|. Return true if successful.
@ -316,11 +329,17 @@ private:
PPluginScriptableObjectParent** aValue,
NPError* aResult);
bool IsAsyncDrawing();
private:
PluginModuleParent* mParent;
NPP mNPP;
const NPNetscapeFuncs* mNPNIface;
NPWindowType mWindowType;
Shmem mRemoteImageDataShmem;
nsAutoPtr<CrossProcessMutex> mRemoteImageDataMutex;
int16_t mDrawingModel;
nsAutoPtr<mozilla::layers::CompositionNotifySink> mNotifySink;
nsDataHashtable<nsVoidPtrHashKey, PluginScriptableObjectParent*> mScriptableObjects;
@ -351,7 +370,6 @@ private:
uint16_t mShWidth;
uint16_t mShHeight;
CGColorSpaceRef mShColorSpace;
int16_t mDrawingModel;
nsRefPtr<nsIOSurface> mIOSurface;
nsRefPtr<nsIOSurface> mFrontIOSurface;
#endif // definied(MOZ_WIDGET_COCOA)

View File

@ -43,6 +43,7 @@
#include "base/message_loop.h"
#include "mozilla/ipc/RPCChannel.h"
#include "mozilla/ipc/CrossProcessMutex.h"
#include "gfxipc/ShadowLayerUtils.h"
#include "npapi.h"
@ -86,6 +87,17 @@ UnmungePluginDsoPath(const std::string& munged);
extern PRLogModuleInfo* gPluginLog;
const uint32_t kAllowAsyncDrawing = 0x1;
inline bool IsDrawingModelAsync(int16_t aModel) {
return aModel == NPDrawingModelAsyncBitmapSurface
#ifdef XP_WIN
|| aModel == NPDrawingModelAsyncWindowsDXGISurface
|| aModel == NPDrawingModelAsyncWindowsDX9ExSurface
#endif
;
}
#if defined(_MSC_VER)
#define FULLFUNCTION __FUNCSIG__
#elif (__GNUC__ >= 4)
@ -142,8 +154,10 @@ typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
#ifdef XP_WIN
typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
typedef HANDLE DXGISharedSurfaceHandle;
#else
typedef mozilla::null_t WindowsSharedMemoryHandle;
typedef mozilla::null_t DXGISharedSurfaceHandle;
#endif
// XXX maybe not the best place for these. better one?
@ -354,6 +368,32 @@ struct ParamTraits<NPWindowType>
}
};
template <>
struct ParamTraits<NPImageFormat>
{
typedef NPImageFormat paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
aMsg->WriteInt16(int16(aParam));
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
int16 result;
if (aMsg->ReadInt16(aIter, &result)) {
*aResult = paramType(result);
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"%d", int16(aParam)));
}
};
template <>
struct ParamTraits<mozilla::plugins::NPRemoteWindow>
{

View File

@ -975,6 +975,17 @@ _convertpoint(NPP instance,
static void NP_CALLBACK
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
static NPError NP_CALLBACK
_initasyncsurface(NPP instance, NPSize *size,
NPImageFormat format, void *initData,
NPAsyncSurface *surface);
static NPError NP_CALLBACK
_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface);
static void NP_CALLBACK
_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
} /* namespace child */
} /* namespace plugins */
} /* namespace mozilla */
@ -1036,7 +1047,10 @@ const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
mozilla::plugins::child::_convertpoint,
NULL, // handleevent, unimplemented
NULL, // unfocusinstance, unimplemented
mozilla::plugins::child::_urlredirectresponse
mozilla::plugins::child::_urlredirectresponse,
mozilla::plugins::child::_initasyncsurface,
mozilla::plugins::child::_finalizeasyncsurface,
mozilla::plugins::child::_setcurrentasyncsurface
};
PluginInstanceChild*
@ -1809,6 +1823,26 @@ _urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
}
NPError NP_CALLBACK
_initasyncsurface(NPP instance, NPSize *size,
NPImageFormat format, void *initData,
NPAsyncSurface *surface)
{
return InstCast(instance)->NPN_InitAsyncSurface(size, format, initData, surface);
}
NPError NP_CALLBACK
_finalizeasyncsurface(NPP instance, NPAsyncSurface *surface)
{
return InstCast(instance)->NPN_FinalizeAsyncSurface(surface);
}
void NP_CALLBACK
_setcurrentasyncsurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
{
InstCast(instance)->NPN_SetCurrentAsyncSurface(surface, changed);
}
} /* namespace child */
} /* namespace plugins */
} /* namespace mozilla */
@ -1832,11 +1866,13 @@ PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
}
bool
PluginModuleChild::AnswerNP_Initialize(NPError* _retval)
PluginModuleChild::AnswerNP_Initialize(const uint32_t& aFlags, NPError* _retval)
{
PLUGIN_LOG_DEBUG_METHOD;
AssertPluginThread();
mAsyncDrawingAllowed = aFlags & kAllowAsyncDrawing;
#ifdef OS_WIN
SetEventHooks();
#endif

View File

@ -123,7 +123,7 @@ protected:
// Implement the PPluginModuleChild interface
virtual bool AnswerNP_GetEntryPoints(NPError* rv);
virtual bool AnswerNP_Initialize(NPError* rv);
virtual bool AnswerNP_Initialize(const uint32_t& aFlags, NPError* rv);
virtual PPluginIdentifierChild*
AllocPPluginIdentifier(const nsCString& aString,
@ -228,6 +228,8 @@ public:
bool NPObjectIsRegistered(NPObject* aObject);
#endif
bool AsyncDrawingAllowed() { return mAsyncDrawingAllowed; }
/**
* The child implementation of NPN_CreateObject.
*/
@ -357,6 +359,7 @@ private:
nsCString mPluginFilename; // UTF8
nsCString mUserAgent;
int mQuirks;
bool mAsyncDrawingAllowed;
// we get this from the plugin
NP_PLUGINSHUTDOWN mShutdownFunc;

View File

@ -749,7 +749,12 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs
return NS_ERROR_FAILURE;
}
if (!CallNP_Initialize(error)) {
uint32_t flags = 0;
if (mozilla::Preferences::GetBool("plugin.allow.asyncdrawing", false)) {
flags |= kAllowAsyncDrawing;
}
if (!CallNP_Initialize(flags, error)) {
return NS_ERROR_FAILURE;
}
else if (*error != NPERR_NO_ERROR) {
@ -773,7 +778,12 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
return NS_ERROR_FAILURE;
}
if (!CallNP_Initialize(error))
uint32_t flags = 0;
if (mozilla::Preferences::GetBool("plugin.allow.asyncdrawing", false)) {
flags |= kAllowAsyncDrawing;
}
if (!CallNP_Initialize(flags, error))
return NS_ERROR_FAILURE;
#if defined XP_WIN

View File

@ -0,0 +1,14 @@
<!doctype html>
<html><head>
<title>div boxes</title>
<style>
div {
width: 400px;
height: 400px;
display: inline-block;
}
</style>
</head>
<body>
<div style="background-color: #00FF00;"></div> <!-- green -->
</body></html>

View File

@ -0,0 +1,10 @@
<!doctype html>
<html><head>
<title>Plugin boxes</title>
</head>
<body>
<embed type="application/x-test" width="400" height="400" drawmode="solid" color="FFFF0000" asyncmodel="bitmap"></embed> <!-- red -->
<embed type="application/x-test" width="400" height="400" drawmode="solid" color="FF00FF00" asyncmodel="bitmap"></embed> <!-- green -->
<embed type="application/x-test" width="400" height="400" drawmode="solid" color="FF0000FF" asyncmodel="bitmap"></embed> <!-- blue -->
<embed type="application/x-test" width="400" height="400" drawmode="solid" color="FF999999" asyncmodel="bitmap"></embed> <!-- gray -->
</body></html>

View File

@ -0,0 +1,24 @@
<!doctype html>
<html class="reftest-wait"><head>
<title>Plugin boxes</title>
</head>
<body>
<embed type="application/x-test" width="400" height="400" drawmode="solid" color="FFFF0000" id="plugin" asyncmodel="bitmap"></embed> <!-- red -->
<script>
var prevPaintCount = 0;
function doTestWait() {
if (window.mozPaintCount != prevPaintCount) {
document.documentElement.removeAttribute('class');
} else {
setTimeout(doTestWait, 0);
}
}
function doTest() {
prevPaintCount = window.mozPaintCount;
document.getElementById("plugin").setColor("FF00FF00");
setTimeout(doTestWait, 0);
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
</body></html>

View File

@ -1,6 +1,9 @@
# basic sanity checking
random-if(!haveTestPlugin) != plugin-sanity.html about:blank
random-if(!haveTestPlugin) != plugin-asyncbitmap-sanity.html about:blank
fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
fails-if(!haveTestPlugin) == plugin-asyncbitmap-sanity.html div-sanity.html
skip-if(!haveTestPlugin) == plugin-asyncbitmap-update.html plugin-async-update-ref.html
fails-if(!haveTestPlugin) == plugin-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) == plugin-alpha-opacity.html div-alpha-opacity.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832

View File

@ -540,6 +540,39 @@ DuplicateNPVariant(NPVariant& aDest, const NPVariant& aSrc)
}
}
void
drawAsyncBitmapColor(InstanceData* instanceData)
{
NPP npp = instanceData->npp;
PRUint32 *pixelData = (PRUint32*)instanceData->backBuffer->bitmap.data;
PRUint32 rgba = instanceData->scriptableObject->drawColor;
unsigned char subpixels[4];
subpixels[0] = rgba & 0xFF;
subpixels[1] = (rgba & 0xFF00) >> 8;
subpixels[2] = (rgba & 0xFF0000) >> 16;
subpixels[3] = (rgba & 0xFF000000) >> 24;
subpixels[0] = PRUint8(float(subpixels[3] * subpixels[0]) / 0xFF);
subpixels[1] = PRUint8(float(subpixels[3] * subpixels[1]) / 0xFF);
subpixels[2] = PRUint8(float(subpixels[3] * subpixels[2]) / 0xFF);
PRUint32 premultiplied;
memcpy(&premultiplied, subpixels, sizeof(premultiplied));
for (PRUint32* lastPixel = pixelData + instanceData->backBuffer->size.width * instanceData->backBuffer->size.height;
pixelData < lastPixel;
++pixelData) {
*pixelData = premultiplied;
}
NPN_SetCurrentAsyncSurface(npp, instanceData->backBuffer, NULL);
NPAsyncSurface *oldFront = instanceData->frontBuffer;
instanceData->frontBuffer = instanceData->backBuffer;
instanceData->backBuffer = oldFront;
}
//
// function signatures
//
@ -746,6 +779,9 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
instanceData->eventModel = 0;
instanceData->closeStream = false;
instanceData->wantsAllStreams = false;
instanceData->asyncDrawing = AD_NONE;
instanceData->frontBuffer = NULL;
instanceData->backBuffer = NULL;
instance->pdata = instanceData;
TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
@ -782,6 +818,13 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
requestWindow = true;
}
}
else if (strcmp(argn[i], "asyncmodel") == 0) {
if (strcmp(argv[i], "bitmap") == 0) {
if (pluginSupportsAsyncBitmapDrawing()) {
instanceData->asyncDrawing = AD_BITMAP;
}
}
}
if (strcmp(argn[i], "streammode") == 0) {
if (strcmp(argv[i], "normal") == 0) {
instanceData->streamMode = NP_NORMAL;
@ -884,6 +927,16 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
NPN_SetValue(instance, NPPVpluginTransparentBool, (void*)true);
}
if (instanceData->asyncDrawing == AD_BITMAP) {
NPBool supportsAsyncBitmap = false;
if ((NPN_GetValue(instance, NPNVsupportsAsyncBitmapSurfaceBool, &supportsAsyncBitmap) == NPERR_NO_ERROR) &&
supportsAsyncBitmap) {
NPN_SetValue(instance, NPPVpluginDrawingModel, (void*)NPDrawingModelAsyncBitmapSurface);
} else {
instanceData->asyncDrawing = AD_NONE;
}
}
instanceData->lastReportedPrivateModeState = false;
instanceData->lastMouseX = instanceData->lastMouseY = -1;
instanceData->widthAtLastPaint = -1;
@ -969,6 +1022,16 @@ NPP_Destroy(NPP instance, NPSavedData** save)
currentrange = nextrange;
}
if (instanceData->frontBuffer) {
NPN_SetCurrentAsyncSurface(instance, NULL, NULL);
NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
NPN_MemFree(instanceData->frontBuffer);
}
if (instanceData->backBuffer) {
NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
NPN_MemFree(instanceData->backBuffer);
}
pluginInstanceShutdown(instanceData);
NPN_ReleaseObject(instanceData->scriptableObject);
@ -1000,6 +1063,35 @@ NPP_SetWindow(NPP instance, NPWindow* window)
if (instanceData->hasWidget && oldWindow != instanceData->window.window) {
pluginWidgetInit(instanceData, oldWindow);
}
if (instanceData->asyncDrawing == AD_BITMAP) {
if (instanceData->frontBuffer &&
instanceData->frontBuffer->size.width == window->width &&
instanceData->frontBuffer->size.height == window->height) {
return NPERR_NO_ERROR;
}
if (instanceData->frontBuffer) {
NPN_FinalizeAsyncSurface(instance, instanceData->frontBuffer);
NPN_MemFree(instanceData->frontBuffer);
}
if (instanceData->backBuffer) {
NPN_FinalizeAsyncSurface(instance, instanceData->backBuffer);
NPN_MemFree(instanceData->backBuffer);
}
instanceData->frontBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface));
instanceData->backBuffer = (NPAsyncSurface*)NPN_MemAlloc(sizeof(NPAsyncSurface));
NPSize size;
size.width = window->width;
size.height = window->height;
memcpy(instanceData->backBuffer, instanceData->frontBuffer, sizeof(NPAsyncSurface));
NPN_InitAsyncSurface(instance, &size, NPImageFormatBGRA32, NULL, instanceData->frontBuffer);
NPN_InitAsyncSurface(instance, &size, NPImageFormatBGRA32, NULL, instanceData->backBuffer);
drawAsyncBitmapColor(instanceData);
}
return NPERR_NO_ERROR;
}
@ -1751,6 +1843,25 @@ NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow)
return sBrowserFuncs->urlredirectresponse(instance, notifyData, allow);
}
NPError
NPN_InitAsyncSurface(NPP instance, NPSize *size, NPImageFormat format,
void *initData, NPAsyncSurface *surface)
{
return sBrowserFuncs->initasyncsurface(instance, size, format, initData, surface);
}
NPError
NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface)
{
return sBrowserFuncs->finalizeasyncsurface(instance, surface);
}
void
NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed)
{
sBrowserFuncs->setcurrentasyncsurface(instance, surface, changed);
}
//
// npruntime object functions
//
@ -2621,7 +2732,11 @@ setColor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* r
r.top = 0;
r.right = id->window.width;
r.bottom = id->window.height;
NPN_InvalidateRect(npp, &r);
if (id->asyncDrawing == AD_NONE) {
NPN_InvalidateRect(npp, &r);
} else if (id->asyncDrawing == AD_BITMAP) {
drawAsyncBitmapColor(id);
}
VOID_TO_NPVARIANT(*result);
return true;

View File

@ -61,6 +61,11 @@ typedef enum {
FUNCTION_NPP_WRITE_RPC
} TestFunction;
typedef enum {
AD_NONE,
AD_BITMAP
} AsyncDrawing;
typedef enum {
ACTIVATION_STATE_UNKNOWN,
ACTIVATION_STATE_ACTIVATED,
@ -140,6 +145,9 @@ typedef struct InstanceData {
bool closeStream;
std::string lastKeyText;
bool wantsAllStreams;
AsyncDrawing asyncDrawing;
NPAsyncSurface *frontBuffer;
NPAsyncSurface *backBuffer;
} InstanceData;
void notifyDidPaint(InstanceData* instanceData);

View File

@ -49,6 +49,12 @@ pluginSupportsWindowlessMode()
return true;
}
bool
pluginSupportsAsyncBitmapDrawing()
{
return false;
}
NPError
pluginInstanceInit(InstanceData* instanceData)
{

View File

@ -70,6 +70,12 @@ pluginSupportsWindowlessMode()
return true;
}
bool
pluginSupportsAsyncBitmapDrawing()
{
return false;
}
NPError
pluginInstanceInit(InstanceData* instanceData)
{

View File

@ -49,6 +49,12 @@ pluginSupportsWindowlessMode()
return true;
}
bool
pluginSupportsAsyncBitmapDrawing()
{
return false;
}
NPError
pluginInstanceInit(InstanceData* instanceData)
{

View File

@ -47,6 +47,12 @@ pluginSupportsWindowlessMode()
return true;
}
bool
pluginSupportsAsyncBitmapDrawing()
{
return false;
}
NPError
pluginInstanceInit(InstanceData* instanceData)
{

View File

@ -48,6 +48,11 @@ bool pluginSupportsWindowMode();
*/
bool pluginSupportsWindowlessMode();
/**
* Returns true if the plugin supports async bitmap drawing.
*/
bool pluginSupportsAsyncBitmapDrawing();
/**
* Initialize the plugin instance. Returning an error here will cause the
* plugin instantiation to fail.

View File

@ -57,6 +57,12 @@ pluginSupportsWindowlessMode()
return true;
}
bool
pluginSupportsAsyncBitmapDrawing()
{
return false;
}
NPError
pluginInstanceInit(InstanceData* instanceData)
{

View File

@ -60,14 +60,22 @@ pluginSupportsWindowlessMode()
return true;
}
bool
pluginSupportsAsyncBitmapDrawing()
{
return true;
}
NPError
pluginInstanceInit(InstanceData* instanceData)
{
NPP npp = instanceData->npp;
instanceData->platformData = static_cast<PlatformData*>
(NPN_MemAlloc(sizeof(PlatformData)));
if (!instanceData->platformData)
return NPERR_OUT_OF_MEMORY_ERROR;
instanceData->platformData->childWindow = NULL;
return NPERR_NO_ERROR;
}
@ -83,6 +91,7 @@ void
pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
{
instanceData->window = *newWindow;
NPP npp = instanceData->npp;
}
#define CHILD_WIDGET_SIZE 10

View File

@ -253,6 +253,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
{ (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", NULL } },
{ (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetString, { "GetString", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", NULL } },
{ (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", NULL } },
@ -494,6 +495,13 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mInitialized = false;
}
}
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", NULL } },
{ NULL, { NULL } },
};
LoadSymbols(&auxSymbols[0], trygl, prefix);
}
if (mInitialized) {
@ -1598,10 +1606,73 @@ GLContext::MarkDestroyed()
mSymbols.Zero();
}
static void SwapRAndBComponents(gfxImageSurface* aSurf)
{
gfxIntSize size = aSurf->GetSize();
for (int j = 0; j < size.height; ++j) {
PRUint32 *row = (PRUint32*) (aSurf->Data() + aSurf->Stride() * j);
for (int i = 0; i < size.width; ++i) {
*row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16);
row++;
}
}
}
static already_AddRefed<gfxImageSurface> YInvertImageSurface(gfxImageSurface* aSurf)
{
gfxIntSize size = aSurf->GetSize();
nsRefPtr<gfxImageSurface> temp = new gfxImageSurface(size, aSurf->Format());
nsRefPtr<gfxContext> ctx = new gfxContext(temp);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Scale(1.0, -1.0);
ctx->Translate(-gfxPoint(0.0, size.height));
ctx->SetSource(aSurf);
ctx->Paint();
return temp.forget();
}
already_AddRefed<gfxImageSurface>
GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader)
{
MakeCurrent();
fFinish();
fActiveTexture(LOCAL_GL_TEXTURE0);
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
gfxIntSize size;
fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
if (!surf || surf->CairoStatus()) {
return NULL;
}
PRUint32 currentPackAlignment = 0;
fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)&currentPackAlignment);
if (currentPackAlignment != 4) {
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
}
fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->Data());
if (currentPackAlignment != 4) {
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
if (aShader == RGBALayerProgramType || aShader == RGBXLayerProgramType) {
SwapRAndBComponents(surf);
}
if (aYInvert) {
surf = YInvertImageSurface(surf);
}
return surf.forget();
}
already_AddRefed<gfxImageSurface>
GLContext::ReadTextureImage(GLuint aTexture,
const gfxIntSize& aSize,
GLenum aTextureFormat)
GLenum aTextureFormat,
bool aYInvert)
{
MakeCurrent();
@ -1664,6 +1735,8 @@ GLContext::ReadTextureImage(GLuint aTexture,
fs = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
fShaderSource(vs, 1, (const GLchar**) &vShader, NULL);
fShaderSource(fs, 1, (const GLchar**) &fShader, NULL);
fCompileShader(vs);
fCompileShader(fs);
prog = fCreateProgram();
fAttachShader(prog, vs);
fAttachShader(prog, fs);
@ -1707,9 +1780,15 @@ GLContext::ReadTextureImage(GLuint aTexture,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
isurf->Data());
SwapRAndBComponents(isurf);
if (oldPackAlignment != 4)
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, oldPackAlignment);
if (aYInvert) {
isurf = YInvertImageSurface(isurf);
}
cleanup:
// note that deleting 0 has no effect in any of these calls
fDeleteRenderbuffers(1, &rb);

View File

@ -1233,7 +1233,10 @@ public:
*/
already_AddRefed<gfxImageSurface> ReadTextureImage(GLuint aTexture,
const gfxIntSize& aSize,
GLenum aTextureFormat);
GLenum aTextureFormat,
bool aYInvert = false);
already_AddRefed<gfxImageSurface> GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader);
/**
* Call ReadPixels into an existing gfxImageSurface for the given bounds.
@ -2122,6 +2125,22 @@ public:
return result;
}
void fGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *img) {
if (!mSymbols.fGetTexImage) {
return;
}
BEFORE_GL_CALL;
mSymbols.fGetTexImage(target, level, format, type, img);
AFTER_GL_CALL;
};
void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
BEFORE_GL_CALL;
mSymbols.fGetTexLevelParameteriv(target, level, pname, params);
AFTER_GL_CALL;
}
void fGetTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {
BEFORE_GL_CALL;
mSymbols.fGetTexParameterfv(target, pname, params);

View File

@ -155,6 +155,10 @@ struct GLContextSymbols
PFNGLTEXPARAMETERFPROC fTexParameterf;
typedef GLubyte* (GLAPIENTRY * PFNGLGETSTRINGPROC) (GLenum);
PFNGLGETSTRINGPROC fGetString;
typedef void (GLAPIENTRY * PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid* image);
PFNGLGETTEXIMAGEPROC fGetTexImage;
typedef void (GLAPIENTRY * PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params);
PFNGLGETTEXLEVELPARAMETERIVPROC fGetTexLevelParameteriv;
typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
PFNGLGETTEXPARAMETERFVPROC fGetTexParameterfv;
typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);

View File

@ -36,6 +36,7 @@
* ***** END LICENSE BLOCK ***** */
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/CrossProcessMutex.h"
#include "ImageLayers.h"
#include "gfxImageSurface.h"
#include "yuv_convert.h"
@ -119,15 +120,91 @@ ImageContainer::SetCurrentImage(Image *aImage)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Lock();
// This is important since it ensures we won't change the active image
// when we currently have a locked image that depends on mRemoteData.
}
mActiveImage = aImage;
CurrentImageChanged();
if (mRemoteData) {
mRemoteDataMutex->Unlock();
}
}
bool
ImageContainer::HasCurrentImage()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
EnsureActiveImage();
return !!mActiveImage.get();
}
return !!mActiveImage.get();
}
already_AddRefed<Image>
ImageContainer::LockCurrentImage()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Lock();
}
EnsureActiveImage();
nsRefPtr<Image> retval = mActiveImage;
return retval.forget();
}
already_AddRefed<gfxASurface>
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
ImageContainer::LockCurrentAsSurface(gfxIntSize *aSize, Image** aCurrentImage)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Lock();
EnsureActiveImage();
if (aCurrentImage) {
NS_IF_ADDREF(mActiveImage);
*aCurrentImage = mActiveImage.get();
}
if (!mActiveImage) {
return nsnull;
}
if (mActiveImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
nsRefPtr<gfxImageSurface> newSurf =
new gfxImageSurface(mRemoteData->mBitmap.mData, mRemoteData->mSize, mRemoteData->mBitmap.mStride,
mRemoteData->mFormat == RemoteImageData::BGRX32 ?
gfxASurface::ImageFormatARGB32 :
gfxASurface::ImageFormatRGB24);
*aSize = newSurf->GetSize();
return newSurf.forget();
}
}
if (aCurrentImage) {
NS_IF_ADDREF(mActiveImage);
*aCurrentImage = mActiveImage.get();
}
if (!mActiveImage) {
return nsnull;
}
@ -136,11 +213,45 @@ ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
return mActiveImage->GetAsSurface();
}
void
ImageContainer::UnlockCurrentImage()
{
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Unlock();
}
}
already_AddRefed<gfxASurface>
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
EnsureActiveImage();
*aSize = mRemoteData->mSize;
return mActiveImage ? mActiveImage->GetAsSurface() : nsnull;
}
*aSize = mActiveImage->GetSize();
return mActiveImage ? mActiveImage->GetAsSurface() : nsnull;
}
gfxIntSize
ImageContainer::GetCurrentSize()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
// We don't need to ensure we have an active image here, as we need to
// be in the mutex anyway, and this is easiest to return from there.
return mRemoteData->mSize;
}
if (!mActiveImage) {
return gfxIntSize(0,0);
}
@ -148,6 +259,47 @@ ImageContainer::GetCurrentSize()
return mActiveImage->GetSize();
}
void
ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(!mActiveImage, "No active image expected when SetRemoteImageData is called.");
NS_ASSERTION(!mRemoteData, "No remote data expected when SetRemoteImageData is called.");
mRemoteData = aData;
if (aData) {
memset(aData, 0, sizeof(RemoteImageData));
} else {
mActiveImage = nsnull;
}
mRemoteDataMutex = aMutex;
}
void
ImageContainer::EnsureActiveImage()
{
if (mRemoteData) {
if (mRemoteData->mWasUpdated) {
mActiveImage = nsnull;
}
if (mRemoteData->mType == RemoteImageData::RAW_BITMAP &&
mRemoteData->mBitmap.mData && !mActiveImage) {
nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage();
newImg->mFormat = mRemoteData->mFormat;
newImg->mData = mRemoteData->mBitmap.mData;
newImg->mSize = mRemoteData->mSize;
newImg->mStride = mRemoteData->mBitmap.mStride;
mRemoteData->mWasUpdated = false;
mActiveImage = newImg;
}
}
}
PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
: Image(nsnull, PLANAR_YCBCR)
, mBufferSize(0)
@ -270,6 +422,21 @@ MacIOSurfaceImage::Update(ImageContainer* aContainer)
}
}
#endif
already_AddRefed<gfxASurface>
RemoteBitmapImage::GetAsSurface()
{
nsRefPtr<gfxImageSurface> newSurf =
new gfxImageSurface(mSize,
mFormat == RemoteImageData::BGRX32 ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32);
for (int y = 0; y < mSize.height; y++) {
memcpy(newSurf->Data() + newSurf->Stride() * y,
mData + mStride * y,
mSize.width * 4);
}
return newSurf.forget();
}
}
}

View File

@ -54,6 +54,12 @@
#endif
namespace mozilla {
class CrossProcessMutex;
namespace ipc {
class Shmem;
}
namespace layers {
enum StereoMode {
@ -120,7 +126,12 @@ public:
*
* It wraps an IOSurface object and binds it directly to a GL texture.
*/
MAC_IO_SURFACE
MAC_IO_SURFACE,
/**
* An bitmap image that can be shared with a remote process.
*/
REMOTE_IMAGE_BITMAP
};
Format GetFormat() { return mFormat; }
@ -194,6 +205,12 @@ FormatInList(const Image::Format* aFormats, PRUint32 aNumFormats,
return false;
}
class CompositionNotifySink
{
public:
virtual void DidComposite() = 0;
};
/**
* A class that manages Image creation for a LayerManager. The only reason
* we need a separate class here is that LayerMananers aren't threadsafe
@ -225,6 +242,46 @@ protected:
BufferRecycleBin *aRecycleBin);
};
/**
* This struct is used to store RemoteImages, it is meant to be able to live in
* shared memory. Therefor it should not contain a vtable pointer. Remote
* users can manipulate the data in this structure to specify what image is to
* be drawn by the container. When accessing this data users should make sure
* the mutex synchronizing access to the structure is held!
*/
struct RemoteImageData {
enum Type {
/**
* This is a format that uses raw bitmap data.
*/
RAW_BITMAP
};
/* These formats describe the format in the memory byte-order */
enum Format {
/* 8 bits per channel */
BGRA32,
/* 8 bits per channel, alpha channel is ignored */
BGRX32
};
// This should be set to true if a change was made so that the ImageContainer
// knows to throw out any cached RemoteImage objects.
bool mWasUpdated;
Type mType;
Format mFormat;
gfxIntSize mSize;
union {
struct {
/* This pointer is set by a remote process, however it will be set to
* the container process' address the memory of the raw bitmap resides
* at.
*/
unsigned char *mData;
int mStride;
} mBitmap;
};
};
/**
* A class that manages Images for an ImageLayer. The only reason
@ -242,7 +299,10 @@ public:
mPaintCount(0),
mPreviousImagePainted(false),
mImageFactory(new ImageFactory()),
mRecycleBin(new BufferRecycleBin())
mRecycleBin(new BufferRecycleBin()),
mRemoteData(nsnull),
mRemoteDataMutex(nsnull),
mCompositionNotifySink(nsnull)
{}
~ImageContainer();
@ -266,26 +326,37 @@ public:
* aImage can be null. While it's null, nothing will be painted.
*
* The Image data must not be modified after this method is called!
*
* Implementations must call CurrentImageChanged() while holding
* mReentrantMonitor.
*/
void SetCurrentImage(Image* aImage);
/**
* Get the current Image.
* This has to add a reference since otherwise there are race conditions
* where the current image is destroyed before the caller can add
* a reference.
* Returns if the container currently has an image.
* Can be called on any thread. This method takes mReentrantMonitor
* when accessing thread-shared state.
* Implementations must call CurrentImageChanged() while holding
* mReentrantMonitor.
*/
already_AddRefed<Image> GetCurrentImage()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
bool HasCurrentImage();
nsRefPtr<Image> retval = mActiveImage;
return retval.forget();
}
/**
* Lock the current Image.
* This has to add a reference since otherwise there are race conditions
* where the current image is destroyed before the caller can add
* a reference. This lock strictly guarantees the underlying image remains
* valid, it does not mean the current image cannot change.
* Can be called on any thread. This method will lock the cross-process
* mutex to ensure remote processes cannot alter underlying data. This call
* -must- be balanced by a call to UnlockCurrentImage and users should avoid
* holding the image locked for a long time.
*/
already_AddRefed<Image> LockCurrentImage();
/**
* This call unlocks the image. For remote images releasing the cross-process
* mutex.
*/
void UnlockCurrentImage();
/**
* Get the current image as a gfxASurface. This is useful for fallback
@ -301,9 +372,25 @@ public:
* modify it.
* Can be called on any thread. This method takes mReentrantMonitor
* when accessing thread-shared state.
* If the current image is a remote image, that is, if it is an image that
* may be shared accross processes, calling this function will make
* a copy of the image data while holding the mRemoteDataMutex. If possible,
* the lock methods should be used to avoid the copy, however this should be
* avoided if the surface is required for a long period of time.
*/
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
/**
* This is similar to GetCurrentAsSurface, however this does not make a copy
* of the image data and requires the user to call UnlockCurrentImage when
* done with the image data. Once UnlockCurrentImage has been called the
* surface returned by this function is no longer valid! This works for any
* type of image. Optionally a pointer can be passed to receive the current
* image.
*/
already_AddRefed<gfxASurface> LockCurrentAsSurface(gfxIntSize* aSizeResult,
Image** aCurrentImage = nsnull);
/**
* Returns the size of the image in pixels.
* Can be called on any thread. This method takes mReentrantMonitor when accessing
@ -354,7 +441,8 @@ public:
*/
void NotifyPaintedImage(Image* aPainted) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsRefPtr<Image> current = GetCurrentImage();
nsRefPtr<Image> current = mActiveImage;
if (aPainted == current) {
if (mPaintTime.IsNull()) {
mPaintTime = TimeStamp::Now();
@ -367,11 +455,40 @@ public:
mPaintCount++;
mPreviousImagePainted = true;
}
if (mCompositionNotifySink) {
mCompositionNotifySink->DidComposite();
}
}
void SetCompositionNotifySink(CompositionNotifySink *aSink) {
mCompositionNotifySink = aSink;
}
/**
* This function is called to tell the ImageContainer where the
* (cross-process) segment lives where the shared data about possible
* remote images are stored. In addition to this a CrossProcessMutex object
* is passed telling the container how to synchronize access to this data.
* NOTE: This should be called during setup of the container and not after
* usage has started.
*/
void SetRemoteImageData(RemoteImageData *aRemoteData,
CrossProcessMutex *aRemoteDataMutex);
/**
* This can be used to check if the container has RemoteData set.
*/
RemoteImageData *GetRemoteImageData() { return mRemoteData; }
protected:
typedef mozilla::ReentrantMonitor ReentrantMonitor;
// This is called to ensure we have an active image, this may not be true
// when we're storing image information in a RemoteImageData structure.
// NOTE: If we have remote data mRemoteDataMutex should be locked when
// calling this function!
void EnsureActiveImage();
// ReentrantMonitor to protect thread safe access to the "current
// image", and any other state which is shared between threads.
ReentrantMonitor mReentrantMonitor;
@ -407,6 +524,56 @@ protected:
gfxIntSize mScaleHint;
nsRefPtr<BufferRecycleBin> mRecycleBin;
// This contains the remote image data for this container, if this is NULL
// that means the container has no other process that may control its active
// image.
RemoteImageData *mRemoteData;
// This cross-process mutex is used to synchronise access to mRemoteData.
// When this mutex is held, we will always be inside the mReentrantMonitor
// however the same is not true vice versa.
CrossProcessMutex *mRemoteDataMutex;
CompositionNotifySink *mCompositionNotifySink;
};
class AutoLockImage
{
public:
AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
AutoLockImage(ImageContainer *aContainer, gfxASurface **aSurface) : mContainer(aContainer) {
*aSurface = mContainer->LockCurrentAsSurface(&mSize, getter_AddRefs(mImage)).get();
}
~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
Image* GetImage() { return mImage; }
const gfxIntSize &GetSize() { return mSize; }
void Unlock() {
if (mContainer) {
mImage = nsnull;
mContainer->UnlockCurrentImage();
mContainer = nsnull;
}
}
/** Things get a little tricky here, because our underlying image can -still-
* change, and OS X requires a complicated callback mechanism to update this
* we need to support staying the lock and getting the new image in a proper
* way. This method makes any images retrieved with GetImage invalid!
*/
void Refresh() {
if (mContainer) {
mContainer->UnlockCurrentImage();
mImage = mContainer->LockCurrentImage();
}
}
private:
ImageContainer *mContainer;
nsRefPtr<Image> mImage;
gfxIntSize mSize;
};
/**
@ -676,6 +843,20 @@ private:
};
#endif
class RemoteBitmapImage : public Image {
public:
RemoteBitmapImage() : Image(NULL, REMOTE_IMAGE_BITMAP) {}
already_AddRefed<gfxASurface> GetAsSurface();
gfxIntSize GetSize() { return mSize; }
unsigned char *mData;
int mStride;
gfxIntSize mSize;
RemoteImageData::Format mFormat;
};
}
}

View File

@ -458,6 +458,10 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformT
float opacity = GetEffectiveOpacity();
if (opacity != 1.0f && HasMultipleChildren()) {
useIntermediateSurface = true;
#ifdef MOZ_DUMP_PAINTING
} else if (gfxUtils::sDumpPainting) {
useIntermediateSurface = true;
#endif
} else {
useIntermediateSurface = false;
gfxMatrix contTransform;
@ -552,17 +556,60 @@ LayerManager::StopFrameTimeRecording()
static nsACString& PrintInfo(nsACString& aTo, ShadowLayer* aShadowLayer);
#ifdef MOZ_DUMP_PAINTING
template <typename T>
void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
{
nsCString string(aObj->Name());
string.Append("-");
string.AppendInt((PRUint64)aObj);
fprintf(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
}
template <typename T>
void WriteSnapshotToDumpFile_internal(T* aObj, gfxASurface* aSurf)
{
nsCString string(aObj->Name());
string.Append("-");
string.AppendInt((PRUint64)aObj);
fprintf(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
fprintf(gfxUtils::sDumpPaintFile, "\";");
}
void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf)
{
WriteSnapshotToDumpFile_internal(aLayer, aSurf);
}
void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf)
{
WriteSnapshotToDumpFile_internal(aManager, aSurf);
}
#endif
void
Layer::Dump(FILE* aFile, const char* aPrefix)
{
fprintf(aFile, "<li><a id=\"%p\" ", this);
#ifdef MOZ_DUMP_PAINTING
if (GetType() == TYPE_CONTAINER || GetType() == TYPE_THEBES) {
WriteSnapshotLinkToDumpFile(this, aFile);
}
#endif
fprintf(aFile, ">");
DumpSelf(aFile, aPrefix);
fprintf(aFile, "</a>");
if (Layer* kid = GetFirstChild()) {
nsCAutoString pfx(aPrefix);
pfx += " ";
fprintf(aFile, "<ul>");
kid->Dump(aFile, pfx.get());
fprintf(aFile, "</ul>");
}
fprintf(aFile, "</li>");
if (Layer* next = GetNextSibling())
next->Dump(aFile, aPrefix);
}
@ -714,17 +761,27 @@ void
LayerManager::Dump(FILE* aFile, const char* aPrefix)
{
FILE* file = FILEOrDefault(aFile);
fprintf(file, "<ul><li><a ");
#ifdef MOZ_DUMP_PAINTING
WriteSnapshotLinkToDumpFile(this, aFile);
#endif
fprintf(file, ">");
DumpSelf(file, aPrefix);
#ifdef MOZ_DUMP_PAINTING
fprintf(aFile, "</a>");
#endif
nsCAutoString pfx(aPrefix);
pfx += " ";
if (!GetRoot()) {
fprintf(file, "%s(null)", pfx.get());
fprintf(file, "%s(null)</li></ul>", pfx.get());
return;
}
fprintf(file, "<ul>");
GetRoot()->Dump(file, pfx.get());
fprintf(file, "</ul></li></ul>");
}
void

View File

@ -1345,6 +1345,11 @@ protected:
bool mDirty;
};
#ifdef MOZ_DUMP_PAINTING
void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf);
void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf);
#endif
}
}

View File

@ -904,9 +904,11 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nsnull : BasicManager()->GetImageFactory());
nsRefPtr<Image> image = mContainer->GetCurrentImage();
nsRefPtr<gfxASurface> surface;
AutoLockImage autoLock(mContainer, getter_AddRefs(surface));
Image *image = autoLock.GetImage();
mSize = autoLock.GetSize();
nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&mSize);
if (!surface || surface->CairoStatus()) {
return nsnull;
}
@ -2522,13 +2524,16 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext)
return;
}
nsRefPtr<Image> image = mContainer->GetCurrentImage();
AutoLockImage autoLock(mContainer);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
if (image->GetFormat() == Image::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) {
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image.get());
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image);
const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");

View File

@ -44,6 +44,34 @@
namespace mozilla {
namespace layers {
static already_AddRefed<ID3D10Texture2D>
DataToTexture(ID3D10Device *aDevice,
unsigned char *data,
int stride,
const gfxIntSize &aSize)
{
D3D10_SUBRESOURCE_DATA srdata;
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
aSize.width,
aSize.height,
1, 1);
desc.Usage = D3D10_USAGE_IMMUTABLE;
srdata.pSysMem = data;
srdata.SysMemPitch = stride;
nsRefPtr<ID3D10Texture2D> texture;
HRESULT hr = aDevice->CreateTexture2D(&desc, &srdata, getter_AddRefs(texture));
if (FAILED(hr)) {
LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for data"),
hr);
}
return texture.forget();
}
static already_AddRefed<ID3D10Texture2D>
SurfaceToTexture(ID3D10Device *aDevice,
@ -78,26 +106,7 @@ SurfaceToTexture(ID3D10Device *aDevice,
context->Paint();
}
D3D10_SUBRESOURCE_DATA data;
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
imageSurface->GetSize().width,
imageSurface->GetSize().height,
1, 1);
desc.Usage = D3D10_USAGE_IMMUTABLE;
data.pSysMem = imageSurface->Data();
data.SysMemPitch = imageSurface->Stride();
nsRefPtr<ID3D10Texture2D> texture;
HRESULT hr = aDevice->CreateTexture2D(&desc, &data, getter_AddRefs(texture));
if (FAILED(hr)) {
LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for image surface"),
hr);
}
return texture.forget();
return DataToTexture(aDevice, imageSurface->Data(), imageSurface->Stride(), aSize);
}
Layer*
@ -109,11 +118,14 @@ ImageLayerD3D10::GetLayer()
void
ImageLayerD3D10::RenderLayer()
{
if (!GetContainer()) {
ImageContainer *container = GetContainer();
if (!container) {
return;
}
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
@ -122,27 +134,51 @@ ImageLayerD3D10::RenderLayer()
ID3D10EffectTechnique *technique;
if (image->GetFormat() == Image::CAIRO_SURFACE)
if (image->GetFormat() == Image::CAIRO_SURFACE || image->GetFormat() == Image::REMOTE_IMAGE_BITMAP)
{
CairoImage *cairoImage =
static_cast<CairoImage*>(image.get());
bool hasAlpha = false;
gfxIntSize size;
if (!cairoImage->mSurface) {
return;
}
if (image->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
RemoteBitmapImage *remoteImage =
static_cast<RemoteBitmapImage*>(image);
if (!image->GetBackendData(LayerManager::LAYERS_D3D10)) {
nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData();
dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize);
if (!cairoImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
nsAutoPtr<CairoD3D10BackendData> dat(new CairoD3D10BackendData());
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
cairoImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
if (dat->mTexture) {
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
image->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
}
}
hasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
size = remoteImage->mSize;
} else {
CairoImage *cairoImage =
static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return;
}
if (!image->GetBackendData(LayerManager::LAYERS_D3D10)) {
nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData();
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
image->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
}
}
hasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
size = cairoImage->mSize;
}
CairoD3D10BackendData *data =
static_cast<CairoD3D10BackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_D3D10));
TextureD3D10BackendData *data =
static_cast<TextureD3D10BackendData*>(image->GetBackendData(LayerManager::LAYERS_D3D10));
if (!data) {
return;
@ -154,7 +190,7 @@ ImageLayerD3D10::RenderLayer()
return;
}
if (cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
if (hasAlpha) {
if (mFilter == gfxPattern::FILTER_NEAREST) {
technique = effect()->GetTechniqueByName("RenderRGBALayerPremulPoint");
} else {
@ -174,12 +210,12 @@ ImageLayerD3D10::RenderLayer()
ShaderConstantRectD3D10(
(float)0,
(float)0,
(float)cairoImage->mSize.width,
(float)cairoImage->mSize.height)
(float)size.width,
(float)size.height)
);
} else if (image->GetFormat() == Image::PLANAR_YCBCR) {
PlanarYCbCrImage *yuvImage =
static_cast<PlanarYCbCrImage*>(image.get());
static_cast<PlanarYCbCrImage*>(image);
if (!yuvImage->mBufferSize) {
return;
@ -262,11 +298,15 @@ ImageLayerD3D10::RenderLayer()
(float)yuvImage->mData.mPicSize.height / yuvImage->mData.mYSize.height)
);
}
bool resetTexCoords = image->GetFormat() == Image::PLANAR_YCBCR;
image = nsnull;
autoLock.Unlock();
technique->GetPassByIndex(0)->Apply(0);
device()->Draw(4, 0);
if (image->GetFormat() == Image::PLANAR_YCBCR) {
if (resetTexCoords) {
effect()->GetVariableByName("vTextureCoords")->AsVector()->
SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
}

View File

@ -74,7 +74,7 @@ struct PlanarYCbCrD3D10BackendData : public ImageBackendData
nsRefPtr<ID3D10ShaderResourceView> mCrView;
};
struct CairoD3D10BackendData : public ImageBackendData
struct TextureD3D10BackendData : public ImageBackendData
{
nsRefPtr<ID3D10Texture2D> mTexture;
nsRefPtr<ID3D10ShaderResourceView> mSRView;

View File

@ -53,23 +53,11 @@ namespace mozilla {
namespace layers {
static already_AddRefed<IDirect3DTexture9>
SurfaceToTexture(IDirect3DDevice9 *aDevice,
gfxASurface *aSurface,
const gfxIntSize &aSize)
DataToTexture(IDirect3DDevice9 *aDevice,
unsigned char *aData,
int aStride,
const gfxIntSize &aSize)
{
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
if (!imageSurface) {
imageSurface = new gfxImageSurface(aSize,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->SetSource(aSurface);
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->Paint();
}
nsRefPtr<IDirect3DTexture9> texture;
nsRefPtr<IDirect3DDevice9Ex> deviceEx;
aDevice->QueryInterface(IID_IDirect3DDevice9Ex,
@ -103,7 +91,7 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
surface->LockRect(&lockedRect, NULL, 0);
for (int y = 0; y < aSize.height; y++) {
memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y,
imageSurface->Data() + imageSurface->Stride() * y,
aData + aStride * y,
aSize.width * 4);
}
surface->UnlockRect();
@ -127,7 +115,7 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
// use memcpy
for (int y = 0; y < aSize.height; y++) {
memcpy((char*)lockrect.pBits + lockrect.Pitch * y,
imageSurface->Data() + imageSurface->Stride() * y,
aData + aStride * y,
aSize.width * 4);
}
@ -137,6 +125,27 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
return texture.forget();
}
static already_AddRefed<IDirect3DTexture9>
SurfaceToTexture(IDirect3DDevice9 *aDevice,
gfxASurface *aSurface,
const gfxIntSize &aSize)
{
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
if (!imageSurface) {
imageSurface = new gfxImageSurface(aSize,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->SetSource(aSurface);
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->Paint();
}
return DataToTexture(aDevice, imageSurface->Data(), imageSurface->Stride(), aSize);
}
static void AllocateTexturesYCbCr(PlanarYCbCrImage *aImage,
IDirect3DDevice9 *aDevice,
LayerManagerD3D9 *aManager)
@ -302,37 +311,61 @@ ImageLayerD3D9::GetLayer()
void
ImageLayerD3D9::RenderLayer()
{
if (!GetContainer()) {
ImageContainer *container = GetContainer();
if (!container) {
return;
}
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
SetShaderTransformAndOpacity();
if (image->GetFormat() == Image::CAIRO_SURFACE)
if (image->GetFormat() == Image::CAIRO_SURFACE || image->GetFormat() == Image::REMOTE_IMAGE_BITMAP)
{
CairoImage *cairoImage =
static_cast<CairoImage*>(image.get());
bool hasAlpha = false;
gfxIntSize size;
if (!cairoImage->mSurface) {
return;
}
if (!cairoImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
nsAutoPtr<CairoD3D9BackendData> dat(new CairoD3D9BackendData());
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
cairoImage->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
if (image->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
RemoteBitmapImage *remoteImage =
static_cast<RemoteBitmapImage*>(image);
if (!image->GetBackendData(LayerManager::LAYERS_D3D9)) {
nsAutoPtr<TextureD3D9BackendData> dat = new TextureD3D9BackendData();
dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize);
if (dat->mTexture) {
image->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
}
}
hasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
size = remoteImage->mSize;
} else {
CairoImage *cairoImage =
static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return;
}
if (!image->GetBackendData(LayerManager::LAYERS_D3D9)) {
nsAutoPtr<TextureD3D9BackendData> dat = new TextureD3D9BackendData();
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
image->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
}
}
hasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
size = cairoImage->mSize;
}
CairoD3D9BackendData *data =
static_cast<CairoD3D9BackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_D3D9));
TextureD3D9BackendData *data =
static_cast<TextureD3D9BackendData*>(image->GetBackendData(LayerManager::LAYERS_D3D9));
if (!data) {
return;
@ -344,12 +377,6 @@ ImageLayerD3D9::RenderLayer()
return;
}
gfxIntSize size;
nsRefPtr<gfxASurface> surface =
GetContainer()->GetCurrentAsSurface(&size);
nsRefPtr<IDirect3DTexture9> texture =
SurfaceToTexture(device(), surface, size);
device()->SetVertexShaderConstantF(CBvLayerQuad,
ShaderConstantRect(0,
0,
@ -357,7 +384,7 @@ ImageLayerD3D9::RenderLayer()
size.height),
1);
if (surface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
if (hasAlpha) {
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
} else {
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
@ -367,7 +394,12 @@ ImageLayerD3D9::RenderLayer()
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
}
device()->SetTexture(0, texture);
device()->SetTexture(0, data->mTexture);
image = nsnull;
data = nsnull;
autoLock.Unlock();
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
if (mFilter == gfxPattern::FILTER_NEAREST) {
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
@ -375,7 +407,7 @@ ImageLayerD3D9::RenderLayer()
}
} else {
PlanarYCbCrImage *yuvImage =
static_cast<PlanarYCbCrImage*>(image.get());
static_cast<PlanarYCbCrImage*>(image);
if (!yuvImage->mBufferSize) {
return;
@ -459,6 +491,10 @@ ImageLayerD3D9::RenderLayer()
device()->SetTexture(1, data->mCbTexture);
device()->SetTexture(2, data->mCrTexture);
image = nsnull;
data = nsnull;
autoLock.Unlock();
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device()->SetVertexShaderConstantF(CBvTextureCoords,

View File

@ -71,7 +71,7 @@ public:
};
struct CairoD3D9BackendData : public ImageBackendData
struct TextureD3D9BackendData : public ImageBackendData
{
nsRefPtr<IDirect3DTexture9> mTexture;
};

View File

@ -256,6 +256,14 @@ ContainerRender(Container* aContainer,
if (needsFramebuffer) {
// Unbind the current framebuffer and rebind the previous one.
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
nsRefPtr<gfxImageSurface> surf =
aContainer->gl()->GetTexImage(containerSurface, true, aManager->GetFBOLayerProgramType());
WriteSnapshotToDumpFile(aContainer, surf);
}
#endif
// Restore the viewport
aContainer->gl()->PopViewportRect();

View File

@ -214,19 +214,26 @@ void
ImageLayerOGL::RenderLayer(int,
const nsIntPoint& aOffset)
{
if (!GetContainer())
nsRefPtr<ImageContainer> container = GetContainer();
if (!container)
return;
mOGLManager->MakeCurrent();
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
NS_ASSERTION(image->GetFormat() != Image::REMOTE_IMAGE_BITMAP,
"Remote images aren't handled yet in OGL layers!");
if (image->GetFormat() == Image::PLANAR_YCBCR) {
PlanarYCbCrImage *yuvImage =
static_cast<PlanarYCbCrImage*>(image.get());
static_cast<PlanarYCbCrImage*>(image);
if (!yuvImage->mBufferSize) {
return;
@ -276,7 +283,7 @@ ImageLayerOGL::RenderLayer(int,
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
} else if (image->GetFormat() == Image::CAIRO_SURFACE) {
CairoImage *cairoImage =
static_cast<CairoImage*>(image.get());
static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return;
@ -424,16 +431,18 @@ ImageLayerOGL::RenderLayer(int,
#ifdef XP_MACOSX
} else if (image->GetFormat() == Image::MAC_IO_SURFACE) {
MacIOSurfaceImage *ioImage =
static_cast<MacIOSurfaceImage*>(image.get());
static_cast<MacIOSurfaceImage*>(image);
if (!mOGLManager->GetThebesLayerCallback()) {
// If its an empty transaction we still need to update
// the plugin IO Surface and make sure we grab the
// new image
ioImage->Update(GetContainer());
image = GetContainer()->GetCurrentImage();
image = nsnull;
autoLock.Refresh();
image = autoLock.GetImage();
gl()->MakeCurrent();
ioImage = static_cast<MacIOSurfaceImage*>(image.get());
ioImage = static_cast<MacIOSurfaceImage*>(image);
}
if (!ioImage) {

View File

@ -54,6 +54,8 @@
#include "LayerManagerOGLShaders.h"
#include "gfxContext.h"
#include "gfxUtils.h"
#include "gfxPlatform.h"
#include "nsIWidget.h"
#include "GLContext.h"
@ -779,8 +781,20 @@ LayerManagerOGL::Render()
mWidget->DrawWindowOverlay(this, rect);
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
nsIntRect rect;
mWidget->GetBounds(rect);
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(rect.Size(), gfxASurface::CONTENT_COLOR_ALPHA);
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
CopyToTarget(ctx);
WriteSnapshotToDumpFile(this, surf);
}
#endif
if (mTarget) {
CopyToTarget();
CopyToTarget(mTarget);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
return;
}
@ -986,7 +1000,7 @@ LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
}
void
LayerManagerOGL::CopyToTarget()
LayerManagerOGL::CopyToTarget(gfxContext *aTarget)
{
nsIntRect rect;
mWidget->GetBounds(rect);
@ -1050,11 +1064,11 @@ LayerManagerOGL::CopyToTarget()
}
}
mTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
mTarget->Scale(1.0, -1.0);
mTarget->Translate(-gfxPoint(0.0, height));
mTarget->SetSource(imageSurface);
mTarget->Paint();
aTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
aTarget->Scale(1.0, -1.0);
aTarget->Translate(-gfxPoint(0.0, height));
aTarget->SetSource(imageSurface);
aTarget->Paint();
}
LayerManagerOGL::ProgramType LayerManagerOGL::sLayerProgramTypes[] = {

View File

@ -236,9 +236,13 @@ public:
}
ColorTextureLayerProgram *GetFBOLayerProgram() {
return static_cast<ColorTextureLayerProgram*>(mPrograms[GetFBOLayerProgramType()]);
}
gl::ShaderProgramType GetFBOLayerProgramType() {
if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB)
return static_cast<ColorTextureLayerProgram*>(mPrograms[gl::RGBARectLayerProgramType]);
return static_cast<ColorTextureLayerProgram*>(mPrograms[gl::RGBALayerProgramType]);
return gl::RGBARectLayerProgramType;
return gl::RGBALayerProgramType;
}
GLContext *gl() const { return mGLContext; }
@ -451,7 +455,7 @@ private:
/**
* Copies the content of our backbuffer to the set transaction target.
*/
void CopyToTarget();
void CopyToTarget(gfxContext *aTarget);
/**
* Updates all layer programs with a new projection matrix.

View File

@ -145,6 +145,15 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
mTexImageOnWhite->EndUpdate();
}
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
nsRefPtr<gfxImageSurface> surf =
gl()->GetTexImage(mTexImage->GetTextureID(), false, mTexImage->GetShaderProgramType());
WriteSnapshotToDumpFile(mLayer, surf);
}
#endif
PRInt32 passes = mTexImageOnWhite ? 2 : 1;
for (PRInt32 pass = 1; pass <= passes; ++pass) {
LayerProgram *program;

View File

@ -716,9 +716,16 @@ gfxASurface::WriteAsPNG(const char* aFile)
}
void
gfxASurface::DumpAsDataURL()
gfxASurface::DumpAsDataURL(FILE* aOutput)
{
WriteAsPNG_internal(aOutput, false);
}
void
gfxASurface::PrintAsDataURL()
{
WriteAsPNG_internal(stdout, false);
fprintf(stdout, "\n");
}
void
@ -776,7 +783,6 @@ gfxASurface::WriteAsPNG_internal(FILE* aFile, bool aBinary)
for (PRInt32 x = 0; x < w; ++x) {
printf("%x ", reinterpret_cast<PRUint32*>(imgsurf->Data())[y*imgsurf->Stride()+ x]);
}
printf("\n");
}
return;
}
@ -846,7 +852,6 @@ gfxASurface::WriteAsPNG_internal(FILE* aFile, bool aBinary)
if (aFile) {
fprintf(aFile, "%s", string.BeginReading());
fprintf(aFile, "\n");
} else {
nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
if (clipboard) {

View File

@ -257,10 +257,15 @@ public:
*/
void WriteAsPNG(const char* aFile);
/**
* Write as a PNG encoded Data URL to a file.
*/
void DumpAsDataURL(FILE* aOutput = stdout);
/**
* Write as a PNG encoded Data URL to stdout.
*/
void DumpAsDataURL();
void PrintAsDataURL();
/**
* Copy a PNG encoded Data URL to the clipboard.

View File

@ -692,4 +692,8 @@ gfxUtils::CopyAsDataURL(DrawTarget* aDT)
NS_WARNING("Failed to get Thebes surface!");
}
}
bool gfxUtils::sDumpPainting = getenv("MOZ_DUMP_PAINT_LIST") != 0;
bool gfxUtils::sDumpPaintingToFile = getenv("MOZ_DUMP_PAINT_TO_FILE") != 0;
FILE *gfxUtils::sDumpPaintFile = NULL;
#endif

View File

@ -167,7 +167,12 @@ public:
* Copy a PNG encoded Data URL to the clipboard.
*/
static void CopyAsDataURL(mozilla::gfx::DrawTarget* aDT);
static bool sDumpPainting;
static bool sDumpPaintingToFile;
static FILE* sDumpPaintFile;
#endif
};
#endif

View File

@ -137,182 +137,194 @@ static void PrintImageDecoders()
#endif
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ImagesMallocSizeOf, "images")
class imgMemoryReporter MOZ_FINAL :
public nsIMemoryReporter
public nsIMemoryMultiReporter
{
public:
enum ReporterType {
CHROME_BIT = PR_BIT(0),
USED_BIT = PR_BIT(1),
RAW_BIT = PR_BIT(2),
HEAP_BIT = PR_BIT(3),
ChromeUsedRaw = CHROME_BIT | USED_BIT | RAW_BIT | HEAP_BIT,
ChromeUsedUncompressedHeap = CHROME_BIT | USED_BIT | HEAP_BIT,
ChromeUsedUncompressedNonheap = CHROME_BIT | USED_BIT,
ChromeUnusedRaw = CHROME_BIT | RAW_BIT | HEAP_BIT,
ChromeUnusedUncompressedHeap = CHROME_BIT | HEAP_BIT,
ChromeUnusedUncompressedNonheap = CHROME_BIT,
ContentUsedRaw = USED_BIT | RAW_BIT | HEAP_BIT,
ContentUsedUncompressedHeap = USED_BIT | HEAP_BIT,
ContentUsedUncompressedNonheap = USED_BIT,
ContentUnusedRaw = RAW_BIT | HEAP_BIT,
ContentUnusedUncompressedHeap = HEAP_BIT,
ContentUnusedUncompressedNonheap = 0
};
imgMemoryReporter(ReporterType aType)
: mType(aType)
imgMemoryReporter()
{
// If the RAW bit is set, HEAP should also be set, because we don't
// currently understand storing compressed image data off the heap.
NS_ASSERTION(!(aType & RAW_BIT) || (aType & HEAP_BIT),
"RAW bit should imply HEAP bit.");
}
NS_DECL_ISUPPORTS
NS_IMETHOD GetProcess(nsACString &process)
NS_IMETHOD GetName(nsACString &name)
{
process.Truncate();
name.Assign("images");
return NS_OK;
}
NS_IMETHOD GetPath(nsACString &path)
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
if (mType == ChromeUsedRaw) {
path.AssignLiteral("explicit/images/chrome/used/raw");
} else if (mType == ChromeUsedUncompressedHeap) {
path.AssignLiteral("explicit/images/chrome/used/uncompressed-heap");
} else if (mType == ChromeUsedUncompressedNonheap) {
path.AssignLiteral("explicit/images/chrome/used/uncompressed-nonheap");
} else if (mType == ChromeUnusedRaw) {
path.AssignLiteral("explicit/images/chrome/unused/raw");
} else if (mType == ChromeUnusedUncompressedHeap) {
path.AssignLiteral("explicit/images/chrome/unused/uncompressed-heap");
} else if (mType == ChromeUnusedUncompressedNonheap) {
path.AssignLiteral("explicit/images/chrome/unused/uncompressed-nonheap");
} else if (mType == ContentUsedRaw) {
path.AssignLiteral("explicit/images/content/used/raw");
} else if (mType == ContentUsedUncompressedHeap) {
path.AssignLiteral("explicit/images/content/used/uncompressed-heap");
} else if (mType == ContentUsedUncompressedNonheap) {
path.AssignLiteral("explicit/images/content/used/uncompressed-nonheap");
} else if (mType == ContentUnusedRaw) {
path.AssignLiteral("explicit/images/content/unused/raw");
} else if (mType == ContentUnusedUncompressedHeap) {
path.AssignLiteral("explicit/images/content/unused/uncompressed-heap");
} else if (mType == ContentUnusedUncompressedNonheap) {
path.AssignLiteral("explicit/images/content/unused/uncompressed-nonheap");
AllSizes chrome;
AllSizes content;
imgLoader::sChromeCache.EnumerateRead(EntryAllSizes, &chrome);
imgLoader::sCache.EnumerateRead(EntryAllSizes, &content);
#define REPORT(_path, _kind, _amount, _desc) \
do { \
nsresult rv; \
rv = callback->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
_kind, nsIMemoryReporter::UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), closure); \
NS_ENSURE_SUCCESS(rv, rv); \
} while (0)
REPORT("explicit/images/chrome/used/raw",
nsIMemoryReporter::KIND_HEAP, chrome.mUsedRaw,
"Memory used by in-use chrome images (compressed data).");
REPORT("explicit/images/chrome/used/uncompressed-heap",
nsIMemoryReporter::KIND_HEAP, chrome.mUsedUncompressedHeap,
"Memory used by in-use chrome images (uncompressed data).");
REPORT("explicit/images/chrome/used/uncompressed-nonheap",
nsIMemoryReporter::KIND_NONHEAP, chrome.mUsedUncompressedNonheap,
"Memory used by in-use chrome images (uncompressed data).");
REPORT("explicit/images/chrome/unused/raw",
nsIMemoryReporter::KIND_HEAP, chrome.mUnusedRaw,
"Memory used by not in-use chrome images (compressed data).");
REPORT("explicit/images/chrome/unused/uncompressed-heap",
nsIMemoryReporter::KIND_HEAP, chrome.mUnusedUncompressedHeap,
"Memory used by not in-use chrome images (uncompressed data).");
REPORT("explicit/images/chrome/unused/uncompressed-nonheap",
nsIMemoryReporter::KIND_NONHEAP, chrome.mUnusedUncompressedNonheap,
"Memory used by not in-use chrome images (uncompressed data).");
REPORT("explicit/images/content/used/raw",
nsIMemoryReporter::KIND_HEAP, content.mUsedRaw,
"Memory used by in-use content images (compressed data).");
REPORT("explicit/images/content/used/uncompressed-heap",
nsIMemoryReporter::KIND_HEAP, content.mUsedUncompressedHeap,
"Memory used by in-use content images (uncompressed data).");
REPORT("explicit/images/content/used/uncompressed-nonheap",
nsIMemoryReporter::KIND_NONHEAP, content.mUsedUncompressedNonheap,
"Memory used by in-use content images (uncompressed data).");
REPORT("explicit/images/content/unused/raw",
nsIMemoryReporter::KIND_HEAP, content.mUnusedRaw,
"Memory used by not in-use content images (compressed data).");
REPORT("explicit/images/content/unused/uncompressed-heap",
nsIMemoryReporter::KIND_HEAP, content.mUnusedUncompressedHeap,
"Memory used by not in-use content images (uncompressed data).");
REPORT("explicit/images/content/unused/uncompressed-nonheap",
nsIMemoryReporter::KIND_NONHEAP, content.mUnusedUncompressedNonheap,
"Memory used by not in-use content images (uncompressed data).");
#undef REPORT
return NS_OK;
}
NS_IMETHOD GetExplicitNonHeap(PRInt64 *n)
{
size_t n2 = 0;
imgLoader::sChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
imgLoader::sCache.EnumerateRead(EntryExplicitNonHeapSize, &n2);
*n = n2;
return NS_OK;
}
static PRInt64 GetImagesContentUsedUncompressed()
{
size_t n = 0;
imgLoader::sCache.EnumerateRead(EntryUsedUncompressedSize, &n);
return n;
}
private:
struct AllSizes {
size_t mUsedRaw;
size_t mUsedUncompressedHeap;
size_t mUsedUncompressedNonheap;
size_t mUnusedRaw;
size_t mUnusedUncompressedHeap;
size_t mUnusedUncompressedNonheap;
AllSizes() {
memset(this, 0, sizeof(*this));
}
return NS_OK;
}
NS_IMETHOD GetKind(PRInt32 *kind)
{
if (mType & HEAP_BIT) {
*kind = KIND_HEAP;
}
else {
*kind = KIND_MAPPED;
}
return NS_OK;
}
NS_IMETHOD GetUnits(PRInt32 *units)
{
*units = UNITS_BYTES;
return NS_OK;
}
struct EnumArg {
EnumArg(ReporterType aType)
: rtype(aType), n(0)
{ }
ReporterType rtype;
size_t n;
};
static PLDHashOperator EnumEntries(const nsACString&,
imgCacheEntry *entry,
void *userArg)
static PLDHashOperator EntryAllSizes(const nsACString&,
imgCacheEntry *entry,
void *userArg)
{
EnumArg *arg = static_cast<EnumArg*>(userArg);
ReporterType rtype = arg->rtype;
if (rtype & USED_BIT) {
if (entry->HasNoProxies())
return PL_DHASH_NEXT;
} else {
if (!entry->HasNoProxies())
return PL_DHASH_NEXT;
}
nsRefPtr<imgRequest> req = entry->GetRequest();
Image *image = static_cast<Image*>(req->mImage.get());
if (!image)
return PL_DHASH_NEXT;
if (rtype & RAW_BIT) {
arg->n += image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
} else if (rtype & HEAP_BIT) {
arg->n += image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
} else {
arg->n += image->NonHeapSizeOfDecoded();
if (image) {
AllSizes *sizes = static_cast<AllSizes*>(userArg);
if (entry->HasNoProxies()) {
sizes->mUnusedRaw +=
image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
sizes->mUnusedUncompressedHeap +=
image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
sizes->mUnusedUncompressedNonheap += image->NonHeapSizeOfDecoded();
} else {
sizes->mUsedRaw +=
image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
sizes->mUsedUncompressedHeap +=
image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
sizes->mUsedUncompressedNonheap += image->NonHeapSizeOfDecoded();
}
}
return PL_DHASH_NEXT;
}
NS_IMETHOD GetAmount(PRInt64 *amount)
static PLDHashOperator EntryExplicitNonHeapSize(const nsACString&,
imgCacheEntry *entry,
void *userArg)
{
EnumArg arg(mType);
if (mType & CHROME_BIT) {
imgLoader::sChromeCache.EnumerateRead(EnumEntries, &arg);
} else {
imgLoader::sCache.EnumerateRead(EnumEntries, &arg);
size_t *n = static_cast<size_t*>(userArg);
nsRefPtr<imgRequest> req = entry->GetRequest();
Image *image = static_cast<Image*>(req->mImage.get());
if (image) {
*n += image->NonHeapSizeOfDecoded();
}
*amount = arg.n;
return NS_OK;
return PL_DHASH_NEXT;
}
NS_IMETHOD GetDescription(nsACString &desc)
static PLDHashOperator EntryUsedUncompressedSize(const nsACString&,
imgCacheEntry *entry,
void *userArg)
{
if (mType == ChromeUsedRaw) {
desc.AssignLiteral("Memory used by in-use chrome images (compressed data).");
} else if (mType == ChromeUsedUncompressedHeap) {
desc.AssignLiteral("Memory used by in-use chrome images (uncompressed data).");
} else if (mType == ChromeUsedUncompressedNonheap) {
desc.AssignLiteral("Memory used by in-use chrome images (uncompressed data).");
} else if (mType == ChromeUnusedRaw) {
desc.AssignLiteral("Memory used by not in-use chrome images (compressed data).");
} else if (mType == ChromeUnusedUncompressedHeap) {
desc.AssignLiteral("Memory used by not in-use chrome images (uncompressed data).");
} else if (mType == ChromeUnusedUncompressedNonheap) {
desc.AssignLiteral("Memory used by not in-use chrome images (uncompressed data).");
} else if (mType == ContentUsedRaw) {
desc.AssignLiteral("Memory used by in-use content images (compressed data).");
} else if (mType == ContentUsedUncompressedHeap) {
desc.AssignLiteral("Memory used by in-use content images (uncompressed data).");
} else if (mType == ContentUsedUncompressedNonheap) {
desc.AssignLiteral("Memory used by in-use content images (uncompressed data).");
} else if (mType == ContentUnusedRaw) {
desc.AssignLiteral("Memory used by not in-use content images (compressed data).");
} else if (mType == ContentUnusedUncompressedHeap) {
desc.AssignLiteral("Memory used by not in-use content images (uncompressed data).");
} else if (mType == ContentUnusedUncompressedNonheap) {
desc.AssignLiteral("Memory used by not in-use content images (uncompressed data).");
if (!entry->HasNoProxies()) {
size_t *n = static_cast<size_t*>(userArg);
nsRefPtr<imgRequest> req = entry->GetRequest();
Image *image = static_cast<Image*>(req->mImage.get());
if (image) {
*n += image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
*n += image->NonHeapSizeOfDecoded();
}
}
return NS_OK;
}
ReporterType mType;
return PL_DHASH_NEXT;
}
};
NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryReporter)
// This is used by telemetry.
NS_MEMORY_REPORTER_IMPLEMENT(
ImagesContentUsedUncompressed,
"images-content-used-uncompressed",
KIND_OTHER,
UNITS_BYTES,
imgMemoryReporter::GetImagesContentUsedUncompressed,
"This is the sum of the 'explicit/images/content/used/uncompressed-heap' "
"and 'explicit/images/content/used/uncompressed-nonheap' numbers. However, "
"it is measured at a different time and so may give slightly different "
"results.")
NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryMultiReporter)
NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy,
nsIProgressEventSink,
@ -922,18 +934,8 @@ nsresult imgLoader::InitCache()
else
sCacheMaxSize = 5 * 1024 * 1024;
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ChromeUsedRaw));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ChromeUsedUncompressedHeap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ChromeUsedUncompressedNonheap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ChromeUnusedRaw));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ChromeUnusedUncompressedHeap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ChromeUnusedUncompressedNonheap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ContentUsedRaw));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ContentUsedUncompressedHeap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ContentUsedUncompressedNonheap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ContentUnusedRaw));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ContentUnusedUncompressedHeap));
NS_RegisterMemoryReporter(new imgMemoryReporter(imgMemoryReporter::ContentUnusedUncompressedNonheap));
NS_RegisterMemoryMultiReporter(new imgMemoryReporter());
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(ImagesContentUsedUncompressed));
return NS_OK;
}

View File

@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_CrossProcessMutex_h
#define mozilla_CrossProcessMutex_h
#include "base/process.h"
#include "mozilla/Mutex.h"
namespace IPC {
template<typename T>
struct ParamTraits;
}
//
// Provides:
//
// - CrossProcessMutex, a non-recursive mutex that can be shared across processes
// - CrossProcessMutexAutoLock, an RAII class for ensuring that Mutexes are
// properly locked and unlocked
//
// Using CrossProcessMutexAutoLock/CrossProcessMutexAutoUnlock is MUCH
// preferred to making bare calls to CrossProcessMutex.Lock and Unlock.
//
namespace mozilla {
#ifdef XP_WIN
typedef HANDLE CrossProcessMutexHandle;
#else
// Stub for other platforms. We can't use uintptr_t here since different
// processes could disagree on its size.
typedef uintptr_t CrossProcessMutexHandle;
#endif
class NS_COM_GLUE CrossProcessMutex
{
public:
/**
* CrossProcessMutex
* @param name A name which can reference this lock (currently unused)
**/
CrossProcessMutex(const char* aName);
/**
* CrossProcessMutex
* @param handle A handle of an existing cross process mutex that can be
* opened.
*/
CrossProcessMutex(CrossProcessMutexHandle aHandle);
/**
* ~CrossProcessMutex
**/
~CrossProcessMutex();
/**
* Lock
* This will lock the mutex. Any other thread in any other process that
* has access to this mutex calling lock will block execution until the
* initial caller of lock has made a call to Unlock.
*
* If the owning process is terminated unexpectedly the mutex will be
* released.
**/
void Lock();
/**
* Unlock
* This will unlock the mutex. A single thread currently waiting on a lock
* call will resume execution and aquire ownership of the lock. No
* guarantees are made as to the order in which waiting threads will resume
* execution.
**/
void Unlock();
/**
* ShareToProcess
* This function is called to generate a serializable structure that can
* be sent to the specified process and opened on the other side.
*
* @returns A handle that can be shared to another process
*/
CrossProcessMutexHandle ShareToProcess(base::ProcessHandle aTarget);
private:
friend struct IPC::ParamTraits<CrossProcessMutex>;
CrossProcessMutex();
CrossProcessMutex(const CrossProcessMutex&);
CrossProcessMutex &operator=(const CrossProcessMutex&);
#ifdef XP_WIN
HANDLE mMutex;
#endif
};
typedef BaseAutoLock<CrossProcessMutex> CrossProcessMutexAutoLock;
typedef BaseAutoUnlock<CrossProcessMutex> CrossProcessMutexAutoUnlock;
}
#endif

View File

@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CrossProcessMutex.h"
#include "nsDebug.h"
namespace mozilla {
CrossProcessMutex::CrossProcessMutex(const char*)
{
NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform.");
}
CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle)
{
NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform.");
}
CrossProcessMutex::~CrossProcessMutex()
{
NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform - woah! We should've aborted by now!");
}
void
CrossProcessMutex::Lock()
{
NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform - woah! We should've aborted by now!");
}
void
CrossProcessMutex::Unlock()
{
NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform - woah! We should've aborted by now!");
}
CrossProcessMutexHandle
CrossProcessMutex::ShareToProcess(base::ProcessHandle aHandle)
{
NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform - woah! We should've aborted by now!");
return NULL;
}
}

View File

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <windows.h>
#include "base/process_util.h"
#include "CrossProcessMutex.h"
#include "nsDebug.h"
#include "nsTraceRefcnt.h"
using namespace base;
namespace mozilla {
CrossProcessMutex::CrossProcessMutex(const char*)
{
// We explicitly share this using DuplicateHandle, we do -not- want this to
// be inherited by child processes by default! So no security attributes are
// given.
mMutex = ::CreateMutexA(NULL, FALSE, NULL);
if (!mMutex) {
NS_RUNTIMEABORT("This shouldn't happen - failed to create mutex!");
}
MOZ_COUNT_CTOR(CrossProcessMutex);
}
CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle aHandle)
{
DWORD flags;
if (!::GetHandleInformation(aHandle, &flags)) {
NS_RUNTIMEABORT("Attempt to construct a mutex from an invalid handle!");
}
mMutex = aHandle;
}
CrossProcessMutex::~CrossProcessMutex()
{
NS_ASSERTION(mMutex, "Improper construction of mutex or double free.");
::CloseHandle(mMutex);
MOZ_COUNT_DTOR(CrossProcessMutex);
}
void
CrossProcessMutex::Lock()
{
NS_ASSERTION(mMutex, "Improper construction of mutex.");
::WaitForSingleObject(mMutex, INFINITE);
}
void
CrossProcessMutex::Unlock()
{
NS_ASSERTION(mMutex, "Improper construction of mutex.");
::ReleaseMutex(mMutex);
}
CrossProcessMutexHandle
CrossProcessMutex::ShareToProcess(ProcessHandle aHandle)
{
HANDLE newHandle;
bool succeeded = ::DuplicateHandle(GetCurrentProcessHandle(),
mMutex, aHandle, &newHandle,
NULL, FALSE, DUPLICATE_SAME_ACCESS);
if (!succeeded) {
return NULL;
}
return newHandle;
}
}

View File

@ -56,6 +56,7 @@ EXPORTS_IPC = IPCMessageUtils.h
EXPORTS_mozilla/ipc = \
AsyncChannel.h \
BrowserProcessSubThread.h \
CrossProcessMutex.h \
GeckoChildProcessHost.h \
IOThreadChild.h \
ProcessChild.h \
@ -111,12 +112,14 @@ CPPSRCS += \
SharedMemory_windows.cpp \
Transport_win.cpp \
WindowsMessageLoop.cpp \
CrossProcessMutex_windows.cpp \
$(NULL)
else
# POSIX
CPPSRCS += \
SharedMemory_posix.cpp \
Transport_posix.cpp \
CrossProcessMutex_unimplemented.cpp \
$(NULL)
endif #}

View File

@ -507,10 +507,12 @@ DumpHeap(JSContext *cx,
}
}
ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
ok = JS_DumpHeap(JS_GetRuntime(cx), dumpFile, startThing, startTraceKind, thingToFind,
maxDepth, thingToIgnore);
if (dumpFile != stdout)
fclose(dumpFile);
if (!ok)
JS_ReportOutOfMemory(cx);
return ok;
not_traceable_arg:

View File

@ -2835,7 +2835,7 @@ jsdService::DumpHeap(const nsACString &fileName)
rv = NS_ERROR_FAILURE;
} else {
JSContext *cx = JSD_GetDefaultJSContext (mCx);
if (!JS_DumpHeap(cx, file, NULL, JSTRACE_OBJECT, NULL, (size_t)-1, NULL))
if (!JS_DumpHeap(JS_GetRuntime(cx), file, NULL, JSTRACE_OBJECT, NULL, (size_t)-1, NULL))
rv = NS_ERROR_FAILURE;
if (file != stdout)
fclose(file);

View File

@ -1062,7 +1062,7 @@ class HashMap
*/
typedef typename Impl::Range Range;
Range all() const { return impl.all(); }
size_t count() const { return impl.count(); }
uint32_t count() const { return impl.count(); }
size_t capacity() const { return impl.capacity(); }
size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
return impl.sizeOfExcludingThis(mallocSizeOf);
@ -1272,7 +1272,7 @@ class HashSet
*/
typedef typename Impl::Range Range;
Range all() const { return impl.all(); }
size_t count() const { return impl.count(); }
uint32_t count() const { return impl.count(); }
size_t capacity() const { return impl.capacity(); }
size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
return impl.sizeOfExcludingThis(mallocSizeOf);

View File

@ -115,7 +115,7 @@ extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */
# define JS_OOM_POSSIBLY_FAIL() \
do \
{ \
if (OOM_counter++ >= OOM_maxAllocations) { \
if (++OOM_counter > OOM_maxAllocations) { \
return NULL; \
} \
} while (0)

View File

@ -3,8 +3,13 @@ dnl disabling frame pointers in this architecture based on the configure
dnl options
AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [
case "$target" in
*android*)
unwind_tables="-funwind-tables"
;;
esac
if test "$GNU_CC"; then
MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer"
MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer $unwind_tables"
MOZ_DISABLE_FRAME_PTR="-fomit-frame-pointer"
else
case "$target" in

View File

@ -42,6 +42,7 @@
#include "jscntxt.h"
#include "jsgcmark.h"
#include "jsiter.h"
#include "jsobj.h"
#include "vm/GlobalObject.h"
@ -62,7 +63,7 @@ InitClass(JSContext *cx, GlobalObject *global, Class *clasp, JSProtoKey key, Nat
proto->setPrivate(NULL);
JSAtom *atom = cx->runtime->atomState.classAtoms[key];
JSFunction *ctor = global->createConstructor(cx, construct, clasp, atom, 0);
JSFunction *ctor = global->createConstructor(cx, construct, clasp, atom, 1);
if (!ctor ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndBrand(cx, proto, NULL, methods) ||
@ -165,6 +166,7 @@ Class MapObject::class_ = {
};
JSFunctionSpec MapObject::methods[] = {
JS_FN("size", size, 0, 0),
JS_FN("get", get, 1, 0),
JS_FN("has", has, 1, 0),
JS_FN("set", set, 2, 0),
@ -201,6 +203,37 @@ MapObject::finalize(JSContext *cx, JSObject *obj)
cx->delete_(map);
}
class AddToMap {
private:
ValueMap *map;
public:
AddToMap(ValueMap *map) : map(map) {}
bool operator()(JSContext *cx, const Value &v) {
JSObject *pairobj = js_ValueToNonNullObject(cx, v);
if (!pairobj)
return false;
Value key;
if (!pairobj->getElement(cx, 0, &key))
return false;
HashableValue hkey;
if (!hkey.setValue(cx, key))
return false;
Value val;
if (!pairobj->getElement(cx, 1, &val))
return false;
if (!map->put(hkey, val)) {
js_ReportOutOfMemory(cx);
return false;
}
return true;
}
};
JSBool
MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
{
@ -209,11 +242,21 @@ MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
return false;
ValueMap *map = cx->new_<ValueMap>(cx->runtime);
if (!map || !map->init())
if (!map)
return false;
if (!map->init()) {
js_ReportOutOfMemory(cx);
return false;
}
obj->setPrivate(map);
CallArgsFromVp(argc, vp).rval().setObject(*obj);
CallArgs args = CallArgsFromVp(argc, vp);
if (args.hasDefined(0)) {
if (!ForOf(cx, args[0], AddToMap(map)))
return false;
}
args.rval().setObject(*obj);
return true;
}
@ -240,6 +283,15 @@ MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
if (args.length() > 0 && !key.setValue(cx, args[0])) \
return false
JSBool
MapObject::size(JSContext *cx, unsigned argc, Value *vp)
{
THIS_MAP(get, cx, argc, vp, args, map);
JS_STATIC_ASSERT(sizeof map.count() <= sizeof(uint32_t));
args.rval().setNumber(map.count());
return true;
}
JSBool
MapObject::get(JSContext *cx, unsigned argc, Value *vp)
{
@ -267,7 +319,10 @@ MapObject::set(JSContext *cx, unsigned argc, Value *vp)
{
THIS_MAP(set, cx, argc, vp, args, map);
ARG0_KEY(cx, args, key);
map.put(key, args.length() > 1 ? args[1] : UndefinedValue());
if (!map.put(key, args.length() > 1 ? args[1] : UndefinedValue())) {
js_ReportOutOfMemory(cx);
return false;
}
args.rval().setUndefined();
return true;
}
@ -314,6 +369,7 @@ Class SetObject::class_ = {
};
JSFunctionSpec SetObject::methods[] = {
JS_FN("size", size, 0, 0),
JS_FN("has", has, 1, 0),
JS_FN("add", add, 1, 0),
JS_FN("delete", delete_, 1, 0),
@ -348,6 +404,25 @@ SetObject::finalize(JSContext *cx, JSObject *obj)
cx->delete_(set);
}
class AddToSet {
private:
ValueSet *set;
public:
AddToSet(ValueSet *set) : set(set) {}
bool operator()(JSContext *cx, const Value &v) {
HashableValue key;
if (!key.setValue(cx, v))
return false;
if (!set->put(key)) {
js_ReportOutOfMemory(cx);
return false;
}
return true;
}
};
JSBool
SetObject::construct(JSContext *cx, unsigned argc, Value *vp)
{
@ -356,17 +431,36 @@ SetObject::construct(JSContext *cx, unsigned argc, Value *vp)
return false;
ValueSet *set = cx->new_<ValueSet>(cx->runtime);
if (!set || !set->init())
if (!set)
return false;
if (!set->init()) {
js_ReportOutOfMemory(cx);
return false;
}
obj->setPrivate(set);
CallArgsFromVp(argc, vp).rval().setObject(*obj);
CallArgs args = CallArgsFromVp(argc, vp);
if (args.hasDefined(0)) {
if (!ForOf(cx, args[0], AddToSet(set)))
return false;
}
args.rval().setObject(*obj);
return true;
}
#define THIS_SET(native, cx, argc, vp, args, set) \
UNPACK_THIS(SetObject, native, cx, argc, vp, args, set)
JSBool
SetObject::size(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SET(has, cx, argc, vp, args, set);
JS_STATIC_ASSERT(sizeof set.count() <= sizeof(uint32_t));
args.rval().setNumber(set.count());
return true;
}
JSBool
SetObject::has(JSContext *cx, unsigned argc, Value *vp)
{
@ -381,8 +475,10 @@ SetObject::add(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SET(add, cx, argc, vp, args, set);
ARG0_KEY(cx, args, key);
if (!set.put(key))
if (!set.put(key)) {
js_ReportOutOfMemory(cx);
return false;
}
args.rval().setUndefined();
return true;
}

View File

@ -89,6 +89,7 @@ class MapObject : public JSObject {
static void mark(JSTracer *trc, JSObject *obj);
static void finalize(JSContext *cx, JSObject *obj);
static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
static JSBool size(JSContext *cx, unsigned argc, Value *vp);
static JSBool get(JSContext *cx, unsigned argc, Value *vp);
static JSBool has(JSContext *cx, unsigned argc, Value *vp);
static JSBool set(JSContext *cx, unsigned argc, Value *vp);
@ -106,6 +107,7 @@ class SetObject : public JSObject {
static void mark(JSTracer *trc, JSObject *obj);
static void finalize(JSContext *cx, JSObject *obj);
static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
static JSBool size(JSContext *cx, unsigned argc, Value *vp);
static JSBool has(JSContext *cx, unsigned argc, Value *vp);
static JSBool add(JSContext *cx, unsigned argc, Value *vp);
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);

View File

@ -244,7 +244,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
*/
JSObject &sourceObj = sourceValue.toObject();
if (args.length() >= 2 && !args[1].isUndefined()) {
if (args.hasDefined(1)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
return false;
}
@ -293,7 +293,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
}
RegExpFlag flags = RegExpFlag(0);
if (args.length() > 1 && !args[1].isUndefined()) {
if (args.hasDefined(1)) {
JSString *flagStr = ToString(cx, args[1]);
if (!flagStr)
return false;
@ -343,8 +343,9 @@ regexp_construct(JSContext *cx, unsigned argc, Value *vp)
* Otherwise, delegate to the standard constructor.
* See ECMAv5 15.10.3.1.
*/
if (args.length() >= 1 && IsObjectWithClass(args[0], ESClass_RegExp, cx) &&
(args.length() == 1 || args[1].isUndefined()))
if (args.hasDefined(0) &&
IsObjectWithClass(args[0], ESClass_RegExp, cx) &&
!args.hasDefined(1))
{
args.rval() = args[0];
return true;

View File

@ -913,6 +913,7 @@ sechash.h
secoidt.h
certdb.h
secerr.h
nssutil.h
nssb64.h
secasn1.h
secder.h

View File

@ -0,0 +1,14 @@
(function() {
for (var i = 0; i < 64; ++i) {
var name;
switch (this) {
case 0: name = 'firstAttr'; break;
case 1: name = 'secondAttr';
case 2: name = 'thirdAttr'; break;
}
switch (name) {
case 'firstAttr': assertEq(result, 'value'); break;
}
}
})();

View File

@ -0,0 +1,6 @@
gczeal(2,1);
var count = 0;
var a = {__noSuchMethod__: function() { count++; } }
for (var i = 0; i < 10; i++) {
a.b();
}

View File

@ -0,0 +1,6 @@
// The Map constructor creates an empty Map by default.
assertEq(Map().size(), 0);
assertEq((new Map).size(), 0);
assertEq(Map(undefined).size(), 0);
assertEq(new Map(undefined).size(), 0);

View File

@ -0,0 +1,6 @@
// The Map constructor can take an argument that is an array of pairs.
var arr = [["zero", 0], ["one", 1], ["two", 2]];
var m = Map(arr);
for (var [k, v] of arr)
assertEq(m.get(k), v);

View File

@ -0,0 +1,9 @@
// Map can take an argument that is an array of singleton arrays.
var arr = [["a"], ["b"], ["c"]];
var m = Map(arr);
assertEq(m.size(), 3);
for (var [k, _] of arr) {
assertEq(m.has(k), true);
assertEq(m.get(k), undefined);
}

View File

@ -0,0 +1,6 @@
// Map(x) throws if x is not iterable (unless x is undefined).
load(libdir + "asserts.js");
var nonIterables = [null, true, 1, -0, 3.14, NaN, "", "xyzzy", {}, Math, this];
for (let k of nonIterables)
assertThrowsInstanceOf(function () { Map(k); }, TypeError);

View File

@ -0,0 +1,7 @@
// Map(arr) throws if arr contains holes (or undefined values).
load(libdir + "asserts.js");
assertThrowsInstanceOf(function () { Map([undefined]); }, TypeError);
assertThrowsInstanceOf(function () { Map([null]); }, TypeError);
assertThrowsInstanceOf(function () { Map([[0, 0], [1, 1], , [3, 3]]); }, TypeError);
assertThrowsInstanceOf(function () { Map([[0, 0], [1, 1], ,]); }, TypeError);

View File

@ -0,0 +1,8 @@
// When the argument to Map contains a key multiple times, the last value is retained.
var arg = [["zero", 7], ["one", 1], ["two", 4], ["zero", 8], ["two", 2], ["zero", 0]];
var m = Map(arg);
assertEq(m.get("zero"), 0);
assertEq(m.get("one"), 1);
assertEq(m.get("two"), 2);
assertEq(m.size(), 3);

View File

@ -0,0 +1,19 @@
// The argument to Map can be a generator.
var done = false;
function data(n) {
var s = '';
for (var i = 0; i < n; i++) {
yield [s, i];
s += '.';
}
done = true;
}
var m = Map(data(50));
assertEq(done, true); // the constructor consumes the argument
assertEq(m.size(), 50);
assertEq(m.get(""), 0);
assertEq(m.get("....."), 5);
assertEq(m.get(Array(49+1).join(".")), 49);
assertEq(m.has(undefined), false);

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